如何绘制复杂多边形?
我正在从一个地理信息系统(GIS)数据库中读取数据,并使用mpl_toolkits.basemap和matplotlib来创建地图。有些数据会生成复杂的多边形,这些多边形是由外圈和内圈组成的。不过,我一直找不到如何创建带孔的多边形的方法。请问,这在matplotlib中可能吗?有没有其他方法可以制作这个图像?
4 个回答
2
虽然我来得有点晚,但我对@Matt的回答进行了修改,使用了这种方法,生成了这段代码(也可以在这个链接中找到):
import numpy as np
from matplotlib.path import Path
from matplotlib.patches import PathPatch
def patchify(polys):
"""Returns a matplotlib patch representing the polygon with holes.
polys is an iterable (i.e list) of polygons, each polygon is a numpy array
of shape (2, N), where N is the number of points in each polygon. The first
polygon is assumed to be the exterior polygon and the rest are holes. The
first and last points of each polygon may or may not be the same.
This is inspired by
https://sgillies.net/2010/04/06/painting-punctured-polygons-with-matplotlib.html
Example usage:
ext = np.array([[-4, 4, 4, -4, -4], [-4, -4, 4, 4, -4]])
t = -np.linspace(0, 2 * np.pi)
hole1 = np.array([2 + 0.4 * np.cos(t), 2 + np.sin(t)])
hole2 = np.array([np.cos(t) * (1 + 0.2 * np.cos(4 * t + 1)),
np.sin(t) * (1 + 0.2 * np.cos(4 * t))])
hole2 = np.array([-2 + np.cos(t) * (1 + 0.2 * np.cos(4 * t)),
1 + np.sin(t) * (1 + 0.2 * np.cos(4 * t))])
hole3 = np.array([np.cos(t) * (1 + 0.5 * np.cos(4 * t)),
-2 + np.sin(t)])
holes = [ext, hole1, hole2, hole3]
patch = patchify([ext, hole1, hole2, hole3])
ax = plt.gca()
ax.add_patch(patch)
ax.set_xlim([-6, 6])
ax.set_ylim([-6, 6])
"""
def reorder(poly, cw=True):
"""Reorders the polygon to run clockwise or counter-clockwise
according to the value of cw. It calculates whether a polygon is
cw or ccw by summing (x2-x1)*(y2+y1) for all edges of the polygon,
see https://stackoverflow.com/a/1165943/898213.
"""
# Close polygon if not closed
if not np.allclose(poly[:, 0], poly[:, -1]):
poly = np.c_[poly, poly[:, 0]]
direction = ((poly[0] - np.roll(poly[0], 1)) *
(poly[1] + np.roll(poly[1], 1))).sum() < 0
if direction == cw:
return poly
else:
return poly[::-1]
def ring_coding(n):
"""Returns a list of len(n) of this format:
[MOVETO, LINETO, LINETO, ..., LINETO, LINETO CLOSEPOLY]
"""
codes = [Path.LINETO] * n
codes[0] = Path.MOVETO
codes[-1] = Path.CLOSEPOLY
return codes
ccw = [True] + ([False] * (len(polys) - 1))
polys = [reorder(poly, c) for poly, c in zip(polys, ccw)]
codes = np.concatenate([ring_coding(p.shape[1]) for p in polys])
vertices = np.concatenate(polys, axis=1)
return PathPatch(Path(vertices.T, codes))
15
其实你可以在matplotlib中绘制带孔的多边形。诀窍是使用Path和PathPatch。比如说:
import matplotlib.pyplot as plt
from matplotlib.patches import PathPatch
from matplotlib.path import Path
axes = plt.gca()
path = Path([(2,2) ,(2,-2) ,(-2,-2) ,(-2,2) ,(0,0) ,(1,0) ,(-1,1) ,(-1,-1) ,(0,0) ],
[Path.MOVETO,Path.LINETO,Path.LINETO,Path.LINETO,Path.CLOSEPOLY,Path.MOVETO,Path.LINETO,Path.LINETO,Path.CLOSEPOLY])
patch = PathPatch(path)
axes.set_xlim(-3,3)
axes.set_ylim(-3,3)
axes.add_patch(patch)
plt.savefig('example.png')
plt.close('all')
上面的代码会得到这样的结果:
注意,绘制的顺序似乎很重要。
1
这个问题虽然老旧,但还是可以说说。
你只需要把外部和内部的边界都明确地关闭,然后把它们加在一起。技术上来说,会有一个接缝,但你看不出来(如果你提供了颜色参数——我也不太确定为什么会这样)。
#!/usr/bin/env python3
import matplotlib.pyplot as plt
# a 4x4 box (counterclockwise)
ext_x = [2, -2, -2, 2, 2]
ext_y = [2, 2, -2, -2, 2]
# a 2x2 hole in the box (clockwise)
int_x = [item/2.0 for item in ext_x][::-1]
int_y = [item/2.0 for item in ext_y][::-1]
# if you don't specify a color, you will see a seam
plt.fill(ext_x+int_x, ext_y+int_y, color='blue')
plt.show()