Matplotlib进阶教程:图例讲解

2f9b134881edcd04e16130b09ecdc676.gif

在后台回复【阅读书籍】

即可获取python相关电子书~

Hi,我是山月。

今天来给大家介绍Matplotlib里的图例部分~

术语解释:

  • 图例条目(legend entry):图例由一个或多个图例条目组成,一个条目由一个键和一个标签组成。

  • 图例键(legend key):每个图例标签左侧的颜色/图案标记。

  • 图例标签(legend label):描述键表示的句柄的文本。

  • 图例句柄(legend handle):用于在图例中生成适当条目的原始对象。

1、控制图例条目

不带参数调用 legend() 会自动获取图例句柄及其相关标签,此功能等效于:

handles, labels = ax.get_legend_handles_labels()
ax.legend(handles, labels)

get_legend_handles_labels() 函数返回轴上存在的句柄/artists列表,可用于生成图例的条目。

注意,并非所有的artists都可以添加到图例中,有时候需要创建一个“proxy”。

比如标签为空字符串或标签以“_”开头的artists会被忽略。

为了完全控制添加到图例中的内容,通常将句柄直接传递给 legend():

hline_up, = plt.plot([1, 2, 3], label='Line 2')
line_down, = plt.plot([3, 2, 1], label='Line 1')
plt.legend(handles=[line_up, line_down])

在某些情况下,可能无法设置句柄的标签,因此可以将标签列表传递给legend():

line_up, = plt.plot([1, 2, 3], label='Line 2')
line_down, = plt.plot([3, 2, 1], label='Line 1')
plt.legend([line_up, line_down], ['Line Up', 'Line Down'])

2、创建专门添加到图例的artists

并非所有句柄都可以自动转换为图例条目,因此通常需要创建可以自动转换的artists。

示例1:

import matplotlib.patches as mpatches
import matplotlib.pyplot as plt

red_patch = mpatches.Patch(color='red', label='The red data')
plt.legend(handles=[red_patch])

plt.show()

效果:

46176de31c8d2cfc6bb7566b6c09e070.png

示例2:

import matplotlib.pyplot as plt
import matplotlib.lines as mlines

blue_line = mlines.Line2D([], [], color='blue', marker='*',
                          markersize=15, label='Blue stars')
plt.legend(handles=[blue_line])

plt.show()

效果:

d958f1d98ae1a3ff58ce8fa853c3fea0.png

3、图例位置

图例的位置可以通过关键字参数 loc 来指定,bbox_to_anchor 关键字可以用来手动放置图例。

如:

import matplotlib.pyplot as plt

plt.subplot(211)
plt.plot([1, 2, 3], label="test1")
plt.plot([3, 2, 1], label="test2")

# 在此子图上方放置一个图例
plt.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc='lower left',
           ncol=2, mode="expand", borderaxespad=0.)

plt.subplot(223)
plt.plot([1, 2, 3], label="test1")
plt.plot([3, 2, 1], label="test2")
# 在小子图右侧放置一个图例。
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0.)

plt.show()

效果:

5e8a2b2255d2aba8594140ea67ae447b.png

4、一个轴上的多个图例

有时将图例条目拆分为多个图例会更清楚。执行此操作的方法是多次调用 legend() 函数,并手动将它们添加到轴:

import matplotlib.pyplot as plt

line1, = plt.plot([1, 2, 3], label="Line 1", linestyle='--')
line2, = plt.plot([3, 2, 1], label="Line 2", linewidth=4)

# 为第一个线条创建图例
first_legend = plt.legend(handles=[line1], loc='upper right')
# 将图例手动添加到当前轴
ax = plt.gca().add_artist(first_legend)
# 为第二个线条创建另一个图例
plt.legend(handles=[line2], loc='lower right')

plt.show()

效果:

b276233d5aa7428827d0bf1b28d50713.png

5、图例处理程序

为了创建图例条目,可以将句柄作为参数提供给HandlerBase子类。处理程序子类的选择有以下规则:

  • 使用 handler_map 关键字中的值更新 get_legend_handler_map()。

  • 检查句柄是否在新创建的 handler_map 中。

  • 检查句柄类型是否在新创建的 handler_map 中。

  • 检查句柄 mro 中的任何类型是否在新创建的 handler_map 中。

