matplotlib:利用legend_handler模块在图例中插入图片(一)

概述

默认情况下,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)
# 绘制散点图
s1 = 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(
    [s1, s2],
    ["类型1", "类型2"],
    handler_map={s1: 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>}

案例:在图例中插入图片(自定义代理可视对象)

在这里插入图片描述

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 AnyObject:
    pass


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


# 获取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")

# 构造代理对象
s1 = AnyObject()
s2 = AnyObject()
# 添加图例,通过handler_map参数添加自定义映射
plt.legend([s1, s2], ['类型1', '类型2'],
           handler_map={s1: custom_handler1, s2: custom_handler2})

plt.show()
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值