Как убрать легенду из сюжета


988

У меня есть серия из 20 сюжетов (не субплотов), которые должны быть выполнены в одной фигуре. Я хочу, чтобы легенда была за пределами коробки. В то же время я не хочу менять оси, так как размер фигуры уменьшается. Пожалуйста, помогите мне по следующим вопросам:

  1. Я хочу, чтобы поле с надписями находилось за пределами участка. (Я хочу, чтобы легенда находилась снаружи с правой стороны области сюжета).
  2. Есть ли в любом случае, что я уменьшаю размер шрифта текста внутри поля легенды, чтобы размер окна легенды был маленьким.

14
Для более новых версий matplotlib этот ответ показывает, как настроить matplotlib для автоматического определения места размещения легенды без вмешательства в графики .
dotancohen

2
У меня был тот же вопрос, и я нашел этот замечательный пример, который работал для меня «из коробки»: matplotlib.org/1.3.1/users/legend_guide.html
robodasha

1
Этот ответ имеет большую глубину https://stackoverflow.com/a/43439132/52074. и делает это с двумя строками кода! ответ с ответом +1200 тоже хорош, но я нашел его менее общим.
Тревор Бойд Смит

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

кстати, список вариантов loc: best; верхний правый; верхний левый; нижний левый; Нижний правый; правильно; центр слева; правый центр; нижний центр; верхний центр; центр;
Z-Y00

Ответы:


57

Вы можете уменьшить текст легенды, создав свойства шрифта:

from matplotlib.font_manager import FontProperties

fontP = FontProperties()
fontP.set_size('small')
legend([plot1], "title", prop=fontP) 
# or add prop=fontP to whatever legend() call you already have

50
что plot1в этом ответе?
Пол Х

41
что legendв этом ответе?
Ричард

28
Это отвечает на вторичную часть вопроса, но не на первичную (ту, которая называется).
Матин Улхак

8
Кроме того, правильный способ сделать этоplt.legend(fontsize='small')
Матин Улхак

41
Этот ответ ужасен и дает очень мало контекста!
Tekill

1799

Есть несколько способов сделать то, что вы хотите. Чтобы добавить к тому, что @inalis и @Navi уже сказали, вы можете использовать bbox_to_anchorключевое слово аргумент, чтобы частично разместить легенду за пределами осей и / или уменьшить размер шрифта.

Прежде чем подумать об уменьшении размера шрифта (что может сильно усложнить чтение), попробуйте поиграть с размещением легенды в разных местах:

Итак, давайте начнем с общего примера:

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(10)

fig = plt.figure()
ax = plt.subplot(111)

for i in xrange(5):
    ax.plot(x, i * x, label='$y = %ix$' % i)

ax.legend()

plt.show()

альтернативный текст

Если мы делаем то же самое, но используем bbox_to_anchorключевое слово аргумент, мы можем немного сместить легенду за границы осей:

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(10)

fig = plt.figure()
ax = plt.subplot(111)

for i in xrange(5):
    ax.plot(x, i * x, label='$y = %ix$' % i)

ax.legend(bbox_to_anchor=(1.1, 1.05))

plt.show()

альтернативный текст

Точно так же вы можете сделать легенду более горизонтальной и / или поместить ее вверху рисунка (я также включаю закругленные углы и простую тень):

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(10)

fig = plt.figure()
ax = plt.subplot(111)

for i in xrange(5):
    line, = ax.plot(x, i * x, label='$y = %ix$'%i)

ax.legend(loc='upper center', bbox_to_anchor=(0.5, 1.05),
          ncol=3, fancybox=True, shadow=True)
plt.show()

альтернативный текст

