如何在子图的角上放置一个字母,包括轴标签(不是轴的角)
How to place a letter in the corner of the subplot including axis labels (not the corner of the axis)
我想用左上角的字母(A、B、C、...)标记子图,这些字母要么与 ylabels 对齐,要么与子图的实际角(而不是轴)对齐。
如果子图的宽度不同,我不能再使用轴变换坐标偏移的文本,因为这会导致每个子图的距离不同。所以我通常使用偏移变换。但是如果 ylabels 有不同的宽度,这就不再起作用了。我目前还关注每个地块的偏移量,但这还不够好。
这是我目前拥有的:
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)
正如您在下图中看到的,标签与轴脊柱的距离相同,但我希望它们与 ylabels 的左边缘或子图的角对齐,在这种情况下会重合与 ylabels 水平排列。虽然没有 transSubplot,只有 transAxes 和 transFigure
看来这个想法是将标签放在各个轴的紧密边界框的边缘。
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 机制。因此,此类解决方案仅适用于图形边界内的位置。
我想用左上角的字母(A、B、C、...)标记子图,这些字母要么与 ylabels 对齐,要么与子图的实际角(而不是轴)对齐。
如果子图的宽度不同,我不能再使用轴变换坐标偏移的文本,因为这会导致每个子图的距离不同。所以我通常使用偏移变换。但是如果 ylabels 有不同的宽度,这就不再起作用了。我目前还关注每个地块的偏移量,但这还不够好。
这是我目前拥有的:
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)
正如您在下图中看到的,标签与轴脊柱的距离相同,但我希望它们与 ylabels 的左边缘或子图的角对齐,在这种情况下会重合与 ylabels 水平排列。虽然没有 transSubplot,只有 transAxes 和 transFigure
看来这个想法是将标签放在各个轴的紧密边界框的边缘。
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 机制。因此,此类解决方案仅适用于图形边界内的位置。