Reputation: 551
I'm using matplotlib.gridspec
and tight_layout()
to create a complex plot layout. My current code looks like
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import matplotlib
from matplotlib.ticker import MaxNLocator
fig = plt.figure(figsize=(15,15))
gs1 = gridspec.GridSpec(8, 2)
gs1.update(left=0.05, right=0.95, wspace=0.05, hspace=0.05)
ax1 = plt.subplot(gs1[0:4, 0]) # Original
ax2 = plt.subplot(gs1[0:4, 1]) # Model
ax3 = plt.subplot(gs1[4:8, 0]) # Residual+Sky
ax4 = plt.subplot(gs1[4:7, 1]) # SB profile
ax5 = plt.subplot(gs1[7:8, 1])# SB residuals
# Hide tick labels
plt.setp(ax1.get_yticklabels(), visible=False)
plt.setp(ax1.get_xticklabels(), visible=False)
plt.setp(ax2.get_yticklabels(), visible=False)
plt.setp(ax2.get_xticklabels(), visible=False)
plt.setp(ax3.get_yticklabels(), visible=False)
plt.setp(ax3.get_xticklabels(), visible=False)
plt.setp(ax4.get_xticklabels(), visible=False)
ax4.invert_yaxis()
ax4.set_ylabel(r'Surface Brightness, $\mu$ [mag arcsec$^{-2}$]')
ax5.set_ylabel(r'$\Delta\mu$')
ax5.set_xlabel('Semi-major Axis [arcsec]')
ax5.grid(b=True)
ax4.set_xscale('log')
ax5.set_xscale('log')
gs1.tight_layout(fig)
nbins = len(ax5.get_xticklabels())
ax5.yaxis.set_major_locator(MaxNLocator(nbins=nbins, prune='upper'))
ax4.yaxis.set_major_locator(MaxNLocator(nbins=nbins, prune='upper'))
# Show the plot
plt.show()
which produces a layout that looks like
What I need to do is either
shrink the vertical space between ax4 and ax5 (the two bottom-right subplots), or
make ax4 and ax5 share the same x-axis, such that the space between the subplots is zero
I really like the way gridspec
and tight_layout()
formats the plots, however I don't know of a way to "force" the spacing between individual subplots. Is there an easy way to do this using both matplotlib.gridspec
and tight_layout()
?
Upvotes: 1
Views: 2700
Reputation: 86
You can use the get_position and set_position methods of the axes instance to change the location of an axes in the figure (http://matplotlib.org/api/axes_api.html).
get_position returns a Bbox instance and you can use get_points to obtain a 2x2 numpy array of the form [[x0, y0], [x1, y1]], where x0, y0, x1, y1 are the figure coordinates of your axes.
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import matplotlib
from matplotlib.ticker import MaxNLocator
fig = plt.figure(figsize=(15,15))
gs1 = gridspec.GridSpec(8, 2)
gs1.update(left=0.05, right=0.95, wspace=0.05, hspace=0.05)
ax1 = plt.subplot(gs1[0:4, 0]) # Original
ax2 = plt.subplot(gs1[0:4, 1]) # Model
ax3 = plt.subplot(gs1[4:8, 0]) # Residual+Sky
ax4 = plt.subplot(gs1[4:7, 1]) # SB profile
ax5 = plt.subplot(gs1[7:8, 1])# SB residuals
# Hide tick labels
plt.setp(ax1.get_yticklabels(), visible=False)
plt.setp(ax1.get_xticklabels(), visible=False)
plt.setp(ax2.get_yticklabels(), visible=False)
plt.setp(ax2.get_xticklabels(), visible=False)
plt.setp(ax3.get_yticklabels(), visible=False)
plt.setp(ax3.get_xticklabels(), visible=False)
plt.setp(ax4.get_xticklabels(), visible=False)
ax4.invert_yaxis()
ax4.set_ylabel(r'Surface Brightness, $\mu$ [mag arcsec$^{-2}$]')
ax5.set_ylabel(r'$\Delta\mu$')
ax5.set_xlabel('Semi-major Axis [arcsec]')
ax5.grid(b=True)
ax4.set_xscale('log')
ax5.set_xscale('log')
gs1.tight_layout(fig)
nbins = len(ax5.get_xticklabels())
ax5.yaxis.set_major_locator(MaxNLocator(nbins=nbins, prune='upper'))
ax4.yaxis.set_major_locator(MaxNLocator(nbins=nbins, prune='upper'))
# change axis location of ax5
pos4 = ax4.get_position()
pos5 = ax5.get_position()
points4 = pos4.get_points()
points5 = pos5.get_points()
points5[1][1]=points4[0][1]
pos5.set_points(points5)
ax5.set_position(pos5)
# Show the plot
plt.show()
This code should produce this: plot with adjusted ax5
Upvotes: 4