csssstdent
csssstdent

Reputation: 1

plotting 2 dictionaries in matplotlib

I have 2 dictionaries: dict1 = {'Beef':10, 'Poultry': 13, 'Pork': 14, 'Lamb': 11} and dict2 = {'Beef':3, 'Poultry': 1, 'Pork': 17, 'Lamb': 16}

I want to plot a double bar chart using the dictionary keys as the x-axis values, and the associated values on the y-axis. I am using matplotlib for this. does anyone have any information?

Upvotes: 0

Views: 130

Answers (2)

gboffi
gboffi

Reputation: 25023

I'd like to propose a more general approach: instead of just two dicts, what happens if we have a list of dictionaries?

In [89]: from random import randint, seed, shuffle
    ...: seed(20201213)
    ...: cats = 'a b c d e f g h i'.split() # categories
    ...: # List Of Dictionaries
    ...: lod = [{k:randint(5, 15) for k in shuffle(cats) or cats[:-2]} for _ in range(5)]
    ...: lod
Out[89]: 
[{'d': 14, 'h': 10, 'i': 13, 'f': 13, 'c': 5, 'b': 5, 'a': 14},
 {'h': 12, 'd': 5, 'c': 5, 'i': 11, 'b': 14, 'g': 8, 'e': 13},
 {'d': 8, 'a': 12, 'f': 7, 'h': 10, 'g': 10, 'c': 11, 'i': 12},
 {'g': 11, 'f': 8, 'i': 14, 'h': 11, 'a': 5, 'c': 7, 'b': 8},
 {'e': 11, 'h': 13, 'c': 5, 'i': 8, 'd': 12, 'a': 11, 'g': 11}]

As you can see, the keys are not ordered in the same way and the dictionaries do not contain all the possible keys...

Our first step is to find a list of keys (lok), using a set comprehension, followed by sorting the keys (yes, we already know the keys, but here we are looking for a general solution…)

In [90]: lok = sorted(set(k for d in lod for k in d))

The number of elements in the two lists are

In [91]: nk, nd = len(lok), len(lod)

At this point we can compute the width of a single bar, saying that the bar groups are 1 unit apart (hence x = range(nk)) and that we leave 1/3 unit between the groups, we have

In [92]: x, w = range(nk), 0.67/nd

We are ready to go with the plot

In [93]: import matplotlib.pyplot as plt
    ...: for n, d in enumerate(lod):
    ...:     plt.bar([ξ+n*w for ξ in x], [d.get(k, 0) for k in lok], w,
    ...:             label='dict %d'%(n+1))
    ...: plt.xticks([ξ+w*nd/2 for ξ in x], lok)
    ...: plt.legend();

a nice bar plot


Let's write a small function

def plot_lod(lod, ws=0.33, ax=None, legend=True):
    """bar plot from the values in a list of dictionaries.

    lod: list of dictionaries,
    ws: optional, white space between groups of bars as a fraction of unity,
    ax: optional, the Axes object to draw into,
    legend: are we going to draw a legend?

    Return: the Axes used to plot and a list of BarContainer objects."""

    from matplotlib.pyplot import subplot
    from numpy import arange, nan

    if ax is None : ax = subplot()

    lok = sorted({k for d in lod for k in d})
    nk, nd = len(lok), len(lod)
    x, w = arange(nk), (1.0-ws)/nd

    lobars = [
        ax.bar(x+n*w, [d.get(k, nan) for k in lok], w, label='%02d'%(n+1))
        for n, d in enumerate(lod)
        ]
    ax.set_xticks(x+w*nd/2-w/2)
    ax.set_xticklabels(lok)
    if legend : ax.legend()
    return ax, lobars

Using the data of the previous example, we get a slightly different graph…

a better graph, slightly different

Upvotes: 0

BenB
BenB

Reputation: 658

This part of the matplotlib documentation may what you are looking for. To plot your data, the x and y values need to be extracted from the dicts, for example via dict.keys() and dict.values().

import matplotlib.pyplot as plt
import numpy as np

dict1 = {'Beef':10, 'Poultry': 13, 'Pork': 14, 'Lamb': 11} 
dict2 = {'Beef':3, 'Poultry': 1, 'Pork': 17, 'Lamb': 16}

x = dict1.keys()
y1 = dict1.values()
y2 = dict2.values()

N = len(x)

fig, ax = plt.subplots()

ind = np.arange(N)    # the x locations for the groups
width = 0.35         # the width of the bars

p1 = ax.bar(ind, y1, width)
p2 = ax.bar(ind + width, y2, width) 

ax.set_xticks(ind + width / 2)
ax.set_xticklabels(x)

ax.legend((p1[0], p2[0]), ('dict1', 'dict2'))

plt.show()

Result:

enter image description here

Upvotes: 1

Related Questions