Кажется, идея состоит в том, чтобы разместить метку на краю жесткой ограничительной рамки соответствующих осей.
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(5, 2), constrained_layout=True)
gs = fig.add_gridspec(1, 3, width_ratios=[1, 2, 3])
axes = [fig.add_subplot(gs[i]) for i in range(3)]
ylabels = ["flat label", "bigger\nlabel", "even\nbigger\nlabel"]
labels = ["A", "B", "C"]
for ax, ylabel in zip(axes, ylabels):
ax.set_ylabel(ylabel)
fig.canvas.draw()
for ax, label in zip(axes, labels):
bbox = ax.get_tightbbox(fig.canvas.get_renderer())
fig.text(bbox.x0, bbox.y1, label, fontsize=12, fontweight="bold", va="top", ha="left",
transform=None)
plt.show()
Очевидным недостатком этого является то, что впоследствии нельзя изменить размер фигуры. Немного лучше было бы сначала преобразовать обратно в координаты фигуры, а также использовать обратный вызов при событиях отрисовки для обновления координат.
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(5, 2), constrained_layout=True)
gs = fig.add_gridspec(1, 3, width_ratios=[1, 2, 3])
axes = [fig.add_subplot(gs[i]) for i in range(3)]
ylabels = ["flat label", "bigger\nlabel", "even\nbigger\nlabel"]
labels = ["A", "B", "C"]
for ax, ylabel in zip(axes, ylabels):
ax.set_ylabel(ylabel)
fig.canvas.draw()
axlabels = [fig.text(0,0, label, fontsize=12, fontweight="bold", va="top", ha="left")
for ax, label in zip(axes, labels)]
def update_labels(evt=None):
trans = fig.transFigure.inverted()
for ax, label in zip(axes, axlabels):
bbox = ax.get_tightbbox(fig.canvas.get_renderer())
label.set_position(trans.transform_point([bbox.x0, bbox.y1]))
update_labels()
cid = fig.canvas.mpl_connect("draw_event", update_labels)
plt.show()
Обратите внимание, что одним из ключевых элементов здесь является то, что fig.text
не участвует в механизме constrained_layout. Поэтому такие решения будут работать только для позиций, которые находятся в пределах границ фигуры.