I saw this tutorial on how to make a scatter plot with a histogram for the x and y axes and I thought it would be neat to also tack on a colorbar for an extra dimension of information. To do this, I utilized "the make_axes_locatable" function, like so:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
# generating fake data
tx = np.random.randn(1000)
ty = np.random.randn(1000)
tz = np.random.randn(1000)
fig = plt.figure(figsize=(5, 5))
gs = fig.add_gridspec(2, 2, width_ratios=(4, 1), height_ratios=(1, 4),
left=0.1, right=0.9, bottom=0.1, top=0.9,
wspace=0.05, hspace=0.05)
# Create the Axes.
ax = fig.add_subplot(gs[1, 0])
ax_histx = fig.add_subplot(gs[0, 0], sharex=ax)
ax_histy = fig.add_subplot(gs[1, 1], sharey=ax)
def scatter_hist_and_colorbar(x, y, c, ax, ax_histx, ax_histy,label):
# no labels
ax_histx.tick_params(axis="x", labelbottom=False)
ax_histy.tick_params(axis="y", labelleft=False)
# the scatter plot:
sc=ax.scatter(x,y,marker='o',label=label,c=c)
# now determine nice limits by hand:
binwidth = 0.25
xlim = (int(np.max(np.abs(x))/binwidth) + 1) * binwidth
ylim = (int(np.max(np.abs(y))/binwidth) + 1) * binwidth
xbins = np.arange(-xlim, xlim + binwidth, binwidth)
ybins = np.arange(-ylim, ylim + binwidth, binwidth)
ax_histx.hist(x, bins=xbins)
ax_histy.hist(y, bins=ybins, orientation='horizontal')
return sc
sc1= scatter_hist_and_colorbar(tx,ty,tz, ax, ax_histx, ax_histy,label='data')
ax.set_ylabel('x data')
ax.set_xlabel('y data')
ax.legend()
divider = make_axes_locatable(ax)
cax = divider.append_axes('left', size='5%', pad=1)
cbar=fig.colorbar(sc1, cax=cax, orientation='vertical')
cbar.ax.set_ylabel('z data',rotation=90,labelpad=5)
cbar.ax.yaxis.set_ticks_position("left")
plt.savefig('example.png')
plt.show()][2]][2]
This almost works except the "ax_histx" axis is now stretched and doesn't properly line up due to the addition of the colorbar. Is there a way to resize the "ax_histx" axis or is there a better way to add a colorbar to the "ax" subplot so that it wouldn't affect the "ax_histx" or "ax_histy" axes?
After getting a suggestion form #r-beginners , I tried tweaking this code to place a colorbar in the upper right, perpendicular to the histogram axes. This way, it doesn't distort the width/heights of the other shared axes:
# some random data
tx = np.random.randn(1000)
ty = np.random.randn(1000)
tz = np.random.randn(1000)
fig = plt.figure(figsize=(5, 5))
gs = fig.add_gridspec(2, 2, width_ratios=(4, 1), height_ratios=(1, 4),
left=0.1, right=0.9, bottom=0.1, top=0.9,
wspace=0.05, hspace=0.05)
# Create the Axes.
ax0 = fig.add_subplot(gs[0, 1])
ax = fig.add_subplot(gs[1, 0])
ax_histx = fig.add_subplot(gs[0, 0], sharex=ax)
ax_histy = fig.add_subplot(gs[1, 1], sharey=ax)
def scatter_hist_and_colorbar(x, y, c, ax, ax_histx, ax_histy,label):
# no labels
ax_histx.tick_params(axis="x", labelbottom=False)
ax_histy.tick_params(axis="y", labelleft=False)
# the scatter plot:
sc=ax.scatter(x,y,marker='o',label=label,c=c)
# now determine nice limits by hand:
binwidth = 0.25
xymax = max(np.max(np.abs(x)), np.max(np.abs(y)))
lim = (int(xymax/binwidth) + 1) * binwidth
xlim = (int(np.max(np.abs(x))/binwidth) + 1) * binwidth
ylim = (int(np.max(np.abs(y))/binwidth) + 1) * binwidth
xbins = np.arange(-xlim, xlim + binwidth, binwidth)
ybins = np.arange(-ylim, ylim + binwidth, binwidth)
ax_histx.hist(x, bins=xbins)
ax_histy.hist(y, bins=ybins, orientation='horizontal')
return sc
sc1= scatter_hist_and_colorbar(tx,ty,tz, ax, ax_histx, ax_histy,label='data')
ax.set_ylabel('x data')
ax.set_xlabel('y data')
ax.legend()
divider = make_axes_locatable(ax)
divider = make_axes_locatable(ax0)
ca = divider.append_axes('left', size='50%')
ax0.axis('off')
cbar=fig.colorbar(sc1, cax=ca, orientation='vertical')
cbar.ax.set_ylabel('z data',rotation=270,labelpad=5)
cbar.ax.yaxis.set_ticks_position("right")
gs.tight_layout(fig,pad=1)
plt.savefig('example.png')
plt.show()
I am trying to make plot with two 2d histograms. And i need them both to have a colorbar. But, i was able to plot the colobar at the lateral of one of these histograms, but as can see in the image below, the limits of the color bar doesn't reflect the limits of the histogram. The bin with higher number of events should have around 830 events. (ps: i had set the limits of the colorbar by hand using im2.set_clim(vmin=0, vmax=10000), but before that it was from -20 to 20) .
The code i used to plotis something like:
plt.set_cmap('gnuplot')
fig = plt.figure()
fig.set_size_inches(10, 10)
ax = fig.add_subplot(121,aspect='equal')
ax2 = fig.add_subplot(122, aspect='equal')
ax2.hist2d(data2,datay2,bins=(100,100), rasterized=True,range=np.array([(-7.9, 7.9), (-7.9, 7.9)]))
ax2.set_title('HMC with L=5.0 and t=1.5 ', size= 16, fontname='Comic Sans MS')
ax2.tick_params(axis='both', which='major', labelsize=10)
ax2.tick_params(axis='both', which='minor', labelsize=10)
ax.hist2d(data,datay,bins=(100,100), rasterized=True,range=np.array([(-7.9, 7.9), (-7.9, 7.9)]))
ax.set_title('NUTS ', size= 16, fontname='Comic Sans MS')
ax.tick_params(axis='both', which='major', labelsize=10)
ax.tick_params(axis='both', which='minor', labelsize=10)
#down here i am trying to plot the color map
im2 = ax2.imshow(chain,cmap ='gnuplot' ,interpolation='None')
divider = make_axes_locatable(ax2)
cax = divider.append_axes('right', size='5%', pad=0.05)
im2.set_clim(vmin=0, vmax=10000)
fig.colorbar(im2, cax=cax, orientation='vertical');
fig.text(0.5, 0.02, 'Generalized Coordinate', ha='center', size = 16)
fig.text(0.07, 0.5, 'Generalized Momenta', va='center', rotation='vertical',size = 16)
plt.savefig('2DHMCpog.pdf')
plt.savefig('2DHMCpog.png')
plt.show()
From this answer, you can use the return values of hist2d to set a local color bar. E.g.:
h = ax2.hist2d(data2,datay2,bins=(100,100), …
fig.colorbar(h[3], ax=ax2)
ax2.set_title('HMC with …
Do the same for the second histogram.
I'm trying to draw two rows with three columns of pcolormesh plots and a combined colorbar for all plots. So far it seems to work. However, I'm sure I'm not using the most elegant way...
The only problem I have, is that I can't decrease the horizontal spacing any further. The following line should set the horizontal spacing to zero:
fig.subplots_adjust(left=0.05, right=0.98, top=0.93, bottom=0.00, wspace=0, hspace=0.03)
But this does not work in conjunction with
ax.set_aspect('equal')
I've attached a small code snippet that creates the following figure:
Example figure
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
rows = 2
columns = 3
fig = plt.figure()
gs = gridspec.GridSpec(rows+1, columns)
lines = []
x = np.linspace(1,10,100)
y = x
X, Y = np.meshgrid(x,y)
Z = np.random.rand(100,100)
lines = []
for i in range(rows):
lines.append([])
for j in range(columns):
ax = fig.add_subplot(gs[i, j])
line = ax.pcolormesh(X, Y, Z, cmap=plt.cm.Reds)
lines[i].append(line)
ax.set_aspect('equal')
for tick in ax.get_xticklabels():
tick.set_rotation(45)
if i!=rows-1:
ax.set_xticklabels([])
if j!=0:
ax.set_yticklabels([])
#title
props = dict(boxstyle='round', facecolor='white', alpha=0.7)
ax.text(0.05, 0.95, "plot (%i, %i)" % (i,j), transform=ax.transAxes, fontsize=5,
verticalalignment='top', bbox=props)
ax.tick_params(labelsize=7)
cb_ax = fig.add_subplot(gs[-1,:])
cb_ax.set_aspect(0.05)
cbar = fig.colorbar(lines[0][0], cax=cb_ax, orientation='horizontal')
cb_ax.tick_params(labelsize=7)
fig.subplots_adjust(left=0.05, right=0.98, top=0.93, bottom=0.00, wspace=0, hspace=0.03)
#fig.tight_layout()
fig.text(0.5, 0.2, "x axis", ha='center', va='center')
fig.text(0.5, 0.97, "overall title", ha='center', va='center')
fig.text(0.02, 0.5, "y axis", ha='center', va='center', rotation='vertical')
fig.text(0.5, 0.02, "quantity [unit]", ha='center', va='center',)
plt.savefig("test.png", dpi=600)
I am trying to inset a graph inside the parent graph following the accepted answer here.
However, the plotting framework I am using is quite different:
1) First of all, the Legend is located outside the graph, for which I have followed the second answer posted here, i.e. via shrinking the parent graph:
plt.figure()
# Shrink current axis by 20%
box = ax1.get_position()
ax1.set_position([box.x0, box.y0, box.width * 0.8, box.height])
2) For the labeling, I am using the ax1.legend((p1, p2, p3), ("label for p1", "label for p2", "label for p3")) procedure.
If I ran the code with plt.show() and sys.exit() commented, the entire graph is produced:
However when implementing the inset answer, and trying to inset to the area of the pink and blue data:
(1) Replace plt.figure() by fig, ax1 = plt.subplots(),
(2) Using a ax2 for the inset, since a ax1 has already been used for placing the legend outside the graph,
(3) Uncommentplt.show() and sys.exit(),
no data is plotted both in the parent and inset graphs:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
import sys
x_1 = np.array([ 2.56480648, 2.56635664, 2.57565757, 2.59425943, 2.61906191, 2.64463946,
2.66711671, 2.69966997, 2.72292229, 2.75392539, 2.79422942, 2.81360636,
2.84460946, 2.88026303, 2.91746675, 2.94846985, 2.99187419, 3.01822682,
3.06085609, 3.08565857, 3.12286229, 3.18331833, 3.24067407, 3.25772577,
3.36158616, 3.35616062, 3.43056806, 3.45847085, 3.61574815, 3.65387259,
3.89764927, 9.1 ])
x_2 = np.array([ 5.77982798, 5.77827783, 5.79067907, 5.81083108, 5.82788279, 5.85113511,
5.87438744, 5.89763976, 5.92011701, 5.94414441, 5.96584658, 5.98987399,
6.01467647, 6.03637864, 6.06118112, 6.08443344, 6.11543654, 6.13248825,
6.16194119, 6.18751875, 6.21077108, 6.23479848, 6.26192619, 6.29137914,
6.32083208, 6.35028503, 6.38128813, 6.41306631, 6.45569557, 6.47894789,
6.50530053, 6.55645565, 6.5959846 , 6.62853785, 6.67349235, 6.71612161,
6.76417642, 6.80293029, 6.86726173, 6.91841684, 6.96182118, 7.04165417,
7.10908591, 7.23774877, 7.30208021, 9.40021502])
y_1 = np.array([ 0., 10., 30.1, 50.2, 70.3, 90.4, 110.51, 130.61, 150.71,
170.81, 190.91, 211.01, 231.11, 251.21, 271.31, 291.41, 311.52, 331.62,
351.72, 371.82, 391.92, 412.02, 432.12, 452.22, 472.32, 492.42, 512.53,
532.63, 552.73, 572.83, 592.93, 592.93])
y_2 = np.array([ 0., 10., 30.1, 50.2, 70.3, 90.4, 110.51, 130.61, 150.71,
170.81, 190.91, 211.01, 231.11, 251.21, 271.31, 291.41, 311.52, 331.62,
351.72, 371.82, 391.92, 412.02, 432.12, 452.22, 472.32, 492.42, 512.53,
532.63, 552.73, 572.83, 592.93, 613.03, 633.13, 653.23, 673.33, 693.43,
713.54, 733.64, 753.74, 773.84, 793.94, 814.04, 834.14, 854.24, 874.34,
894.44])
x_3 = np.array([ 273.15, 323.15, 373.15, 423.15, 473.15])
x_4 = np.array([ 295.16725084, 378.53216084, 476.23703528, 490.56204235])
y_3 = np.array([ 1.4709975, 1.42196425, 1.372931 , 1.32389775, 1.2748645 ])
y_4 = np.array([ 1.43766266, 1.46267139, 1.51159861, 1.52367087])
### Plotting:
plt.figure()
#fig, ax1 = plt.subplots()
p1 = plt.scatter(x_1, y_1, color='red', marker='o', s=40)
p3 = plt.scatter(x_2, y_2, marker="o", color='black', facecolors='none', s=40)
p3c = plt.scatter(y_3, x_3, color='magenta', marker="o", facecolors='none', s=40)
p4 = plt.scatter(y_4, x_4, color='blue', marker='o', s=40)
fontP = FontProperties()
fontP.set_size('12')
ax1 = plt.subplot(111)
# Shrink current axis by 20% in order to allow the legend to be outside the plot:
box = ax1.get_position()
ax1.set_position([box.x0, box.y0, box.width * 0.8, box.height])
ax1.legend((\
p1,\
p3,\
p3c,\
p4\
),\
(\
"1",\
"2",\
"3",\
"4"\
),\
prop=fontP, loc='center left', bbox_to_anchor=(1, 0.5))# loc=4)
extraticks=[273.15+25]
plt.yticks(list(plt.yticks()[0]) + extraticks)
plt.gca().set_xlim(right=8)
plt.gca().set_ylim(bottom=-41.72, top=1040)
plt.grid()
plt.show()
sys.exit()
left, bottom, width, height = [0.25, 0.6, 0.2, 0.2]
ax2 = fig.add_axes([left, bottom, width, height])
p3 = ax2.scatter(x_2, y_2, color='black', marker="o", facecolors='none', s=40)
p3c = ax2.scatter(x_3, y_3, color='magenta', marker="o", facecolors='none', s=40)
ax2.set_xlim(right=2.26)
plt.gca().set_ylim(bottom=200, top=1040)
plt.grid()
plt.savefig('plot.pdf', bbox_inches='tight')
plt.show()
I think there are simply some useless commands all over the place which make the code produce 2 figures instead of one and several subplots instead of one. Also the limits of the inset seem to be off. Removing all of this would give you the following plot, which might be what you're after.
### Plotting:
fig, ax1 = plt.subplots()
p1 = plt.scatter(x_1, y_1, color='red', marker='o', s=40)
p3 = plt.scatter(x_2, y_2, marker="o", color='black', facecolors='none', s=40)
p3c = plt.scatter(y_3, x_3, color='magenta', marker="o", facecolors='none', s=40)
p4 = plt.scatter(y_4, x_4, color='blue', marker='o', s=40)
fontP = FontProperties()
fontP.set_size('12')
box = ax1.get_position()
ax1.set_position([box.x0, box.y0, box.width * 0.8, box.height])
ax1.legend((p1,p3,p3c,p4),("1","2","3","4"),
prop=fontP, loc='center left', bbox_to_anchor=(1, 0.5))
extraticks=[273.15+25]
plt.yticks(list(plt.yticks()[0]) + extraticks)
plt.gca().set_xlim(right=8)
plt.gca().set_ylim(bottom=-41.72, top=1040)
plt.grid()
left, bottom, width, height = [0.25, 0.6, 0.2, 0.2]
ax2 = fig.add_axes([left, bottom, width, height])
p3 = ax2.scatter(x_2, y_2, color='black', marker="o", facecolors='none', s=40)
p3c = ax2.scatter(x_3, y_3, color='magenta', marker="o", facecolors='none', s=40)
plt.grid()
plt.savefig('plot.pdf', bbox_inches='tight')
plt.show()