Python Matplotlib:调整图例位置/位置

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24061296/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 03:54:11  来源:igfitidea点击:

Matplotlib: Adjust legend location/position

pythonmatplotlibplotpositionlegend

提问by Caleris

I'm creating a figure with multiple subplots. One of these subplots is giving me some trouble, as none of the axes corners or centers are free (or can be freed up) for placing the legend. What I'd like to do is to have the legend placed somewhere in between the 'upper left' and 'center left' locations, while keeping the padding between it and the y-axis equal to the legends in the other subplots (that are placed using one of the predefined legend location keywords).

我正在创建一个带有多个子图的图形。这些子图之一给我带来了一些麻烦,因为轴的角或中心都没有空闲(或可以释放)用于放置图例。我想要做的是将图例放置在“左上角”和“左中角”位置之间的某个位置,同时保持它与 y 轴之间的填充等于其他子图中的图例(即使用预定义的图例位置关键字之一放置)。

I know I can specify a custom position by using loc=(x,y), but then I can't figure out how to get the padding between the legend and the y-axis to be equal to that used by the other legends. Would it be possible to somehow use the borderaxespadproperty of the first legend? Though I'm not succeeding at getting that to work.

我知道我可以使用 指定自定义位置loc=(x,y),但是我无法弄清楚如何使图例和 y 轴之间的填充等于其他图例使用的填充。是否有可能以某种方式使用borderaxespad第一个图例的属性?虽然我没有成功地让它发挥作用。

Any suggestions would be most welcome!

任何建议将是最受欢迎的!

Edit: Here is a (very simplified) illustration of the problem:

编辑:这是问题的(非常简化的)说明:

import matplotlib.pyplot as plt

fig, ax = plt.subplots(1, 2, sharex=False, sharey=False)
ax[0].axhline(y=1, label='one')
ax[0].axhline(y=2, label='two')
ax[0].set_ylim([0.8,3.2])
ax[0].legend(loc=2)

ax[1].axhline(y=1, label='one')
ax[1].axhline(y=2, label='two')
ax[1].axhline(y=3, label='three')
ax[1].set_ylim([0.8,3.2])
ax[1].legend(loc=2)

plt.show()

enter image description here

在此处输入图片说明

What I'd like is that the legend in the right plot is moved down somewhat so it no longer overlaps with the line. As a last resort I could change the axis limits, but I would very much like to avoid that.

我想要的是右图中的图例稍微向下移动,因此它不再与线重叠。作为最后的手段,我可​​以更改轴限制,但我非常想避免这种情况。

采纳答案by Caleris

After spending way too much time on this, I've come up with the following satisfactory solution (the Transformations Tutorialdefinitely helped):

在花了太多时间之后,我想出了以下令人满意的解决方案(转换教程肯定有帮助):

bapad = plt.rcParams['legend.borderaxespad']
fontsize = plt.rcParams['font.size']
axline = plt.rcParams['axes.linewidth']  #need this, otherwise the result will be off by a few pixels
pad_points = bapad*fontsize + axline  #padding is defined in relative to font size
pad_inches = pad_points/72.0  #convert from points to inches
pad_pixels = pad_inches*fig.dpi  #convert from inches to pixels using the figure's dpi

Then, I found that both of the following work and give the same value for the padding:

然后,我发现以下两个都可以工作并为填充提供相同的值:

# Define inverse transform, transforms display coordinates (pixels) to axes coordinates
inv = ax[1].transAxes.inverted()
# Inverse transform two points on the display and find the relative distance
pad_axes = inv.transform((pad_pixels, 0)) - inv.transform((0,0))  
pad_xaxis = pad_axes[0]

or

或者

# Find how may pixels there are on the x-axis
x_pixels = ax[1].transAxes.transform((1,0)) - ax[1].transAxes.transform((0,0))
# Compute the ratio between the pixel offset and the total amount of pixels 
pad_xaxis = pad_pixels/x_pixels[0]

And then set the legend with:

然后设置图例:

ax[1].legend(loc=(pad_xaxis,0.6))

Plot:

阴谋:

回答by The Dude

I saw the answer you posted and tried it out. The problem however is that it is also depended on the figure size.

我看到你发布的答案并尝试了它。然而,问题是它也取决于图形大小。

Here's a new try:

这是一个新的尝试:

import numpy
import matplotlib.pyplot as plt


x = numpy.linspace(0, 10, 10000)
y = numpy.cos(x) + 2.

x_value = .014    #Offset by eye
y_value = .55

fig, ax = plt.subplots(1, 2, sharex = False, sharey = False)
fig.set_size_inches(50,30)

ax[0].plot(x, y, label = "cos")
ax[0].set_ylim([0.8,3.2])
ax[0].legend(loc=2)

line1 ,= ax[1].plot(x,y)
ax[1].set_ylim([0.8,3.2])

axbox = ax[1].get_position()

fig.legend([line1], ["cos"], loc = (axbox.x0 + x_value, axbox.y0 + y_value))

plt.show()

So what I am now doing is basically getting the coordinates from the subplot. I then create the legend based on the dimensions of the entire figure. Hence, the figure size does not change anything to the legend positioning anymore.

所以我现在所做的基本上是从子图中获取坐标。然后我根据整个图形的尺寸创建图例。因此,图形大小不再对图例定位进行任何更改。

With the values for x_valueand y_valuethe legend can be positioned in the subplot. x_valuehas been eyeballed for a good correspondence with the "normal" legend. This value can be changed at your desire. y_valuedetermines the height of the legend.

x_valuey_value图例的值可以定位在子图中。x_value因与“正常”传说的良好对应而受到关注。您可以根据需要更改此值。y_value确定图例的高度。

enter image description here

在此处输入图片说明

Good luck!

祝你好运!