В качестве альтернативы, вы можете уменьшить ширину текущего графика и поместить легенду полностью вне оси фигуры (примечание: если вы используете quiet_layout () , то оставьте в стороне ax.set_position ():

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(10)

fig = plt.figure()
ax = plt.subplot(111)

for i in xrange(5):
    ax.plot(x, i * x, label='$y = %ix$'%i)

# Shrink current axis by 20%
box = ax.get_position()
ax.set_position([box.x0, box.y0, box.width * 0.8, box.height])

# Put a legend to the right of the current axis
ax.legend(loc='center left', bbox_to_anchor=(1, 0.5))

plt.show()

альтернативный текст

Аналогичным образом вы можете уменьшить сюжет по вертикали и поместить горизонтальную легенду внизу:

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(10)

fig = plt.figure()
ax = plt.subplot(111)

for i in xrange(5):
    line, = ax.plot(x, i * x, label='$y = %ix$'%i)

# Shrink current axis's height by 10% on the bottom
box = ax.get_position()
ax.set_position([box.x0, box.y0 + box.height * 0.1,
                 box.width, box.height * 0.9])

# Put a legend below current axis
ax.legend(loc='upper center', bbox_to_anchor=(0.5, -0.05),
          fancybox=True, shadow=True, ncol=5)

plt.show()

альтернативный текст

Взгляните на руководство по легендам matplotlib . Вы также можете взглянуть на plt.figlegend().


10
Если у кого-то возникли проблемы с этим, обратите внимание, что непростое_положение () вызовет проблемы!
Мэтью Г.

4
отличный ответ! правильная ссылка на документ: matplotlib.org/users/legend_guide.html#legend-location
meduz,

4
В качестве полноты можно сказать, что в общем случае (суммируется из документа) " bbox_to_anchorэто кортеж из 4 поплавков (x, y, ширина, высота bbox) или кортеж из 2 поплавков (x, y) в нормализованных осях координаты. "
Медуз

5
Я должен признать, что это, вероятно, мой самый посещаемый SO ответ когда-либо. Я просто не могу не возвращаться к этому снова и снова, потому что разумный человек не может вспомнить эту логику, не изучая ее здесь.
КТ.

9
Обратите внимание, что если вы хотите сохранить рисунок в файл, вам, вероятно, следует сохранить возвращенный объект, т. legend = ax.legend()fig.savefig(bbox_extra_artists=(legend,))
Е.

795

Размещение легенды ( bbox_to_anchor)

Легенда располагается внутри ограничительной рамки осей, используя locаргумент to plt.legend.
Например, loc="upper right"легенда размещается в правом верхнем углу ограничивающего прямоугольника, который по умолчанию расширяется от (0,0)до до (1,1)в координатах осей (или в обозначениях ограничивающего прямоугольника (x0,y0, width, height)=(0,0,1,1)).

Чтобы разместить легенду за пределами ограничительной рамки осей, можно указать кортеж (x0,y0)координат осей нижнего левого угла легенды.

plt.legend(loc=(1.04,0))

Однако более универсальным подходом было бы вручную указать ограничивающий прямоугольник, в который следует поместить легенду, используя bbox_to_anchorаргумент. Можно ограничить себя, чтобы предоставить только (x0,y0)часть bbox. Это создает поле с нулевым интервалом, из которого легенда будет расширяться в направлении, заданном locаргументом. Например

plt.legend (bbox_to_anchor = (1.04,1), loc = "верхний левый")

размещает легенду вне осей, так что верхний левый угол легенды находится в положении (1.04,1)в координатах осей.

Ниже приведены дополнительные примеры, где дополнительно показано взаимодействие между различными аргументами типа modeи ncols.

введите описание изображения здесь

l1 = plt.legend(bbox_to_anchor=(1.04,1), borderaxespad=0)
l2 = plt.legend(bbox_to_anchor=(1.04,0), loc="lower left", borderaxespad=0)
l3 = plt.legend(bbox_to_anchor=(1.04,0.5), loc="center left", borderaxespad=0)
l4 = plt.legend(bbox_to_anchor=(0,1.02,1,0.2), loc="lower left",
                mode="expand", borderaxespad=0, ncol=3)
l5 = plt.legend(bbox_to_anchor=(1,0), loc="lower right", 
                bbox_transform=fig.transFigure, ncol=3)
l6 = plt.legend(bbox_to_anchor=(0.4,0.8), loc="upper right")

Подробности о том, как интерпретировать аргумент из 4-х кортежей bbox_to_anchor, например l4, можно найти в этом вопросе . Расширение mode="expand"расширяет легенду по горизонтали внутри ограничительной рамки, заданной 4-кортежем. Для вертикально развернутой легенды см. Этот вопрос .

Иногда может быть полезно указать ограничивающий прямоугольник в координатах фигуры вместо координат осей. Это показано в примере l5сверху, где bbox_transformаргумент используется для размещения легенды в левом нижнем углу рисунка.

Постобработка

Размещение легенды вне осей часто приводит к нежелательной ситуации, когда она полностью или частично выходит за пределы рисунка.

Решения этой проблемы:

  • Корректировка параметров подплота
    Можно настроить параметры подплота так, чтобы оси занимали меньше места внутри фигуры (и тем самым оставляли больше места легенде) с помощью plt.subplots_adjust. Например

    plt.subplots_adjust(right=0.7)

    оставляет 30% свободного пространства на правой стороне фигуры, где можно разместить легенду.

  • Плотная компоновка
    Использование plt.tight_layoutПозволяет автоматически настраивать параметры подзаговора таким образом, чтобы элементы фигуры плотно прилегали к краям фигуры. К сожалению, легенда не принимается во внимание в этом автомате, но мы можем предоставить прямоугольник, в который будет помещаться вся область сюжетов (включая метки).

    plt.tight_layout(rect=[0,0,0.75,1])
  • Сохранение рисунка с помощьюbbox_inches = "tight"
    аргумента bbox_inches = "tight"to plt.savefigможно использовать для сохранения рисунка, чтобы все художники на холсте (включая легенду) помещались в сохраненную область. При необходимости размер фигуры настраивается автоматически.

    plt.savefig("output.png", bbox_inches="tight")
  • автоматическая настройка параметров подзаговора
    В этом ответе можно найти способ автоматической настройки положения подзаголовка таким образом, чтобы легенда помещалась внутри холста без изменения размера фигуры . Создание фигуры с точным размером и без отступов (и легенда вне осей)

Сравнение между случаями, обсужденными выше:

введите описание изображения здесь

альтернативы

Легенда фигуры
Можно использовать легенду для фигуры вместо осей matplotlib.figure.Figure.legend. Это стало особенно полезным для версии matplotlib> = 2.1, где не требуется никаких специальных аргументов

fig.legend(loc=7) 

создать легенду для всех художников по разным осям фигуры. Легенда размещается с использованием locаргумента, аналогично тому, как он расположен внутри осей, но со ссылкой на всю фигуру - следовательно, он будет несколько вне осей автоматически. Осталось отрегулировать вспомогательные сюжеты так, чтобы не было перекрытия между легендой и осями. Здесь будет полезен пункт «Настройка параметров подзаговора» сверху. Пример:

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0,2*np.pi)
colors=["#7aa0c4","#ca82e1" ,"#8bcd50","#e18882"]
fig, axes = plt.subplots(ncols=2)
for i in range(4):
    axes[i//2].plot(x,np.sin(x+i), color=colors[i],label="y=sin(x+{})".format(i))

fig.legend(loc=7)
fig.tight_layout()
fig.subplots_adjust(right=0.75)   
plt.show()

введите описание изображения здесь

Легенда внутри выделенных осей вспомогательных сюжетов
Альтернативой использованию bbox_to_anchorбудет размещение легенды в выделенных осях вспомогательных сюжетов ( lax). Поскольку вспомогательный сюжет должен быть меньше сюжета, мы можем использовать его gridspec_kw={"width_ratios":[4,1]}при создании осей. Мы можем скрыть оси, lax.axis("off")но все же поместить легенду. Дескрипторы и метки легенды должны быть получены из реального сюжета через h,l = ax.get_legend_handles_labels(), а затем могут быть переданы легенде в laxподзаговоре lax.legend(h,l). Полный пример ниже.

import matplotlib.pyplot as plt
plt.rcParams["figure.figsize"] = 6,2

fig, (ax,lax) = plt.subplots(ncols=2, gridspec_kw={"width_ratios":[4,1]})
ax.plot(x,y, label="y=sin(x)")
....

h,l = ax.get_legend_handles_labels()
lax.legend(h,l, borderaxespad=0)
lax.axis("off")

plt.tight_layout()
plt.show()

Это создает сюжет, который визуально очень похож на сюжет сверху:

введите описание изображения здесь

Мы также можем использовать первые оси для размещения легенды, но использовать bbox_transformоси легенды,

ax.legend(bbox_to_anchor=(0,0,1,1), bbox_transform=lax.transAxes)
lax.axis("off")

При таком подходе нам не нужно получать маркеры легенды извне, но нам нужно указать bbox_to_anchorаргумент.

Дальнейшее чтение и заметки:

  • Рассмотрим Matplotlib руководство легенды с некоторыми примерами других вещей , которые вы хотите сделать с легендами.
  • Пример кода для размещения легенд для круговых диаграмм можно найти непосредственно в ответе на этот вопрос: Python - легенда перекрывается с круговой диаграммой
  • locАргумент может принимать цифры вместо строки, которые делают звонки короче, тем не менее, они не очень интуитивно сопоставляются друг с другом. Вот отображение для справки:

введите описание изображения здесь


Помещение легенды в выделенную ось синергии очень хорошо сочетается с fig.tight_layout. Если вы используете plt.subplotsдля создания осей, просто дайте ему что-то вроде gridspec_kw={'height_ratios': [100, 1]}(или width_ratios), чтобы оси легенды были крошечными ... Затем fig.tight_layout()разверните их до нужного размера. По крайней мере для matplotlib 3.0.3.
travc

161

Просто позвоните legend()позвоните после plot()звонка, как это:

# matplotlib
plt.plot(...)
plt.legend(loc='center left', bbox_to_anchor=(1, 0.5))

# Pandas
df.myCol.plot().legend(loc='center left', bbox_to_anchor=(1, 0.5))

Результаты будут выглядеть примерно так:

введите описание изображения здесь


4
работает и при передаче тех же параметров в matplotlib.pyplot.legend
kidmose

8
Отрезает ли это слова в легенде для кого-то еще?
user1717828

85

Чтобы разместить легенду вне области сюжета, используйте locи bbox_to_anchorключевые слова legend(). Например, следующий код поместит легенду справа от области графика:

legend(loc="upper left", bbox_to_anchor=(1,1))

Для получения дополнительной информации см. Руководство легенды


10
Хорошо - мне нравится реализация, но когда я иду, чтобы сохранить рисунок (без изменения размера вручную в окне, что я не хочу делать каждый раз), легенда отрубается. Есть идеи о том, как я могу это исправить?
astromax

@astromax Я не уверен, но, возможно, попробую позвонить plt.tight_layout()?
Кристиан Алис

81

Краткий ответ: вы можете использовать bbox_to_anchor+ bbox_extra_artists+ bbox_inches='tight'.


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

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

import matplotlib.pyplot as plt

# data 
all_x = [10,20,30]
all_y = [[1,3], [1.5,2.9],[3,2]]

# Plot
fig = plt.figure(1)
ax = fig.add_subplot(111)
ax.plot(all_x, all_y)

# Add legend, title and axis labels
lgd = ax.legend( [ 'Lag ' + str(lag) for lag in all_x], loc='center right', bbox_to_anchor=(1.3, 0.5))
ax.set_title('Title')
ax.set_xlabel('x label')
ax.set_ylabel('y label')

fig.savefig('image_output.png', dpi=300, format='png')

введите описание изображения здесь

Чтобы предотвратить обрезку поля легенды, при сохранении рисунка вы можете использовать параметры bbox_extra_artistsи bbox_inchesпопросить savefigвключить обрезанные элементы в сохраненное изображение:

fig.savefig('image_output.png', bbox_extra_artists=(lgd,), bbox_inches='tight')

Пример (я только изменил последнюю строку, чтобы добавить 2 параметра fig.savefig()):

import matplotlib.pyplot as plt

# data 
all_x = [10,20,30]
all_y = [[1,3], [1.5,2.9],[3,2]]

# Plot
fig = plt.figure(1)
ax = fig.add_subplot(111)
ax.plot(all_x, all_y)

# Add legend, title and axis labels
lgd = ax.legend( [ 'Lag ' + str(lag) for lag in all_x], loc='center right', bbox_to_anchor=(1.3, 0.5))
ax.set_title('Title')
ax.set_xlabel('x label')
ax.set_ylabel('y label')    

fig.savefig('image_output.png', dpi=300, format='png', bbox_extra_artists=(lgd,), bbox_inches='tight')

введите описание изображения здесь

Хотелось бы, чтобы matplotlib изначально разрешал внешнее местоположение для блока легенды, как это делает Matlab :

figure
x = 0:.2:12;
plot(x,besselj(1,x),x,besselj(2,x),x,besselj(3,x));
hleg = legend('First','Second','Third',...
              'Location','NorthEastOutside')
% Make the text of the legend italic and color it brown
set(hleg,'FontAngle','italic','TextColor',[.3,.2,.1])

введите описание изображения здесь


6
Спасибо огромное! Параметры "bbox_to_anchor", "bbox_extra_artist" и "" bbox_inches = 'stretch "были именно тем, что мне было нужно, чтобы заставить его работать правильно. Удивительно!
Демитриан

6
Спасибо, но на самом деле bbox_inches='tight'у меня отлично работает даже без bbox_extra_artist
автомат

1
@avtomaton Спасибо, приятно знать, какую версию matplotlib вы используете?
Франк Дернонкур

1
@FranckDernoncourt python3, matplotlib версия 1.5.3
автомат

68

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

pylab.legend(loc='best')

Это автоматически поместит легенду от данных, если это возможно! Сравните использование loc = 'best'

Однако, если нет места для размещения легенды без наложения данных, вам нужно попробовать один из других ответов; Использование loc="best"никогда не поставит легенду за пределы сюжета.


2
Спасибо за указание на это! Я искал это несколько лет назад и не нашел этого, и это действительно облегчает мне жизнь.
Эдгар Х

4
эта опция полезна, но не отвечает на вопрос, поэтому я проголосовал. насколько я могу судить, лучше всего никогда не помещать легенду за пределы сюжета
Томми

3
@Tommy: В комментариях OP (которые, кажется, уже нет) было ясно разъяснено, что OP хотел, чтобы легенда не охватывала данные графика, и он думал, что единственный способ сделать это за пределами графика. Вы можете увидеть это в ответах Мефатии, Матео Санчеса, Бастиана и Радтека. OP попросил X, но он хотел Y .
Dotancohen

1
Вообще-то нет. Он / она специально попросил, чтобы легенда была за пределами сюжета. Это в названии вопроса;) «Как убрать легенду из сюжета».
дурбачить

