Matplotlib: настройка местоположения/положения легенды

Я создаю фигуру с несколькими подзаголовками. Один из этих подзаголовков доставляет мне некоторые проблемы, поскольку ни один из углов или центров осей не свободен (или не может быть освобожден) для размещения легенды. Что я хотел бы сделать, так это поместить легенду где-то между "верхним левым" и "левым центральным" местоположениями, сохраняя при этом заполнение между ним и осью y равным легендам в других подзаголовках (которые размещаются с использованием одного из предопределенных ключевых слов расположения легенды).

Я знаю, что могу указать пользовательскую позицию, используя loc=(x,y), но тогда я не могу понять, как получить заполнение между легендой и осью y, чтобы быть равным тому, что используется другими легендами. Можно ли как-то использовать borderaxespad свойство первой легенды? Хотя мне это не удается.

любые предложения будут приветствоваться!

Edit: вот (очень упрощенная) иллюстрация проблема:

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

что я хотел бы, так это то, что легенда в правом сюжете немного сдвинута вниз, чтобы она больше не перекрывалась с линией. В крайнем случае я мог бы изменить пределы оси, но мне бы очень хотелось этого избежать.

2 ответов


Я видел ответ, который вы опубликовали, и попробовал его. Однако проблема в том, что это также зависит от размера фигуры.

вот новая попытка:

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()

Итак, то, что я сейчас делаю, в основном получает координаты из подзаголовка. Затем я создаю легенду на основе размеров всей фигуры. Следовательно, размер фигуры больше ничего не меняет в позиционировании легенды.

со значениями x_value и y_value легенда может быть расположен в подзаголовке. x_value был проверен на хорошее соответствие с" нормальной " легендой. Это значение может быть изменено по вашему желанию. y_value определяет высоту легенда.

enter image description here

удачи!


потратив слишком много времени на это, я придумал следующее удовлетворительного решения (Преобразований Учебник наверняка помогло):

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

затем я обнаружил, что обе следующие работы и дают одинаковое значение для заполнения:

# 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]

или

# 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]

и затем установить легенду с:

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

сюжет: