I'm try to label each of the differently-sized panels in a Gridspec at the upper left corner outside the panel. However, this results in the labels being offset by different distances. I think this is because the x and y offset are a function the axis dimensions, but what's the most elegant way to make the labels all the same absolute horizontal and vertical distance to their respective panels? Here's the code:
import numpy as np
from matplotlib import pyplot as plt
from matplotlib.gridspec import GridSpec
def label_panels(fig, panels, xloc = -0.1, yloc = 1.2, size = 20):
for n, ax in enumerate(fig.axes):
if n < len(panels):
ax.text(xloc, yloc, panels[n],
size=size, weight='bold')
fig_7 = plt.figure(constrained_layout=True, figsize = (4,5))
fig7_gs = GridSpec(5, 4, figure=fig_7)
exemplars_subplots = np.array([[fig_7.add_subplot(fig7_gs[i:i 1, j]) for i in range(2)] for j in range(4)])
STDP_subplots = [fig_7.add_subplot(fig7_gs[2 i:3 i,0:2]) for i in range(3)]
ax_imshow = fig_7.add_subplot(fig7_gs[2:5, 2:4])
label_panels(fig_7, range(len(fig_7.axes)), xloc = -0.25, yloc = 1.2)
plt.show()
And this is what it shows. As you can see, panels 0-7 have a different label offset than 8-10 and 11 has a different offset than both of them.:
CodePudding user response:
You are quite correct, the text positions need to be corrected to the actual scale for each axis. For this, you need to obtain the dimension of the gridspec container and the relative dimension of each axis.
A solution (Note: this is quickly written, this should be cleaned up especially with regards to the parameters actually needed for label_panels()
) might look like this:
import numpy as np
from matplotlib import pyplot as plt
from matplotlib.gridspec import GridSpec
## need to include transforms
import matplotlib.transforms as transforms
def label_panels(fig, panels, xloc = 0, yloc = 0, size = 20):
# first, we get the bounding box for the gridspec "container"
gs_bb=transforms.Bbox(fig7_gs[1].get_position(fig))
x0,y0,x1,y1= gs_bb.extents
_gsu_x=x1-x0
_gsu_y=y1-y0
for n, ax in enumerate(fig.axes):
if n < len(panels):
# now, we get the bounding box for each axis inside the gridspec
ax_bb=transforms.Bbox(ax.get_position(fig))
x0,y0,x1,y1= ax_bb.extents
ax_scaling_x=(x1-x0)/_gsu_x
ax_scaling_y=(y1-y0)/_gsu_y
print(f"ax {n} has scaling: ({ax_scaling_x:.2f},{ax_scaling_y:.2f})",)
ax.text(-0.1, 1 0.2/ax_scaling_y, panels[n],
ha="center",va="center",
transform=ax.transAxes,
size=size, weight='bold')
fig_7 = plt.figure(constrained_layout=True, figsize = (4,5))
fig7_gs = GridSpec(5, 4, figure=fig_7)
exemplars_subplots = np.array([[fig_7.add_subplot(fig7_gs[i:i 1, j]) for i in range(2)] for j in range(4)])
STDP_subplots = [fig_7.add_subplot(fig7_gs[2 i:3 i,0:2]) for i in range(3)]
ax_imshow = fig_7.add_subplot(fig7_gs[2:5, 2:4])
label_panels(fig_7, range(len(fig_7.axes)), xloc = -0.25, yloc = 1.2)
plt.show()
CodePudding user response:
Thanks to Jody's link, this works:
import matplotlib.transforms as transforms
def label_panels(fig, labels, xloc = 0, yloc = 1.0, size = 20):
for n, ax in enumerate(fig.axes):
trans = transforms.ScaledTranslation(-20/72, 7/72, fig.dpi_scale_trans)
ax.text(xloc, yloc, labels[n], transform=ax.transAxes trans,
fontsize=size, va='bottom')