当前位置: 首页>编程语言>正文

python matplotlib 图例放在外面 matplotlib自定义图例

20210416 -

0. 引言

在做实验绘图的过程中,经常要进行图例的调整,一般关于matplotlib的问题都记录在《matplotlib绘图问题》中,但是考虑到这部分内容比较多,就单独列出来进行记录。

  1. 自定义图例
  2. 调整图例部分的风格
  3. 图例放置在axes外面
  4. 多个子图共享图例

1. 遇到的问题

1.1 自定义图例

这里的自定义图例仅仅是想替换原有的图形,还没有到使用图片这种级别;而这种方法的话,官方文档中[1]就有相关的例子,先上效果图:

python matplotlib 图例放在外面 matplotlib自定义图例,python matplotlib 图例放在外面 matplotlib自定义图例_图例,第1张

上面的图例部分是经过调整后的,而具体的代码如下:

from matplotlib.lines import Line2D
custom_lines = [Line2D([0], [0], color=cmap(0.), lw=4),
                Line2D([0], [0], color=cmap(.5), lw=4),
                Line2D([0], [0], color=cmap(1.), lw=4)]

fig, ax = plt.subplots()
lines = ax.plot(data)
ax.legend(custom_lines, ['Cold', 'Medium', 'Hot'])

那么假如我想利用一个圆形或者其他的东西来代码呢,下面的代码提供了具体的思路。

from matplotlib.patches import Patch
from matplotlib.lines import Line2D

legend_elements = [Line2D([0], [0], color='b', lw=4, label='Line'),
                   Line2D([0], [0], marker='o', color='w', label='Scatter',
                          markerfacecolor='g', markersize=15),
                   Patch(facecolor='orange', edgecolor='r',
                         label='Color Patch')]

# Create the figure
fig, ax = plt.subplots()
ax.legend(handles=legend_elements, loc='center')

plt.show()

这部分代码的效果图如下所示:

python matplotlib 图例放在外面 matplotlib自定义图例,python matplotlib 图例放在外面 matplotlib自定义图例_ci_02,第2张

例如我想自己弄一个星星风格的图例(因为要其他图例是自定义的,所以即使这部分和绘图时一样,也得自己来控制),可以修改代码为:

Line2D([0], [0], marker='*', color='w', markerfacecolor='k', markersize= 12)

1.2 调整图例部分的风格

1.2.1 调整图例中的距离

对于图例中的一些距离,例如边框填充,标签间距离等,在问答[2]中介绍了这部分的相关内容。
主要解决的问题就是,图例样本距离边框太近等。

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0, 10, 5)

fig, ax = plt.subplots()
for i in range(1, 6):
    ax.plot(x, i*x + x, marker='o', markersize=20,
            label='$y={i}x + {i}$'.format(i=i))
ax.legend(loc='upper left', handlelength=5, borderpad=1.2, labelspacing=1.2)
plt.show()

python matplotlib 图例放在外面 matplotlib自定义图例,python matplotlib 图例放在外面 matplotlib自定义图例_ci_03,第3张

而控制这部分代码的参数就是 handlelength=5, borderpad=1.2, labelspacing=1.2,分别进行解释,handlelength调整两个圆圈之间的大小,borderpad对边框进行填充,放置图例实际内容和边框距离太近,labelspacing调整各个标签之间的大小。还有一些其他的参数,暂时没有用到。

Padding and spacing between various elements use following
keywords parameters. These values are measure in font-size
units. E.g., a fontsize of 10 points and a handlelength=5
implies a handlelength of 50 points.  Values from rcParams
will be used if None.

=====================================================================
Keyword       |    Description
=====================================================================
borderpad          the fractional whitespace inside the legend border
labelspacing       the vertical space between the legend entries
handlelength       the length of the legend handles
handletextpad      the pad between the legend handle and text
borderaxespad      the pad between the axes and legend border
columnspacing      the spacing between columns

1.2.2 将图例单独保存为另一个文件

在进行论文写作的过程中,在部署多个子图的时候,肯定不能让多个子图都有图例,最好的办法就是多个子图,共享同一个图例。一种方案就是,多个子图仅仅最右边或者最左边的图带有图例,这种方案比较简单,但是如果图例比较大,如果将图例放置在图片外面,在导入的时候,就会导致图片失调,因为这样多个子图之间就不协调了,需要自己进行比例的控制,而且可能还涉及到标题的不对称问题。
那既然这样,就可以采用另外一种方式,将图例保存为另外一个文件,这个文件放置在最右边。

