使用matplotlib画图自定义marker
作者:qiu_xingye
matplotlib画图自定义marker
在matplotlib工具箱中可以画marker的高级作图函数一共有两个,分别为plot和scatter,可以画出多种marker。
但如果需要绘制一些特殊的marker,则必须通过自的定义marker来实现。
一般有两种方式可以实现:
- 一是在绘图中插入特殊marker的icon图片
- 二是借助于matplotlib.path中的Path类,自定义marker的Path参数。
但无论何种方式,实现的marker都要具有一般marker的特点。
marker的特点
- 固定大小:marker的大小只依赖于markersize关键字定义的数值,不随着绘制的图形的放大或缩小而变化;
- 可改变方向: matplotlib默认支持的某些marker可以通过传入的参数调整marker的方向
基于marker的上述两个特点,因此不能简单地通过plot绘制特殊marker的折线或者简单地进行图片插入实现。
通过插入图片实现自定义marker
from matplotlib import pyplot as pltimport numpy as np '图片插入(普通)' N = 100 x = np.linspace(0, 10, N) y = np.sin(x) fig = plt.figure() ax = fig.add_subplot(111) ax.imshow(plt.imread('icon\\icon-test.png'), extent=(x[0],x[0]+1,y[0],y[0]+1)) ax.plot(x, y) plt.show()
如上图所示,基本可以实现marker的插入,但大小会随figure的大小变化,而且也不能改变方向。
进一步完善代码如下:
from matplotlib import pyplot as plt from matplotlib.offsetbox import OffsetImage, AnnotationBbox import numpy as np '图片插入(大小不变)' N = 100 x = np.linspace(0, 10, N) y = np.sin(x) fig = plt.figure() ax = fig.add_subplot(111) ax.plot(x, y) img = plt.imread('icon\\icon-test.png') im = OffsetImage(img, zoom=0.3) ab = AnnotationBbox(im, (x[0],y[0]), xycoords='data', frameon=False) ax.add_artist(ab) plt.show()
此时插入的marker不再随figure大小的变化而变化,但还不能做到自定义旋转角度,如果要实现该功能,则可以通过定义旋转矩阵,将plt.imread读取的图片数据img进行旋转变换以实现对marker的角度旋转。
但这种方法仍然不同灵活,不像真正的“marker”,而且效率也不高。
下面介绍如何通过Path实现自定义marker。
通过Path实现自定义marker
from matplotlib import pyplot as plt from matplotlib.path import Path import numpy as np '通过Path类自定义marker' #定义旋转矩阵 def rot(verts, az): #顺时针旋转 rad = az / 180 * np.pi verts = np.array(verts) rotMat = np.array([[np.cos(rad), -np.sin(rad)], [np.sin(rad), np.cos(rad)]]) transVerts = verts.dot(rotMat) return transVerts iconMat = np.array([[-1.414, 1.414], [0, 0], [2.828, 2.828], [0, 0], [-1.414, 1.414]]) class CustomMarker(Path): def __init__(self, icon, az): if icon == "icon": verts = iconMat vertices = rot(verts, az) super().__init__(vertices) N = 30 x = np.linspace(0, 10, N) y = np.sin(x) fig = plt.figure() ax = fig.add_subplot(111) ax.scatter(x, y, marker=IconMarker("icon", 20), c="red", s=1000) plt.show()
实现效果如上图所示,就像普通的marker一样,大小固定,不随figure大小变化,而且可以调节方向(旋转)。
实现的主要原理是
matplotlib中的plot和scatter绘图函数中的marker关键字传递的值会被matplotlib.markers中的MarkerStyle类处理,而MarkerStyle类中的set_marker是可以处理path对象的。
因此,先生成自定义的marker的Path对象的路径点参数,然后定义旋转矩阵,根据旋转角度对路径点参数进行旋转,生成指定方向的marker的Path对象的路径点参数。
剩下的marker的大小/颜色等可由MarkerStyle类或plot/scatter函数其他相关的关键字属性自动处理。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。