Как поместить легенду вне графика
У меня есть серия из 20 графиков (не подзаголовков), которые нужно создать на одном рисунке. Я хочу, чтобы легенда была нестандартной. В то же время я не хочу менять оси, так как размер рисунка уменьшается.
- Я хочу сохранить поле легенды за пределами области графика (я хочу, чтобы легенда была снаружи с правой стороны области графика).
- Есть ли способ уменьшить размер шрифта текста внутри поля легенды, чтобы размер поля легенды был небольшим?
Переведено автоматически
Ответ 1
Есть несколько способов сделать то, что вы хотите. Чтобы добавить к тому, что уже сказали Кристиан Алис и 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()
Alternatively, shrink the current plot's width, and put the legend entirely outside the axis of the figure (note: if you use tight_layout()
, then leave out 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()
.
Ответ 2
Размещение легенды (bbox_to_anchor
)
Легенда размещается внутри ограничивающей рамки осей с помощью loc
аргумента to plt.legend
.
Например, loc="upper right"
помещает легенду в правый верхний угол ограничивающей рамки, которая по умолчанию имеет размеры от (0, 0)
до (1, 1)
в координатах осей (или в обозначении ограничивающей рамки (x0, y0, width, height) = (0, 0, 1, 1)
).
Чтобы поместить легенду за пределы ограничивающей рамки axes, можно указать кортеж (x0, y0)
координат axes в нижнем левом углу легенды.
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"
toplt.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
может принимать числа вместо строк, что сокращает вызовы, однако они не очень интуитивно сопоставляются друг с другом. Вот сопоставление для справки:
Ответ 3
Просто вызовите 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
- Вы можете уменьшить размер текста легенды, указав
set_size
ofFontProperties
. - Ресурсы:
- Руководство по легендам
matplotlib.legend
matplotlib.pyplot.legend
matplotlib.font_manager
set_size(self, size)
- Допустимые размеры шрифта: xx-small, x-small, small, medium, large, x-large, xx-large, large, small и None.
- Реальный Python: построение графиков на Python с помощью Matplotlib (руководство)
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
fontP = FontProperties()
fontP.set_size('xx-small')
p1, = plt.plot([1, 2, 3], label='Line 1')
p2, = plt.plot([3, 2, 1], label='Line 2')
plt.legend(handles=[p1, p2], title='title', bbox_to_anchor=(1.05, 1), loc='upper left', prop=fontP)
fontsize='xx-small'
также работает без импортаFontProperties
.
plt.legend(handles=[p1, p2], title='title', bbox_to_anchor=(1.05, 1), loc='upper left', fontsize='xx-small')