Matplotlib subplots how to align colorbars with other legends, or how to justify subplots to left - matplotlib

How can I add a colorbar scale to the 2nd & 3rd subplots, such that it is inline with my legends in the 1st and 4th subplots? Or, another way to say the question: how can I add a colorbar scale without changing the alignment/justification of the 2nd & 3rd subplots?
There are good examples available on setting colorbar locations (e.g., here on stackoverflow and in the matplotlib docs), but I still haven't been able to solve this.
Below is a reproducible example. The real data are more complicated, and this is part of a loop to produce many figures, so the "extra" stuff about setting axis limits and subplot aspect ratios is needed and will change with different datasets.
Using Python 3.8.
Reproducible example without colorbar
## Specify axes limits, tick intervals, and aspect ratio
xl, yl, xytick, ar = [-40000,120000], [-30000,10000], 20000, 0.8
## Global plot layout stuff
fig = plt.figure(figsize=(10, 7.5), constrained_layout=True)
gs = fig.add_gridspec(4, 1)
ax1 = fig.add_subplot(gs[0, 0])
ax2 = fig.add_subplot(gs[1, 0], sharex = ax1, sharey = ax1)
ax3 = fig.add_subplot(gs[2, 0], sharex = ax1)
ax4 = fig.add_subplot(gs[3, 0], sharex = ax1, sharey = ax3)
fig.execute_constrained_layout()
fig.suptitle('Suptitle')
## First Plot
ax1.plot([-30000, 500], [-2000, -21000], c='red', label='A')
ax1.plot([80000, 110000], [-9000, 800], c='blue', label='B')
ax1.set_title('ax1', style='italic');
ax1.set_xlabel('x');
ax1.set_ylabel('beta');
ax1.set_xlim(xl)
ax1.set_ylim(yl)
ax1.xaxis.set_major_locator(ticker.MultipleLocator(xytick))
ax1.yaxis.set_major_locator(ticker.MultipleLocator(xytick))
ax1.legend(handles=leg, bbox_to_anchor=(1.05, 1), loc='upper left')
ax1.set_aspect(aspect=ar)
## Dummy data for plots 2/3/4
x = [-15000, -2000, 0, 5000, 6000, 11000, 18000, 21000, 25000, 36000, 62000]
beta = [1000, 200, -800, 100, 1000, -2000, -5000, -5000, -15000, -21000, -1500]
y = [0.01, 0.2, 1.3, 0.35, 0.88, 2.2, 2.5, 1.25, 3.4, 4.1, 2.1]
## Second Plot
vals = ax2.scatter(x, beta, c=y, norm=mcolors.LogNorm(), cmap='rainbow')
ax2.set_title('ax2', style='italic');
ax2.set_xlabel('x');
ax2.set_ylabel('beta');
ax2.set_aspect(aspect=ar)
## Attempt to add colorbar
#cbar = fig.colorbar(vals, ax=ax2, format = '%1.2g', location='right', aspect=25)
#cbar.ax.set_ylabel('y')
#cbar.ax.yaxis.set_label_position('left')
#cbar_range = [min(y), max(y)]
#ticklabels = cbar.ax.get_ymajorticklabels()
#cbarticks = list(cbar.get_ticks())
#cbar.set_ticks(cbar_range + cbarticks)
## Third Plot
ax3.scatter(x, y, c=y, norm=mcolors.LogNorm(), cmap='rainbow')
ax3.set_title('ax3', style='italic');
ax3.set_xlabel('x');
ax3.set_ylabel('y');
ax3.yaxis.set_major_formatter(FormatStrFormatter('%1.2g'))
## Fourth Plot
ax4.scatter(x, y, c='black', label='Dots')
ax4.set_title('ax4', style='italic');
ax4.set_xlabel('x');
ax4.set_ylabel('y');
ax4.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
## Clean-up, set aspect ratios
figW, figH = ax1.get_figure().get_size_inches()
_, _, w, h = ax1.get_position().bounds
disp_ratio = (figH * h) / (figW * w)
data_ratio = sub(*ax3.get_ylim()) / sub(*ax3.get_xlim())
ax3.set_aspect(aspect=disp_ratio / data_ratio )
ax4.set_aspect(aspect=disp_ratio / data_ratio)
## Clean-up, turn axis ticks back on after messing with cbar
#ax1.tick_params(axis='both', which='both', labelbottom='on')
#ax2.tick_params(axis='both', which='both', labelbottom='on')
#ax3.tick_params(axis='both', which='both', labelbottom='on')
Result when trying colorbar, note misalignment of second plot

