matplotlib必会|使用OffsetBox尽情的添加自定义元素!

共 4262字,需浏览 9分钟

 ·

2021-01-26 10:43

大家好,我是早起。

如果你对数据可视化感兴趣,可以点击上方「可视化图鉴」关注!

我们都知道,如果想要在matplotlib中添加文字注释可以使用plt.text根据坐标来添加,如果想要添加箭头也同样可以使用plt.arrow根据坐标完成。

那如果想要添加自定义的图片呢?

在matplotlib中添加自定义图片有多种方法,本文将基于matplotlib中的Artists容器类讲解,如何在我们制作的图中添加任意自已想要的元素。

作为示例,和以前的文章一样,本文不罗列各种参数,用下图作为示例,step by step的介绍每部分制作流程

一句话看懂原理

关于Artists类的中文参考文章并不多,为了方便后面解释,我从官方文档中找到一张比较容易理解的图👇

如上图所示,我们使用的是Artists类中的OffsetBox模块,我们将想要展示的元素(文字、图片等)放在这个模块中,并使用AnnotationBbox根据坐标放在指定位置。

那么和类似plt.text直接添加文字等操作有什么区别呢,本文这个方法要求你先创建一个需要放置的元素,本质上是两个步骤,而plt.xxxx则是简单调用API,一步完成。

因为此时我们将制作元素和防止元素分隔开,所以就可以有更多的细节支持调整,下面我们来基于例子讲解。

导入与初始化

老规矩,首先我们需要导入相关库,并创建一张画布

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.patches import Circle
from matplotlib.offsetbox import (TextArea, DrawingArea, OffsetImage,
                                  AnnotationBbox)
from matplotlib.cbook import get_sample_data

fig, ax = plt.subplots(figsize = (9,7),dpi = 150)

ax.set_xlim(0,1)
ax.set_ylim(0,1)

其中TextArea=用于创建文字元素,OffsetImage用于创建图片元素,导入之后我们创建画布并调整了坐标轴范围。

添加自定义图片

现在我们来讲解如何添加自定义图片到画布中,其实很简单,总共分两步,根据路径打开一张图片-->根据坐标添加到画布中

先是打开一张图片,在仿制官方文档图中我们使用mpimg.imread打开

arr_lena = mpimg.imread('/Users/liuhuanshuo/Desktop/WechatIMG2278.png')

这里我们也可以使用with语句

