首页 > 解决方案 > 自动获取子图的坐标,以便将它们设置为图例的自动定位

问题描述

我第一次尝试手动设置Getdist 工具生成的主图的主要图例的位置。

下图表示来自具有联合分布的协方差矩阵的 1/2 sigma 置信水平。它由Getdist 工具生成。

图例手动定位

生成此图的主要例程是:

    # g.settings
    g = plots.get_subplot_plotter()
    g.settings.figure_legend_frame = True
    g.settings.legend_fontsize = 21
        g.triangle_plot([matrix1, matrix2],
                          names,
                          filled = True,
                          contour_colors = ['darkblue','red'],
                          line_args = [{'lw':2, 'color':'darkblue'},
                          {'lw':2, 'color':'red'}]
                          )

g.add_legend(['Opt. Flat. No Gamma. - cross - standard situation - Criterion taking into accound a = 200',\
  'Pess. Flat. No Gamma. - cross - standard situation - Criterion taking into account a = 300' ],\
  bbox_to_anchor = [1.5, 8.5])

该值1.5似乎对应于 x 坐标(宽度)8.5对应于图例的 y 坐标(高度)。

现在,我想自动执行此过程,而不是每次手动设置图例的位置。

我希望图例的右上角位于第一个左上框的顶部边框(就在“1sigma ± 0.0012”标题下方的顶线边框级别)。

我还希望将图例推到图的右侧(直到图右下框的右边框:标识为sigma8 "1sigma ± 0.001" title; 注意:我希望它位于 1.0 和 0.0 xticks 之前,就在 x - 右线边界的坐标)。

在这里,我试图获取此左上框的顶部边框的全局坐标(整个图):

# First, get y coordinates of top border for first Likelihood
  box1 = g.subplots[0,0]
  box1_coords = box1._position.bounds
  print('box1_coords = ', box1_coords)

我在执行时得到以下值:

box1_coords =  (0.125, 0.7860975609756098, 0.09451219512195125, 0.09390243902439022)

如您所见,这些值似乎已标准化,所以如果我想将这些值插入到:

bbox_to_anchor = [box1_coords[0], box1_coords[1]]

正如预期的那样,这行代码为图例产生了错误的位置。

那么,我怎样才能设法自动为 bbox_to_anchor 分配好的值以获得我想要的("1sigma ± 0.0012" title由框(由 sigma8 标识的 x 坐标"1sigma ± 0.001" title)?

更新 1

我试图使它们适应我的情况,但问题仍然存在。这是我所做的:

# g.settings
g = plots.get_subplot_plotter()

# get the max y position of the top left axis
top_left_plot = g.subplots[0,0].axes.get_position().ymax
# get the max x position of the bottom right axis
# it is -1 to reference the last plot
bottom_right_plot = g.subplots[-1,-1].axes.get_position().xmax

我不知道为什么价值top_left_plotbottom_right_plot不是好的价值。

我认为subplots[0,0](对于y-coordinate图例的顶部)是指左上角的子图和subplots[-1,-1]右下角的子图(对于x-coordinate图例的右侧),但考虑到这一点,它不起作用。

例如 :

# g.settings
g = plots.get_subplot_plotter()
# Call triplot
g.triangle_plot([matrix1, matrix2],
                names,
                filled = True,
                legend_labels = [],
                contour_colors = ['darkblue','red'],
                line_args = [{'lw':2, 'color':'darkblue'},
                {'lw':2, 'color':'red'}])

g.add_legend(['Opt. Flat. No Gamma. - cross - standard situation - Criterion taking into accound a = 200',
'Pess. Flat. No Gamma. - cross - standard situation - Criterion taking into account a = 300'],
legend_loc='upper right',
bbox_to_anchor=(bottom_right_plot, top_left_plot)
)

我得到:

legend_coords y_max, x_max  0.88 0.9000000000000001

我不明白为什么这些值(似乎包含在 0.0 和 1.0 之间)没有被考虑在内g.add_legend

使用@mullinscr的解决方案,我得到下图:

图例位置错误

如果我通过强制获取图例位置的坐标:

top_left_plot = 8.3
bottom_right_plot = 1.0

这看起来像这篇文章的第一个图。但是这两个值并不像它应该的那样包含在 0.0 和 1.0 之间。

更新 2

@mullinscr,谢谢,我关注了你的更新,总是遇到问题。如果我直接在我的脚本中应用相同的代码片段,即:

g.add_legend(['An example legend - item 1'],
         legend_loc='upper right', # we want to specify the location of this point
         bbox_to_anchor=(bottom_right_plot, top_left_plot),
         bbox_transform=plt.gcf().transFigure, # this is the x and y co-ords we extracted above
         borderaxespad=0, # this means there is no padding around the legend
         edgecolor='black')

然后我得到下图:

建议的解决方案

如您所见,坐标并不是真正预期的:在x-coordinate和上稍有偏移y-coordinate

如果我将您的代码片段应用于我的图例文本,我会得到:

适用于我的案例的方法

我给你我整个脚本的链接,这可能会让你更容易看到与预期相比的错误:

我的整个 Python 脚本

标签: pythonmatplotlibpositionlegend

解决方案


它基本上像你描述的那样工作。轴的 bbox(xmin, ymin, width, height)以图中的分数给出,并plt.legend()使用相同的格式,因此两者是兼容的。通过将upper right图例的角设置为由最外轴定义的角,您可以获得干净的布局,而不必担心图例的确切大小。

import matplotlib.pyplot as plt

n = 4

# Create the subplot grid
# Alternative: fig, ax = plt.subplots(n, n); ax[i, j].remove() for j > i
fig = plt.figure()
gs = fig.add_gridspec(nrows=n, ncols=n)
ax = np.zeros((n, n), dtype=object)
for i in range(n):
    for j in range(n):
        if j <= i:
            ax[i, j] = fig.add_subplot(gs[i, j])
# add this to make the position of the legend easier to spot
ax[0, -1] = fig.add_subplot(gs[0, -1])

# Plot some dummy data 
ax[0, 0].plot(range(10), 'b-o', label='Dummy Label 4x4')

# Set the legend
y_max = ax[0][0].get_position().ymax
x_max = ax[-1][-1].get_position().xmax
fig.legend(loc='upper right', bbox_to_anchor=(x_max, y_max),
           borderaxespad=0)

plt.show()

Constrained Layout 保存文件时可能会出现一些陷阱,bbox_inches='tight'因为两者都会以意想不到的方式搞砸图例的位置。

有关图例放置的更多示例,我发现此集合 非常有用。


推荐阅读