matplotlib高级教程之形状与路径——patches和path

matplotlib高级教程之形状与路径——patches和path

一个小例子

%matplotlib notebook
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from matplotlib import patches

#绘制一个椭圆需要制定椭圆的中心,椭圆的长和高
xcenter, ycenter = 1, 1
width, height = 0.8, 0.5
angle = -30  #椭圆的旋转角度

#第一步:创建绘图对象
fig = plt.figure()
ax = fig.add_subplot(211, aspect='auto')
ax.set_xbound(-1, 3)  #这个好,直接给一个轴的范围
ax.set_ybound(-1, 3)
#第二步
e1 = patches.Ellipse((xcenter, ycenter),
                     width,
                     height,
                     angle=angle,
                     linewidth=2,
                     fill=True,
                     zorder=2)
#第三步
ax.add_patch(e1)

#第一步
ax = fig.add_subplot(212, aspect='equal')
ax.set_xbound(-1, 3)
ax.set_ybound(-1, 3)
#第二步
e2 = patches.Arc((xcenter, ycenter),
                 width,
                 height,
                 angle=angle,
                 linewidth=2,
                 fill=False,
                 zorder=2)
#第三步
ax.add_patch(e2)

plt.show()
<IPython.core.display.Javascript object>

使用集合的源代码

import numpy as np
from matplotlib import patches
import matplotlib.pyplot as plt
from matplotlib.collections import PatchCollection
%matplotlib notebook

#绘制一个椭圆需要制定椭圆的中心,椭圆的长和高
xcenter, ycenter = 1, 1
width, height = 0.8, 0.5
angle = -30  #椭圆的旋转角度

fig = plt.figure()
ax = fig.add_subplot(211, aspect='auto')
ax.set_xbound(-1, 3)
ax.set_ybound(-1, 3)

e1 = patches.Ellipse((0, 0),
                     width,
                     height,
                     angle=angle,
                     linewidth=2,
                     fill=False,
                     zorder=2)

# Arc是继承自Ellipse类的,故而等价
e2 = patches.Arc((2, 2),
                 width=3,
                 height=2,
                 angle=angle,
                 linewidth=2,
                 fill=False,
                 zorder=2)

patches = []
patches.append(e1)
patches.append(e2)
collection = PatchCollection(patches)
ax.add_collection(collection)

plt.show()
<IPython.core.display.Javascript object>

图形的综合应用案例

import matplotlib.pyplot as plt
import numpy as np
import matplotlib.path as mpath
import matplotlib.lines as mlines
import matplotlib.patches as mpatches
from matplotlib.collections import PatchCollection


#定义函数,给每一个patch都设置标签说明
def label(xy, text):
    y = xy[1] - 0.15  # 标签放置在patch下方的0.15位置处
    plt.text(xy[0], y, text, ha="center", family='sans-serif', size=14)


fig, ax = plt.subplots()
# 创建一个3x3的网格
grid = np.mgrid[0.2:0.8:3j, 0.2:0.8:3j].reshape(2, -1).T

#创建容纳patch的集合
patches = []

# 添加一个圆Circle
circle = mpatches.Circle(grid[0], 0.1, ec="none")
patches.append(circle)
label(grid[0], "Circle")

# 添加一个Rectangle
rect = mpatches.Rectangle(grid[1] - [0.025, 0.05], 0.05, 0.1, ec="none")
patches.append(rect)
label(grid[1], "Rectangle")

# 添加一个楔形,即圆的一部分
wedge = mpatches.Wedge(grid[2], 0.1, 30, 270, ec="none")
patches.append(wedge)
label(grid[2], "Wedge")

# 添加一多边形,这里添加一个五边形
polygon = mpatches.RegularPolygon(grid[3], 5, 0.1)
patches.append(polygon)
label(grid[3], "Polygon")

# 添加一个椭圆,也可以使用Arc
ellipse = mpatches.Ellipse(grid[4], 0.2, 0.1)
patches.append(ellipse)
label(grid[4], "Ellipse")

# 添加一个箭头
arrow = mpatches.Arrow(grid[5, 0] - 0.05,
                       grid[5, 1] - 0.05,
                       0.1,
                       0.1,
                       width=0.1)