4
Это не гарантирует, что легенда не затеняет данные. Просто сделайте очень плотный сюжет - негде поставить легенду. Например, попробуйте это ... из numpy import arange, sin, pi import matplotlib.pyplot как plt t = arange (0.0, 100.0, 0.01) fig = plt.figure (1) ax1 = fig.add_subplot (211) ax1. scatter (t, sin (2 * pi * t), label = 'test') ax1.grid (True) # ax1.set_ylim ((- 2, 2)) ax1.set_ylabel ('1 Гц') ax1.set_title ( 'Синусоида или два') для метки в ax1.get_xticklabels (): label.set_color ('r') plt.legend (loc = 'best') plt.show ()
adam.r

56

Краткий ответ : вызывайте перетаскиваемую легенду и перемещайте ее в интерактивном режиме, куда хотите:

ax.legend().draggable()

Длинный ответ : Если вы предпочитаете размещать легенду интерактивно / вручную, а не программно, вы можете переключить режим легенды с перетаскиванием, чтобы вы могли перетащить ее туда, куда вы хотите. Проверьте пример ниже:

import matplotlib.pylab as plt
import numpy as np
#define the figure and get an axes instance
fig = plt.figure()
ax = fig.add_subplot(111)
#plot the data
x = np.arange(-5, 6)
ax.plot(x, x*x, label='y = x^2')
ax.plot(x, x*x*x, label='y = x^3')
ax.legend().draggable()
plt.show()