Suggest you simplify your code and make sure it all works; for instance I have no idea what sub does.
A partial solution to your problem could be panchor=False, which is a bit of an obscure kwarg, but...
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
## Specify axes limits, tick intervals, and aspect ratio
ar = 1.2
## Global plot layout stuff
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 4), constrained_layout=True, sharex=True, sharey=True)
## First Plot
ax1.plot([-20_000, 20_000], [-20_000, 20_000] )
ax1.set_aspect(aspect=ar)
## Dummy data for plots 2/3/4
x = [-15000, -2000, 0, 5000, 6000, 11000, 18000, 21000, 25000, 36000, 62000]
beta = [1000, 200, -800, 100, 1000, -2000, -5000, -5000, -15000, -21000, -1500]
y = [0.01, 0.2, 1.3, 0.35, 0.88, 2.2, 2.5, 1.25, 3.4, 4.1, 2.1]
## Second Plot
vals = ax2.scatter(x, beta, c=y, norm=mcolors.LogNorm(), cmap='rainbow')
ax2.set_aspect(aspect=ar)
cbar = fig.colorbar(vals, ax=ax2, format = '%1.2g', location='right',
aspect=25, panchor=False)
plt.show()
Depending on the size of the figure, this could comically place the colorbar far to the right. The problem here is the aspect ratio of your plots, which makes the actual axes more narrow than the figure. But the colorbar doesn't really know about that, and places itself on the outside of the space allocated for the axes.
If this is displeasing, then you can also specify an inset axes for the colorbar.
cbax = ax2.inset_axes([1.05, 0.2, 0.05, 0.6], transform=ax2.transAxes)
cbar = fig.colorbar(vals, cax=cbax, format = '%1.2g', orientation='vertical')

Using inset_axes() solves this, as suggested in the other answer, but the parameters relative to the transform were not explained in the example, but I was able to figure it out with some research.
The parameters in inset_axes are [x-corner, y-corner, width, height] and the transform is like a local reference. So, using [1,0,0.5,0.75] means: x = 100% or end of parent ax; y = 0% or bottom of parent ax; width = 50% of parent ax; and height = 75% of parent ax.
Here I wanted the colorbar to be the same height as the parent ax (ax2 and ax3), very thin, and offset a little bit to be more in line with the other legends. Using cbax = ax2.inset_axes([1.1, 0, 0.03, 1], transform=ax2.transAxes) achieves this.
This code works for any aspect ratio ar.
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import matplotlib.colors as mcolors
from operator import sub
%matplotlib inline
plt.style.use('seaborn-whitegrid')
## Specify axes limits, tick intervals, and aspect ratio
xl, yl, ar = [-40000,120000], [-30000,10000], .5
## Global plot layout stuff
fig = plt.figure(figsize=(10, 7.5), constrained_layout=True)
gs = fig.add_gridspec(4, 1)
ax1 = fig.add_subplot(gs[0, 0])
ax2 = fig.add_subplot(gs[1, 0], sharex = ax1, sharey = ax1)
ax3 = fig.add_subplot(gs[2, 0], sharex = ax1)
ax4 = fig.add_subplot(gs[3, 0], sharex = ax1, sharey = ax3)
fig.execute_constrained_layout()
fig.suptitle('Suptitle')
## First Plot
ax1.plot([-30000, 500], [-2000, -21000], c='red', label='A')
ax1.plot([80000, 110000], [-9000, 800], c='blue', label='B')
ax1.set_title('ax1', style='italic');
ax1.set_xlim(xl)
ax1.set_ylim(yl)
ax1.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
ax1.set_aspect(aspect=ar)
## Dummy data for plots 2/3/4
x = [-15000, -2000, 0, 5000, 6000, 11000, 18000, 21000, 25000, 36000, 62000]
beta = [1000, 200, -800, 100, 1000, -2000, -5000, -5000, -15000, -21000, -1500]
y = [0.01, 0.2, 1.3, 0.35, 0.88, 2.2, 2.5, 1.25, 3.4, 4.1, 2.1]
## Second Plot
vals = ax2.scatter(x, beta, c=y, norm=mcolors.LogNorm(), cmap='rainbow')
ax2.set_title('ax2', style='italic');
ax2.set_aspect(aspect=ar)
cbax = ax2.inset_axes([1.1, 0, 0.03, 1], transform=ax2.transAxes)
cbar2 = fig.colorbar(vals, cax=cbax, format = '%1.2g', orientation='vertical')
## Third Plot
ax3.scatter(x, y, c=y, norm=mcolors.LogNorm(), cmap='rainbow')
ax3.set_title('ax3', style='italic');
cbax = ax3.inset_axes([1.1, 0, 0.03, 1], transform=ax3.transAxes)
cbar3 = fig.colorbar(vals, cax=cbax, format = '%1.2g', orientation='vertical')
## Fourth Plot
ax4.scatter(x, y, c='black', label='Dots')
ax4.set_title('ax4', style='italic');
ax4.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
## Clean-up, set aspect ratios
figW, figH = ax1.get_figure().get_size_inches()
_, _, w, h = ax1.get_position().bounds
disp_ratio = (figH * h) / (figW * w)
data_ratio = sub(*ax3.get_ylim()) / sub(*ax3.get_xlim())
ax3.set_aspect(aspect=disp_ratio / data_ratio )
ax4.set_aspect(aspect=disp_ratio / data_ratio)
## Colorbars
cbar2.ax.set_ylabel('y')
cbar2.ax.yaxis.set_label_position('left')
cbar3.ax.set_ylabel('y')
cbar3.ax.yaxis.set_label_position('left')
Result with aspect ratio = 0.5 for top 2 plots
Result with aspect ratio = 2 for top 2 plots

