Я разрабатываю веб-приложение и хочу отображать фигуру и ее легенду в разных местах на странице. Это означает, что мне нужно сохранить легенду как отдельный файл png. Возможно ли это в Matplotlib более или менее прямолинейно?
Получите легенду как отдельное изображение в Matplotlib
Ответ 1
Это может сработать:
import pylab
fig = pylab.figure()
figlegend = pylab.figure(figsize=(3,2))
ax = fig.add_subplot(111)
lines = ax.plot(range(10), pylab.randn(10), range(10), pylab.randn(10))
figlegend.legend(lines, ('one', 'two'), 'center')
fig.show()
figlegend.show()
figlegend.savefig('legend.png')
Ответ 2
используйте pylab.figlegend(..)
и get_legend_handles_labels(..)
:
import pylab, numpy
x = numpy.arange(10)
# create a figure for the data
figData = pylab.figure()
ax = pylab.gca()
for i in xrange(3):
pylab.plot(x, x * (i+1), label='line %d' % i)
# create a second figure for the legend
figLegend = pylab.figure(figsize = (1.5,1.3))
# produce a legend for the objects in the other figure
pylab.figlegend(*ax.get_legend_handles_labels(), loc = 'upper left')
# save the two figures to files
figData.savefig("plot.png")
figLegend.savefig("legend.png")
Это может быть сложно, хотя автоматическое получение размера фигуры легенды.
Ответ 3
Это автоматически вычисляет размер легенды. Если mode == 1
, код похож на ответ Стива Тхоа, а mode == 2
- аналогичный ответ Андре Хольцнера.
Параметр loc
должен быть установлен на 'center'
, чтобы он работал (но я не знаю, почему это необходимо).
mode = 1
#mode = 2
import pylab
fig = pylab.figure()
if mode == 1:
lines = fig.gca().plot(range(10), pylab.randn(10), range(10), pylab.randn(10))
legend_fig = pylab.figure(figsize=(3,2))
legend = legend_fig.legend(lines, ('one', 'two'), 'center')
if mode == 2:
fig.gca().plot(range(10), pylab.randn(10), range(10), pylab.randn(10), label='asd')
legend_fig = pylab.figure()
legend = pylab.figlegend(*fig.gca().get_legend_handles_labels(), loc = 'center')
legend.get_frame().set_color('0.70')
legend_fig.canvas.draw()
legend_fig.savefig('legend_cropped.png',
bbox_inches=legend.get_window_extent().transformed(legend_fig.dpi_scale_trans.inverted()))
legend_fig.savefig('legend_original.png')
Оригинальная (необрезанная) легенда:
Обрезанная легенда:
Ответ 4
Вы можете ограничить сохраненную область рисунка в ограничительной рамки легенды, используя bbox_inches
аргумент fig.savefig
. Ниже вариантов функции, которую вы можете просто вызвать с легендой, которую вы хотите сохранить в качестве аргумента. Вы можете использовать легенду, созданную на исходном рисунке (и удалить ее впоследствии, legend.remove()
), или вы можете создать новую фигуру для легенды и просто использовать функцию как есть.
Экспорт легендарной рамки
Если полная легенда будет сохранена, ограничивающая рамка, поставленная в аргумент bbox_inches
, будет просто преобразованной ограничивающей рамкой легенды. Это хорошо работает, если у легенды нет границы вокруг него.
import matplotlib.pyplot as plt
colors = ["crimson", "purple", "gold"]
f = lambda m,c: plt.plot([],[],marker=m, color=c, ls="none")[0]
handles = [f("s", colors[i]) for i in range(3)]
labels = colors
legend = plt.legend(handles, labels, loc=3, framealpha=1, frameon=False)
def export_legend(legend, filename="legend.png"):
fig = legend.figure
fig.canvas.draw()
bbox = legend.get_window_extent().transformed(fig.dpi_scale_trans.inverted())
fig.savefig(filename, dpi="figure", bbox_inches=bbox)
export_legend(legend)
plt.show()
Экспортировать расширительную рамку
Если вокруг легенды есть граница, вышеупомянутое решение может быть субоптимальным. В этом случае имеет смысл расширить ограничительную рамку на несколько пикселей, чтобы включить границу в полную силу.
import numpy as np
import matplotlib.pyplot as plt
colors = ["crimson", "purple", "gold"]
f = lambda m,c: plt.plot([],[],marker=m, color=c, ls="none")[0]
handles = [f("s", colors[i]) for i in range(3)]
labels = colors
legend = plt.legend(handles, labels, loc=3, framealpha=1, frameon=True)
def export_legend(legend, filename="legend.png", expand=[-5,-5,5,5]):
fig = legend.figure
fig.canvas.draw()
bbox = legend.get_window_extent()
bbox = bbox.from_extents(*(bbox.extents + np.array(expand)))
bbox = bbox.transformed(fig.dpi_scale_trans.inverted())
fig.savefig(filename, dpi="figure", bbox_inches=bbox)
export_legend(legend)
plt.show()
Ответ 5
Можно использовать axes.get_legend_handles_labels
чтобы получить axes.get_legend_handles_labels
легенды и метки из одного объекта axes
и использовать их для добавления их к осям на другой фигуре.
# create a figure with one subplot
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot([1,2,3,4,5], [1,2,3,4,5], 'r', label='test')
# save it *without* adding a legend
fig.savefig('image.png')
# then create a new image
# adjust the figure size as necessary
figsize = (3, 3)
fig_leg = plt.figure(figsize=figsize)
ax_leg = fig_leg.add_subplot(111)
# add the legend from the previous axes
ax_leg.legend(*ax.get_legend_handles_labels(), loc='center')
# hide the axes frame and the x/y labels
ax_leg.axis('off')
fig_leg.savefig('legend.png')
Если по какой-то причине вы хотите скрыть только метку осей, вы можете использовать:
ax.xaxis.set_visible(False)
ax.yaxis.set_visible(False)
или если по какой-то более странной причине вы хотите скрыть рамку осей, но не метки осей, которые вы можете использовать:
ax.set_frame_on(False)
PS: этот ответ был адаптирован из моего ответа на повторяющийся вопрос
Ответ 6
Я обнаружил, что самый простой способ - просто создать свою легенду, а затем просто отключить axis
с помощью plt.gca().set_axis_off()
:
# Create a color palette
palette = dict(zip(['one', 'two'], ['b', 'g']))
# Create legend handles manually
handles = [mpl.patches.Patch(color=palette[x], label=x) for x in palette.keys()]
# Create legend
plt.legend(handles=handles)
# Get current axes object and turn off axis
plt.gca().set_axis_off()
plt.show()