Не уверен, что я понимаю это полностью. Как мне «перетащить» легенду туда, куда я хочу? Я использую Python 3.6 и Jupyter Notebook
sb2020

14

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

Сделайте это с:

fig = pylab.figure()
ax = fig.add_subplot(111)
ax.plot(x,y,label=label,color=color)
# Make the legend transparent:
ax.legend(loc=2,fontsize=10,fancybox=True).get_frame().set_alpha(0.5)
# Make a transparent text box
ax.text(0.02,0.02,yourstring, verticalalignment='bottom',
                     horizontalalignment='left',
                     fontsize=10,
                     bbox={'facecolor':'white', 'alpha':0.6, 'pad':10},
                     transform=self.ax.transAxes)

8

Как уже отмечалось, вы также можете разместить легенду на сюжете или слегка отодвинуть ее к краю. Вот пример использования API Plotly Python , созданный с помощью IPython Notebook . Я в команде.

Для начала вам нужно установить необходимые пакеты:

import plotly
import math
import random
import numpy as np

Затем установите Plotly:

un='IPython.Demo'
k='1fw3zw2o13'
py = plotly.plotly(username=un, key=k)


def sin(x,n):
sine = 0
for i in range(n):
    sign = (-1)**i
    sine = sine + ((x**(2.0*i+1))/math.factorial(2*i+1))*sign
