【问题标题】:matplotlib label subplots of different sizes the exact same distance from corner of each subplotmatplotlib标签不同大小的子图与每个子图角的距离完全相同
【发布时间】:2018-09-12 02:10:14
【问题描述】:

我正在寻找一个优雅的解决方案,使用 matplotlib 在每个子图的角上方放置一个图形标签(A、B、C),但每个标签与子图轴角的距离完全相同。我遇到的问题是典型的标签解决方案利用了轴分数-因此很容易将 A、B、C 放置在相对于每个图的相同位置。

import matplotlib as mpl
import matplotlib.pyplot as plt
fig, ax = plt.subplots(2,2, figsize = (10,10))

texts = ['A', 'B', 'C', 'D']
axes = fig.get_axes()
for a,l in zip(axes, texts):
    a.annotate(l, xy=(-0.1, 1.1), xycoords="axes fraction", fontsize=15, weight = 'bold')
plt.suptitle('Label_Distance Consistent', fontsize = 20)

但是,如果图的大小不同,您将获得远离图角的标签(由于纵横比)。例如,参见标签 A 和 C。我正在寻找一种好方法来确保包含多个尺寸/纵横比子图的面板的标签与轴角的比例距离,和/或显式设置文本与轴的特定距离(以英寸或图形坐标单位为单位)角落

过去我在面板中每个子图轴的角落放置了相同大小的方轴,使它们不可见,并将文本缩放到这些,但这是一种复杂的方法。

fig, ax = plt.subplots(2,2, figsize = (10,10))

ax1 = plt.subplot2grid((3, 3), (0, 0), colspan=3)
ax2 = plt.subplot2grid((3, 3), (1, 0), colspan=2)
ax3 = plt.subplot2grid((3, 3), (1, 2), rowspan=2)
ax4 = plt.subplot2grid((3, 3), (2, 0))
ax5 = plt.subplot2grid((3, 3), (2, 1))

axes = fig.get_axes()
texts = ['A', 'B', 'C', 'D', 'E']
for a,l in zip(axes, texts):
    a.annotate(l, xy=(-0.1, 1.1), xycoords="axes fraction", fontsize=15, weight = 'bold')
plt.suptitle('Label Distance Inconsistent', fontsize = 20)

【问题讨论】:

    标签: python matplotlib annotate


    【解决方案1】:

    您可以使用axes pixels 而不是axes fraction 作为参考,并添加各个高度以补偿参考原点左下角:

    为简洁起见,这里仅显示循环中更改的行,其余代码保持不变:

        a.annotate(l, xy=(-40, 10 + a.bbox.height), xycoords="axes pixels", fontsize=15, weight = 'bold')
    

    【讨论】:

    • 很好的答案,这几乎是我所希望的。我发现当 dpi 不是 80 时,这并不能始终如一地工作,有没有办法解决这个问题?因此,例如,如果我将 dpi 放大到 100,则标签将与轴再次不一致 - C 将离 ax3 的角(右下角)更远(高度)。有没有办法将文本设置为相对于轴顶角以英寸(x 英寸,y 英寸)为单位的指定距离,以便对 dpi 更改/图形尺寸具有鲁棒性?非常感谢您的帮助!
    • 再想一想,这似乎在我尝试的任何 DPI 上都不起作用,它也可能是 matplotlib 版本特定的,因为你的图像看起来一致(我是 2.2.3)。对我来说,a.bbox.height 似乎没有返回一个与地块高度相符的值。
    • 刚刚使用 matplotlib 2.2.3 对其进行了测试,它仍然适用于 a.bbox.heightaxes pixels
    • 这绝对是有道理的,但无论出于何种原因,我的字体仍然与情节的尺寸成比例。事实上,即使我用 xy= (0,bbox.height) (理论上是顶角)绘制它们,字母也不会放在角落里。奇怪的。我在这个 ax.annotate 方法中观察到了其他奇怪的结果,即在 xycoords='figure points' 或 'figure pixel' 上绘图似乎没有将文本放置在预期的位置 - 这就是为什么在我下面的答案中我从显示转换回到轴分数。
    • 确认这适用于与我一起工作的其他人,必须是特定于我的软件配置的东西。
    【解决方案2】:

    您可以获取每个子图的位置并在图形级别添加文本,以便偏移量是图形大小的分数 - 这对于所有子图都是相等的:

    X = a.get_position().x0
    Y = a.get_position().y1    
    fig.text(X - .04, Y + .015, l, size=15, weight='bold')
    

    结果:

    【讨论】:

    • 接受这个答案,因为它解决了我的问题的大部分要求,并且可能会满足大多数人的需求。
    【解决方案3】:

    简单地添加子图的标题怎么样?

    (同样只有循环中要替换的行:)

    a.set_title(l, size=15, weight='bold', loc='left')
    

    结果:

    【讨论】:

    • 我从来没有想过这个!如果它们不需要抵消,则非常有效。
    【解决方案4】:

    虽然上述两种解决方案都有效(并且更简单/满足大多数人的需求),但我想我会发布一个我拼凑在一起的解决方案,允许您放置与特定的偏移量具有精确英寸/点的文本/对象轴点。这意味着无论图形面板大小/dpi如何,文本都可以放置在距角落相同的距离 - 如果制作多个不同尺寸的图形并希望它们保持一致(例如用于发布),这很有用。显然matplotlib.transforms.offset_copy() 函数是为此目的而设计的,允许指定英寸、点(1/72 英寸)或点作为偏移量。

    https://matplotlib.org/examples/pylab_examples/transoffset.html

    import matplotlib as mpl
    import matplotlib.pyplot as plt
    import matplotlib.ticker as ticker
    
    fig, ax = plt.subplots(2,2, figsize = (10,7), dpi = 500)
    
    ax1 = plt.subplot2grid((3, 3), (0, 0), colspan=3)
    ax2 = plt.subplot2grid((3, 3), (1, 0), colspan=2)
    ax3 = plt.subplot2grid((3, 3), (1, 2), rowspan=2)
    ax4 = plt.subplot2grid((3, 3), (2, 0))
    ax5 = plt.subplot2grid((3, 3), (2, 1))
    
    axes = fig.get_axes()
    texts = ['A', 'B', 'C', 'D', 'E']
    for a,l in zip(axes, texts):
        a.set_xlim(0,10)
        inv = a.transData.inverted()
    
        # specify the number of points or inches or dots to transform by
        # places an axes transform here for the axes on which you want to pick an anchor point on
        offsetter = mpl.transforms.offset_copy(a.transAxes, fig=fig, x= -2, y= 6, units = 'points')
    
        # offset an anchor point - this will return display coordinates 
        corner_offset = offsetter.transform([0,1])
    
        # convert display coordinate to axes fraction
        axes_frac = inv.transform(corner_offset)
        a.annotate(l, xy=(axes_frac[0],axes_frac[1]), xycoords="axes fraction", fontsize=15, weight = 'bold', color='blue')
    

    或改变 figsize/dpi

    【讨论】:

      猜你喜欢
      • 2017-03-01
      • 2021-08-05
      • 1970-01-01
      • 2022-01-07
      • 2017-07-25
      • 2015-10-18
      • 2023-04-06
      相关资源
      最近更新 更多