'plot barplot from nested dictionary using matplotlib

I have a nested dict that looks like this.

{A: {   'apples': 3,
        'bananas':5,
        'oranges':6,
        'kiwis':9},
B: {    'apples': 1,
        'bananas':9,
        'oranges':3,
        'kiwis':1},
C: {    'apples': 6,
        'bananas':9,
        'oranges':3,
        'kiwis':3}}

In my case A,B,C are months of the year for two years. x axis would be the months ie, A,B,C etc. Apples, bananas, kiwis and oranges are counts. I'd like to plot a grouped vertical bar chart using matplotlib. It would have a legend with three colors for apples, bananas and oranges.

I am only able to plot using dataframe.plot method:

pd.Dataframe(mydict).T.plot(kind=bar)

I want to be able to plot the same using matplotlib so I can manage figure size and change the size of the bars etc.

Any help is appreciated.

Thanks



Solution 1:[1]

Below is the sample code. Please let me know if you have any questions, i would be very happy to help you.

# libraries
import numpy as np
import matplotlib.pyplot as plt

# set width of bar
barWidth = 0.25

# set height of bar
bars1 = [12, 30, 1, 8, 22]
bars2 = [28, 6, 16, 5, 10]
bars3 = [29, 3, 24, 25, 17]

# Set position of bar on X axis
r1 = np.arange(len(bars1))
r2 = [x + barWidth for x in r1]
r3 = [x + barWidth for x in r2]

# Make the plot
plt.bar(r1, bars1, color='#ff0000', width=barWidth, edgecolor='red', label='Apples')
plt.bar(r2, bars2, color='#FFFF00', width=barWidth, edgecolor='yellow', label='bananas')
plt.bar(r3, bars3, color='#FFA500', width=barWidth, edgecolor='orange', label='oranges')

# Add xticks on the middle of the group bars
plt.xlabel('group', fontweight='bold')
plt.xticks([r + barWidth for r in range(len(bars1))], ['04/01/2019', '04/02/2019', '04/03/2019', '04/04/2019', '04/05/2019'])

# Create legend & Show graphic
plt.legend()
plt.show()

Solution 2:[2]

Firstly, you can manage figsize with the figsize argument or store the axes that are returned by the .plot method on the dataframe, so a pure matplotlib solution isn't the only way to go.

Having said that... The important takeaway for learning grouped bars in matplotlib is to have an offset. Each set of grouped bars (e.g. apple) needs to be offset from the xticks by a function of width (e.g. width * 2)

d = {"A": {...}, ...}

import matplotlib.pyplot as plt
import numpy as np

# Get the ax object and hardcode a bar width
fig, ax = plt.subplots()

width = 0.05

# Each set of bars (e.g. "bananas") is offset from the xtick so they're grouped
# For example np.arange(3) - width*2 for an offset of negative two bar widths 
ax.bar(np.arange(3) - width*2, [d[j]["apples"] for j in d], width)
ax.bar(np.arange(3) - width, [d[j]["bananas"] for j in d], width)
ax.bar(np.arange(3), [d[j]["oranges"] for j in d], width)
ax.bar(np.arange(3) + width, [d[j]["kiwis"] for j in d], width)

# Labels
ax.set_xticks(np.arange(3))
ax.set_xticklabels(["A", "B", "C"])

Solution 3:[3]

The documentation of pandas says that pandas.DataFrame.plot() returns a matplotlib.axes.Axes object. So, basically, you can handle it in the same way you will handle the plot aspects using matplotlib.

So, using your example:

# Import libraries 
import pandas as pd
import matplotlib.pyplot as plt

# Create dictionary
plot_dict = {'A': {'Apples': 3,'Bananas':5,'Oranges':6,'Kiwis':9}, 'B': {'Apples': 1,'Bananas':9,'Oranges':3,'Kiwis':1}, 'C': {'Apples': 6,'Bananas':9,'Oranges':3,'Kiwis':3}}

# Plot using pandas built-in function plot()
ax = pd.DataFrame(plot_dict).T.plot.bar(zorder=5)

# Define aspects of the plot using matplotlib
ax.set_ylabel("Quantity")
ax.set_xlabel("Category")
ax.grid(axis='y', color='black', linestyle='-', linewidth=0.3)
ax.legend(loc='lower center', bbox_to_anchor=(0.5, -0.25), ncol=4, edgecolor='1', fontsize=10)
ax.locator_params(axis='y', nbins=12)

plt.savefig(f'./plot_from_nested_dict.svg', bbox_inches='tight')

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Venkata Muttineni
Solution 2 Charles Landau
Solution 3 Juanca Oviedo