return sine

x = np.arange(-12,12,0.1)

anno = {
'text': '$\\sum_{k=0}^{\\infty} \\frac {(-1)^k x^{1+2k}}{(1 + 2k)!}$',
'x': 0.3, 'y': 0.6,'xref': "paper", 'yref': "paper",'showarrow': False,
'font':{'size':24}
}

l = {
'annotations': [anno], 
'title': 'Taylor series of sine',
'xaxis':{'ticks':'','linecolor':'white','showgrid':False,'zeroline':False},
'yaxis':{'ticks':'','linecolor':'white','showgrid':False,'zeroline':False},
'legend':{'font':{'size':16},'bordercolor':'white','bgcolor':'#fcfcfc'}
}

py.iplot([{'x':x, 'y':sin(x,1), 'line':{'color':'#e377c2'}, 'name':'$x\\\\$'},\
      {'x':x, 'y':sin(x,2), 'line':{'color':'#7f7f7f'},'name':'$ x-\\frac{x^3}{6}$'},\
      {'x':x, 'y':sin(x,3), 'line':{'color':'#bcbd22'},'name':'$ x-\\frac{x^3}{6}+\\frac{x^5}{120}$'},\
      {'x':x, 'y':sin(x,4), 'line':{'color':'#17becf'},'name':'$ x-\\frac{x^5}{120}$'}], layout=l)