Related

constrained_layout=True moves one column deeper

I used constrained_layout= True multiple times and everything worked good... now I added a second Colorbar an i get somthing like that:
How I can fix this? I want the same hight and space between the bars and plots.
colorbar_shrink = 0.6
pad=-0.15
fig, axarr = plt.subplots(nrows=2, ncols=2, figsize=(15, 10), constrained_layout=True,
sharey=True, subplot_kw={'projection': crs})
# fig.tight_layout()
# fig.subplots_adjust(wspace=0.01)
# fig.set_constrained_layout_pads(w_pad=0.02, h_pad=0.02, hspace=-0.2,
# wspace=0.2)
fig.suptitle('Bla', y=1.01)
# fig.set_constrained_layout_pads(w_pad=0, h_pad=0.05,hspace=0.1, wspace=0.2)
axlist = axarr.flatten()
for ax in axlist:
plot_background(ax)
print('First .')
levels = np.linspace(0, 2, 10)
cf1 = axlist[0].contourf(lon_2d, lat_2d, aod_dust_550nm, cmap='Oranges',
transform=ccrs.PlateCarree(), zorder=0, levels=levels, extend='both')
cf2 = axlist[0].contourf(lon_2d, lat_2d, tq, cmap='Blues', vmin=0.0001, vmax=10 ,
levels=tq_lev, norm=matplotlib.colors.LogNorm(),
transform=ccrs.PlateCarree(), zorder=0, extend='max')
cb1 = fig.colorbar(cf1, ax=axlist[0], orientation='horizontal', format='%.1f',
shrink=colorbar_shrink, pad=pad)
cb2 = fig.colorbar(cf2, ax=axlist[0], orientation='vertical', #format='%.4f',
shrink=colorbar_shrink)
cb1.set_label('Dust optical depth #550nm',labelpad=-45, fontsize=12)
cb2.ax.set_ylabel('TQ in kg m$^{-2}$')
cb2.formatter = LogFormatter()
cb2.set_ticks([1e-4,1e-3, 1e-2, 1e-1, 1e0, 10])
cb2.update_ticks()
print('Second..')
# Upper right plot - Wind and Windspeed
levels = np.linspace(0.0, 50.0, 50)
cf2 = axlist[1].contourf(lon_2d, lat_2d, windspeed_900, levels=levels,
cmap='jet', transform=ccrs.PlateCarree() ,zorder=0, extend='max')
#Every n-th quiver
wind_slice = (slice(None, None, 15), slice(None, None, 15))
c2 = axlist[1].quiver(lon_2d[wind_slice], lat_2d[wind_slice] ,
u_300.values[wind_slice] , v_300.values[wind_slice],
color='black', transform=ccrs.PlateCarree())
cb2 = fig.colorbar(cf2, ax=axlist[1], orientation='horizontal',format='%i',
shrink=colorbar_shrink)#, pad=paddy)
cb2.set_label('Wind speed in m s-1 #900hPa',labelpad=-45, fontsize=12)
plt.quiverkey(c2, 0.99, -0.16, 10,'velocity (10 m s$^{-1}$)',
labelpos='W',transform=ccrs.PlateCarree(), color='r')
# plt.show()
THanks a lot.

