python: multiple barchart in subplot - python

In order to plot multiple barcharts I use the following code:
import numpy as np
import matplotlib.pyplot as plt
X = ['Group A','Group B','Group C','Group D']
Ygirls = [10,20,20,40]
Zboys = [20,30,25,30]
X_axis = np.arange(len(X))
plt.bar(X_axis - 0.2, Ygirls, 0.4, label = 'Girls')
plt.bar(X_axis + 0.2, Zboys, 0.4, label = 'Boys')
plt.xticks(X_axis, X)
plt.xlabel("Groups")
plt.ylabel("Number of Students")
plt.title("Number of Students in each group")
plt.legend()
plt.show()
getting this result:
I would like to plot two of these figures attached to eachother, using the same y axis.
For a normal bar chart the code would be:
fig, (ax1, ax2) = plt.subplots(1, 2, sharey=True)
fig.suptitle('Horizontally stacked subplots')
ax1.bar(, )
ax2.bar(, )
fig.subplots_adjust(wspace=0.0)
ax2.spines['left'].set_visible(False)
ax2.tick_params(axis='y', which='both', length=0)
How do I modify the code for the multiple bar charts?

What you want is a stacked bar dragram: you can view this example code here.
For your code, it would be like:
import numpy as np
import matplotlib.pyplot as plt
X = ['Group A','Group B','Group C','Group D']
Ygirls = [10,20,20,40]
Zboys = [20,30,25,30]
X_axis = np.arange(len(X))
fig, ax = plt.subplots()
ax.bar(X, Zboys, label = 'Boys')
ax.bar(X, Ygirls, label ='Grils', bottom=Zboys)
plt.xticks(X_axis, X)
plt.xlabel("Groups")
plt.ylabel("Number of Students")
plt.title("Number of Students in each group")
ax.legend()
plt.show()
And the output will be like:

Related

Python - Matplotlib not showing any axis labels on twin plot