那么首先要解决的第一个问题就是怎么将图例保存起来。实际上要想实现这个功能也比较简单,如果你的图例是自动生成的,那么可以使用如下代码获取对象;然后利用这个对象放置在一个新的图片中,这个图片比较小,或者比较长(图例比较多的话),然后给这个图片绘制图像。

#ax要保存图例的图片的axes对象可以通过plt.gca()获取
leg = ax.get_legend_handles_labels()

figl, axl = plt.subplots(figsize = (1, 3))
#axl.axis(False)
leg = axl.legend(*label_params, loc = "center")
leg.get_frame().set_edgecolor('k')
leg.get_frame().set_linewidth(1.0)
figl.savefig("legend.pdf")

以上代码获取到的结果如下:

python matplotlib 图例放在外面 matplotlib自定义图例,python matplotlib 图例放在外面 matplotlib自定义图例_图例_04,第4张

注意,这个loc一定要选定为"center"。

对于边框来说,只需要对坐标轴进行设置即可,也可以直接axl.axis(False)

有时候可能还需要对图例表格的位置进行调整,可以使用下面的代码:

leg = axl.legend(*label_params, loc = "center", bbox_to_anchor=(0.5, 0.7), prop={"size":10})

这样生成的图片就是这样:

python matplotlib 图例放在外面 matplotlib自定义图例,python matplotlib 图例放在外面 matplotlib自定义图例_图例_05,第5张

然后具体调整即可。

该部分主要参考了两个文章[3][4];

前面部分是利用了已有图片的图例,如果是自定义的图例,只需要在legend中按照自定义的方法传入即可。

1.2.3 调整图例边框

实际上这部分内容已经在1.2.2中的代码展示,主要内容来自于[5]

#设置边框颜色
leg.get_frame().set_edgecolor('k')
#设置边框线长
leg.get_frame().set_linewidth(1.0)
#设置背景色
legend.get_frame().set_facecolor('none')

1.3 图例放置在axes外面

在问答[6]中,提供了解决方案,同时包含如何将图例放置在外面,同时设置label字体大小。

plt.legend(handles=[p1, p2], title='title', bbox_to_anchor=(1.05, 1), loc='upper left', fontsize='xx-small')

其中比较关键的参数就是bbox_to_anchor。而对于这些情况的具体内容,可以参考问答[9]中的其他回答,介绍的比较详细,包括如何放置图例,以及如何横向放置图例,更重要的是,如果将图例放置在外面,可能会导致图片保存时候被阶段,一种比较简单的方式就是

plt.savefig("output.png", bbox_inches="tight")

多个子图共享图例

当存在多个子图时,例如使用seaborn进行绘图,他会在每个子图上都添加上图例,这个就非常尴尬。所以最好是多个子图共享图例,然后这个图例还放置在外面。图例放置在外面可以参考前面的做法。多个子图需要下面的做法[8]:

handles, labels = ax.get_legend_handles_labels()
fig.legend(handles, labels, loc='upper center')

其中fig是整个大图像文件的对象,为了能够绘制,ax是其中一个子图,从中去处图例的相关对象。

2. 自定义图例

时隔一年,又到了重新来设置图例的时候了,由于之前的时候,弄的东西比较紧凑,当时对于图例是将其保存为另外的文件中,这种形式,反正当时撰写论文的时候,是可以的。不过最近再弄的时候,不太好放置。所以需要考虑其他的方式。可能还是要将图例放置到这个图片里面也没办法。

在文章[7]中给出了不少解决方案,例如现在比较关心的将图例横放的情况。

参考

[1]Composing Custom Legends [2]How to adjust the size of matplotlib legend box? [3]Get legend as a separate picture in Matplotlib [4]creating-separate-legend-figure-with-matplotlib [5]Remove or adapt border of frame of legend using matplotlib [6]How to put the legend out of the plot [7]Custom legends in Matplotlib [8]How do I make a single legend for many subplots?



https://www.xamrdz.com/lan/5y71924564.html

相关文章: