Wykreśl pasek za pomocą matplotlib za pomocą słownika

96

Czy istnieje sposób na wykreślenie wykresu słupkowego przy matplotlibużyciu danych bezpośrednio z dyktu?

Mój dykt wygląda tak:

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

Spodziewałem się

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)

do pracy, ale tak nie jest.

Oto błąd:

>>> 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
źródło
Czy możesz podzielić się konkretnie, co nie działa? Czy masz wyjątek? Jaki wyjątek? Udostępnij jak najwięcej informacji.
Inbar Rose
@InbarRose przepraszam, zaktualizowałem pytanie o błąd, który pokazuje ... coś dotyczy łańcucha lub bufora ... Nie rozumiem tego komunikatu o błędzie.
otmezger
2
Nie jest jasne, co chcesz osiągnąć, ale ax.bar(D,range(1,len(D)+1,1),0.5)w twoim przypadku w pierwszym argumencie powinna być lista liczb D.values().
adrianp
2
Jedna linijka nie jest do tego możliwa, przynajmniej o ile wiem.
adrianp
1
W tym celu możesz przesłać prośbę o dodanie funkcji do witryny github, ponieważ wydaje się to przydatne.
tacaswell

Odpowiedzi:

162

Możesz to zrobić w dwóch liniach, najpierw wykreślając wykres słupkowy, a następnie ustawiając odpowiednie tiki:

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()

Zauważ, że przedostatnia linia powinna czytać plt.xticks(range(len(D)), list(D.keys()))w python3, ponieważ D.keys()zwraca generator, którego matplotlib nie może używać bezpośrednio.

David Zwicker
źródło
2
możesz oczywiście zawinąć te dwie linie w funkcję, a wtedy stanie się to
jednolinijkowym
2
Jeśli użyjesz obiektów figur i osi, to jestax.set_xticklabels
Mark
2
dzięki! Ale mam pewne problemy estetyczne z plt.xticks, czy mógłbyś nam powiedzieć, jak przesuwać je w pionie w poziomie.
mołdawski
2
czy pary klucz-wartość są wyrównane, gdy dykt nie jest posortowany?
ssm
2
Nie można sortować nakazów Pythona. W konsekwencji kolejność jest zawsze dowolna. Jednak klucze i wartości są zawsze wyrównane z powyższym kodem.
David Zwicker
41

To trochę prostsze, niż sugeruje większość odpowiedzi:

import matplotlib.pyplot as plt

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

wprowadź opis obrazu tutaj

ImportanceOfBeingErnest
źródło
35

Na przyszłość, powyższy kod nie działa z Pythonem 3. W przypadku Pythona 3 D.keys()należy przekonwertować go na listę.

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.
źródło
8

Najlepszym sposobem na wdrożenie tego jest użycie, matplotlib.pyplot.bar(range, height, tick_label)gdzie zakres zawiera wartości skalarne do pozycjonowania odpowiedniego słupka na wykresie. tick_labeldziała tak samo jak xticks(). Można go również zastąpić liczbą całkowitą i użyć wielokrotności plt.bar(integer, height, tick_label). Szczegółowe informacje można znaleźć w dokumentacji .

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()

wprowadź opis obrazu tutaj

Dodatkowo ten sam wykres można wygenerować bez użycia range(). Ale napotkany problem polegał na tym, tick_labelże zadziałał w przypadku ostatniego plt.bar()połączenia. Stąd xticks()użyto do oznakowania:

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()

wprowadź opis obrazu tutaj

Swaraj Kumar
źródło
4

Często ładuję dyktafon do pandy DataFrame, a następnie używam funkcji wykresu DataFrame.
Oto jeden wiersz:

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

wynikowa fabuła

anilbey
źródło
4

Dlaczego nie tylko:

import seaborn as sns

sns.barplot(list(D.keys()), list(D.values()))
rwilsker
źródło