patches.append(arrow)
label(grid[5], "Arrow")

# 添加一个路径path,路径的详细解释后面会讲到,相比于简单的patch,稍显复杂
Path = mpath.Path
path_data = [(Path.MOVETO, [0.018, -0.11]), (Path.CURVE4, [-0.031, -0.051]),
             (Path.CURVE4, [-0.115, 0.073]), (Path.CURVE4, [-0.03, 0.073]),
             (Path.LINETO, [-0.011, 0.039]), (Path.CURVE4, [0.043, 0.121]),
             (Path.CURVE4, [0.075, -0.005]), (Path.CURVE4, [0.035, -0.027]),
             (Path.CLOSEPOLY, [0.018, -0.11])]
codes, verts = zip(*path_data)
path = mpath.Path(verts + grid[6], codes)
patch = mpatches.PathPatch(path)
patches.append(patch)
label(grid[6], "PathPatch")

# 添加一个box
fancybox = mpatches.FancyBboxPatch(grid[7] - [0.025, 0.05],
                                   0.05,
                                   0.1,
                                   boxstyle=mpatches.BoxStyle("Round",
                                                              pad=0.02))
patches.append(fancybox)
label(grid[7], "FancyBboxPatch")

# 添加一条折线——注意这里的折线和前面所画的这显示不一样的,这里的折线是一个形状
x, y = np.array([[-0.06, 0.0, 0.1], [0.05, -0.05, 0.05]])
line = mlines.Line2D(x + grid[8, 0], y + grid[8, 1], lw=5., alpha=0.3)
label(grid[8], "Line2D")

#将patch集合包装成PatchCollection
collection = PatchCollection(patches, cmap=plt.cm.hsv, alpha=0.3)
# 给九个图形设置图像颜色
colors = np.linspace(0, 1, len(patches))
collection.set_array(np.array(colors))
#将PatchCollection添加给axes对象
ax.add_collection(collection)
#将折线添加到axes对象
ax.add_line(line)

plt.axis('equal')  # x、y轴等宽
plt.axis('off')  # 不显示x、y轴
plt.tight_layout()  # 调整图像中子图的布局以及子图和图片的

plt.show()
<IPython.core.display.Javascript object>

路径path

小实例

import matplotlib.pyplot as plt
from matplotlib.path import Path
import matplotlib.patches as patches

#import matplotlib.patheffects
#import matplotlib.transforms

verts = [
    (0., 0.),  # 矩形左下角的坐标(left,bottom)
    (0., 1.),  # 矩形左上角的坐标(left,top)
    (1., 1.),  # 矩形右上角的坐标(right,top)
    (1., 0.),  # 矩形右下角的坐标(right, bottom)
    (0., 0.),  # 封闭到起点    
]

codes = [
    Path.MOVETO,
    Path.LINETO,
    Path.LINETO,
    Path.LINETO,
    Path.CLOSEPOLY,
]
# matplotlib中的rectangle、circle、polygon等所有简单的简单图形都采用简单的路径path去实现的,只不过用类的形式进行了更高级的封装。
path = Path(verts, codes)  #创建一个路径path对象

#依然是三步走
#第一步:创建画图对象以及创建子图对象
fig = plt.figure()
ax = fig.add_subplot(111)

#第二步:创建一个patch,路径依然也是通过patch实现的,只不过叫做pathpatch
patch = patches.PathPatch(path, facecolor='orange', lw=2)

#第三步:将创建的patch添加到axes对象中
ax.add_patch(patch)

#显示
ax.set_xlim(-2, 2)
ax.set_ylim(-2, 2)
plt.show()
<IPython.core.display.Javascript object>

绘制一个条形统计图

import numpy as np

import matplotlib.pyplot as plt
import matplotlib.patches as patches
import matplotlib.path as path

fig = plt.figure()
ax = fig.add_subplot(111)

# 固定随机数种子
np.random.seed(19680801)

# 产生1000组随机数,并进行组织
data = np.random.randn(1000)
# hist是每一个柱子的高;bins是所有柱子的分割点。所以len(bins) = len(hist)+1
hist, bins = np.histogram(data, 100)

