I have a pyplot code.
Since I want to group multiple bars, I am trying to write text in the graph using plt.annotate.
However, as you can see in the picture, the word 'Something' in left bottom gets cropped. Does anyone know How I can fix this?
Here is my code
#!/usr/bin/python
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import operator as o
import numpy as np
n_groups = 5
means_men = (20, 35, 30, 35, 27)
std_men = (2, 3, 4, 1, 2)
means_women = (25, 32, 34, 20, 25)
std_women = (3, 5, 2, 3, 3)
fig, ax = plt.subplots()
index = np.arange(n_groups)
bar_width = 0.35
opacity = 0.4
error_config = {'ecolor': '0.3'}
rects1 = plt.bar(index, means_men, bar_width, alpha=opacity, color='b', yerr=std_men, error_kw=error_config, label='Men')
rects2 = plt.bar(index + bar_width, means_women, bar_width,
alpha=opacity,
color='r',
yerr=std_women,
error_kw=error_config,
label='Women')
#plt.xlabel('Group')
plt.ylabel('Scores')
plt.title('Scores by group and gender')
plt.annotate('Something', (0,0), (50,-40), xycoords = 'axes fraction', textcoords='offset points', va='top');
plt.annotate('Something', (0,0), (200,-20), xycoords = 'axes fraction', textcoords='offset points', va='top');
plt.xticks(index + bar_width, ('A', 'B', 'C', 'D', 'E'))
plt.legend()
plt.savefig('barchart_3.png')
For some reason, matplotlib sometimes clips too aggressively. If you add bbox_inches='tight' to save fig this should include the figure correctly,
plt.savefig('barchart_3.png', bbox_inches='tight')
More generally, you can adjust your main figure with something like,
plt.subplots_adjust(bottom=0.1)
Related
Assume that we are plotting bar plots in matplotlib.
When the values are in the same range we can see all bars.
However, when some values are too high we can not see the bars with very low values.
Is there a way to know which bars are shown (visible) or not after the call of ax.bar()
using its returned object of type class 'matplotlib.container.BarContainer'?
import numpy as np
import matplotlib.pyplot as plt
N = 5
# menMeans = (20, 35, 30, 35, 27) # All 5 bars are shown
menMeans = (20, 35000, 30, 35, 27) # Only 2nd bar is shown
menStd = (2, 3, 4, 1, 2)
ind = np.arange(N)
width = 0.35
fig = plt.figure()
ax = fig.add_subplot(111)
rects1 = ax.bar(ind, menMeans, width, color='royalblue', yerr=menStd)
ax.set_ylabel('Scores')
ax.set_title('Scores')
ax.set_xticks(ind)
ax.set_xticklabels( ('a1', 'a2', 'a3', 'a4', 'a5') )
plt.show()
These commands write that all bars are plotted.
However, they aren't shown in the final plot.
for i in rects1.patches:
print(i.get_height(),i.get_bbox(), i.get_visible())
I set a DataFrame like this.
import numpy as np
import matplotlib.pyplot as plt
midterm = np.random.randint(0, 100, size = (1,5))
finals = np.random.randint(0, 100, size = (1,5))
print(midterm)
print(finals)
Next I made some codes.
fig = plt.figure()
ax1 = fig.add_subplot(3, 1, 1)
ax2 = fig.add_subplot(3, 1, 2)
ax3 = fig.add_subplot(3, 1, 3)
labels = ['a', 'b', 'c', 'd', 'e']
width = 0.35
ax1.bar(labels, midterm, width, label='midterm')
ax.legend()
plt.subplots_adjust(hspace=0.1)
plt.show()
ax2.bar(labels, finals, width, label='finals')
ax2.legend()
plt.subplots_adjust(hspace=0.1)
plt.show()
My goal is combining ax1 with ax2 and printing in ax3, so I tried to do it.
ax3.bar(labels, midterm*0.4, width, label='midterm')
ax3.bar(labels, finals*0.6, width, bottom=midterm,
label='finals')
ax3.set_ylabel('Scores')
ax3.set_title('Scores by each term')
ax3.legend()
plt.show()
But the result didn't come out. What should I do?
Create your data as a pandasonic DataFrame:
midterm = np.random.randint(0, 100, size = 5)
finals = np.random.randint(0, 100, size = 5)
labels = ['a', 'b', 'c', 'd', 'e']
df = pd.DataFrame({'midterm': midterm, 'finals': finals}, index=labels)
Then, to print all 3 subplots, run:
fig = plt.figure(figsize=(6, 8))
ax1 = fig.add_subplot(3, 1, 1)
ax2 = fig.add_subplot(3, 1, 2)
ax3 = fig.add_subplot(3, 1, 3)
width = 0.5
df.midterm.plot.bar(width=width, ax=ax1, rot=0, legend=True)
df.finals.plot.bar(width=width, ax=ax2, rot=0, legend=True)
df.plot.bar(width=width, stacked=True, ax=ax3, rot=0)
plt.show()
Note added figsize, otherwise all subplots have very small height.
The result is:
I'm trying to create a barchart that keeps always a fixed distance between outer and inner position, regardless of the labels length. I would like to see bar and bar_long in the same position as bar_long and bar_perfect do. I've tried to work with axes.set_position(), but in vain. Thanks in advance for appreciated help!
import matplotlib.pyplot as plt
def createBar(figx, figy, labels):
fig, ax = plt.subplots(figsize=(figx, figy)
performance = [10, 70, 120]
ax.barh(labels, performance)
return fig
bar = createBar(2, 1, ('Tom', 'Dick', 'Fred'))
bar_long = createBar(2, 1, ('Tom Cruise', 'Dick & Doof', 'Fred Astaire'))
bar_perfect = createBar(2, 1, (' Tom', 'Dick', 'Fred'))
I would not call it a proper solution, and I feel a bit ashamed to even post it, but if you really need something working in the meanwhile...
import matplotlib.pyplot as plt
def createBar(figx, figy, labels):
fig, (ax0, ax) = plt.subplots(1, 2, figsize=(figx, figy),
gridspec_kw={'width_ratios': [1, 2]})
performance = [10, 70, 120]
ax.barh(labels, performance)
ax0.set_axis_off()
return fig
bar = createBar(3, 1, ('Tom', 'Dick', 'Fred'))
bar_long = createBar(3, 1, ('Tom Cruise', 'Dick & Doof', 'Fred Astaire'))
bar_perfect = createBar(3, 1, (' Tom', 'Dick', 'Fred'))
plt.show()
To get all plots the same, you need the same margins for all of them. So, you'll need to set them all to some fixed value. plt.subplots_adjust(...) does this. The numbers are fractions from 0 to 1, where 0 is the left bottom of the figure, and 1 the top right.
For your 2x1 example, the following would work:
import matplotlib.pyplot as plt
def createBar(figx, figy, labels):
fig, ax = plt.subplots(figsize=(figx, figy))
performance = [10, 70, 120]
ax.barh(labels, performance)
plt.subplots_adjust(left=0.4, right=0.95, top=0.97, bottom=0.25)
return fig
bar = createBar(2, 1, ('Tom', 'Dick', 'Fred'))
bar_long = createBar(2, 1, ('Tom Cruise', 'Dick & Doof', 'Fred Astaire'))
bar_perfect = createBar(2, 1, (' Tom', 'Dick', 'Fred'))
plt.show()
I would like to remove legends from individual subplots in panda. I created a bar chart and the #subplots. I would like to keep the titles of each subplot and remove the legends since they show the #same verbiage. I have tried several techniques, and even some that has me calling on each individual #subplot but am sure there is a simple solution. The fourth result image below is the one I need help with.
Here is my code so far:
import matplotlib.pyplot as plt
import pandas as pd
import scipy.stats as st
import numpy as np
mouse_metadata = "Mouse_metadata.csv"
study_results = "Study_results.csv"
mouse_metadata = pd.read_csv(mouse_metadata)
study_results = pd.read_csv(study_results)
study_data_combined = pd.merge(mouse_metadata,study_results, on= "Mouse ID")
pyma_sd = study_data_combined
pyma_sd.head()
pyma_sd_grouped = pyma_sd.groupby(["Drug Regimen"])
pyma_sd_grouped_mean = pyma_sd_grouped["Tumor Volume (mm3)"].mean()
pyma_sd_grouped_median = pyma_sd_grouped["Tumor Volume (mm3)"].median()
pyma_sd_grouped_variance = pyma_sd_grouped["Tumor Volume (mm3)"].var()
pyma_sd_grouped_std = pyma_sd_grouped["Tumor Volume (mm3)"].std()
pyma_sd_grouped_sem = pyma_sd_grouped["Tumor Volume (mm3)"].sem()
pyma_sd_grouped_stats = pd.DataFrame({ "Mean":pyma_sd_grouped_mean,
"Median": pyma_sd_grouped_median,
"Variance": pyma_sd_grouped_variance,
"Standard Error of Mean ": pyma_sd_grouped_sem})
print(" ","Stats of Tumor Volume")
print(pyma_sd_grouped_stats)
chart_pyma_sd_grouped_stats = pyma_sd_grouped_stats.plot(kind='bar', rot=50, figsize = (10, 6),
width = .8)
plt.title("Stats on Drug Regimen")Output 2
plt.xlabel("Drug Regimen")
plt.ylabel("Stats per Drug Regimen")
plt.tight_layout()
plt.show()
axes = pyma_sd_grouped_stats.plot.bar(rot=50, subplots=True, figsize = (10, 6), width = .75,)
axes[1].legend(loc=1)
plt.subplots_adjust(hspace=0.5)
plt.show()
**
Simply supply legend=False in your call to DataFrame.plot.bar.
import matplotlib.pyplot as plt
import pandas as pd
speed = [0.1, 17.5, 40, 48, 52, 69, 88]
lifespan = [2, 8, 70, 1.5, 25, 12, 28]
index = ['snail', 'pig', 'elephant', 'rabbit', 'giraffe', 'coyote', 'horse']
df = pd.DataFrame({'speed': speed, 'lifespan': lifespan}, index=index)
axes = df.plot.bar(rot=0, subplots=True, legend=False)
plt.show()
Compare the image above to the one generated in the doc.
I have been following the example provided in:
https://matplotlib.org/examples/api/barchart_demo.html
My problem is that I want to add edges to the bars. But when I set the
linewidth=1, edgecolor='black'
parameters, the edges are only applied to the first pair of bars, leaving the remaining pairs unchanged.
"""
========
Barchart
========
A bar plot with errorbars and height labels on individual bars
"""
import numpy as np
import matplotlib.pyplot as plt
N = 5
men_means = (20, 35, 30, 35, 27)
men_std = (2, 3, 4, 1, 2)
ind = np.arange(N) # the x locations for the groups
width = 0.35 # the width of the bars
fig, ax = plt.subplots()
rects1 = ax.bar(ind, men_means, width, color='r', yerr=men_std,linewidth=1, edgecolor='black')
women_means = (25, 32, 34, 20, 25)
women_std = (3, 5, 2, 3, 3)
rects2 = ax.bar(ind + width, women_means, width, color='y', yerr=women_std, linewidth=1, edgecolor='black')
# 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 / 2)
ax.set_xticklabels(('G1', 'G2', 'G3', 'G4', 'G5'))
ax.legend((rects1[0], rects2[0]), ('Men', 'Women'))
def autolabel(rects):
"""
Attach a text label above each bar displaying its height
"""
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)
plt.show()
Thanks for your help.
David.