带洞的Matplotlib补丁

时间:2016-08-30 05:58:46

标签: python 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()

2 个答案:

答案 0 :(得分:0)

基于您的第一个示例,我添加了更多注释,应该很清楚。 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) 的关键是获取顶点代码。有关顶点和代码的更多详细信息,请参见 here

虽然这是一个很老的问题,但我希望我在这里的回答对需要它的人有用。

{{1}}

答案 1 :(得分:-1)

这不是为什么此代码起作用的答案,但是现在https://matplotlib.org/gallery/shapes_and_collections/donut.html处有一个示例代码。 这似乎是在SVG实施之后。