Removing axes and lining up a subplot - python

I have produced a graph with two subplots and am trying to add a histogram to the end of the residuals plot but am unable to remove the x-axis of the histogram plot and get it to line up with the end of the residual plot.
Here is a copy of my current code:
#graph with histogram and std error plot thing
fig1 = plt.figure(figsize =(9.6,7.2))
ax = fig1.add_axes((0.2,0.4,.75,.6))
ax.errorbar(xval, yval*1000, yerr=yerr*1000, xerr=xerr, marker='x', linestyle='None')
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.yaxis.set_ticks_position('left')
ax.xaxis.set_ticks_position('bottom')
# Axis labels
plt.xlabel('Height (m)', fontsize = 12)
plt.ylabel('dM/dt (g $s^{-1}$) × $10^{3}$', fontsize = 12)
# Generate best fit line using model function and best fit parameters, and add to plot
fit_line=model_funct(xval, [a_soln, b_soln])
plt.plot(xval, fit_line*1000)
# Set suitable axis limits: you will probably need to change these...
#pyplot.xlim(-1, 61)
#pyplot.ylim(65, 105)
# pyplot.show()
ax2 = fig1.add_axes((0.2,0.2,.75,.2)) #start frame1 at 0.2, 0.4
plt.xlabel("Height of Water (m)", fontsize = 12)
plt.ylabel("Normalised\nResiduals", fontsize = 12) #\n is used to start a new line
ax2.plot(h,normalised_residuals,"x", color = "green")
plt.axhline(0, linewidth=1, linestyle="--", color="black")
plt.savefig("Final Graph with added parts.png", dpi = 500)
ax2.axhspan(ymin = -np.std(normalised_residuals), ymax = np.std(normalised_residuals), color = 'gray', alpha =0.5)
ax3 = fig1.add_axes((1,0.2,0.2,0.2))
ax3.hist(normalised_residuals, bins=8, orientation="horizontal")
ax3.spines['right'].set_visible(False)
ax3.spines['top'].set_visible(False)
ax3.spines['left'].set_visible(False)
ax3.yaxis.set_ticks_position('left')
ax3.xaxis.set_ticks_position('bottom')
and here is a picture of my graph currently:

An example with random data. Using tick_params and manually setting both ylim and the histogram range, did the trick.
import matplotlib.pyplot as plt
import numpy as np
fig1 = plt.figure(figsize=(20, 15))
ax = fig1.add_axes((0.2, 0.4, .75, .6))
ax2 = fig1.add_axes((0.2, 0.2, .75, .2))
ax3 = fig1.add_axes((.95, 0.2, 0.2, 0.2))
xval = (np.linspace(0.02, 0.15, 20)
+ (np.random.default_rng(0).random(20) - 0.5) / 30)
yval = 2 * xval + 0.08
xerr = (np.random.default_rng(0).random(20) * 2 - 1) / 60
yerr = (np.random.default_rng(1).random(20) * 2 - 1) / 60
ax.errorbar(xval, yval, yerr=yerr, xerr=xerr, marker='x', linestyle='None')
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.tick_params(labelbottom=False)
ax.set_xlabel('Height (m)', fontsize=12)
ax.set_ylabel('dM/dt (g $s^{-1}$) × $10^{3}$', fontsize=12)
ax2.plot(xval, xerr, 'x', color='green')
ax2.axhline(0, linewidth=1, linestyle='--', color='black')
ax2.axhspan(ymin=-np.std(xerr), ymax=np.std(xerr), color='gray', alpha=0.5)
ax2.set_xlabel('Height of Water (m)', fontsize=12)
ax2.set_ylabel('Normalised\nResiduals', fontsize=12)
resLim = ax2.get_ylim()
ax3.hist(xerr, bins=8, orientation='horizontal', range=resLim, rwidth=0.9)
ax3.spines['right'].set_visible(False)
ax3.spines['top'].set_visible(False)
ax3.spines['left'].set_visible(False)
ax3.spines['bottom'].set_visible(False)
ax3.tick_params(labelbottom=False, labelleft=False, bottom=False, left=False)
ax3.set_ylim(resLim)
fig1.savefig('so.png', bbox_inches='tight')

Related

Properly displaying pyplot scatter plot with X/Y histograms and a colorbar

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()

Color bar limits doesn't follow the data limits

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.

Getting ticks on same horizontal grid for plots with different scale

This site describes well how to draw two lines with different scales on the same plot.
However, the y ticks are not aligned as you can see in the following picture if I draw an horizontal grid across.
Is there a way to add ticks so that they align (e.g. the 5000 on the left is aligned with the 0.50 on the right, etc.)?
One could align the right ticks by setting their ylims to the corresponding ylims of the left:
ymin1, ymax1 = ax1.get_ylim()
ax2.set_ylim(ymin1 / 10000, ymax1 / 10000)
Or set the ylims of both axes to the widest range:
import numpy as np
import matplotlib.pyplot as plt
# Create some mock data
t = np.arange(0.01, 10.0, 0.01)
data1 = np.exp(t)
data2 = np.sin(2 * np.pi * t)
fig, ax1 = plt.subplots()
color = 'tab:red'
ax1.set_xlabel('time (s)')
ax1.set_ylabel('exp', color=color)
ax1.plot(t, data1, color=color)
ax1.tick_params(axis='y', labelcolor=color)
ax2 = ax1.twinx() # instantiate a second axes that shares the same x-axis
color = 'tab:blue'
ax2.set_ylabel('sin', color=color) # we already handled the x-label with ax1
ax2.plot(t, data2, color=color)
ax2.tick_params(axis='y', labelcolor=color)
ymin1, ymax1 = ax1.get_ylim()
ymin2, ymax2 = ax2.get_ylim()
ymin1 = min(ymin1, ymin2 * 10000)
ymax1 = max(ymax1, ymax2 * 10000)
ax1.set_ylim(ymin1, ymax1)
ax2.set_ylim(ymin1 / 10000, ymax1 / 10000)
ax1.grid(True, axis='y')
fig.tight_layout() # otherwise the right y-label is slightly clipped
plt.show()

matplotlib: horizontal spacing of subplots with equal aspect ratio

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)

Inset graph, when using a legend placed outside the parent graph

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()

Categories

Resources