Это создаст ваш график и позволит вам сохранить легенду внутри самого графика. По умолчанию для легенды, если она не установлена, это поместить ее в график, как показано здесь.

введите описание изображения здесь

Для альтернативного размещения вы можете точно выровнять край графика и границу легенды и удалить граничные линии для более точного соответствия.

введите описание изображения здесь

Вы можете перемещать и изменять стиль легенды и графика с помощью кода или с помощью графического интерфейса. Чтобы переместить легенду, у вас есть следующие опции, чтобы расположить легенду внутри графика, присваивая значения x и y <= 1. Например:

  • {"x" : 0,"y" : 0} -- Внизу слева
  • {"x" : 1, "y" : 0} -- Внизу справа
  • {"x" : 1, "y" : 1} -- В правом верхнем углу
  • {"x" : 0, "y" : 1} -- Верхний левый
  • {"x" :.5, "y" : 0} - Нижний Центр
  • {"x": .5, "y" : 1} - Топ Центр

В этом случае мы выбираем верхний правый угол legendstyle = {"x" : 1, "y" : 1}, также описанный в документации :

введите описание изображения здесь


3

Что-то в этом роде помогло мне. Начиная с небольшого кода, взятого у Джо, этот метод изменяет ширину окна, чтобы автоматически соответствовать легенде справа от рисунка.

import matplotlib.pyplot as plt
import numpy as np

plt.ion()

x = np.arange(10)

fig = plt.figure()
ax = plt.subplot(111)

for i in xrange(5):
    ax.plot(x, i * x, label='$y = %ix$'%i)

# Put a legend to the right of the current axis
leg = ax.legend(loc='center left', bbox_to_anchor=(1, 0.5))

plt.draw()

# Get the ax dimensions.
box = ax.get_position()
xlocs = (box.x0,box.x1)
ylocs = (box.y0,box.y1)

# Get the figure size in inches and the dpi.
w, h = fig.get_size_inches()
dpi = fig.get_dpi()

# Get the legend size, calculate new window width and change the figure size.
legWidth = leg.get_window_extent().width
winWidthNew = w*dpi+legWidth
fig.set_size_inches(winWidthNew/dpi,h)

# Adjust the window size to fit the figure.
mgr = plt.get_current_fig_manager()
mgr.window.wm_geometry("%ix%i"%(winWidthNew,mgr.window.winfo_height()))

# Rescale the ax to keep its original size.
factor = w*dpi/winWidthNew
x0 = xlocs[0]*factor
x1 = xlocs[1]*factor
width = box.width*factor
ax.set_position([x0,ylocs[0],x1-x0,ylocs[1]-ylocs[0]])

plt.draw()

Я нашел это весьма полезным, и это сработало для меня. Обратите внимание, что если вы находитесь в бэкэнде wx (например, используете windows), замените mgr.window.wm_geometry ("% ix% i"% (winWidthNew, mgr.window.winfo_height ())) на mgr.window.SetClientSizeWH (winWidthNew) , winHeightNew) или тому подобное
Иезекииль Круглик

