如何绘制复杂的多边形?

时间:2012-01-19 00:52:39

标签: python matplotlib

我正在从GIS数据库中读取数据并使用mpl_toolkits.basemap和matplotlib创建地图。一些数据创建复杂的多边形(由外部和内部环定义)。但是,我无法追踪如何创建带孔的多边形。 matplotlib甚至可以实现这一点吗?还有另一种创建此图像的方法吗?

4 个答案:

答案 0 :(得分:6)

您可以在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')

以上结果为this example(无法发布图片)。 请注意,绕线顺序似乎很重要。

答案 1 :(得分: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()

答案 2 :(得分:0)

fill_between()怎么样?

http://matplotlib.sourceforge.net/api/pyplot_api.html#matplotlib.pyplot.fill_between

我不确定如何拉出多边形,但它的工作原理如下

import numpy as np
import matplotlib.pylab as plt

x=np.arange(-3,3.5,.5)
y1=-x**2+9
y2=-x**2+10
plt.fill_between(x,y1,y2)

results

你应该能够一次建立一个fill_between,直到你拥有你想要的东西。

或者可能是path。查看这些screenshots并查看是否有任何内容。

编辑:你可能意味着像这样的洞

import numpy as np
import matplotlib.pylab as plt

x=np.arange(-3,3.5,.5)
y1=-x**2+9
y2=0
plt.fill_between(x,y1,y2)
circ=plt.Circle((0,4),2,color='w')
ax=plt.gca()
ax.add_patch(circ)
plt.show()

enter image description here

答案 3 :(得分:0)

来晚了,但是我用this approach修补了@Matt的答案以产生此代码(也在this gist中):

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))