'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 |