Matplotlib mutli-barchart plots - python

can someone please post an example for drawing to images on one plot, both of them are barcharts.
Every one should look like this one here :
http://matplotlib.org/examples/api/barchart_demo.html
The problem with this example, it doesn't tell how add another chart to it, and if, how to set the configurations of every one of them.

You should use fig=plt.figure() and after that add two subplots ax=fig.add_subplot(2,2,1) and ax2=fig.add_subplot(2,2,2). After that you can do everything with ax and ax2.
A modified example from your reference:
import numpy as np
import matplotlib.pyplot as plt
N = 5
menMeans = (20, 35, 30, 35, 27)
menStd = (2, 3, 4, 1, 2)
ind = np.arange(N) # the x locations for the groups
width = 0.35 # the width of the bars
fig = plt.figure()
ax = fig.add_subplot(2,2,1)
rects1 = ax.bar(ind, menMeans, width, color='r', yerr=menStd)
womenMeans = (25, 32, 34, 20, 25)
womenStd = (3, 5, 2, 3, 3)
rects2 = ax.bar(ind+width, womenMeans, width, color='y', yerr=womenStd)
# add some text for labels, title and axes ticks
ax.set_ylabel('Scores')
ax.set_title('Scores by group and gender')
ax.set_xticks(ind+width)
ax.set_xticklabels( ('G1', 'G2', 'G3', 'G4', 'G5') )
ax.legend( (rects1[0], rects2[0]), ('Men', 'Women') )
def autolabel(rects):
# attach some text labels
for rect in rects:
height = rect.get_height()
ax.text(rect.get_x()+rect.get_width()/2., 1.05*height, '%d'%int(height),
ha='center', va='bottom')
autolabel(rects1)
autolabel(rects2)
ax2 = fig.add_subplot(2,2,2)
rects3 = ax2.bar(ind, menMeans, width, color='r', yerr=menStd)
womenMeans = (20, 32, 34, 20, 25)
womenStd = (3, 7, 2, 3, 3)
rects4 = ax2.bar(ind+width, womenMeans, width, color='y', yerr=womenStd)
ax2.set_ylabel('Scores_2')
ax2.set_title('Scores by group and gender_2')
ax2.set_xticks(ind+width)
ax2.set_xticklabels( ('G1_2', 'G2_2', 'G3_2', 'G4_2', 'G5_2') )
ax2.legend( (rects1[0], rects2[0]), ('Men_2', 'Women_2') )
def autolabel(rects):
# attach some text labels
for rect in rects:
height = rect.get_height()
ax2.text(rect.get_x()+rect.get_width()/2., 1.05*height, '%d'%int(height),
ha='center', va='bottom')
autolabel(rects3)
autolabel(rects4)
plt.show()

Related

Can't get readable text on top of bars with 4 bars in Python's bar plot [duplicate]

This question already has answers here:
How to add value labels on a bar chart
(7 answers)
Closed last year.
I have the following code:
import matplotlib.pyplot as plt
import numpy as np
plt.style.use('ggplot')
def autolabel(rects):
"""Attach a text label above each bar in *rects*, displaying its height."""
for rect in rects:
height = int(rect.get_height())
ax.annotate('{}'.format(height),
xy=(rect.get_x() + rect.get_width() / 2, height),
xytext=(0, 3), # 3 points vertical offset
textcoords="offset points",
ha='center', va='bottom', fontsize=6)
data = [108, 140.9, 187, 237.6, 299.2, 360.9, 413.3, 431.9, 437.2, 441.9]
set1 = [140.973, 161.588, 202.391, 213.57, 408.55, 442.648, 491.883, 517.456, 534.018, 545.594]
set2 = [140.386, 156.932, 200.106, 213.789, 401.426, 440.09, 490.252, 516.478, 533.255, 545.232]
set3 = [141.046, 162.663, 202.05, 213.613, 408.678, 442.685, 491.894, 517.552, 534.028, 545.858]
stage = [1,2,3,4,5,6,7,8,9,10]
x = np.arange(len(stage)) # the label locations
y = [50, 100, 150, 200, 250, 300, 350, 400, 450, 500, 550, 600]
width = 0.20 # the width of the bars
fig, ax = plt.subplots()
rects1 = ax.bar(x - 3*width/2, data, width, color = "tab:gray", label='Data')
rects2 = ax.bar(x - width/2, set1, width, color = "tab:red", label='Set 1')
rects3 = ax.bar(x + width/2, set2, width, color = "tab:blue", label='Set 2')
rects4 = ax.bar(x + 3*width/2, set3, width, color = "tab:purple", label='Set 3')
ax.set_yticks(y)
ax.set_yticklabels(y, fontsize=10)
ax.set_ylim(0,580)
ax.set_xticks(x)
ax.set_xticklabels(stage, fontsize=10)
ax.legend(fontsize=8)
ax.grid(True)
autolabel(rects1)
autolabel(rects2)
autolabel(rects3)
autolabel(rects4)
fig.savefig("plot.png", dpi=300)
which gives me the following bar plot:
Bar Plot
Can anyone help me to plot this with readable text on top of all the bars? I tried increasing the width for more text visibility but then the bars at second point on the x-axis and so on are overlapped with previous bars.
matplotlib now has a method for adding labels to bars, bar_label. You can replace your custom function with that and add your options there. To make your labels fit, without reducing the size of the text further, you can rotate by 90 degrees e.g.
ax.bar_label(rects1, fmt="%d", fontsize=6, rotation=90, padding=3)

