134

Is there any way to plot a bar plot using matplotlib using data directly from a dict?

My dict looks like this:

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

I was expecting

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)

to work, but it does not.

Here is the error:

>>> 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
martineau
  • 119,623
  • 25
  • 170
  • 301
otmezger
  • 10,410
  • 21
  • 64
  • 90
  • Can you share specifically what does not work? Do you get an exception? What exception? Share as much information as possible. – Inbar Rose Apr 15 '13 at 08:38
  • @InbarRose sorry, I have updated the question with the error it shows... something concerning string or buffer... I don't understand this error message. – otmezger Apr 15 '13 at 08:40
  • 2
    It's not clear what you want to achieve, but in `ax.bar(D,range(1,len(D)+1,1),0.5)` the first argument should be a list of numbers, in your case `D.values()`. – adrianp Apr 15 '13 at 08:43
  • @adrianp I know it can't work... but what I tried to do is to just plot a bar chart with one line, giving it the strings and values at once. I tough maybe there is a way to add data and labels at the same time... but `D.values()` was also new for me and it's pretty cool. – otmezger Apr 15 '13 at 08:47
  • 2
    A one-liner is not possible for this, at least to my knowledge. – adrianp Apr 15 '13 at 09:03
  • 1
    You might want to submit a feature request to the github site for this, because it does seem useful. – tacaswell Apr 15 '13 at 16:05
  • Usefull or not, it seems "natural" :-) – otmezger Apr 15 '13 at 19:35

7 Answers7

205

You can do it in two lines by first plotting the bar chart and then setting the appropriate ticks:

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

Note that the penultimate line should read plt.xticks(range(len(D)), list(D.keys())) in python3, because D.keys() returns a generator, which matplotlib cannot use directly.

Engineero
  • 12,340
  • 5
  • 53
  • 75
David Zwicker
  • 23,581
  • 6
  • 62
  • 77
  • 2
    you can of course wrap those two lines up in a function and then it becomes a one-liner ;) – tacaswell Apr 15 '13 at 16:04
  • 3
    If you use figure and axes objects, it's `ax.set_xticklabels` – Mark Jan 13 '14 at 05:41
  • 2
    thanks! But I have some estetic issues with plt.xticks, could you please tell us how to move them vertically from horizontally. – moldovean Mar 11 '14 at 14:58
  • I don't understand your question. Could you elaborate on what you mean by moving sticks vertically from horizontally? – David Zwicker Mar 11 '14 at 16:36
  • 2
    are the key-value pairs aligned when the dict is not sorted? – ssm Mar 18 '15 at 05:46
  • 3
    Python dicts cannot be sorted. Consequently, the order is always arbitrary. However, the keys and values are always aligned with the above code. – David Zwicker Mar 18 '15 at 18:03
  • Note that this does not work in python 3.x. You'd have to write something like `list(D.keys())`. See http://stackoverflow.com/questions/31755900/python-3-xs-dictionary-view-objects-and-matplotlib for further details. – j-i-l Jul 31 '15 at 22:49
  • (new to matplotlib) I seemed to have to do plt.hist(D) before the plt.show(). Am I doing something wrong? – David Jun 18 '16 at 06:01
  • To plot n columns, like this: d = { 'u1':26,56,n..., 'u2':34,45,...}, what I have to change in the script? – F.Lira Jan 25 '18 at 14:55
  • It's not clear what you want the plot to look like. Could you post an example image in a separate question? – David Zwicker Jan 25 '18 at 16:15
  • Using a dictionary is probably a bad idea, since the bars will always show up in a random order! – Mauricio Mar 12 '18 at 19:33
  • matplotlib can take `keys` as an arg now so can reduce to one line and simplify like: `plt.bar(D.keys(), D.values(), align='center')` – jedge Jan 12 '19 at 12:28
109

It's a little simpler than most answers here suggest:

import matplotlib.pyplot as plt

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

enter image description here

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
41

For future reference, the above code does not work with Python 3. For Python 3, the D.keys() needs to be converted to a 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()
Engineero
  • 12,340
  • 5
  • 53
  • 75
Michael T
  • 1,033
  • 9
  • 13
14

Why not just:

names, counts = zip(*D.items())
plt.bar(names, counts)

enter image description here

Hong Z
  • 192
  • 2
  • 5
11

The best way to implement it using matplotlib.pyplot.bar(range, height, tick_label) where the range provides scalar values for the positioning of the corresponding bar in the graph. tick_label does the same work as xticks(). One can replace it with an integer also and use multiple plt.bar(integer, height, tick_label). For detailed information please refer the documentation.

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

enter image description here

Additionally the same plot can be generated without using range(). But the problem encountered was that tick_label just worked for the last plt.bar() call. Hence xticks() was used for labelling:

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

enter image description here

Stephen Rauch
  • 47,830
  • 31
  • 106
  • 135
Swaraj Kumar
  • 323
  • 3
  • 6
7

I often load the dict into a pandas DataFrame then use the plot function of the DataFrame.
Here is the one-liner:

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

resulting plot

anilbey
  • 1,817
  • 4
  • 22
  • 38
6

Why not just:

import seaborn as sns

sns.barplot(list(D.keys()), list(D.values()))
Andronicus
  • 25,419
  • 17
  • 47
  • 88
rwilsker
  • 107
  • 1
  • 4