with get_sample_data("/Users/liuhuanshuo/Desktop/可视化图鉴/多媒体素材/logo/高清图/水印.png"as file:
    arr_img = plt.imread(file, format='png')

这里不多解释,两种方法等价,就是根据路径打开一张图片,接下来将图片放在OffsetBox容器中

imagebox = OffsetImage(arr_img, zoom=0.2)
imagebox.image.axes = ax

接下来使用AnnotationBbox添加到画布中

ab = AnnotationBbox(imagebox, [0.15,0.5],
                    xybox=(170.-50.),
                    xycoords='data',
                    boxcoords="offset points",
                    pad=0.5
                    )

这个AnnotationBbox接收的参数比较多,也比较复杂,这里我们仅说下常用的几个参数。

首先第一个参数是你要添加到画布的元素,这里就是刚刚存储图片的imagebox,之后总要告诉它放在哪里,所以接下来是一个坐标。

后面的xybox、xycoords、boxcoords是什么呢?

注意到我们可以发现在初始化时,我有这样一行代码imagebox.image.axes = ax

其实这里的ax并不是我们看到画布中的坐标系,而是这个元素自己有一个坐标系,为什么要新建一个坐标系,就是为了方便调整!

比如若沿用画布原有坐标系,我要是想将元素放置到坐标系外,就没有办法了,所以我们元素自己有一个坐标系这样就没有限制了!

所以我们用xycoords、boxcoords来控制这个新坐标系的位置,而xybox就是在这个坐标系中的偏移量,比如data就是沿用原有坐标系,其他位置参数参考如下:

参数说明
'figure points'距离图形左下角的点数量
'figure pixels'距离图形左下角的像素数量
'figure fraction'0,0 是图形左下角,1,1 是右上角
'axes points'距离轴域左下角的点数量
'axes pixels'距离轴域左下角的像素数量
'axes fraction'0,0 是轴域左下角,1,1 是右上角
'data'使用轴域数据坐标系

这一块理解起来是比较抽象的,我建议如果想搞明白,可以一边修改参数,一边观察图片变化来加深理解

最后用ax.add_artist(ab)应用,我们的图片就成功加入到画布中了!

添加文字、箭头

下面介绍如何添加文字和箭头,其实和添加图片一样,把字写好加上去呗!我们直接看代码,使用的是TextArea存储需要展示的文字

offsetbox = TextArea("这是我的公众号",textprops = dict(fontsize = 15))

ab = AnnotationBbox(offsetbox, [0.730.5],
                    xybox=(1.050.5),
                    xycoords='data',
                    boxcoords=("axes fraction""data"),
                    box_alignment=(0.0.5),
                    arrowprops=dict(arrowstyle="->"))
ax.add_artist(ab)

offsetbox = TextArea("微信搜索:可视化图鉴",textprops = dict(fontsize = 15))

ab = AnnotationBbox(offsetbox,[0.530.72],
                    xybox=(-2070),
                    xycoords='data',
                    boxcoords="offset points",
                    arrowprops=dict(arrowstyle="->",color = 'deeppink'))
ax.add_artist(ab)

可以看到,我先使用TextArea创建文字,和其他要出现文字的方法一样,支持调整字体、大小等参数,传给textprops即可,不多解释。

接下来使用AnnotationBbox添加文字,这里和刚刚是一样的,指定坐标、指定坐标系、指定偏移量。

注意这里我在添加这是我的公众号几个字的时候,指定的坐标系就是boxcoords=("axes fraction", "data"),一个是画布坐标系data另一个一个是自己的坐标系axes fraction,这样我就能够根据偏移量来将文字添加到原有画布坐标系之外。

大家可以自己体会一下,如果不明白还是建议可以一边修改参数,一边观察图片变化来加深理解

最后是添加箭头,这里添加箭头是在添加文字同时完成的,只需要设定arrowprops就能根据上面的坐标添加箭头了!

箭头的样式除了图中的还有更多的样式可以通过arrowprops进行调整,大家可以自行参考来修改上面的箭头形状、颜色,关于箭头的详细设置我会在下一篇的箭头专题中单独讲解!

现在我们的图案就是这样,注意这里其实是有两个坐标系(可以这么理解):一个是原有画布的(利用坐标值的绝对量控制)另一个是用于放置元素的(利用相对偏移量控制)!

彩蛋

最后想说一下,offsetbox的用法远不止添加文字、图片,比如使用offsetbox设置箭头除了可以调整颜色、大小、位置,还有更多的样式可以实现👇

这个就是可以自定义箭头的类型、角度,比如我们进一步设置弯的箭头,就是在添加图片哪里额外增加一个箭头样式参数connectionstyle="angle3,angleA=0,angleB=30")接着添加新如下文字

offsetbox = TextArea("专注于数据可视化",textprops = dict(fontsize = 12))
ab = AnnotationBbox(offsetbox,[0.130.57],

                   )
ax.add_artist(ab)

小结

到这里,有关offsetbox我要讲解的就结束了,大家应该可以看到使用offsetbox添加元素时,对细节的调整更加丰富,所以如果你在matplotlib绘图路上走的更远,这个模块你必须要会使用!

最后早起想说的是,本文介绍的库还是比较复杂的,我已经尽可能努力的解释,如果你还是感觉抽象,那就撸起袖子写代码(完整代码全部在文中!),一边修改参数,一边观察图片变化来加深理解!有任何疑问也可以给我留言,谢谢!

最后还是厚着脸皮说一下,如果大家喜欢本文,希望看到更多本系列文章,可以帮忙点赞、在看、转发,谢谢!

如果你也对数据可视化感兴趣,可以长按扫描下方二维码关注!

浏览 48
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报