matplotlib - break in the y axis for multiple bar graph

I'm trying to create a break in the y axis for the plot below. I've tried using the brokenaxis method (but I end up being unable to have headings on my bars and things didn't look great) and from the documentation here, but I can't seem to get it working. I either end up creating two figures with the exact plot I want but with no data and the other figure exactly the same as before. Can somebody help me out? Thanks
from matplotlib import pyplot as plt
import numpy as np
from brokenaxes import brokenaxes
system_x = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
x_indexes = np.arange(len(system_x))
width = 0.2
fig, (ax) = plt.subplots()
cof_1 = [15, 0.0798, 0.0696, 0.0540, 0.0616, 0.0601, 0.0590]
cof_2 = [0.3856, 0.1428, 0.1803, 0.1694, 0.1172, 0.1913, 0.1474]
cof_3 = [1, 1, 2, 3, 1, 2, 2]
cof_4 = [0.0874, 0.0846, 0.0730, 0.1114, 0.0541, 0.0823, 0.0803]
r0 = ax.bar(x_indexes - 1.5*width, cof_1, label='1', color='crimson', width=width)
r1 = ax.bar(x_indexes - 0.5*width, cof_2, label='2', color='slategrey', width=width)
r2 = ax.bar(x_indexes + 0.5*width, cof_3,
label='3', color='yellowgreen', width=width)
r3 = ax.bar(x_indexes + 1.5*width, cof_4, label='3', color='orange', width=width)
def autolabel(rects):
for rect in rects:
height = rect.get_height()
ax.annotate('{}'.format(height),
xy=(rect.get_x() + rect.get_width() / 2, height),
xytext=(0, 3),
textcoords="offset points",
ha='center', va='bottom', rotation='vertical',
fontweight='bold')
autolabel(r0)
autolabel(r1)
autolabel(r2)
autolabel(r3)
plt.xticks(ticks=x_indexes, labels=system_x)
plt.xlabel('Test')
plt.ylabel('Test1')
plt.title('Mean Test')
axes = plt.gca()
axes.set_ylim([0, 10])
leg = plt.legend()
leg_lines = leg.get_lines()
leg_texts = leg.get_texts()
plt.setp(leg_lines, linewidth=4)
plt.grid(False)
plt.tight_layout()
plt.show()
Since your data are different scale, why don't you use log scale on y:
# modify auto label function
def autolabel(rects, vals):
for rect,val in zip(rects,vals):
height = rect.get_height()
ax.annotate('{}'.format(val),
xy=(rect.get_x() + rect.get_width() / 2, height),
xytext=(0, 3),
textcoords="offset points",
ha='center', va='bottom', rotation='vertical',
fontweight='bold')
autolabel(r0,cof_1)
autolabel(r1,cof_2)
autolabel(r2,cof_3)
autolabel(r3,cof_4)
# other codes
# ...
plt.xlabel('Test')
plt.ylabel('Test1')
plt.title('Mean Test')
plt.yscale('log')
# other codes
# ...
Output:
Also, consider plotting horizontal bars.

How to plot.bar base on other value than zero

Generally, the bar chart will show bottom on zero. which change the bottom, the bar move up or down.
import numpy as np
import matplotlib.pyplot as plt
N = 5
menMeans = (20, 35, 30, 35, 27)
ind = np.arange(N) # the x locations for the groups
width = 0.35 # the width of the bars: can also be len(x) sequence
p1 = plt.bar(ind, menMeans, width, bottom=0,color='#d62728')
plt.ylabel('Scores')
plt.title('Scores by group and gender')
plt.xticks(ind, ('G1', 'G2', 'G3', 'G4', 'G5'))
plt.yticks(np.arange(0, 81, 10))
plt.legend('Men')
plt.savefig('bar.png')
plt.show()
while I want isn't moving up or down. the following code show the bottom of zero.
I want to show the chart based on value such as 25. if the data,such as 20, then it shows 5 below the 25 in the chart.
You can convert menMeans to numpy and then subtract the bottom. Subtracting 25, the example array would be [-5, 10, 5, 10, 2].
The x-axis can be moved to that height via ax.spines['bottom'].set_position(('data', bottom)). Similarly, the other spines can be made invisible (ax.spines[...].set_color('none')).
plt.tick_params() can remove the tick marks by setting their length to 0.
ax.text(x, y, text) can be used to set a text at a given position. Newlines can help to get an adequate padding independent of the y-axis.
import numpy as np
import matplotlib.pyplot as plt
N = 5
menMeans = (20, 35, 30, 35, 27)
menMeans = np.array(menMeans)
ind = np.arange(N) # the x locations for the groups
width = 0.35 # the width of the bars: can also be len(x) sequence
bottom = 25
p1 = plt.bar(ind, menMeans-bottom, width, bottom=bottom, color='#d62728', label='Men')
plt.ylabel('Scores')
plt.title('Scores by group and gender')
plt.xticks(ind, ('G1', 'G2', 'G3', 'G4', 'G5'))
plt.yticks(np.arange(0, 81, 10))
plt.tick_params(axis='both', length=0)
ax = plt.gca()
ax.spines['left'].set_color('none')
ax.spines['right'].set_color('none')
ax.spines['bottom'].set_position(('data', bottom))
ax.spines['top'].set_color('none')
for i, mean in zip(ind, menMeans):
ax.text(i, mean, f'{mean}\n' if mean >= bottom else f'\n{mean}', ha='center', va='center')
plt.legend()
plt.savefig('bar.png')
plt.show()

Barplot python yticks in equal range despite value (pseudo logarithmic)

I'm trying to manipulate my y axis in a barplot. Say I have this code
import numpy as np
import matplotlib.pyplot as plt
N = 11
men_means = (-500,0,1,2,5,10,20,50,100,200,500)
men_std = (-500,0,1,2,5,10,20,50,100,200,500)
ind = np.arange(N) # the x locations for the groups
width = 0.25 # the width of the bars
fig, ax = plt.subplots()
rects1 = ax.bar(ind, men_means, width, color='r', yerr=men_std)
women_means = (-500,0,1,2,5,10,20,50,100,200,500)
women_std = (-500,0,1,2,5,10,20,50,100,200,500)
rects2 = ax.bar(ind + width, women_means, width, color='y', yerr=women_std)
ax.set_ylabel('Scores')
ax.set_title('Scores by group and gender')
ax.set_xticks(ind + width)
ax.set_xticklabels(('G1', 'G2', 'G3', 'G4', 'G5', 'G6', 'G7'))
ax.legend((rects1[0], rects2[0]), ('Men', 'Women'))
plt.show()
It will give me a y axis that is linear. Of course I could use 'symlog' to make the y-axis logarithmic (for my original data there are negative values as well) but what I really want is to have a 'pseudo logarithmic y axis', where the ticks are set to -500, -200, -100, -50, [..],0, 1, 2 ,5, 10, 20, [...], 500, but are equally distributed along the yaxis.
Can anyone help? :-)

