Trace uma barra usando matplotlib usando um dicionário

92

Existe alguma maneira de plotar um gráfico de barra matplotlibusando dados diretamente de um dicionário?

Meu dict se parece com este:

D = {u'Label1':26, u'Label2': 17, u'Label3':30}

eu estava esperando

fig = plt.figure(figsize=(5.5,3),dpi=300)
ax = fig.add_subplot(111)
bar = ax.bar(D,range(1,len(D)+1,1),0.5)

funcionar, mas não funciona.

Aqui está o erro:

>>> ax.bar(D,range(1,len(D)+1,1),0.5)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python2.7/site-packages/matplotlib/axes.py", line 4904, in bar
    self.add_patch(r)
  File "/usr/local/lib/python2.7/site-packages/matplotlib/axes.py", line 1570, in add_patch
    self._update_patch_limits(p)
  File "/usr/local/lib/python2.7/site-packages/matplotlib/axes.py", line 1588, in _update_patch_limits
    xys = patch.get_patch_transform().transform(vertices)
  File "/usr/local/lib/python2.7/site-packages/matplotlib/patches.py", line 580, in get_patch_transform
    self._update_patch_transform()
  File "/usr/local/lib/python2.7/site-packages/matplotlib/patches.py", line 576, in _update_patch_transform
    bbox = transforms.Bbox.from_bounds(x, y, width, height)
  File "/usr/local/lib/python2.7/site-packages/matplotlib/transforms.py", line 786, in from_bounds
    return Bbox.from_extents(x0, y0, x0 + width, y0 + height)
TypeError: coercing to Unicode: need string or buffer, float found
Otmezger
fonte
Você pode compartilhar especificamente o que não funciona? Você consegue uma exceção? Que exceção? Compartilhe o máximo de informações possível.
Inbar Rose de
@InbarRose desculpe, eu atualizei a pergunta com o erro que mostra ... algo relacionado a string ou buffer ... Eu não entendo esta mensagem de erro.
otmezger
2
Não está claro o que você deseja alcançar, mas no ax.bar(D,range(1,len(D)+1,1),0.5)primeiro argumento deve haver uma lista de números, no seu caso D.values().
Adrianp de
2
Um one-liner não é possível para isso, pelo menos que eu saiba.
adrianp de
1
Você pode querer enviar uma solicitação de recurso ao site do github para isso, porque parece útil.
tacaswell

Respostas:

154

Você pode fazer isso em duas linhas, primeiro plotando o gráfico de barras e, em seguida, definindo os tiques apropriados:

import matplotlib.pyplot as plt

D = {u'Label1':26, u'Label2': 17, u'Label3':30}

plt.bar(range(len(D)), list(D.values()), align='center')
plt.xticks(range(len(D)), list(D.keys()))
# # for python 2.x:
# plt.bar(range(len(D)), D.values(), align='center')  # python 2.x
# plt.xticks(range(len(D)), D.keys())  # in python 2.x

plt.show()

Observe que a penúltima linha deve ser lida plt.xticks(range(len(D)), list(D.keys()))em python3, porque D.keys()retorna um gerador, que matplotlib não pode usar diretamente.

David Zwicker
fonte
2
você pode, é claro, agrupar essas duas linhas em uma função e, em seguida, torna-se uma linha única;)
tacaswell
2
Se você usar objetos de figura e eixo, éax.set_xticklabels
Marcos
2
obrigado! Mas eu tenho alguns problemas estéticos com plt.xticks, você poderia nos dizer como movê-los verticalmente a partir da horizontal.
moldavo de
2
os pares de valores-chave estão alinhados quando o dicionário não é classificado?
ssm
2
Os dictos do Python não podem ser classificados. Conseqüentemente, a ordem é sempre arbitrária. No entanto, as chaves e valores estão sempre alinhados com o código acima.
David Zwicker
36

É um pouco mais simples do que a maioria das respostas aqui sugere:

import matplotlib.pyplot as plt

D = {u'Label1':26, u'Label2': 17, u'Label3':30}
plt.bar(*zip(*D.items()))
plt.show()

insira a descrição da imagem aqui

ImportanceOfBeingErnest
fonte
34

Para referência futura, o código acima não funciona com Python 3. Para Python 3, o D.keys()precisa ser convertido em uma lista.

import matplotlib.pyplot as plt

D = {u'Label1':26, u'Label2': 17, u'Label3':30}

plt.bar(range(len(D)), D.values(), align='center')
plt.xticks(range(len(D)), list(D.keys()))

plt.show()
Michael T
fonte
8

A melhor forma de implementá-lo é matplotlib.pyplot.bar(range, height, tick_label)onde o intervalo fornece valores escalares para o posicionamento da barra correspondente no gráfico. tick_labelfaz o mesmo trabalho que xticks(). Também se pode substituí-lo por um inteiro e usar vários plt.bar(integer, height, tick_label). Para obter informações detalhadas, consulte a documentação .

import matplotlib.pyplot as plt

data = {'apple': 67, 'mango': 60, 'lichi': 58}
names = list(data.keys())
values = list(data.values())

#tick_label does the some work as plt.xticks()
plt.bar(range(len(data)),values,tick_label=names)
plt.savefig('bar.png')
plt.show()

insira a descrição da imagem aqui

Além disso, o mesmo gráfico pode ser gerado sem o uso range(). Mas o problema encontrado foi que tick_labelfuncionou apenas para a última plt.bar()chamada. Portanto, xticks()foi usado para rotulagem:

data = {'apple': 67, 'mango': 60, 'lichi': 58}
names = list(data.keys())
values = list(data.values())
plt.bar(0,values[0],tick_label=names[0])
plt.bar(1,values[1],tick_label=names[1])
plt.bar(2,values[2],tick_label=names[2])
plt.xticks(range(0,3),names)
plt.savefig('fruit.png')
plt.show()

insira a descrição da imagem aqui

Swaraj Kumar
fonte
4

Costumo carregar o dicionário em um DataFrame do pandas e, em seguida, usar a função plot do DataFrame.
Aqui está o one-liner:

pandas.DataFrame(D, index=['quantity']).plot(kind='bar')

enredo resultante

Anilbey
fonte
3

Por que não apenas:

import seaborn as sns

sns.barplot(list(D.keys()), list(D.values()))
Rwilsker
fonte