简体   繁体   English

Matplotlib:调整图例位置/位置

[英]Matplotlib: Adjust legend location/position

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. 我知道我可以使用loc=(x,y)来指定自定义位置,但是我无法弄清楚如何使图例和y轴之间的填充等于其他图例所使用的填充。 Would it be possible to somehow use the borderaxespad property of the first legend? 是否有可能以某种方式使用第一个传奇的borderaxespad属性? Though I'm not succeeding at getting that to work. 虽然我没有成功地让它发挥作用。

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. 作为最后的手段我可以改变轴限制,但我非常想避免这种情况。

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_valuey_value的值,图例可以定位在子图中。 x_value has been eyeballed for a good correspondence with the "normal" legend. x_value已被x_value与“正常”传奇的良好对应。 This value can be changed at your desire. 可以根据需要更改此值。 y_value determines the height of the legend. y_value确定图例的高度。

在此输入图像描述

Good luck! 祝好运!

After spending way too much time on this, I've come up with the following satisfactory solution (the Transformations Tutorial definitely 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: 然后,我发现以下两个工作并为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: 情节:

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

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