How do I plot stacked histograms side by side in matplotlib?

I'm looking to plot two side-by-side stacked histograms (similar to the example image below) in matplotlib.
I've tried several variations on
bins = np.arange(10)
a1,b1,c1 =plt.hist([arr1,arr2,arr3],bins,stacked=True)
a2,b2,c2 =plt.hist([arr4,arr5,arr6],bins,stacked=True)
But can't seem to avoid getting the second plot to directly overlay the first.
Any ideas on how this could be resolved?
The picture shows a bar chart and not a histogram. I am pointing this out, not only because I am an obnoxious pedant, but also because I believe it could help you find the right tool :-)
Indeed, for your purpose plt.bar is probably a better pick than plt.hist.
Based on Scironic's suggestion, I modified this demonstration example to make stacked bars, like the ones on your figure.
Adding an offset to the position index (first argument in plt.bar()) is what prevents the bars from overlapping each other.
import numpy as np
import matplotlib.pyplot as plt
N = 5
men1 = (130, 90, 70, 64, 55)
men2 = (120, 85, 62, 50, 53)
men3 = (100, 70, 60, 45, 50)
ind = np.arange(N) + .15 # the x locations for the groups
width = 0.35 # the width of the bars
fig, ax = plt.subplots()
rects1 = ax.bar(ind, men1, width, color='g')
rects2 = ax.bar(ind, men2, width, color='r')
rects3 = ax.bar(ind, men3, width, color='b')
women4 = (140, 90, 78, 65, 50)
women5 = (130, 80, 70, 60, 45)
women6 = (120, 60, 60, 55, 44)
xtra_space = 0.05
rects2 = ax.bar(ind + width + xtra_space , women1, width, color='orange')
rects2 = ax.bar(ind + width + xtra_space, women2, width, color='cyan')
rects2 = ax.bar(ind + width + xtra_space, women3, width, color='purple')
# add some text for labels, title and axes ticks
ax.set_ylabel('Population, millions')
ax.set_title('Population: Age Structure')
ax.set_xticks(ind+width+xtra_space)
ax.set_xticklabels( ('USA', 'Brazil', 'Russia', 'Japan', 'Mexico') )
plt.show()

Categories