Если вы используете бэкэнд Qt4Agg (который по умолчанию используется в моей установке Linux для matplotlib), замените строку mgr.window.wm_geometry(...)на mgr.window.setFixedWidth(winWidthNew).
Филип С.

И, как я только что обнаружил, если вы используете бэкэнд, который не показывает никаких окон, предназначенный для сохранения прямо в файл (например, бэкэнды SVG и AGG), просто пропустите изменение размера окна. fig.set_size_inches(...)заботится о том, чтобы изменить размер вам нужно.
Филип С.

3

Стоит обновить этот вопрос, поскольку более новые версии Matplotlib значительно упростили размещение легенды за пределами сюжета. Я создал этот пример с версией Matplotlib 3.1.1.

Пользователи могут передать 2 locпараметра координат параметру, чтобы расположить легенду в любом месте ограничительной рамки. Единственное, что вам нужно - это запустить plt.tight_layout()matplotlib для пересчета размеров графика, чтобы легенда была видимой:

import matplotlib.pyplot as plt

plt.plot([0, 1], [0, 1], label="Label 1")
plt.plot([0, 1], [0, 2], label='Label 2')

plt.legend(loc=(1.05, 0.5))
plt.tight_layout()

Это приводит к следующему сюжету:

сюжет с легендой снаружи

Ссылки:


2

Вы также можете попробовать figlegend. Можно создать легенду независимо от любого объекта Оси. Однако вам может понадобиться создать несколько «фиктивных» путей, чтобы убедиться, что форматирование объектов передается правильно.


1

Вот пример из учебника по matplotlib, найденного здесь . Это один из более простых примеров, но я добавил прозрачность в легенду и добавил plt.show (), чтобы вы могли вставить это в интерактивную оболочку и получить результат:

import matplotlib.pyplot as plt
p1, = plt.plot([1, 2, 3])
p2, = plt.plot([3, 2, 1])
p3, = plt.plot([2, 3, 1])
plt.legend([p2, p1, p3], ["line 1", "line 2", "line 3"]).get_frame().set_alpha(0.5)
plt.show()

1

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

f = plt.figure()
ax = f.add_subplot(414)
lgd = ax.legend(loc='upper left', bbox_to_anchor=(0, 4), mode="expand", borderaxespad=0.3)
ax.autoscale_view()
plt.savefig(fig_name, format='svg', dpi=1200, bbox_extra_artists=(lgd,), bbox_inches='tight')

1

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

Вместо того, чтобы добавлять все свои дополнения в ограничивающий прямоугольник, когда вы хотите их записать, вы можете добавлять их заранее Figureхудожникам. Используя что-то похожее на ответ Франка Дернонкура выше :

import matplotlib.pyplot as plt

# data 
all_x = [10,20,30]
all_y = [[1,3], [1.5,2.9],[3,2]]

# plotting function
def gen_plot(x, y):
    fig = plt.figure(1)
    ax = fig.add_subplot(111)
    ax.plot(all_x, all_y)
    lgd = ax.legend( [ "Lag " + str(lag) for lag in all_x], loc="center right", bbox_to_anchor=(1.3, 0.5))
    fig.artists.append(lgd) # Here's the change
    ax.set_title("Title")
    ax.set_xlabel("x label")
    ax.set_ylabel("y label")
    return fig

# plotting
fig = gen_plot(all_x, all_y)

# No need for `bbox_extra_artists`
fig.savefig("image_output.png", dpi=300, format="png", bbox_inches="tight")

Вот сгенерированный сюжет.


-1

не знаю, разобрались ли вы уже с вашей проблемой ... возможно, да, но ... я просто использовал строку 'outside' для местоположения, как в matlab. Я импортировал pylab из matplotlib. увидеть код следующим образом:

from matplotlib as plt
from matplotlib.font_manager import FontProperties
...
...
t = A[:,0]
sensors = A[:,index_lst]

for i in range(sensors.shape[1]):
    plt.plot(t,sensors[:,i])

plt.xlabel('s')
plt.ylabel('°C')
lgd = plt.legend(b,loc='center left', bbox_to_anchor=(1, 0.5),fancybox = True, shadow = True)

Нажмите, чтобы увидеть сюжет

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.