Plot circle at the title in matplotlib python

I have a 2 line title and first line has a number at the end of the line.
Can we plot a circle around the number?
Here is the code to generate the figure.
from matplotlib import rcParams
from matplotlib import pyplot as plt
import numpy as np
import os
rcParams.update({'figure.autolayout': True})
some_text = 'XXX'
any_number=15
title = '%s: %d\n YYY ZZZZ WWWWW' % (some_text,any_number)
fig = plt.figure(figsize=(8, 8), dpi=100)
plt.tick_params(axis='y', which='major', labelsize=60, width=3, length=10, pad=40)
plt.tick_params(axis='y', which='minor', labelsize=60, width=3, length=10, pad=40)
ax = plt.gca()
plt.title(title, fontsize=60, pad=40, loc='center', fontweight='semibold')
plt.style.use('ggplot')
ax.set_facecolor('white')
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.spines['left'].set_visible(True)
for edge_i in ['left']:
ax.spines[edge_i].set_edgecolor("black")
ax.spines[edge_i].set_linewidth(3)
ax.spines[edge_i].set_bounds(0, 1)
x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
plt.yticks(np.arange(0, 1.01, step=0.2))
data_list= np.array([1,1,1,1,1,0.9, 0.8, 0.7, 0.8,0.85])
plt.bar(x, data_list, 0.9, color='indianred',edgecolor="black", linewidth=3,zorder=1)
plt.tick_params(
axis='x', # changes apply to the x-axis
which='both', # both major and minor ticks are affected
bottom=False, # ticks along the bottom edge are off
top=False, # ticks along the top edge are off
labelbottom=False) # labels along the bottom edge are off
figure_name = 'figure_with_circle.png'
figure_file = os.path.join('/Users/burcakotlu/Desktop',figure_name)
fig.savefig(figure_file, dpi=100, bbox_inches="tight")
plt.close(fig)
Here is the current figure and the wanted circle.
One could use the following without ax.bar():
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.set_title('title')
circle1 = plt.Circle((2,4.15), 0.2, color='k', clip_on=False, zorder=100, fill=False)
ax.add_patch(circle1)
ax.set_xlim(0,4)
ax.set_ylim(0,4)
plt.show()
I have found a way to plot circle together with bar plots without distorting bars. Here is the code below:
from matplotlib import rcParams
from matplotlib import pyplot as plt
import numpy as np
import os
import matplotlib.patches as patches
from matplotlib.offsetbox import AnchoredText
rcParams.update({'figure.autolayout': True})
some_text = 'XXX'
any_number=15
title = '%s: %d\n YYY ZZZZ WWWWW' % (some_text,any_number)
fig = plt.figure(figsize=(12,12), dpi=100)
plt.tick_params(axis='y', which='major', labelsize=60, width=3, length=10, pad=40)
plt.tick_params(axis='y', which='minor', labelsize=60, width=3, length=10, pad=40)
ax = plt.gca()
number_of_xxx = '12'
anchored_text_number_of_xxx = AnchoredText(number_of_xxx,
frameon=False, borderpad=0, pad=0.1,
loc='upper right',
bbox_to_anchor=[0.95, 1.3],
bbox_transform=plt.gca().transAxes,
prop={'fontsize': 60,
'fontweight': 'semibold'})
ax.add_artist(anchored_text_number_of_xxx)
circle1 = patches.Circle((0.88, 1.25), radius=0.1, transform=ax.transAxes, zorder=100, fill=False, color='gold', lw=8, clip_on=False)
ax.add_patch(circle1)
ax.set_title(title, fontsize=60, pad=40, loc='center', fontweight='semibold', zorder=50)
ax.set_facecolor('white')
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.spines['left'].set_visible(True)
for edge_i in ['left']:
ax.spines[edge_i].set_edgecolor("black")
ax.spines[edge_i].set_linewidth(3)
ax.spines[edge_i].set_bounds(0, 1)
x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
ax.set_yticks(np.arange(0, 1.01, step=0.2))
data_list= np.array([1,1,1,1,1,0.9, 0.8, 0.7, 0.8,0.85])
ax.bar(x, data_list, 0.9, color='indianred',edgecolor="black", linewidth=3,zorder=1)
ax.tick_params(
axis='x', # changes apply to the x-axis
which='both', # both major and minor ticks are affected
bottom=False, # ticks along the bottom edge are off
top=False, # ticks along the top edge are off
labelbottom=False) # labels along the bottom edge are off
figure_name = 'figure_with_circle.png'
figure_file = os.path.join('/Users/burcakotlu/Desktop',figure_name)
fig.savefig(figure_file, dpi=100, bbox_inches="tight")
plt.close(fig)

