Which bars will be visible (shown) after matplotlib ax.bar() call? - matplotlib

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())

Related

Set real dimensione of a Chart in Matplotlib

I need to set the dimension of a chart exactly. I tried this, but the result is not what I expected (both if I set px and cm). In addiction, I would like to know how to export correctly the image.
import numpy as np
plt.rcParams['figure.dpi']=100
# create data
x = ['A', 'B', 'C', 'D']
y1 = np.array([10, 20, 10, 30])
y2 = np.array([20, 25, 15, 25])
y3 = np.array([12, 15, 19, 6])
y4 = np.array([10, 29, 13, 19])
# plot bars in stack manner
cm = 1/2.54 # centimeters in inches
px = 1/plt.rcParams['figure.dpi'] # pixel in inches
plt.figure(figsize=(800*px,1000*px))
plt.bar(x, y1, color='r')
plt.bar(x, y2, bottom=y1, color='b')
plt.bar(x, y3, bottom=y1+y2, color='y')
plt.bar(x, y4, bottom=y1+y2+y3, color='g')
plt.xlabel("Teams")
plt.ylabel("Score")
plt.legend(["Round 1", "Round 2", "Round 3", "Round 4"])
plt.title("Scores by Teams in 4 Rounds")
plt.show()
Dimensions expected: 800px x 1000 px, dpi= 100
I attach here a screenshot from Photoshop of the exported image
Not correct dimensions!
The Figure constructor accepts a tuple (numbers in inches) with a default of 80 dpi. You'll want to pass a dpi argument to change this
from matplotlib.figure import Figure
fig = Figure(figsize=(5, 4), dpi=80)
The above is 5 inches by 4 inches at 80dpi, which is 400px by 320px
if you want 800 by 1000 you can do
fig = Figure(figsize=(8, 10), dpi=100)
Exporting an image is as simple as
fig.savefig("MatPlotLib_Graph.png", dpi = 100)

Delete individual legends from subplots in panda

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.

Adding edges to bars in matplotlib

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.

How to set more margins

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)

Matplotlib: combining two bar charts

I'm trying to generate 'violin'-like bar charts, however i'm running in several difficulties described bellow...
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
# init data
label = ['aa', 'b', 'cc', 'd']
data1 = [5, 7, 6, 9]
data2 = [7, 3, 6, 1]
data1_minus = np.array(data1)*-1
gs = gridspec.GridSpec(1, 2, top=0.95, bottom=0.07,)
fig = plt.figure(figsize=(7.5, 4.0))
# adding left bar chart
ax1 = fig.add_subplot(gs[0])
ax1.barh(pos, data1_minus)
ax1.yaxis.tick_right()
ax1.yaxis.set_label(label)
# adding right bar chart
ax2 = fig.add_subplot(gs[1], sharey=ax1)
ax2.barh(pos, data2)
Trouble adding 'label' as labels for both charts to share.
Centering the labels between the both plots (as well as vertically in the center of each bar)
Keeping just the ticks on the outer yaxis (not inner, where the labels would go)
If I understand the question correctly, I believe these changes accomplish what you're looking for:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
# init data
label = ['aa', 'b', 'cc', 'd']
data1 = [5, 7, 6, 9]
data2 = [7, 3, 6, 1]
data1_minus = np.array(data1)*-1
gs = gridspec.GridSpec(1, 2, top=0.95, bottom=0.07,)
fig = plt.figure(figsize=(7.5, 4.0))
pos = np.arange(4)
# adding left bar chart
ax1 = fig.add_subplot(gs[0])
ax1.barh(pos, data1_minus, align='center')
# set tick positions and labels appropriately
ax1.yaxis.tick_right()
ax1.set_yticks(pos)
ax1.set_yticklabels(label)
ax1.tick_params(axis='y', pad=15)
# adding right bar chart
ax2 = fig.add_subplot(gs[1], sharey=ax1)
ax2.barh(pos, data2, align='center')
# turn off the second axis tick labels without disturbing the originals
[lbl.set_visible(False) for lbl in ax2.get_yticklabels()]
plt.show()
This yields this plot:
As for keeping the actual numerical ticks (if you want those), the normal matplotlib interface ties the ticks pretty closely together when the axes are shared (or twinned). However, the axes_grid1 toolkit can allow you more control, so if you want some numerical ticks you can replace the entire ax2 section above with the following:
from mpl_toolkits.axes_grid1 import host_subplot
ax2 = host_subplot(gs[1], sharey=ax1)
ax2.barh(pos, data2, align='center')
par = ax2.twin()
par.set_xticklabels('')
par.set_yticks(pos)
par.set_yticklabels([str(x) for x in pos])
[lbl.set_visible(False) for lbl in ax2.get_yticklabels()]
which yields: