Create a stacked graph ** that corresponds to both the positive and negative directions as shown below.
Created and confirmed to work with Google Colab.
python version 3.6.9
numpy version 1.18.5
pandas version 1.1.2
matplotlib version 3.2.2
Allows Japanese to be used in matplotlib graphs.
python
!pip install japanize_matplotlib
Load the library.
python
%reset -f
import sys
import pandas as pd
import numpy as np
import japanize_matplotlib
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.patheffects as pe
pv = '.'.join([ str(v) for v in sys.version_info[:3] ])
print(f'python version {pv}')
print(f'numpy version {np.__version__}')
print(f'pandas version {pd.__version__}')
print(f'matplotlib version {matplotlib.__version__}')
Prepare sample data.
python
df = pd.DataFrame()
df['Classification']=['Middle school students','High school student','College student']
df['Agree']=[10,20,30]
df['If anything, I agree']=[45,50,45]
df['If anything opposite']=[30,20,20]
df['Opposition']=[15,10,5]
display(df)
For this data, "agree" and "somewhat agree" are piled up on the left side, and "somewhat disagree" and "disagree" are piled up on the right side.
python
def draw(df, y_column,x_columns,colors,x_range):
left_columns ,right_columns = x_columns
left_colors,right_colors = colors
#Create a 1-by-2 graph
fig,ax = plt.subplots(nrows=1, ncols=2, figsize=(6,3), facecolor='white',sharey='row',dpi=150)
#Erase the border
for a in ax:
for x in ['top','bottom','left','right']:
a.spines[x].set_visible(False)
a.tick_params(axis='y',left=False)
#Graph on the left
acc = np.zeros(len(df))
for colum,color in reversed(list(zip(left_columns ,left_colors))):
s = df[colum]
ax[0].barh(df[y_column],s,left=acc,color=color,label=colum)
for i in range(len(df)):
t = ax[0].text(acc[i]+s[i]/2,i,f'{s[i]}%', ha='center',va='center')
t.set_path_effects([pe.Stroke(linewidth=3, foreground='white'), pe.Normal()])
acc+=s
#Graph on the right
acc = np.zeros(len(df))
for colum,color in zip(right_columns,right_colors):
s = df[colum]
ax[1].barh(df[y_column],s,left=acc,color=color,label=colum)
for i in range(len(df)):
t = ax[1].text(acc[i]+s[i]/2,i,f'{s[i]}%', ha='center',va='center')
t.set_path_effects([pe.Stroke(linewidth=3, foreground='white'), pe.Normal()])
acc+=s
#Usage Guide
ha,la = ax[0].get_legend_handles_labels()
ax[0].legend(reversed(ha),reversed(la),bbox_to_anchor=(0.95, 1.05), loc='lower right',ncol=len(left_columns), borderaxespad=0,frameon=False)
ax[1].legend(bbox_to_anchor=(0.05, 1.05), loc='lower left',ncol=len(right_columns), borderaxespad=0,frameon=False)
#Draw a line in the center
ax[1].axvline(x=0,ymin=0,ymax=1,clip_on=False,color='black',lw=1)
ax[0].set_xlim(x_range[0],0) #The graph on the left flips the X axis
ax[1].set_xlim(0,x_range[1])
fig.subplots_adjust(wspace=0.0) #Set the distance between the left and right graphs to zero
plt.savefig('test.png')
plt.show()
#Create a graph with sample data
draw(df,'Classification',
[['Agree','どちらかと言えばAgree'],['If anything opposite','Opposition']],
[['tab:blue','tab:cyan'],['tab:pink','tab:red']],[80,80])
Recommended Posts