Path Tutorial
所有 patches 对象的基础就是 Path 对象
Path 初始化为 一个 (N, 2)的(x, y)顶点数组, 和一个长度为 N 的路径指令(path codes).
例
import matplotlib.pyplot as plt
from matplotlib.path import Path
import matplotlib.patches as patches
verts = [
(0., 0.), # left, bottom
(0., 1.), # left, top
(1., 1.), # right, top
(1., 0.), # right, bottom
(0., 0.), # ignored
]
codes = [
Path.MOVETO,
Path.LINETO,
Path.LINETO,
Path.LINETO,
Path.CLOSEPOLY,
]
path = Path(verts, codes)
fig, ax = plt.subplots()
patch = patches.PathPatch(path, facecolor='orange', lw=2)
ax.add_patch(patch)
ax.set_xlim(-2, 2)
ax.set_ylim(-2, 2)
plt.show()
折线可以不在最后写上起始点, 但是 codes 必须在最后加上 Path.CLOSEPOLY.
Code | Vertices | Description | Value |
---|---|---|---|
STOP | 1 (ignored) | A marker for the end of the entire path (currently not required and ignored). | 0 |
MOVETO | 1 | Pick up the pen and move to the given vertex. | 1 |
LINETO | 1 | Draw a line from the current position to the given vertex. | 2 |
CURVE3 | 2: 1 control point, 1 end point | Draw a quadratic Bézier curve from the current position, with the given control point, to the given end point. | 3 |
CURVE4 | 3: 2 control points, 1 end point | Draw a cubic Bézier curve from the current position, with the given control points, to the given end point. | 4 |
CLOSEPOLY | 1 (the point is ignored) | Draw a line segment to the start point of the current polyline. | 79 |
Bézier example
某些路径组件需要多个顶点来指定, 例如 CURVE 3 是一个贝塞尔曲线, 需要一个控制点和一个结束点, CURVE 4 需要两个控制点和一个结束点.
下例是 CURVE 4 贝塞尔样条(spline) 即贝塞尔曲线会被局限在由一个起点, 两个控制点, 一个终点组成的凸包上.
verts = [
(0., 0.), # P0
(0.2, 1.), # P1
(1., 0.8), # P2
(0.8, 0.), # P3
]
codes = [
Path.MOVETO,
Path.CURVE4,
Path.CURVE4,
Path.CURVE4,
]
path = Path(verts, codes)
fig, ax = plt.subplots()
patch = patches.PathPatch(path, facecolor='none', lw=2)
ax.add_patch(patch)
xs, ys = zip(*verts)
ax.plot(xs, ys, 'x--', lw=2, color='black', ms=10)
ax.text(-0.05, -0.05, 'P0')
ax.text(0.15, 1.05, 'P1')
ax.text(1.05, 0.85, 'P2')
ax.text(0.85, -0.05, 'P3')
ax.set_xlim(-0.1, 1.1)
ax.set_ylim(-0.1, 1.1)
plt.show()
Compound paths
复合路径
所有的简单 patch 原语例如 Rectangle, Circle, Polygon 都是由简单路径实现的. 但是 bar 会创建一个 Rectangle 列表而不是复合路径是有历史原因的, 因为 Path 指令相对较新, 而 bar 要早于它. 如果你要是为了效率的话, 也可以用复合路径.
我们先创建一些随机正态分布的数据, 然后计算直方图.
# histogram our data with numpy
import numpy as np
data = np.random.randn(1000)
n, bins = np.histogram(data, 100)
'''
np.histogram(
a,
bins=10, # bins 是给定范围的条的数量
range=None,
normed=None,
weights=None,
density=None,
)
'''
# n 每个区间的数量
# bins 区间划分
# len(bins) # numpy 会返回bin的边缘而不是中点所以bins个数会比n多一个
# 101
提取矩形的角
# get the corners of the rectangles for the histogram
left = np.array(bins[:-1]) # 左下角的值,
right = np.array(bins[1:]) # 右下角
bottom = np.zeros(len(left)) # 底部
top = bottom + n # 顶部
构建复合路径
由于每个矩形都需要一个 MOVETO, 三个 LINETO, 一个 COLSEPOLY , 所以每个矩形都需要五个顶点. 为 CLOSEPOLY 的顶点可以忽略, 但是我们还是需要让指令和顶点对上.
先创建全为 0 的顶点后续更改.
path.Path.LINETO 本质是 int 所以相乘没有问题.
nrects = len(left)
nverts = nrects*(1+3+1)
verts = np.zeros((nverts, 2))
# 先将所有codes都设置为LINETO 然后再改
codes = np.ones(nverts, int) * path.Path.LINETO
codes[0::5] = path.Path.MOVETO
codes[4::5] = path.Path.CLOSEPOLY
# 设置每个矩形左下角坐标
verts[0::5, 0] = left
verts[0::5, 1] = bottom
# 设置每个矩形左上角坐标
verts[1::5, 0] = left
verts[1::5, 1] = top
verts[2::5, 0] = right
verts[2::5, 1] = top
verts[3::5, 0] = right
verts[3::5, 1] = bottom
Path 初始化为 一个 (N, 2)的(x, y)顶点数组, 和一个长度为 N 的路径指令(path codes).
最后将路径添加到 PathPatch 里, 再加到 axes.
barpath = path.Path(verts, codes)
patch = patches.PathPatch(barpath, facecolor='green',
edgecolor='yellow', alpha=0.5)
ax.add_patch(patch)