Matplotlib补丁与孔



下面的代码可以工作。问题是我不知道它为什么会起作用。代码绘制一个圆形补丁(使用PathPatch),从中心切割出一个三角形。我猜里面的三角形被剪掉是因为它是顺时针画的,而外面的圆是逆时针画的。如果方向不反转,三角形就不会被剪断。我没有在文档中找到任何关于所采用规则的内容。那么为什么这个方法有效呢?

from matplotlib import pyplot
from matplotlib.path import Path
from matplotlib.patches import PathPatch
import numpy
#
# draw a triangle within a circle using PathPatch
#
phi = numpy.linspace(0, 2*numpy.pi, 100)
circle = 4 * numpy.exp(1j * phi)
circleV = [[p.real, p.imag] for p in circle]
phi = numpy.linspace(0, 2*numpy.pi, 4)
triangle = 2 * numpy.exp(1j * phi)
triangleV = [[p.real, p.imag] for p in triangle]
circleC = [Path.LINETO for p in circleV]
circleC[0] = Path.MOVETO
triangleC = [Path.LINETO for p in triangleV]
triangleC[0] = Path.MOVETO
vertices = []
vertices.extend(circleV)
vertices.extend(triangleV[::-1])
codes = []
codes.extend(circleC)
codes.extend(triangleC)
path = Path(vertices, codes)
patch = PathPatch(path, facecolor="#aa6677")
fig, ax = pyplot.subplots()
ax.add_patch(patch)
ax.set_xlim([-5, 5])
ax.set_ylim([-5, 5])
ax.set_aspect(1.0)
pyplot.show()

现在作为一个更复杂的例子,从主圆上切出一个五边形,并且从主圆上切出部分与五边形相交的小圆。如果小圆是顺时针画的,它们在与五边形相交的地方被填充,在与五边形不相交的地方不被填充。这有点符合上面的规则。但是,如果逆时针方向绘制,则表示它们完全填充,这与上述规则不一致。

from matplotlib import pyplot
from matplotlib.path import Path
from matplotlib.patches import PathPatch
import numpy
clockwise_inner_circles = True
#
# draw a pentagon within a circle using PathPatch
#
phi = numpy.linspace(0, 2*numpy.pi, 100)
circle = 4 * numpy.exp(1j * phi)
circleV = [[p.real, p.imag] for p in circle]
phi = numpy.linspace(0, 2*numpy.pi, 6)
triangle = 2 * numpy.exp(1j * phi)
triangleV = [[p.real, p.imag] for p in triangle]
circleC = [Path.LINETO for p in circleV]
circleC[0] = Path.MOVETO
triangleC = [Path.LINETO for p in triangleV]
triangleC[0] = Path.MOVETO
vertices = []
vertices.extend(circleV)
vertices.extend(triangleV[::-1])
codes = []
codes.extend(circleC)
codes.extend(triangleC)
#
# draw circles in a circular pattern
#
phi = numpy.linspace(0, 2*numpy.pi, 100)
for theta in 2*numpy.pi*numpy.arange(5)/5:
    circle = 2*numpy.exp(1j*theta) + 0.5*numpy.exp(1j*phi)
    circleV = [[p.real, p.imag] for p in circle]
    circleC = [Path.LINETO for p in circleV]
    circleC[0] = Path.MOVETO
    if clockwise_inner_circles:
        vertices.extend(circleV[::-1])
    else:
        vertices.extend(circleV[::1])
    codes.extend(circleC)
path = Path(vertices, codes)
patch = PathPatch(path, facecolor="#aa6677")
fig, ax = pyplot.subplots()
ax.add_patch(patch)
ax.set_xlim([-5, 5])
ax.set_ylim([-5, 5])
ax.set_aspect(1.0)
pyplot.show()

根据你的第一个例子,我添加了更多的注释,这应该是清楚的。PathPath的关键是获取顶点代码。关于顶点和代码的更多细节可以在这里找到。

虽然这是一个相当古老的问题,但我希望我的答案可以对需要它的人有用。

from matplotlib import pyplot
from matplotlib.path import Path
from matplotlib.patches import PathPatch
import numpy
# ##########################################
# draw a triangle within a circle using PathPatch
# ##########################################
phi = numpy.linspace(0, 2*numpy.pi, 100)
circle = 4 * numpy.exp(1j * phi)
## generate circle vertices --> "circleV"
circleV = [[p.real, p.imag] for p in circle]
phi = numpy.linspace(0, 2*numpy.pi, 4)
triangle = 2 * numpy.exp(1j * phi)
## generate triangle vertices --> "triangleV"
triangleV = [[p.real, p.imag] for p in triangle]
# generate codes for patch, "C" means "codes"
# codes for circle
circleC = [Path.LINETO for p in circleV]
circleC[0] = Path.MOVETO
# codes for triangle
triangleC = [Path.LINETO for p in triangleV]
triangleC[0] = Path.MOVETO
# combine vertices
vertices = []
vertices.extend(circleV)
vertices.extend(triangleV[::-1])
# combine codes
codes = []
codes.extend(circleC)
codes.extend(triangleC)
# create Path object from vertices and codes
path = Path(vertices, codes)
# create patch from path
patch = PathPatch(path, facecolor="#aa6677")
# plot fig and add patch
fig, ax = pyplot.subplots()
ax.add_patch(patch)
ax.set_xlim([-5, 5])
ax.set_ylim([-5, 5])
ax.set_aspect(1.0)

这不是为什么这个代码工作的答案,但现在有一个示例代码在https://matplotlib.org/gallery/shapes_and_collections/donut.html。这似乎遵循SVG实现。

最新更新