I have found a code for creating stacked bar charts on https://matplotlib.org/3.1.1/gallery/lines_bars_and_markers/horizontal_barchart_distribution.html.
Problem is that decimal places are not shown in the graph. In the code i've found there are no decimals in the list, but if you change them to decimals there are not shown (see code below).
If tried to change str to float in ax.text(x, y, str(int(c)) line. That actually shows decimals, but all of them are 0.
many thanks.
import numpy as np
import matplotlib.pyplot as plt
category_names = ['Strongly disagree', 'Disagree','Neither agree nor
agree', 'agree', 'Strongly agree']
results = {
'Question 1': [(10), (14.99), (17.01), (32), (26)]
}
def survey(results, category_names):
labels = list(results.keys())
data = np.array(list(results.values()))
data_cum = data.cumsum(axis=1)
category_colors = plt.get_cmap('RdYlGn')(
np.linspace(0.15, 0.85, data.shape[1]))
fig, ax = plt.subplots(figsize=(9.2, 5))
ax.invert_yaxis()
ax.xaxis.set_visible(False)
ax.set_xlim(0, np.sum(data, axis=1).max())
for i, (colname, color) in enumerate(zip(category_names, category_colors)):
widths = data[:, i]
starts = data_cum[:, i] - widths
ax.barh(labels, widths, left=starts, height=0.5,
label=colname, color=color)
xcenters = starts + widths / 2
r, g, b, _ = color
text_color = 'white' if r * g * b < 0.5 else 'darkgrey'
for y, (x, c) in enumerate(zip(xcenters, widths)):
ax.text(x, y, str(int(c)), ha='center', va='center',
color=text_color)
ax.legend(ncol=len(category_names), bbox_to_anchor=(0, 1),
loc='lower left', fontsize='small')
return fig, ax
survey(results, category_names)
When you write str(int(c)), you first convert the number to integer, thereby dropping the decimals, and then convert that into a string. To get the desired output, either use str(c), or if you want to be able to control the format of the number better (such as choosing the number of digits after the decimal point) replace str(int(c)) by '{:.2f}'.format(c)
category_names = ['Strongly disagree', 'Disagree','Neither agree nor agree', 'agree', 'Strongly agree']
results = {
'Question 1': [(10), (14.99), (17.01), (32), (26)]
}
def survey(results, category_names):
labels = list(results.keys())
data = np.array(list(results.values()))
data_cum = data.cumsum(axis=1)
category_colors = plt.get_cmap('RdYlGn')(
np.linspace(0.15, 0.85, data.shape[1]))
fig, ax = plt.subplots(figsize=(9.2, 5))
ax.invert_yaxis()
ax.xaxis.set_visible(False)
ax.set_xlim(0, np.sum(data, axis=1).max())
for i, (colname, color) in enumerate(zip(category_names, category_colors)):
widths = data[:, i]
starts = data_cum[:, i] - widths
ax.barh(labels, widths, left=starts, height=0.5,
label=colname, color=color)
xcenters = starts + widths / 2
r, g, b, _ = color
text_color = 'white' if r * g * b < 0.5 else 'darkgrey'
for y, (x, c) in enumerate(zip(xcenters, widths)):
ax.text(x, y, '{:.2f}'.format(c), ha='center', va='center',
color=text_color)
ax.legend(ncol=len(category_names), bbox_to_anchor=(0, 1),
loc='lower left', fontsize='small')
return fig, ax
survey(results, category_names)
Related
I am creating a 2D matplotlib plot (i and j coordinates) which contains 10 subplots. Each subplot contains 150 by 150 grid cell data. How can I insert a small black-colored square mark (3 by 3 ) somewhere fixed (center at coordinates 62 and 62 ) on each generated heatmap sub-plot across those 10 sub-plots? The square mark would therefore contain 10 blocks from 60 to 64 in both x and y direction and contains a written text "Sale 1" centered at x 62 and y 62. My code below does not generate any patches. Any feedback is greatly appreciated.
from matplotlib.patches import Rectangle
import numpy as np
import matplotlib.pyplot as plt
from sklearn.metrics import r2_score, median_absolute_error
import os
import matplotlib.cm as cm
from mpl_toolkits import axes_grid1
import matplotlib.pyplot as plt
#import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
import matplotlib.colors
import matplotlib.colors as colors
data = np.random.rand(10, 150, 150)
data = data.reshape(-1, 1)
property = "Sale"
pmin = data.min()
pmax = data.max()
v = np.linspace(round(pmin,3), round(pmax,3),15, endpoint=True)
v = [round(x,3) for x in v]
fig, ax = plt.subplots(2, 5, figsize=(160, 80))
row_count = 0
col_count = 0
for i in range(10):
sub_plot_data = data[(i)*(150*150):(i+1)*150*150]
x = 150
y = 150
#--------------------------- Define the map boundary ----------------------
xmin = 1258096.6
xmax = 1291155.0
ymin = 11251941.6
ymax = 11285000.0
pmin = min(sub_plot_data)
pmax = max(sub_plot_data)
# --------------------------- define color bar for Discrete color
bounds = np.linspace(-1, 1, 10)
Discrete_colors = plt.get_cmap('jet')(np.linspace(0,1,len(bounds)+1))
# create colormap without the outmost colors
cmap = mcolors.ListedColormap(Discrete_colors[1:-1]) #
actual_2d = np.reshape(sub_plot_data,(y,x))
im1 = ax[row_count, col_count].imshow(actual_2d, interpolation=None, cmap=cmap,
extent=(xmin, xmax, ymin, ymax), vmin=pmin, vmax=pmax)
plt.text(actual_2d[62, 62], actual_2d[62, 62], '%s' % 'Sale_1',
horizontalalignment='center', verticalalignment='center', color= 'black', fontsize= 90)
ax[row_count, col_count].set_title("Sale_Stores-%s - L: %s"%(i+1, layer),
fontsize=130, pad=44, x=0.5, y=0.999) # new
ax[row_count, col_count].set_aspect('auto')
ax[row_count, col_count].tick_params(left=False, labelleft=False, top=False,
labeltop=False, right=False, labelright=False, bottom=False, labelbottom=False) # new
#ax[row_count, col_count] = plt.gca()
plt.gca().add_patch(Rectangle((60, 60), 3, 3, edgecolor='black',
facecolor='black',fill=True,lw=2))
ax[row_count, col_count].add_patch(plt.text(62, 62, '%s' % 'Sale_1',
horizontalalignment='center', verticalalignment='center', color= 'black', fontsize= 90))
col_count +=1
if col_count == 5:
row_count +=1
col_count =0
fig.tight_layout(h_pad=10)
plt.subplots_adjust(left=0.02,
bottom=0.1,
right=0.91,
top=0.8,
wspace=0.1,
hspace=0.2)
cbaxes = fig.add_axes([0.94, 0.05, 0.02, 0.8])
cbar = fig.colorbar(im1, ax=ax.ravel().tolist(), ticks=v, extend='both', cax =cbaxes)
cbar.ax.tick_params(labelsize=70)
#cbar.set_ticks(v)
cbar.ax.set_yticklabels([i for i in v], fontsize=120)
output_dir = r"D/test"
plot_dir = os.path.join(output_dir, reservoir_property)
if not os.path.exists(plot_dir):
os.makedirs(plot_dir)
fig.savefig(r"%s/per_allmodel.png"%(plot_dir))
I tried your code and made a couple of modifications: first, the graph size was too huge and caused errors, so I made it smaller; second, I simplified the subplots: axes has a list of subplot objects, so I took them out with axes.flat; third The second is modifying the text as annotations. The graph size has been reduced and the font size and spacing have been adjusted, so please modify it yourself. Finally, tick_params is not set since the color bar ticks are disabled.
fig, axes = plt.subplots(2, 5, figsize=(16, 8))
row_count = 0
col_count = 0
for i,ax in enumerate(axes.flat):
sub_plot_data = data[(i)*(150*150):(i+1)*150*150]
x = 150
y = 150
#--------------------------- Define the map boundary ----------------------
xmin = 1258096.6
xmax = 1291155.0
ymin = 11251941.6
ymax = 11285000.0
pmin = min(sub_plot_data)
pmax = max(sub_plot_data)
# --------------------------- define color bar for Discrete color
bounds = np.linspace(-1, 1, 10)
Discrete_colors = plt.get_cmap('jet')(np.linspace(0,1,len(bounds)+1))
# create colormap without the outmost colors
cmap = mcolors.ListedColormap(Discrete_colors[1:-1]) #
actual_2d = np.reshape(sub_plot_data,(y,x))
#im = ax.imshow(actual_2d, interpolation=None, cmap=cmap, extent=(xmin, xmax, ymin, ymax), vmin=pmin, vmax=pmax)
im = ax.imshow(actual_2d, interpolation=None, cmap=cmap)
ax.text(actual_2d[62, 62], actual_2d[62, 62]-10, '%s' % 'Sale_1',
horizontalalignment='center', verticalalignment='center', color= 'black', fontsize=18)
ax.set_title("Sale_Stores-%s - L: %s"%(i+1, 1), fontsize=14, pad=30, x=0.5, y=0.999)
ax.set_aspect('auto')
ax.add_patch(Rectangle((60, 60), 6, 6, edgecolor='red', facecolor='red', fill=True, lw=2))
ax.text(62, 62, '%s' % 'Sale_1', ha='center', va='center', color='black', fontsize=14)
fig.tight_layout(h_pad=10)
plt.subplots_adjust(left=0.02,
bottom=0.1,
right=0.91,
top=0.8,
wspace=0.1,
hspace=0.5)
cbaxes = fig.add_axes([0.94, 0.05, 0.02, 0.8])
cbar = fig.colorbar(im, ax=axes.flat, ticks=v, extend='both', cax=cbaxes)
cbar.ax.tick_params(labelsize=10)
#cbar.set_ticks(v)
cbar.ax.set_yticklabels([str(i) for i in v], fontsize=12)
#plt.tick_params(left=False, labelleft=False, top=False, labeltop=False, right=False, labelright=False, bottom=False, labelbottom=False)
plt.show()
If I have several curves on either side of the x-axis (like the green and orange curve in my case) what would be the best way to improve the display of this graph, for a better reading?
I was thinking for example by integrating a zoomed part on the curves between 0 and 0.15s on the x-axis.
Also each value of the curves correspond to a number, represented by a different marker (square, triangle, circle..) on the curves. Is there a better way to represent these curves and display these markers? In a slightly cleaner and more scientific way.
import matplotlib.pyplot as plt
A = [0.807, 0.633, 0.416, 0.274, 0.188]
time_A = [0.0990, 0.1021, 0.1097, 0.1109, 0.1321]
B = [0.764, 0.753, 0.716, 0.576, 0.516]
time_B = [0.1727, 0.1742, 0.1772, 0.1869, 0.1765]
C = [0.729, 0.719, 0.674, 0.631, 0.616]
time_C = [0.5295, 0.5368, 0.5431, 0.5391, 0.5443]
E = [0.709, 0.605, 0.390, 0.259, 0.155]
time_E = [0.0829, 0.0929, 0.0910, 0.0950, 0.0972]
D = [0.703, 0.541, 0.174, 0.062, 0.020]
time_D = [0.0740, 0.0792, 0.0819, 0.0837, 0.0858]
F = [0.748, 0.566, 0.366, 0.198, 0.168]
time_F = [0.0885, 0.0936, 0.09621, 0.0974, 0.0999]
markers = ["s", "^", "o", 'p', '*']
plt.plot(time_A, A, c='tab:blue',
label='A')
plt.plot(time_B, B, c='tab:red',
label='B')
plt.plot(time_C, C, c='tab:orange',
label='C')
plt.plot(time_D, D, c='tab:green',
label='D')
plt.plot(time_E, E, c='yellow',
label='E')
plt.plot(time_F, F, c='tab:cyan',
label='F')
for i in range(5):
plt.plot(time_A[i], A[i], c='tab:blue',
marker=markers[i], markersize=7)
plt.plot(time_B[i], B[i], c='tab:red',
marker=markers[i], markersize=7)
plt.plot(time_C[i], C[i], c='tab:orange',
marker=markers[i], markersize=7)
plt.plot(time_D[i], D[i], c='tab:green',
marker=markers[i], markersize=7)
plt.plot(time_E[i], E[i], c='yellow',
marker=markers[i], markersize=7)
plt.plot(time_F[i], F[i], c='tab:cyan',
marker=markers[i], markersize=7)
textstr = '\n'.join((
f'\u25A0 1',
f'\u25B2 2',
f'\u25CF 3',
f'\u2B1F 4',
f'\u2605 5'))
plt.text(0.4, 0.5, textstr,
verticalalignment='top', fontsize = 'small')
plt.legend(fontsize = 'small')
plt.xlabel('time (s)')
plt.ylabel('score')
plt.show()
Below is the result with the broken axis between 0.2 and 0.5 according to the comments. What is the correct way to integrate markers into curves with matplotlib?
Here are some ideas:
use a dummy line to add labels for the markers; use two columns for the legend
set a log scale on the x-axis, but with regular tick labels
connect the markers of the same style with a fine line (order the points left to right for the line not to cross itself)
use the color 'gold' instead of 'yellow' to make it better visible
write everything as much as possible using loops
import matplotlib.pyplot as plt
from matplotlib.ticker import NullFormatter, ScalarFormatter, FixedLocator
import numpy as np
A = [0.807, 0.633, 0.416, 0.274, 0.188]
time_A = [0.0990, 0.1021, 0.1097, 0.1109, 0.1321]
B = [0.764, 0.753, 0.716, 0.576, 0.516]
time_B = [0.1727, 0.1742, 0.1772, 0.1869, 0.1765]
C = [0.729, 0.719, 0.674, 0.631, 0.616]
time_C = [0.5295, 0.5368, 0.5431, 0.5391, 0.5443]
E = [0.709, 0.605, 0.390, 0.259, 0.155]
time_E = [0.0829, 0.0929, 0.0910, 0.0950, 0.0972]
D = [0.703, 0.541, 0.174, 0.062, 0.020]
time_D = [0.0740, 0.0792, 0.0819, 0.0837, 0.0858]
F = [0.748, 0.566, 0.366, 0.198, 0.168]
time_F = [0.0885, 0.0936, 0.09621, 0.0974, 0.0999]
names = ['A', 'B', 'C', 'D', 'E', 'F']
times = [time_A, time_B, time_C, time_D, time_E, time_F]
scores = [A, B, C, D, E, F]
markers = ["s", "^", "o", 'p', '*']
colors = ['tab:blue', 'tab:red', 'tab:orange', 'tab:green', 'gold', 'tab:cyan']
fig, ax = plt.subplots(figsize=(12, 5))
for time, score, name, color in zip(times, scores, names, colors):
ax.plot(time, score, c=color, label=name)
for i in range(len(scores[0])):
ax.plot([], [], color='black', ls='', marker=markers[i], markersize=7, label=i + 1)
for time, score, name, color in zip(times, scores, names, colors):
ax.plot(time[i], score[i], color=color, marker=markers[i], markersize=7)
time_i = np.array([time[i] for time in times])
score_i = np.array([score[i] for score in scores])
order = np.argsort(time_i)
ax.plot(time_i[order], score_i[order], color='grey', linestyle=':', linewidth=0.5, zorder=0)
ax.legend(fontsize='small', ncol=2)
ax.set_xscale('log')
xmin, xmax = ax.get_xlim()
ax.set_xticks(np.arange(0.1, round(xmax, 1), 0.1))
ax.set_xticks(np.arange(round(xmin, 2), round(xmax, 1), 0.01), minor=True)
ax.xaxis.set_major_formatter(ScalarFormatter())
ax.xaxis.set_minor_formatter(NullFormatter())
ax.set_xlabel('time (s)')
ax.set_ylabel('score')
plt.show()
If the values of the x-ticks are very important, the minor ticks could also get labels, for example:
minor_formatter = lambda x, pos: f'{x:.2f}' if (x < .1) or (x < .2 and round(100 * x) % 2 == 0) or (
x > .2 and round(100 * x) % 10 == 5) else ''
ax.xaxis.set_minor_formatter(minor_formatter)
ax.tick_params(axis='x', which='minor', size=6, labelcolor='grey')
ax.tick_params(axis='x', which='major', size=12)
I have a grouped bar chart and each bar is stacked.
I have annotated each section of the stack with its individual value and now I would like to sum those values and annotate the total value(height) of each bar. I would like this annotation to be on top of each bar.
This is one of the two dataframes I am working from:
df_title = pd.DataFrame(index=['F','M'],
data={'<10':[2.064897, 1.573255], '10-12':[3.933137, 4.326450], '13-17':[9.242871, 16.715831],
'18-24':[10.226155, 12.487709], '18-24':[8.161259, 10.717797], '35-44':[5.801377, 4.916421],
'45-54':[3.539823, 2.851524], '55+':[1.671583, 1.769912]})
I convert both dataframes (df_title and df_comps) into numpy arrays before plotting.
df_title_concat = np.concatenate((np.zeros((len,1)), df_title.T.values), axis=1)
Here is the full code:
df_title
df_comps
len = df_title.shape[1]
df_title_concat = np.concatenate((np.zeros((len,1)), df_title.T.values), axis=1)
df_comps_concat = np.concatenate((np.zeros((len,1)), df_comps.T.values), axis=1)
fig = plt.figure(figsize=(20,10))
ax = plt.subplot()
title_colors = ['skyblue', 'royalblue']
comps_colors = ['lightgoldenrodyellow', 'orange']
for i in range(1,3):
for j in list(range(0, df_title.shape[1]-1)):
j += 1
ax_1 = ax.bar(j, df_title_concat[j,i], width=-0.4, bottom=np.sum(df_title_concat[j,:i]), color = title_colors[i-1],
edgecolor='black', linewidth=3, align='edge')
for p in ax_1.patches:
width, height = p.get_width(), p.get_height()
x, y = p.get_xy()
if height > 2:
ax.annotate('{:.2f}%'.format(height), (p.get_x()+0.875*width, p.get_y()+.4*height),
fontsize=16, fontweight='bold', color='black')
ax_2 = ax.bar(j, df_comps_concat[j,i], width=0.4, bottom=np.sum(df_comps_concat[j,:i]), color = comps_colors[i-1],
edgecolor='black', linewidth=3, align='edge')
for p in ax_2.patches:
width, height = p.get_width(), p.get_height()
x, y = p.get_xy()
if height > 2:
ax.annotate('{:.2f}%'.format(height), (p.get_x()+0.15*width, p.get_y()+.4*height),
fontsize=16, fontweight='bold', color='black')
Here is a solution:
df_title = pd.DataFrame(index=['F','M'],
data={'<10':[2.064897, 1.573255], '10-12':[3.933137, 4.326450], '13-17':[9.242871, 16.715831],
'18-24':[10.226155, 12.487709], '18-24':[8.161259, 10.717797], '35-44':[5.801377, 4.916421],
'45-54':[3.539823, 2.851524], '55+':[1.671583, 1.769912]})
df_title_concat = np.concatenate((np.zeros((len(df_title),1)), df_title.T.values), axis=1)
fig = plt.figure(figsize=(12,8))
ax = plt.subplot()
title_colors = ['skyblue', 'royalblue']
for i in range(1,3):
for j in list(range(0, df_title.shape[1]-1)):
j += 1
bottom=np.sum(df_title_concat[j,:i])
ax_1 = ax.bar(j, df_title_concat[j,i], width=-0.4, bottom=bottom, color = title_colors[i-1],
edgecolor='black', linewidth=3, align='edge')
for p in ax_1.patches:
width, height = p.get_width(), p.get_height()
if bottom != 0:
ax.annotate('{:.2f}%'.format(height+bottom), (p.get_x()+0.875*width, (height+bottom)+0.3),
fontsize=16, fontweight='bold', color='black')
However, I would suggest you to rethink the whole approach you are following and change the plot to something like:
plt.bar(df_title.columns,df_title.loc['M'])
plt.bar(df_title.columns,df_title.loc['F'],bottom=df_title.loc['M'])
So I've got some code that generates a donut chart but the problem is there are cases where the annotations overlap due to the values. Code and problem below.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
def donut_chart(val):
df_vals = pd.DataFrame.from_dict(val, orient='index')
labels = df_vals.index.tolist()
fig, ax = plt.subplots(figsize=(6, 6), subplot_kw=dict(aspect="equal"))
color = ['grey']*20
color[0] = 'red'
wedges, texts, junk = ax.pie(df_vals[0:4], counterclock = True,
wedgeprops=dict(width=0.6, linewidth = 2, edgecolor = 'w'),
startangle=90, colors=color,
autopct='%1.0f%%',
pctdistance=0.75,
textprops={'fontsize': 14})
bbox_props = dict(boxstyle="square,pad=0.3", fc="w", ec="w", lw=0.72)
kw = dict(xycoords='data', textcoords='data', arrowprops=dict(arrowstyle="-"),
bbox=bbox_props, zorder=0, va="center")
for i, p in enumerate(wedges):
ang = (p.theta2 - p.theta1)/2. + p.theta1
y = np.sin(np.deg2rad(ang))
x = np.cos(np.deg2rad(ang))
horizontalalignment = {-1: "right", 1: "left"}[int(np.sign(x))]
connectionstyle = "angle,angleA=0,angleB={}".format(int(ang))
kw["arrowprops"].update({"connectionstyle": connectionstyle})
ax.annotate(labels[i], xy=(x, y), xytext=(1.2*np.sign(x), 1.2*y),
horizontalalignment=horizontalalignment, **kw, size=14)
#centre_circle = plt.Circle((0,0),0.5, fc='white',linewidth=1.25)
#fig.gca().add_artist(centre_circle)
plt.axis('equal')
plt.show()
plt.close()
val = {'Label A':50, 'Label B':2, 'Label C':1, 'Label D':0.5}
donut_chart(val)
Problem:
What I'd like to do is create something like this:
The key appears to be varying the y value in the xytext so the labels don't overlap but I'm stuck on how this might be implemented or even whether it is possible.
Any ideas?
updated code
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
def donut_chart(val):
df_vals = pd.DataFrame.from_dict(val, orient='index')
labels = df_vals.index.tolist()
fig, ax = plt.subplots(figsize=(6, 6), subplot_kw=dict(aspect="equal"))
color = ['grey']*20
color[0] = 'red'
wedges, texts = ax.pie(df_vals[0:5], counterclock = True,
wedgeprops=dict(width=0.6, linewidth = 1, edgecolor = 'w'),
startangle=90, colors=color,
textprops={'fontsize': 14})
bbox_props = dict(boxstyle="square,pad=0", fc="w", ec="w", lw=0.72)
kw = dict(xycoords='data', textcoords='data', arrowprops=dict(arrowstyle="-"),
bbox=bbox_props, zorder=0, va="center")
for i, p in enumerate(wedges):
ang = (p.theta2 - p.theta1)/2. + p.theta1
y = np.sin(np.deg2rad(ang))
x = np.cos(np.deg2rad(ang))
horizontalalignment = {-1: "right", 1: "left"}[int(np.sign(x))]
connectionstyle = "angle,angleA=0,angleB={}".format(int(ang))
kw["arrowprops"].update({"connectionstyle": connectionstyle})
ax.annotate(labels[i], xy=(x, y), xytext=((i/10) + 1.1*np.sign(x), (i/10) + y),
horizontalalignment=horizontalalignment, **kw, size=14)
#centre_circle = plt.Circle((0,0),0.5, fc='white',linewidth=1.25)
#fig.gca().add_artist(centre_circle)
plt.axis('equal')
plt.show()
plt.close()
val = {'Label A':50, 'Label B':2, 'Label C':0.2, 'Label D':0.2,'Label E':0.2}
donut_chart(val)
difference
ax.annotate(labels[i], xy=(x, y), xytext=((i/10) + 1.1*np.sign(x), (i/10) + y),
horizontalalignment=horizontalalignment, **kw, size=14)
output
I've plotted data for females on one axes, and males on another axes. Each plot was made with zorder=0, but with position=1 and position=2 respectively. I label the bars with text with zorder=1, but as you can see, the bars overlap the text. Is it because they are on separate axes? In which case, how can I have text in one axes be higher than the highest zorder in another axes?
def get_ages():
df = pd.read_csv('surveydata.csv', low_memory=False)
fems = df.loc[df['gender'] == 1]
males = df.loc[df['gender'] == 2]
fdata = fems['age'].value_counts()
mdata = males['age'].value_counts()
fdata.sort_index(inplace=True)
mdata.sort_index(inplace=True)
print(fdata)
print(mdata)
fdata2 = fdata[0:14]
mdata2 = mdata[0:14]
fdata2['>31'] = sum(fdata[14:])
mdata2['>31'] = sum(mdata[14:])
fig = plt.figure() # Create matplotlib figure
ax = fig.add_subplot(111) # Create matplotlib axes
ax2 = ax.twinx() # Create another axes that shares the same x-axis as ax.
fdata2.plot(kind='bar', figsize=(10, 5.7), width=.4, color='pink', position=0, ax=ax,zorder=0)
mdata2.plot(kind='bar', figsize=(10, 5.7), width=.4, color='lightskyblue', position=1, ax=ax2, zorder=0)
ax.set_title("Ages", fontsize=18)
ax.set_ylabel("Occurrence", fontsize=18)
ax.set_facecolor('snow')
ax.set_xlim(ax.patches[0].get_x() - 1, ax.patches[-1].get_x() + 1)
ax2.set_yticks([])
totals = []
for i in ax.patches:
totals.append(i.get_height())
total = sum(totals)
for i in ax.patches:
ax.text(i.get_x() , i.get_height() + .5,
str(round((i.get_height() / total) * 100, 2)) + '%', fontsize=8,
color='black', horizontalalignment='left', zorder=9)
totals = []
for i in ax2.patches:
totals.append(i.get_height())
total = sum(totals)
for i in ax2.patches:
t = ax2.text(i.get_x()+ i.get_width(), i.get_height() + .5,
str(round((i.get_height() / total) * 100, 1)) + '%', fontsize=8,
color='black', horizontalalignment='right', zorder=10)
for x in ax.texts: #Shifts text up and down in case they overlap.
bb2 = x.get_window_extent(ax.get_figure().canvas.get_renderer())
bb = t.get_window_extent(ax.get_figure().canvas.get_renderer())
while bb2.overlaps(bb):
t.set_y(a._y - .01)
bb2 = x.get_window_extent(ax.get_figure().canvas.get_renderer())
bb = t.get_window_extent(ax.get_figure().canvas.get_renderer())