Получить легенду как отдельную картинку в Matplotlib - PullRequest
30 голосов
/ 26 декабря 2010

Я занимаюсь разработкой веб-приложения и хочу отобразить фигуру и ее легенду в разных местах на странице.Это значит, что мне нужно сохранить легенду в виде отдельного png-файла.Возможно ли это в Matplotlib более или менее простым способом?

Ответы [ 6 ]

20 голосов
/ 26 декабря 2010

Это может работать:

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

alt text

15 голосов
/ 01 марта 2012

используйте 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")

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

9 голосов
/ 11 декабря 2017

Вы можете ограничить сохраненную область фигуры ограничительной рамкой легенды, используя аргумент 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()

enter image description here

Экспорт расширенной рамки легенды

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

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

enter image description here

7 голосов
/ 19 августа 2013

Это вычисляет размер легенды автоматически.Если 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')

Оригинальная (необрезанная) легенда:

Original (uncropped) legend

Обрезанная легенда:

Cropped legend

5 голосов
/ 10 мая 2018

Можно использовать 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)

пс: этот ответ был адаптирован из моего ответа на дублирующийся вопрос

4 голосов
/ 04 декабря 2018

Я обнаружил, что проще всего создать свою легенду, а затем просто отключить 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()

sample legend

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...