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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4534480/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 16:12:22  来源:igfitidea点击:

Get legend as a separate picture in Matplotlib

pythonmatplotlib

提问by Ruggiero Spearman

I'm developing a Web application and want to display a figure and its legend in different locations on the page. Which means I need to save the legend as a separate png file. Is this possible in Matplotlib in a more or less straightforward way?

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

采纳答案by Steve Tjoa

This could work:

这可以工作:

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

替代文字

回答by Andre Holzner

use pylab.figlegend(..)and get_legend_handles_labels(..):

使用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")

It can be tricky though to get the size of the legend figure right in an automated manner.

尽管以自动方式获得图例图形的大小可能会很棘手。

回答by klaus se

This calculates the size of the legend automatically. If mode == 1, the code is similar to Steve Tjoa's answer, while mode == 2is similar Andre Holzner's answer.

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

The locparameter mustbe set to 'center'to make it work (but I do not know why this is necessary).

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:

原始(未裁剪)图例:

Original (uncropped) legend

原始(未裁剪)图例

Cropped legend:

裁剪图例:

Cropped legend

裁剪图例

回答by ImportanceOfBeingErnest

You may limit the saved region of a figure to the bounding box of the legend using the bbox_inchesargument to fig.savefig. Below to versions of a function which you can simply call with the legend you want to save as argument. You may either use the legend created in the original figure here (and remove it afterwards, legend.remove()) or you may create a new figure for the legend and simply use the function as it is.

您可以使用bbox_inches参数 to将图形的保存区域限制在图例的边界框内fig.savefig。下面是一个函数的版本,您可以简单地使用要保存为参数的图例调用该函数。您可以在此处使用在原始图中创建的图例(然后将其删除,legend.remove()),或者您可以为图例创建一个新图并按原样使用该函数。

Export legend boundingbox

导出图例边界框

In case the complete legend shall be saved, the bounding box supplied to the bbox_inchesargument would be simply the transformed bounding box of the legend. This works well if the legend has no border around it.

如果要保存完整的图例,则提供给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

在此处输入图片说明

Export extended legend bounding box

导出扩展图例边界框

If there is a border around the legend, the above solution may be suboptimal. In this case it makes sense to extend the bounding box by some pixels to include the border to its full.

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

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

在此处输入图片说明

回答by Francesco Montesano

It is possible to use axes.get_legend_handles_labelsto get the legend handles and labels from one axesobject and to use them to add them to an axes in a different figure.

可以使用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')

If for some reason you want to hide only the axes label, you can use:

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

ax.xaxis.set_visible(False)
ax.yaxis.set_visible(False)

or if, for some weirder reason, you want to hide the axes frame but not the axes labels you can use:

或者,如果出于某种更奇怪的原因,您想隐藏轴框架而不是您可以使用的轴标签:

ax.set_frame_on(False)


ps: this answer has been adapted from my answer to a duplicate question

ps:此答案改编自我对重复问题的回答

回答by Michael Silverstein

I've found that the easiest way is just to create your legend and then just turn off the axiswith plt.gca().set_axis_off():

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

sample legend

示例图例

回答by Costa Huang

Inspired by Maxim and ImportanceOfBeingErnest's answers,

受到 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)

which allows me to save legend horizontally in a separate file. As an example

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

enter image description here

在此处输入图片说明