示例:

import matplotlib.pyplot as plt
from matplotlib.legend_handler import HandlerLine2D

line1, = plt.plot([3, 2, 1], marker='o', label='Line 1')
line2, = plt.plot([1, 2, 3], marker='o', label='Line 2')
plt.legend(handler_map={line1: HandlerLine2D(numpoints=4)})

plt.show()

效果:

ca199e0d263b3480bc366f37b8107eda.png

“Line 1”现在有 4 个标记点,而“Line 2”只有 默认的2 个。

如果把handler_map的键从 line1 更改为 type(line1),会让两个 Line2D 实例都获得 4 个标记:

fea024797ea41c0321ed637c2d883a8e.png

默认的 handler_map 有一个特殊的元组处理程序,它可以将给定元组中每个项目的句柄绘制在另一个之上。

import matplotlib.pyplot as plt
from numpy.random import randn

z = randn(10)

red_dot, = plt.plot(z, "ro", markersize=15)
# 在一些数据上画一个白色的十字
white_cross, = plt.plot(z[:5], "w+", markeredgewidth=3, markersize=15)

plt.legend([red_dot, (red_dot, white_cross)], ["Attr A", "Attr A+B"])

plt.show()

效果:

8aeb86214d7df1e6daebbff20bdc6f40.png

HandlerTuple也可将多个图例键分配给同一条目:

import matplotlib.pyplot as plt
from matplotlib.legend_handler import HandlerTuple

p1, = plt.plot([1, 2.5, 3], 'r-d')
p2, = plt.plot([3, 2, 1], 'k-o')

l = plt.legend([(p1, p2)], ['Two keys'], numpoints=1,
               handler_map={tuple: HandlerTuple(ndivide=None)})

plt.show()

效果:

68ec0b619471442e839dc1c1d4357b44.png

可以实现自定义处理程序从而将句柄转换为图例键,但处理程序必须实现一个“legend_artist”方法,该方法会返回一个供图例使用的artist。

import matplotlib.pyplot as plt
import matplotlib.patches as mpatches

class AnyObject:
    pass

class AnyObjectHandler:
    def legend_artist(self, legend, orig_handle, fontsize, handlebox):
        x0, y0 = handlebox.xdescent, handlebox.ydescent
        width, height = handlebox.width, handlebox.height
        patch = mpatches.Rectangle([x0, y0], width, height, facecolor='red',
                                   edgecolor='black', hatch='xx', lw=3,
                                   transform=handlebox.get_transform())
        handlebox.add_artist(patch)
        return patch

plt.legend([AnyObject()], ['My first handler'],
           handler_map={AnyObject: AnyObjectHandler()})

plt.show()

效果:

5c12f3732c26b6b1b37f4e24ab967ed9.png

如果我们想全局接受 AnyObject 实例但不想一直手动设置 handler_map 关键字,可以通过注册新的处理程序:

from matplotlib.legend import Legend
Legend.update_default_handler_map({AnyObject: AnyObjectHandler()})

生成椭圆图例键:

fimport matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from matplotlib.legend_handler import HandlerPatch

class HandlerEllipse(HandlerPatch):
    def create_artists(self, legend, orig_handle,
                       xdescent, ydescent, width, height, fontsize, trans):
        center = 0.5 * width - 0.5 * xdescent, 0.5 * height - 0.5 * ydescent
        p = mpatches.Ellipse(xy=center, width=width + xdescent,
                             height=height + ydescent)
        self.update_prop(p, orig_handle, legend)
        p.set_transform(trans)
        return [p]

c = mpatches.Circle((0.5, 0.5), 0.25, facecolor="green",
                    edgecolor="red", linewidth=3)
plt.gca().add_patch(c)

plt.legend([c], ["An ellipse, not a rectangle"],
           handler_map={mpatches.Circle: HandlerEllipse()})

plt.show()

效果:

c775f0d7c8e8475b56ab63c804f26c0f.png

055891bb4adc4722af001256dc285726.png

END

36d6cdb5e3a9ae6bb457eaaf9dca8f52.gif

您的“点赞”、“在看”和 “分享”是我们产出的动力。

  • 6
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值