在Matplotlib中将图例作为单独的图片获取

Rug*_*man 30 python matplotlib

我正在开发一个Web应用程序,并希望在页面的不同位置显示一个图形及其图例.这意味着我需要将图例保存为单独的png文件.这在Matplotlib中是否可能以一种或多或少的直接方式实现?

Ste*_*joa 20

这可能有效:

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')
Run Code Online (Sandbox Code Playgroud)

替代文字


And*_*ner 15

使用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")
Run Code Online (Sandbox Code Playgroud)

虽然以自动方式获得图例图形的大小,但这可能很棘手.


Imp*_*est 11

您可以使用bbox_inches参数to 将图形的保存区域限制为图例的边界框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()
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

导出扩展图例边界框

如果图例周围有边框,则上述解决方案可能不是最理想的.在这种情况下,将边界框扩展一些像素以将边框包含在其中是有意义的.

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()
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述


Mic*_*ein 9

我发现最简单的方法就是创建您的图例,然后关闭axiswith 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()
Run Code Online (Sandbox Code Playgroud)

示例图例


kla*_* se 7

这会自动计算图例的大小.如果mode == 1,代码类似于Steve Tjoa的回答,那么mode == 2类似于Andre Holzner的回答.

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')
Run Code Online (Sandbox Code Playgroud)

原始(未剪切)传奇:

原始(未剪切)的传说

裁剪的传奇:

裁剪的传奇


Cos*_*ang 6

受到 Maxim 和 ImportanceOfBeingErnest 答案的启发,

def export_legend(ax, filename="legend.pdf"):
    fig2 = plt.figure()
    ax2 = fig2.add_subplot()
    ax2.axis('off')
    legend = ax2.legend(*ax.get_legend_handles_labels(), frameon=False, loc='lower center', ncol=10,)
    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)
Run Code Online (Sandbox Code Playgroud)

这允许我将图例水平保存在单独的文件中。举个例子

在此输入图像描述


Fra*_*ano 5

可以用于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')
Run Code Online (Sandbox Code Playgroud)

如果出于某种原因只想隐藏轴标签,则可以使用:

ax.xaxis.set_visible(False)
ax.yaxis.set_visible(False)
Run Code Online (Sandbox Code Playgroud)

或者,由于某些奇怪的原因,您想隐藏轴框架而不是隐藏可以使用的轴标签:

ax.set_frame_on(False)
Run Code Online (Sandbox Code Playgroud)

ps:此答案已从我的答案改编为重复的问题