How to plot same colors for same values in a map? - pandas

I'm creating a colorbar with the function make_colormap. Source: Create own colormap using matplotlib and plot color scale.
Also i'm plotting many maps with for month, data in normals.groupby('MONTH'):
I want to create a color bar with the same values for the same colors (to be able to compare values in maps) but in the:
rvb = make_colormap(
[c('brown'), c('orange'), 0.10, c('orange'), c('yellow'), 0.20, c('green'), c('cyan'), 0.66, c('blue'), c('purple') ])
I can only put percentages. Do you know how can i modify this to put exact values instead of percentages?
import matplotlib.colors as mcolors
def make_colormap(seq):
"""Return a LinearSegmentedColormap
seq: a sequence of floats and RGB-tuples. The floats should be increasing
and in the interval (0,1).
"""
seq = [(None,) * 3, 0.0] + list(seq) + [1.0, (None,) * 3]
cdict = {'red': [], 'green': [], 'blue': []}
for i, item in enumerate(seq):
if isinstance(item, float):
r1, g1, b1 = seq[i - 1]
r2, g2, b2 = seq[i + 1]
cdict['red'].append([item, r1, r2])
cdict['green'].append([item, g1, g2])
cdict['blue'].append([item, b1, b2])
return mcolors.LinearSegmentedColormap('CustomMap', cdict)
c = mcolors.ColorConverter().to_rgb
rvb = make_colormap(
[c('brown'), c('orange'), 0.10, c('orange'), c('yellow'), 0.20, c('green'), c('cyan'), 0.66, c('blue'), c('purple') ])
for month, data in normals.groupby('MONTH'):
lons, lats= np.array(data['LONGITUDE']), np.array(data['LATITUDE'])
ppvalues=np.array(data['PP']).astype(int)
month = data['MONTH'].iloc[0]
fig = plt.figure('map', figsize=(7,7), dpi=200)
ax = fig.add_axes([0.1, 0.12, 0.80, 0.75], projection=ccrs.PlateCarree())
plt.xlabel('LONGITUDE')
plt.ylabel('LATITUDE')
ax.outline_patch.set_linewidth(0.3)
l = NaturalEarthFeature(category='cultural', name='admin_0_countries', scale='50m', facecolor='none')
ax.add_feature(l, edgecolor='black', linewidth=0.25)
img = ax.scatter(lons, lats, s=7, c=ppvalores, cmap=rvb,
marker='o', transform=ccrs.PlateCarree())
#ticks=[0,1,2,3,4,5,6,7,8,9,10]
cb = plt.colorbar(img, extend='both',
spacing='proportional', orientation='horizontal',
cax=fig.add_axes([0.12, 0.12, 0.76, 0.02]))
plt.show()
fig.savefig("path/".png")
I'm relatively new in python so would you mind to help me?
Thanks in advance.

You could apply a norm. Using the same norm for all plots would make the colors consistent. It is unclear what the range of your data['PP'] column is. Here is an example of the changes if you would like 100, 200 and 660 for the three values in the list given to make_colormap:
vmin = data['PP'].min() # the overall minimum
vmax = data['PP'].max() # the overall maximum
norm = plt.Normalize(vmin, vmax) # function that maps the range of data['PP'] to the range [0,1]
rvb = make_colormap(
[c('brown'), c('orange'), norm(100), c('orange'), c('yellow'), norm(200), c('green'), c('cyan'), norm(660), c('blue'), c('purple')])
for month, data in normals.groupby('MONTH'):
...
img = ax.scatter(..., cmap=rvb, norm=norm)
...

Related

How to customize the colorbar of a heatmap in seaborn?

Background: I compared the performance of 13 models by using each of them for prediction over four data sets. Now I have 4 * 13 R-Squared values which indicate the goodness of fit. The problem is that some large negative R-Squared values exist, making the visualization not so good.
The positive R-Squared values are hard to differentiate because of those negative values like -11 or -9.7. How can I extend the positive range and squeeze the negative range by customizing the color bar? The code and data is as follows.
import numpy as np
import seaborn as sns
from matplotlib import pyplot as plt
fig, ax = plt.subplots()
data = np.array([[ 0.9848, 0. , 0.9504, -0.8198, 0.9501, 0.9071,
0.8598, 0.9348, 0. , 0.713 , 0. , 0.669 ,
0.6184, 0. ],
[ 0.9733, 0. , 0.0566, -9.654 , 0.1291, -0.0926,
-0.0661, -2.3085, 0. , -10.63 , 0. , -3.797 ,
-7.592 , 0. ],
[ 0.9676, 0. , 0.9331, 0.9177, 0.9401, 0.9352,
0.9251, 0.7987, 0. , 0.5635, 0. , 0.5924,
0.2456, 0. ],
[ 0.9759, 0. , -0.114 , 0.1566, 0.0412, 0.3588,
0.2605, -0.5471, 0. , 0.2534, 0. , 0.5216,
0.3784, 0. ]])
def comp_heatmap(ax):
with sns.axes_style('white'):
ax = sns.heatmap(
data, ax=ax, vmax=.3,
annot=True,
xticklabels=np.arange(14),
yticklabels=np.arange(4),
)
ax.set_xlabel('Model', fontdict=font_text)
ax.set_ylabel(r'$R^2$', fontproperties=font_formula, labelpad=5)
ax.figure.colorbar(ax.collections[0])
# set tick labels
xticks = ax.get_xticks()
ax.set_xticks(xticks)
ax.set_xticklabels(xticks.astype(int))
yticks = ax.get_yticks()
ax.set_yticks(yticks)
ax.set_yticklabels(['lnr, fit', 'lg, fit', 'lnr, test', 'lg, test'])
comp_heatmap(ax)
I've used a FuncNorm method to resolve it.
from matplotlib import pyplot as plt, font_manager as fm, colors
def forward(x):
x = base ** x - 1
return x
def inverse(x):
x = np.log(x + 1) / np.log(base)
return x
def comp_heatmap(ax):
plt.rc('font', family='Times New Roman', size=15)
plt.subplots_adjust(left=0.05, right=1)
norm = colors.FuncNorm((forward, inverse), vmin=-11, vmax=1)
mask = np.zeros_like(data)
mask[:, [1, 8, 10, 13]] = 1
mask = mask.astype(np.bool)
with sns.axes_style('white'):
ax = sns.heatmap(
data, ax=ax, vmax=.3,
mask=mask,
annot=True, fmt='.4',
annot_kws=font_annot,
norm=norm,
xticklabels=np.arange(14),
yticklabels=np.arange(4),
cbar=False,
cmap='rainbow'
)
cbar = ax.figure.colorbar(ax.collections[0])
cbar.set_ticks([-11, -0.5, 0, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0])
# set tick labels
xticks = ax.get_xticks()
ax.set_xticks(xticks)
ax.set_xticklabels(xticks.astype(int), **font_tick)
yticks = ax.get_yticks()
ax.set_yticks(yticks)
ax.set_yticklabels(['', '', '', ''])
return ax
font_formula = fm.FontProperties(
math_fontfamily='cm', size=22
)
font_text = {'size': 22, 'fontfamily': 'Times New Roman'}
font_annot = {'size': 17, 'fontfamily': 'Times New Roman'}
font_tick = {'size': 18, 'fontfamily': 'Times New Roman'}
fig, axes = plt.subplots()
base = 5
ax = comp_heatmap(axes)

Getting "ValueError: data mapping points must have x in increasing order" when i plot a map

I'm using the function make_colormap to make my own colors and colorbar in a map. Source: Create own colormap using matplotlib and plot color scale
This is the function:
import matplotlib.colors as mcolors
def make_colormap(seq):
"""Return a LinearSegmentedColormap
seq: a sequence of floats and RGB-tuples. The floats should be increasing
and in the interval (0,1).
"""
seq = [(None,) * 3, 0.0] + list(seq) + [1.0, (None,) * 3]
cdict = {'red': [], 'green': [], 'blue': []}
for i, item in enumerate(seq):
if isinstance(item, float):
r1, g1, b1 = seq[i - 1]
r2, g2, b2 = seq[i + 1]
cdict['red'].append([item, r1, r2])
cdict['green'].append([item, g1, g2])
cdict['blue'].append([item, b1, b2])
return mcolors.LinearSegmentedColormap('CustomMap', cdict)
c = mcolors.ColorConverter().to_rgb
Also i'm defining my range of values with the minimum and maximum value:
vmintmax = min(tmax[['ENE','FEB','MAR','ABR','MAY','JUN','JUL','AGO','SEP','OCT','NOV','DIC']].min()) # the overall minimum
vmaxtmax = max(tmax[['ENE','FEB','MAR','ABR','MAY','JUN','JUL','AGO','SEP','OCT','NOV','DIC']].max()) # the overall maximum
normtmax = plt.Normalize(vmintmax, vmaxtmax) # function that maps the range of tmax to the range [0,1]
And i'm defining my color values:
rvbtmax = make_colormap([c('lime'), c('lime'), normtmax(11), c('forestgreen'), c('forestgreen'),
normtmax(13), c('lightgreen'), c('lightgreen'), normtmax(15), c('lawngreen'),
c('lawngreen'), normtmax(17),c('greenyellow'), c('greenyellow'),normtmax(19),c('yellow'), c('yellow'),
normtmax(21),c('khaki'), c('khaki'),normtmax(23),c('gold'), c('gold'),normtmax(25),
c('goldenrod'), c('goldenrod'),normtmax(27),c('orange'), c('orange'),normtmax(29),c('orangered'), c('orangered'),normtmax(31),
c('red'), c('red'),normtmax(33),c('firebrick'), c('firebrick'),normtmax(35),
c('darkred'), c('darkred')])
Finally i'm plotting my map here:
for mes in ['Enero','Febrero','Marzo','Abril','Mayo','Junio','Julio',
'Agosto','Septiembre','Octubre','Noviembre','Diciembre']:
data = tmax[['CODIGO', 'LONGITUD', 'LATITUD', mes]]
lons, lats= np.array(data['LONGITUD']), np.array(data['LATITUD'])
tmaxvalores=np.array(data[mes]).astype(int)
fig = plt.figure('map', figsize=(7,7), dpi=200)
ax = fig.add_axes([0.1, 0.12, 0.80, 0.75], projection=ccrs.PlateCarree())
plt.title('\nNormales Climáticas Mensuales de Temperatura Máxima\nMes de'+f' {mes}'+'\nPeríodo 1981-2010\n')
plt.xlabel('LONGITUD')
plt.ylabel('LATITUD')
ax.outline_patch.set_linewidth(0.3)
l = NaturalEarthFeature(category='cultural', name='admin_0_countries', scale='50m', facecolor='none')
ax.add_feature(l, edgecolor='black', linewidth=0.1)
img = ax.scatter(lons, lats, s=7, c=tmaxvalores, cmap=rvbtmax, norm=normtmax,
marker='o', transform=ccrs.PlateCarree())
But when im plotting the map i get this error: ValueError: data mapping points must have x in increasing order
I have no idea why i get this error. With similar df's and same code i don't get this error.
Would you mind to help me?
Thanks in advance.

How to show ranges of values with a color assigned in the legend?

With this code i'm creating colorbar scales with the function make_colormap. Source:Create own colormap using matplotlib and plot color scale
import matplotlib.colors as mcolors
def make_colormap(seq):
"""Return a LinearSegmentedColormap
seq: a sequence of floats and RGB-tuples. The floats should be increasing
and in the interval (0,1).
"""
seq = [(None,) * 3, 0.0] + list(seq) + [1.0, (None,) * 3]
cdict = {'red': [], 'green': [], 'blue': []}
for i, item in enumerate(seq):
if isinstance(item, float):
r1, g1, b1 = seq[i - 1]
r2, g2, b2 = seq[i + 1]
cdict['red'].append([item, r1, r2])
cdict['green'].append([item, g1, g2])
cdict['blue'].append([item, b1, b2])
return mcolors.LinearSegmentedColormap('CustomMap', cdict)
c = mcolors.ColorConverter().to_rgb
rvb = make_colormap([c('grey'), c('grey'), norm(3), c('sandybrown'), c('sandybrown'),
norm(5), c('yellow'), c('yellow'), norm(10), c('navajowhite'),
c('navajowhite'), norm(15),c('lightgreen'), c('lightgreen'),norm(20),c('lime'), c('lime'),
norm(50),c('limegreen'), c('limegreen'),norm(80),c('forestgreen'), c('forestgreen'),norm(120),
c('green'), c('green'),norm(160),c('darkgreen'), c('darkgreen'),norm(200),c('teal'), c('teal'),norm(300),
c('mediumaquamarine'), c('mediumaquamarine'),norm(500),c('lightseagreen'), c('lightseagreen'),norm(700),
c('lightskyblue'), c('lightskyblue')])
So in variable rvb i'm asssing a color to ranges of values. How can i assing a color to an specific ranges of values? For example: Grey to 0-3, sandybrown to 4-5, yellow to 6-10, etc.
The map is this:
Also i want to the legend show those values assigned. For example Grey color 0-3, sandybrown 4-5, etc.
Something similar to this image (no need to be equal to the image, just need to show ranges with colors):
I also will show you part of my code when i create the map:
fig = plt.figure('map', figsize=(7,7), dpi=200)
ax = fig.add_axes([0.1, 0.12, 0.80, 0.75], projection=ccrs.PlateCarree())
plt.title('xxx')
plt.xlabel('LONGITUD')
plt.ylabel('LATITUD')
ax.outline_patch.set_linewidth(0.3)
l = NaturalEarthFeature(category='cultural', name='admin_0_countries', scale='50m', facecolor='none')
ax.add_feature(l, edgecolor='black', linewidth=0.25)
img = ax.scatter(lons, lats, s=7, c=ppvalues, cmap=rvb,norm=norm,
marker='o', transform=ccrs.PlateCarree())
handles, labels = img.legend_elements(alpha=0.2)
plt.legend(handles, labels,prop={'weight':'bold','size':10}, title='Meteorological\nStations',title_fontsize=9, scatterpoints=2);
cb = plt.colorbar(img, extend='both',
spacing='proportional', orientation='horizontal',
cax=fig.add_axes([0.12, 0.12, 0.76, 0.02]))
ax.set_extent([-90.0, -60.0, -20.0, 0.0], crs=ccrs.PlateCarree())
I don't understand the function in the question, but I have coded how to create a legend with a specified color, specified label, and specified ticks, and how to give a color bar a specified tick. Please correct the addition of colors and the tick spacing in the color bar.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from matplotlib.colors import LinearSegmentedColormap
list_color = ['grey','sandybrown','sandybrown','yellow',
'navajowhite','lightgreen','lime','limegreen',
'forestgreen','green','darkgreen','teal',
'mediumaquamarine','lightseagreen','lightskyblue']
list_label = ['0-3', '4-5', '6-10', '11-15',
'16-20', '21-50', '51-80', '81-120',
'121-160', '161-200','201-300','301-500',
'501-700','701-900','901-1200']
list_ticks = np.linspace(0, 1, 15)
vmin,vmax = 0, 1
cm = LinearSegmentedColormap.from_list('custom_cmap', list_color, N=len(list_color))
plt.imshow(np.linspace(0, 1, 25).reshape(5,5), cmap=cm, interpolation='nearest', vmin=vmin, vmax=vmax)
cbar = plt.colorbar( orientation='horizontal', extend='neither', ticks=list_ticks)
cbar.ax.set_xticklabels(list_label, rotation=45, fontsize=14)
all_patches = []
for h,l in zip(list_color, list_label):
patch = mpatches.Patch(color=h, label=l)
all_patches.append(patch)
plt.legend(handles=all_patches, loc='upper right', ncol=3, bbox_to_anchor=(3, 1))
plt.show()

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

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

linear regression fit plot over boxplots in shared y-axis

I have a plot in the picture below:
Is it possible to add a colored band to indicate a linear regression between the different x-axis? I want a plot like this, with filling with the same color all the zone between the two green lines:
A quick and dirty solution, to create a visually equal single plot, would be to use range(1,17) for x values and use the matplotlib functions xticks, grid and axvline to fine tune the plot:
# fake some data
xs = range(1, 17)
vals = np.asarray([0.73, 0.74, 0.73, 0.71,
0.75, 0.76, 0.75, 0.73,
0.77, 0.78, 0.77, 0.75,
0.79, 0.80, 0.79, 0.77])
data = np.random.rand(20, len(vals)) * 0.03 + vals
avgs = np.mean(data, axis=0)
# plot linear regr. lines and fill
xs2 = [0,20]
coef = np.polyfit(xs[0::4], avgs[0::4], 1) # values for 0.01
ys2a = np.polyval(coef, xs2)
coef = np.polyfit(xs[3::4], avgs[3::4], 1) # values for 0.5
ys2b = np.polyval(coef, xs2)
plt.fill_between(xs2, ys2a, ys2b, color='OliveDrab', alpha=0.5)
plt.plot(xs2, ys2a, color='OliveDrab', lw=3)
plt.plot(xs2, ys2b, color='OliveDrab', lw=3)
# plot data and manipulate axis and grid
plt.boxplot(data, showfliers=False)
plt.xticks(xs, [0.01, 0.1, 0.2, 0.5] * 4)
plt.xlim(0.5, 16.5)
plt.grid(False)
for i in range(3):
plt.axvline(i * 4 + 4.5, c='white')
plt.xlabel('$\sigma^{2}$')
plt.ylabel('$F_{w}(t)$')
plt.show()