# 得到每一个条形图的四个角落的位置
left = np.array(bins[:-1])
right = np.array(bins[1:])
# 返回一个指定长度的0数组,作为每一个柱子的底高
bottom = np.zeros(len(left)) 
# 获得每一个柱子的高高
top = bottom + hist

# 获得到底有多少个柱子
nrects = len(hist)

# 每一个柱子由4个点完成,首先指定起点Path.MOVETO
# 指向画笔到中间点三次Path.LINETO
# 最后指定终点 Path.CLOSEPOLY
nverts = nrects * (1 + 3 + 1)
# 创造一个柱子坐标空间,这是一个二维数组,每五行表示一个柱子
# left bottom
# left top
# right bottom
# right top
# 0 0
verts = np.zeros((nverts, 2))
# 创造len(hist)*(1 + 3 + 1)个code,这是个一维数组,每一个柱子对应五个code
# 默认都设置为 path.Path.LINETO
codes = np.ones(nverts, int) * path.Path.LINETO
# 设置每一个柱子的第一个code为path.Path.MOVETO
# 设置每一个柱子的最后一个code为path.Path.CLOSEPOLY
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
verts[4::5, 0] = left
verts[4::5, 1] = bottom

# 第二步:构造patches对象
# vertices是指的是路径path所经过的关键点的一系列坐标(x,y)
# codes指的是点与点之间到底是怎么连接的,是直线连接?曲线连接?
barpath = path.Path(verts, codes)
patch = patches.PathPatch(barpath,
                          facecolor='green',
                          edgecolor='yellow',
                          alpha=0.5)

# 添加patch到axes对象
ax.add_patch(patch)

ax.set_xlim(left[0], right[-1])
ax.set_ylim(bottom.min(), top.max())

plt.show()
<IPython.core.display.Javascript object>

(1)vertices
vertices = [
(0., 0.), # left, bottom
(0., 1.), # left, top
(1., 1.), # right, top
(1., 0.), # right, bottom
(0., 0.), # ignored
]
(2)codes
codes = [
Path.MOVETO,
Path.LINETO,
Path.LINETO,
Path.LINETO,
Path.CLOSEPOLY,
]

MOVETO :拿起钢笔, 移动到给定的顶点。一般指的是 “起始点”
LINETO :从当前位置绘制直线到给定顶点。
CURVE3 :从当前位置 (用给定控制点) 绘制一个二次贝塞尔曲线到给定端点。
CURVE4 :从当前位置 (与给定控制点) 绘制三次贝塞尔曲线到给定端点。
CLOSEPOLY :将线段绘制到当前折线的起始点。
STOP :整个路径末尾的标记 (当前不需要和忽略)

  • 总结:在创建vertices和codes的时候,每个点和每一个codes是对应着的,如上面所示,一定要注意这样的对应关系。

(3)path对象的另一种实现
path_data = [
(Path.MOVETO, [0.018, -0.11]),  #起点
(Path.CURVE4, [-0.031, -0.051]),
(Path.CURVE4, [-0.115, 0.073]),
(Path.CURVE4, [-0.03, 0.073]),
(Path.LINETO, [-0.011, 0.039]),
(Path.CURVE4, [0.043, 0.121]),
(Path.CURVE4, [0.075, -0.005]),
(Path.CURVE4, [0.035, -0.027]),
(Path.CLOSEPOLY, [0.018, -0.11])]  #闭合到起点
codes, verts = zip(*path_data)   #使用内置的Zip函数
heartpath = path.Path(verts, codes)   #创建Path对象
patch = mpatches.PathPatch(path)    #将path包装成一个patch对象

  • 补充
    上面知识介绍了一些最基本的路径path的操作,路径的各种操作很复杂,还有各种各样的路径操作函数,还有路径效果和相关的一些操作,在
    import matplotlib.patheffects
    import matplotlib.transforms
    这两个模块里面,关于这两个模块的操作,这里就不讨论了,有兴趣可以查阅官方文档。

作者:LoveMIss-Y
来源:CSDN
原文:https://blog.csdn.net/qq_27825451/article/details/82967904
版权声明:本文为博主原创文章,转载请附上博文链接!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值