How to avoid overlapping bars in plt.bar when x-values aren't spaced evenly?

I have
x = array([0., 0.08, 0.12, 0.18, 0.27, 0.42, 0.65])
y = array([0., 0.03758546, 0.06577713, 0.48786205, 0.28553257, 0.09909356, 0.02414922])
I then write
plt.ticklabel_format(useOffset=False)
plt.figure(figsize=(20,10))
plt.xlabel('D/Dmax')
plt.bar(x, y), align = 'edge', tick_label = x, color = 'red', edgecolor = "black")
And I get the following chart. Why is it like this, and how can I make the bars not overlap and distinct like every other bar chart?
As your bars don't have a constant width, you can calculate these widths as the difference between the x-values: np.diff(x). Note that there is one less difference than there are elements in x. To get a width for the last bar (which in theory could be infinite), you can either repeat the next-to-last width, or add an extra x-value to set the rightmost boundary.
from matplotlib import pyplot as plt
import numpy as np
x = np.array([0., 0.08, 0.12, 0.18, 0.27, 0.42, 0.65])
y = np.array([0., 0.03758546, 0.06577713, 0.48786205, 0.28553257, 0.09909356, 0.02414922])
widths = np.pad(np.diff(x), (0, 1), 'edge')
plt.figure(figsize=(20, 10))
plt.xlabel('D/Dmax')
plt.bar(x, y, width=widths, align='edge', tick_label=x, color='red', edgecolor="black")
plt.show()
In this case, a logical extension for x could be to include 1:
from matplotlib import pyplot as plt
import numpy as np
x = np.array([0., 0.08, 0.12, 0.18, 0.27, 0.42, 0.65])
x = np.concatenate([x, [1]])
y = np.array([0., 0.03758546, 0.06577713, 0.48786205, 0.28553257, 0.09909356, 0.02414922])
widths = np.diff(x)
plt.figure(figsize=(20, 10))
plt.xlabel('D/Dmax')
plt.bar(x[:-1], y, width=widths, align='edge', color='red', edgecolor="black")
plt.xticks(x)
plt.show()
Your real x-values are much smaller than the default bar width which makes the bars overlap. You need to use a smaller bar width, for ex. 0.02 which is of the order of your smaller x-value.
plt.bar(x, y, align='edge', tick_label=x, color='red', edgecolor="black",
width=0.02)

legend outside plot when ax1 ax2 twin axes

