如何在包含轴标签(而不是轴角)的子图的角上放置字母

时间:2019-04-29 08:22:42

标签: python matplotlib text transform subplot

我想用左上角(A,B,C,...)的字母标记子图,这些字母要么与ylabel对齐,要么与子图的实际角(而不是轴)对齐。

如果子图的宽度不同,我将无法再使用在轴变换坐标中具有偏移的文本,因为这将导致每个子图的距离不同。所以我通常使用偏移量转换。但是,如果ylabel的宽度不同,这将不再起作用。我目前还关注每个图的偏移量,但这还不够好。

这是我到目前为止所拥有的:

import matplotlib.pyplot as plt
from matplotlib import transforms
import numpy as np

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"]

scaledtrans = transforms.ScaledTranslation(-0.4, 0, fig.dpi_scale_trans)

for ax, ylabel, label in zip(axes, ylabels, labels):
    ax.set_ylabel(ylabel)
    ax.text(0, 1, label, fontsize=12, fontweight="bold", va="bottom", ha="left",
           transform=ax.transAxes + scaledtrans)

如下图所示,标签与轴刺之间的距离相同,但我希望它们与ylabel的左边缘或子图的角对齐,在这种情况下,它们与水平方向重合ylabel。不过没有transSubplot,只有transAxes和transFigure

enter image description here

1 个答案:

答案 0 :(得分:1)

似乎是将标签放置在各个轴的紧密边界框的边缘。

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

enter image description here

一个明显的缺点是,以后无法更改图形大小。更好的方法可能是先转换回图形坐标,然后在绘制事件上使用回调以更新坐标。

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机制。因此,此类解决方案仅适用于图形边界内的位置。