默认情况下,matplotlib
会根据可视元素(artist)自动生成图例,但是这种机制不是一定成功的,某些情况下可视元素可能不能自动生成图例。因此,matplotlib
提供了自定义图例的机制,这种机制叫做Proxy artists
,通过Proxy artists
可以将一些图中未出现的可视元素添加到matplotlib
图例。
图例的相关术语如下:
entry
:图例由条目构成,每个条目有一个键和一个标签构成。handle
:生成条目的可视对象。label
:描述处理器的文本。key
:标签左侧的标记。如果想正确创建图例条目,处理器必须为matplotlib.legend_handler.HandlerBase
类的子类,且必须添加到图例处理器映射default_handler_map
中。matplotlib
会检测图形中的可视对象,然后根据映射关系的选择处理器生成图例条目。
通过图例(Legend
)对象的get_legend_handler_map
函数可以获取当前图形的图例处理器映射(default_handler_map
)。
通过legend
函数的handler_map
参数可将自定义图例处理器添加到映射中。
matplotlib.legend_handler
模块提供了HandlerBase
类,以及若干已经定义好的HandlerBase
子类。
我们既可以直接使用已经定义好的子类,也可以自定义HandlerBase
类的子类。
HandlerBase
类没有现成的子类可以在图例中插入图片,因此,需要自定义HandlerBase
类的子类,然后通过legend
函数的handler_map
参数将其添加到图例处理器映射中。
import matplotlib.pyplot as plt
# 获取Legend对象
lg=plt.legend()
print(lg.get_legend_handler_map())
{
<class 'matplotlib.container.StemContainer'>: <matplotlib.legend_handler.HandlerStem object at 0x000000000EE1BF08>, <class 'matplotlib.container.ErrorbarContainer'>: <matplotlib.legend_handler.HandlerErrorbar object at 0x000000000EE1BF88>, <class 'matplotlib.lines.Line2D'>: <matplotlib.legend_handler.HandlerLine2D object at 0x000000000EE3F788>, <class 'matplotlib.patches.Patch'>: <matplotlib.legend_handler.HandlerPatch object at 0x0000000007577548>, <class 'matplotlib.collections.LineCollection'>: <matplotlib.legend_handler.HandlerLineCollection object at 0x0000000007577E08>, <class 'matplotlib.collections.RegularPolyCollection'>: <matplotlib.legend_handler.HandlerRegularPolyCollection object at 0x000000000EE41048>, <class 'matplotlib.collections.CircleCollection'>: <matplotlib.legend_handler.HandlerCircleCollection object at 0x000000000EE41DC8>, <class 'matplotlib.container.BarContainer'>: <matplotlib.legend_handler.HandlerPatch object at 0x000000000EE41E48>, <class 'tuple'>: <matplotlib.legend_handler.HandlerTuple object at 0x000000000EE56088>, <class 'matplotlib.collections.PathCollection'>: <matplotlib.legend_handler.HandlerPathCollection object at 0x000000000EE560C8>, <class 'matplotlib.collections.PolyCollection'>: <matplotlib.legend_handler.HandlerPolyCollection object at 0x0000000007577488>}
import os
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from matplotlib.transforms import TransformedBbox, Bbox
from matplotlib.image import BboxImage
from matplotlib.legend_handler import HandlerBase
plt.rcParams["font.family"] = "simhei"
plt.rcParams["axes.unicode_minus"] = False
class ImageHandler(HandlerBase):
def create_artists(
self, legend, orig_handle, xdescent, ydescent, width, height, fontsize, trans
):
# 缩放图像
sx, sy = self.image_stretch
# 创建边框用于放置图像
bb = Bbox.from_bounds(xdescent - sx, ydescent - sy, width + sx, height + sy)
tbb = TransformedBbox(bb, trans)
image = BboxImage(tbb)
image.set_data(self.image_data)
self.update_prop(image, orig_handle, legend)
return [image]
def set_image(self, image_path, image_stretch=(0, 0)):
if os.path.exists(image_path):
self.image_data = plt.imread(image_path)
self.image_stretch = image_stretch
# 构造随机数据
x = np.random.randn(100)
y1 = np.random.randn(100)
y2 = np.random.randn(100)
# 绘制散点图
s = plt.scatter(x, y1, c="b")
s2 = plt.scatter(x, y2, c="r")
# 获取matplotlib数据目录mpl-data
data_path = mpl.get_data_path()
# 构造自定义图例处理器
custom_handler1 = ImageHandler()
# 设置图像图例
custom_handler1.set_image(data_path + r"\images\home.png")
# 构造自定义图例处理器
custom_handler2 = ImageHandler()
# 设置图像图例
custom_handler2.set_image(data_path + r"\images\back.png")
# 添加图例,通过handler_map参数添加自定义映射
lg = plt.legend(
[s, s2],
["类型1", "类型2"],
handler_map={
s: custom_handler1, s2: custom_handler2},
labelspacing=2,
fontsize=10,
frameon=False,
)
# 获取图例handles映射
print(lg.get_legend_handler_map())
plt.show()
通过控制台输出可以发现自定义的图像处理器已经在图例处理器映射中。
{
<class 'matplotlib.container.StemContainer'>: <matplotlib.legend_handler.HandlerStem object at 0x000000000EBDF988>, <class 'matplotlib.container.ErrorbarContainer'>: <matplotlib.legend_handler.HandlerErrorbar object at 0x000000000EBF5E48>, <class 'matplotlib.lines.Line2D'>: <matplotlib.legend_handler.HandlerLine2D object at 0x000000000D71B448>, <class 'matplotlib.patches.Patch'>: <matplotlib.legend_handler.HandlerPatch object at 0x000000000EBF5688>, <class 'matplotlib.collections.LineCollection'>: <matplotlib.legend_handler.HandlerLineCollection object at 0x000000000D734CC8>, <class 'matplotlib.collections.RegularPolyCollection'>: <matplotlib.legend_handler.HandlerRegularPolyCollection object at 0x000000000EBD2E88>, <class 'matplotlib.collections.CircleCollection'>: <matplotlib.legend_handler.HandlerCircleCollection object at 0x000000000EBD2E08>, <class 'matplotlib.container.BarContainer'>: <matplotlib.legend_handler.HandlerPatch object at 0x000000000EBFDC08>, <class 'tuple'>: <matplotlib.legend_handler.HandlerTuple object at 0x000000000EBFDC88>, <class 'matplotlib.collections.PathCollection'>: <matplotlib.legend_handler.HandlerPathCollection object at 0x000000000EC02E88>, <class 'matplotlib.collections.PolyCollection'>: <matplotlib.legend_handler.HandlerPolyCollection object at 0x000000000EC02EC8>, <matplotlib.collections.PathCollection object at 0x000000000D89A988>: <__main__.ImageHandler object at 0x0000000003FB4F88>, <matplotlib.collections.PathCollection object at 0x0000000003FA5E08>: <__main__.ImageHandler object at 0x0000000003FB4A88>}