I am applying this strategy to place legend outside plot. The main difference here is that there are ax1 and ax2 twin axes.
The x value in bbox_to_anchor is set to 0.89 in the following MWE.
As can be seen, the legend box does not display the entire string labels for each color:
MWE:
import matplotlib.pyplot as plt
import numpy as np
suptitle_label = "rrrrrrrr # ttttt yyyyyyy. uuuuuuuuuuuuuuuuuu\n$[$Xx$_{2}$Yy$_{7}]^{-}$ + $[$XxYy$_{2}$(cccc)$_{2}]^{+}$ JjYy model"
# Plotting
fig, ax1 = plt.subplots()
ax1.set_xlabel('Time')
ax1.set_ylabel('y1label')
new_time = np.linspace(1, 8, 100)
j_data = [np.linspace(1, 4, 100), np.linspace(1, 5, 100), np.linspace(1, 6, 100), np.linspace(1, 7, 100)]
sorted_new_LABELS_fmt = ['$[$XxYy$_{2}$(cc)$_{2}]^{+}$', '$[$Xx$_{2}$Yy$_{7}]^{-}$', '$[$XxYy$_{4}]^{-}$', '$[$Xx$_{2}$Yy$_{5}$(cc)$_{2}]^{+}$']
sorted_new_LABELS_colors = ['green', 'red', 'blue', 'orange']
for j,k,c in zip(j_data, sorted_new_LABELS_fmt, sorted_new_LABELS_colors):
ax1.plot(new_time, j, label='%s' % k, color='%s' %c)
All_e_chunks_n = np.linspace(-850, -860, 100)
ax2 = ax1.twinx()
ax2.set_ylabel('y2label')
ax2.plot(new_time, All_e_chunks_n, 'grey', alpha=0.6, linewidth=2.5, label='y2')
# Shrink cccrent axis
box = ax1.get_position()
ax1.set_position([box.x0, box.y0, box.width * 0.9, box.height])
# Put the legend:
fig.legend(loc='center left', bbox_to_anchor=(0.89, 0.5))
fig.suptitle(suptitle_label, fontsize=15)
fig.savefig('mwe.pdf', bbox_inches='tight')
Decreasing this x value and commenting out thebbox_inches='tight' part, yields the following:
For bbox_to_anchor=(0.85, 0.5), this is the result:
For bbox_to_anchor=(0.80, 0.5), this is the result:
For bbox_to_anchor=(0.7, 0.5), this is the result:

How to increase padding (whitespace) for subplots when saving as png?

I have created a 4x2 subplot and I want to save the individual plots as separate png files. I am able to do this with the following code, however the tightbbox format is too tight and it makes it tough to read the title and x,y labels. Is there a way to increase the padding (whitespace) around each individual plot when using this tightbbox layout?
nrow = combined.shape[0]
ncol = combined.shape[1]
shape_row = int((nrow + 1)/2 if (nrow % 2) != 0 else nrow/2)
fig, axes = plt.subplots(shape_row, 2, figsize=(20,45))
fig.subplots_adjust(hspace=0.5, wspace=0.4)
plt.rcParams['savefig.facecolor'] = 'white'
axes = axes.ravel()
for i in range(nrow):
axes[i].bar(range(2), combined.iloc[i,:2].values, color='blue', label=label_1)
axes[i].plot(range(2,ncol-1), combined.iloc[i,2:-1], 'o-', color='orange', markersize=10, label=label_2)
axes[i].plot([-1, 7], [combined.iloc[i,-1]]*2, linestyle='--', color='red', label=label_3)
axes[i].plot([ncol-1,ncol-1],[0, combined.iloc[i,-1]], '--', color='red')
axes[i].set_title(combined.index[i], fontsize=26, fontweight='bold', pad=15)
axes[i].set_xlabel('')
axes[i].set_ylabel("(in local currency '000s)", fontsize=18, labelpad=10)
axes[i].set_xticks(range(ncol))
axes[i].set_xticklabels(combined.columns, rotation=45)
axes[i].tick_params(labelsize=18, pad=10)
axes[i].set_xlim([-.7, nrow-.97])
axes[i].margins(x=0, y=0.2)
blue_bar= mpatches.Patch(color='blue', label='aaa')
orange_line=mlines.Line2D(range(2,ncol-1), combined.iloc[i,2:-1], color='orange', linestyle='-', marker = 'o', markersize=10, label='bbb')
red_line=mlines.Line2D([-1, 7], [combined.iloc[i,-1]]*2, color='red', linestyle='--', label='ccc')
lgd = axes[i].legend(handles=[blue_bar, orange_line, red_line],
loc='upper right', bbox_to_anchor=(1,1), fontsize=18, shadow=True, borderpad=1)
bbox = axes[i].get_tightbbox(fig.canvas.get_renderer())
fig.savefig("subplot{}.png".format(i),
bbox_inches=bbox.transformed(fig.dpi_scale_trans.inverted()))