简体   繁体   English

不同大小的matplotlib标签子图与每个子图角的距离完全相同

[英]matplotlib label subplots of different sizes the exact same distance from corner of each subplot

I am searching for an elegant solution to placing a figure label (A, B, C) above the corner of each subplot using matplotlib- but have each be the exact same distance from the subplot axes corner. 我正在寻找一种优雅的解决方案,使用matplotlib-在每个子图的角上方放置一个图形标签(A,B,C),但每个子图与子图轴角的距离完全相同。 The problem I am having is that typical labeling solutions take advantage of the axes fraction- so it is easy to place A,B,C in the same place relative to each plot. 我遇到的问题是典型的标记解决方案利用了轴分数-因此相对于每个图而言,很容易将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)

在此处输入图片说明

however, if the plots are different sizes you will get labels that are variably far from the corners of the plots (due to aspect ratio). 但是,如果图的大小不同,则得到的标签距离图的拐角处的距离会有所不同(由于长宽比)。 See Label A and C for example. 例如,请参见标签A和C。 I am looking for a good way to ensure proportional distance of labels from axes corners for panels containing multiple sizes/aspect ratio subplots, and/or to explicitly set text a specific distance (in inches or maybe figure coordinate units) from axes corners . 我正在寻找一种方法来确保包含多个尺寸/长宽比子图的面板的标签到轴角的比例距离,和/或显式设置文本到轴角的特定距离(以英寸或图形坐标为单位)

In the past I have placed same sized square axes at the corner of each subplot axes in the panel, made those invisible, and scaled text to these, but it is a convoluted approach. 过去,我在面板中每个子图轴的角上放置了大小相同的方轴,使这些文字不可见,并按比例缩放了这些文字,但这是一种复杂的方法。

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)

在此处输入图片说明

You could use axes pixels istead of axes fraction as reference and add the individual heights to compensate the reference origin lower left corner: 您可以使用axes pixels不是axes fraction作为参考,并添加各个高度以补偿参考原点的左下角:

Here for brevity only the changed line within your loop, rest of your code untouched: 为简洁起见,此处仅循环中已更改的行,其余代码保持不变:

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

在此处输入图片说明

What about simply adding the title of the subplots? 只添加子图的标题怎么办?

(Again only the line to be replaced within your loop:) (仅在循环中重新替换要替换的行:)

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

Result: 结果: 在此处输入图片说明

You can get the position of each subplot and add text on figure-level, so that offsets are in fractions of the figure size - which is equal for all subplots: 您可以获取每个子图的位置并在图形级上添加文本,以使偏移量仅占图形尺寸的几分之一-对于所有子图均相等:

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

Result: 结果: 在此处输入图片说明

While both of the above solutions work (and are more simple/meet most peoples needs), I thought I'd post a solution I pieced together allowing you to place text/objects with exact inches/points of offset from a particular axes point. 尽管以上两种解决方案都可以工作(并且更简单/满足大多数人的需求),但我想我会发布一个我拼凑的解决方案,使您可以将文本/对象放置在与特定轴点偏移的精确英寸/点的位置。 This means that regardless of figure panel size/dpi, the text could be placed the same distance from corners- useful if making multiple figures of different dimensions and want them to be consistent (eg for publication). 这意味着无论图形面板的大小/ dpi如何,都可以将文本放置在距拐角相同的距离处,如果制作多个具有不同尺寸的图形并希望它们保持一致(例如,用于发布),则很有用。 Apparently the matplotlib.transforms.offset_copy() function was designed for this purpose allowing specification of inches, points (1/72 inch) or dots as offset. 显然,为此设计了matplotlib.transforms.offset_copy()函数,以允许指定英寸,点(1/72英寸)或点作为偏移量。

https://matplotlib.org/examples/pylab_examples/transoffset.html 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')

在此处输入图片说明

or with figsize/dpi changed 或更改了figsize / dpi

在此处输入图片说明

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM