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
Matplotlib: Adjust legend location/position
提问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 borderaxespad
property 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()
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_value
and y_value
the legend can be positioned in the subplot. x_value
has been eyeballed for a good correspondence with the "normal" legend. This value can be changed at your desire. y_value
determines the height of the legend.
x_value
和y_value
图例的值可以定位在子图中。x_value
因与“正常”传说的良好对应而受到关注。您可以根据需要更改此值。y_value
确定图例的高度。
Good luck!
祝你好运!