I am unable to see any labels on this plot and I have specified labels for each axis. The same thing is happening with the x axis showing as 0,2,4, rather than 0,1,2,3,4 etc.
For reference - I am using this within my PySimpleGUI code:
import matplotlib.pyplot as plt
data1= [0,1,2,3,4,5,6,7,8,9]
data2= [10,20,30,40,50,60,70,133,121,123]
data3=[100,324,121,432,232,543,332,543,534,122]
data4=[100,312,111,111,322,443,545,122,345,122]
#plt.style.use('dark_background')
title="my graph"
plt.figure(figsize=(8,5))
plt.style.use('ggplot')
plt.rcParams['axes.facecolor'] ='white'
plt.rcParams['font.size'] = '8'
plt.bar(data1,data2, color= 'blue' ,width=0.5,label="data2")
plt.twinx()
plt.plot(data1, data3, label="data 3 label")
plt.plot(data1, data4,label="data4",color='green')
plt.xlabel("my x axis label",fontsize =8)
plt.title(title,fontsize=8)
plt.tight_layout()
fig = plt.gcf()
print(fig)
Please could someone point me in the right direction?
Thank you
Some clean-up using the object-oriented interface:
plt.style.use('ggplot')
plt.rcParams['axes.facecolor'] ='white'
plt.rcParams['font.size'] = '8'
fig, ax = plt.subplots(figsize=(8, 5))
ax.bar(data1,data2, color= 'blue' ,width=0.5,label="data2")
ax2 = ax.twinx()
ax2.plot(data1, data3, label="data 3 label")
ax2.plot(data1, data4,label="data4",color='green')
ax.set_xlabel("my x axis label",fontsize =8)
ax.set_xticks(data1)
ax.set_title(title,fontsize=8)
fig.tight_layout()
Output:
Perhaps better to use MultipleLocator for the tick positions (credit for the idea to #JohanC):
from matplotlib.ticker import MultipleLocator
...
ax.xaxis.set_major_locator(MultipleLocator(1))
Try using plt.axes() to separate it, as shown
import matplotlib.pyplot as plt
data1= [0,1,2,3,4,5,6,7,8,9]
data2= [10,20,30,40,50,60,70,133,121,123]
data3=[100,324,121,432,232,543,332,543,534,122]
data4=[100,312,111,111,322,443,545,122,345,122]
#plt.style.use('dark_background')
title="my graph"
plt.figure(figsize=(8,5))
plt.style.use('ggplot')
plt.rcParams['axes.facecolor'] ='white'
plt.rcParams['font.size'] = '8'
ax = plt.axes()
ax.bar(data1,data2, color= 'blue' ,width=0.5,label="data2")
ax2 = plt.twinx()
ax2.plot(data1, data3, label="data 3 label")
ax2.plot(data1, data4,label="data4",color='green')
ax2.set_xlabel("my x axis label",fontsize =8)
plt.title(title,fontsize=8)
plt.tight_layout()
fig = plt.gcf()
print(fig)

Plotting difficulty combining 3 variables and repositioning the legends in matplotlib

I have data where I have names, proportions and total. I want to show all 3 variables in one plot. Ideally I want to have everything like plot 1 but inside I want to show total as in plot 2
In first plot I don't get line right also this is not my plot of choice.
import pandas as pd
from matplotlib import pyplot as plt
import seaborn as sns
df = pd.DataFrame({"name": list("ABCDEFGHIJ"), "proportion": [0.747223, 0.785883, 0.735542, 0.817368, 0.565193, 0.723029, 0.723004, 0.722595, 0.783929, 0.55152],
"total": [694327, 309681, 239384, 201646, 192267, 189399, 181974, 163483, 157902, 153610]})
fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
sns.barplot(data=df, x="name", y="total", color="lightblue", ax=ax1)
sns.lineplot(data=df, x="name", y= "proportion", color="black", lw=3, ls="--", ax=ax2)
# Plot the figure.
df["male"] = df.proportion * df.total
ax = sns.barplot(data = df, x= "name", y = 'total', color = "lightblue")
sns.barplot(data = df, x="name", y = "male", color = "blue", ax = ax)
ax.set_ylabel("male/no_of_streams")
Is there a way I can achieve my goal of effective plot where
I can show total split
I also want to add proportions values to plot as well
Any help would be appreciated
Thanks in advance
If my understanding is right, for the first plot, I guess you wanna to know why the line is dashed. Just remove argument ls="--", you will get solid line.
The second, following code can work, if you want percentage of "man-number" / "total". If the percentage is computed using other numbers, you can adjust the equation in the for statement:
import pandas as pd
from matplotlib import pyplot as plt
import seaborn as sns
if __name__ == '__main__':
df = pd.DataFrame({"name": list("ABCDEFGHIJ"), "proportion": [0.747223, 0.785883, 0.735542, 0.817368, 0.565193, 0.723029, 0.723004, 0.722595, 0.783929, 0.55152], "total": [694327, 309681, 239384, 201646, 192267, 189399, 181974, 163483, 157902, 153610]})
# fig, ax1 = plt.subplots()
# ax2 = ax1.twinx()
# sns.barplot(data=df, x="name", y="total", color="lightblue", ax=ax1)
# # remove ls='--'
# sns.lineplot(data=df, x="name", y="proportion", color="black", lw=3, ax=ax2)
# Plot the figure.
df["male"] = df.proportion * df.total
ax = sns.barplot(data = df, x= "name", y = 'total', color = "lightblue")
sns.barplot(data = df, x="name", y = "male", color = "blue", ax = ax)
ax.set_ylabel("proportion(male/no_of_streams)")
# this is code block to add percentage
for i, v in enumerate(df['proportion']):
p = ax.patches[i]
height = p.get_height()
ax.text(p.get_x()+p.get_width()/2.,
height + 3,
'{:1.0f}%'.format(v * 100),
ha="center")
plt.show()
BTW, I learn at this page, FYI.

Add legend to pyplot.errorbar

import numpy as np
import matplotlib.pyplot as plt
# example data
x = np.arange(0.1, 4, 0.5)
y = np.exp(-x)
yerr = 0.1*np.random.rand(8)
fig, ax = plt.subplots()
ax.errorbar(x, y, linestyle='none', marker='*', yerr=yerr)
plt.show()
Hi, everyone! The goal is to add legend to the chart. y and yerr are labelled as 'mean' and 'std.Dev', respectively.

Merge matplotlib subplots with shared x-axis

I have two graphs to where both have the same x-axis, but with different y-axis scalings.
The plot with regular axes is the data with a trend line depicting a decay while the y semi-log scaling depicts the accuracy of the fit.
fig1 = plt.figure(figsize=(15,6))
ax1 = fig1.add_subplot(111)
# Plot of the decay model
ax1.plot(FreqTime1,DecayCount1, '.', color='mediumaquamarine')
# Plot of the optimized fit
ax1.plot(x1, y1M, '-k', label='Fitting Function: $f(t) = %.3f e^{%.3f\t} \
%+.3f$' % (aR1,kR1,bR1))
ax1.set_xlabel('Time (sec)')
ax1.set_ylabel('Count')
ax1.set_title('Run 1 of Cesium-137 Decay')
# Allows me to change scales
# ax1.set_yscale('log')
ax1.legend(bbox_to_anchor=(1.0, 1.0), prop={'size':15}, fancybox=True, shadow=True)
Now, i'm trying to figure out to implement both close together like the examples supplied by this link
http://matplotlib.org/examples/pylab_examples/subplots_demo.html
In particular, this one
When looking at the code for the example, i'm a bit confused on how to implant 3 things:
1) Scaling the axes differently
2) Keeping the figure size the same for the exponential decay graph but having a the line graph have a smaller y size and same x size.
For example:
3) Keeping the label of the function to appear in just only the decay graph.
Any help would be most appreciated.
Look at the code and comments in it:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import gridspec
# Simple data to display in various forms
x = np.linspace(0, 2 * np.pi, 400)
y = np.sin(x ** 2)
fig = plt.figure()
# set height ratios for subplots
gs = gridspec.GridSpec(2, 1, height_ratios=[2, 1])
# the first subplot
ax0 = plt.subplot(gs[0])
# log scale for axis Y of the first subplot
ax0.set_yscale("log")
line0, = ax0.plot(x, y, color='r')
# the second subplot
# shared axis X
ax1 = plt.subplot(gs[1], sharex = ax0)
line1, = ax1.plot(x, y, color='b', linestyle='--')
plt.setp(ax0.get_xticklabels(), visible=False)
# remove last tick label for the second subplot
yticks = ax1.yaxis.get_major_ticks()
yticks[-1].label1.set_visible(False)
# put legend on first subplot
ax0.legend((line0, line1), ('red line', 'blue line'), loc='lower left')
# remove vertical gap between subplots
plt.subplots_adjust(hspace=.0)
plt.show()
Here is my solution:
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 2 * np.pi, 400)
y = np.sin(x ** 2)
fig, (ax1,ax2) = plt.subplots(nrows=2, sharex=True, subplot_kw=dict(frameon=False)) # frameon=False removes frames
plt.subplots_adjust(hspace=.0)
ax1.grid()
ax2.grid()
ax1.plot(x, y, color='r')
ax2.plot(x, y, color='b', linestyle='--')
One more option is seaborn.FacetGrid but this requires Seaborn and Pandas libraries.
Here are some adaptions to show how the code could work to add a combined legend when plotting a pandas dataframe. ax=ax0 can be used to plot on a given ax and ax0.get_legend_handles_labels() gets the information for the legend.
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
dates = pd.date_range('20210101', periods=100, freq='D')
df0 = pd.DataFrame({'x': np.random.normal(0.1, 1, 100).cumsum(),
'y': np.random.normal(0.3, 1, 100).cumsum()}, index=dates)
df1 = pd.DataFrame({'z': np.random.normal(0.2, 1, 100).cumsum()}, index=dates)
fig, (ax0, ax1) = plt.subplots(nrows=2, sharex=True, gridspec_kw={'height_ratios': [2, 1], 'hspace': 0})
df0.plot(ax=ax0, color=['dodgerblue', 'crimson'], legend=False)
df1.plot(ax=ax1, color='limegreen', legend=False)
# put legend on first subplot
handles0, labels0 = ax0.get_legend_handles_labels()
handles1, labels1 = ax1.get_legend_handles_labels()
ax0.legend(handles=handles0 + handles1, labels=labels0 + labels1)
# remove last tick label for the second subplot
yticks = ax1.get_yticklabels()
yticks[-1].set_visible(False)
plt.tight_layout()
plt.show()

How to plot with x-axis at the top of the figure?

I would like to ask how to produce a plot similar to that in the figure below? Basically, how to have x-axis at the top of the figure. Thanks
Image from: http://oceanographyclay1987.blogspot.com/2010/10/light-attenuation-in-ocean.html
Use
ax.xaxis.set_ticks_position("top")
For example,
import numpy as np
import matplotlib.pyplot as plt
numdata = 100
t = np.linspace(0, 100, numdata)
y = 1/t**(1/2.0)
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.xaxis.set_ticks_position('top')
ax.yaxis.grid(linestyle = '-', color = 'gray')
ax.invert_yaxis()
ax.plot(t, y, 'g-', linewidth = 1.5)
plt.show()

Categories