Матплотлиб патч с отверстиями
Следующий код работает. Проблема в том, что я не знаю точно, почему это работает. Код рисует патч круга (используя 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 ответа
Основываясь на вашем первом примере, я добавил больше комментариев, которые должны быть ясными. Ключ к
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.