Skip to content

Use Path(..., closed=True) more. #16617

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/animation/animated_histogram.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
# in the ``verts`` array to keep the codes aligned with the vertices.
nverts = nrects * (1 + 3 + 1)
verts = np.zeros((nverts, 2))
codes = np.ones(nverts, int) * path.Path.LINETO
codes = np.full(nverts, path.Path.LINETO)
codes[0::5] = path.Path.MOVETO
codes[4::5] = path.Path.CLOSEPOLY
verts[0::5, 0] = left
Expand Down
14 changes: 4 additions & 10 deletions lib/matplotlib/axes/_axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -3957,17 +3957,11 @@ def line_props_with_rcdefaults(subkey, explicit, zdelta=0,
if meanprops is None or removed_prop not in meanprops:
final_meanprops[removed_prop] = ''

def to_vc(xs, ys):
# convert arguments to verts and codes, append (0, 0) (ignored).
verts = np.append(np.column_stack([xs, ys]), [(0, 0)], 0)
codes = ([mpath.Path.MOVETO]
+ [mpath.Path.LINETO] * (len(verts) - 2)
+ [mpath.Path.CLOSEPOLY])
return verts, codes

def patch_list(xs, ys, **kwargs):
verts, codes = to_vc(xs, ys)
path = mpath.Path(verts, codes)
path = mpath.Path(
# Last vertex will have a CLOSEPOLY code and thus be ignored.
np.append(np.column_stack([xs, ys]), [(0, 0)], 0),
closed=True)
patch = mpatches.PathPatch(path, **kwargs)
self.add_artist(patch)
return [patch]
Expand Down
11 changes: 3 additions & 8 deletions lib/matplotlib/collections.py
Original file line number Diff line number Diff line change
Expand Up @@ -1098,15 +1098,10 @@ def set_verts(self, verts, closed=True):
for xy in verts:
if len(xy):
if isinstance(xy, np.ma.MaskedArray):
xy = np.ma.concatenate([xy, xy[0:1]])
xy = np.ma.concatenate([xy, xy[:1]])
else:
xy = np.asarray(xy)
xy = np.concatenate([xy, xy[0:1]])
codes = np.empty(xy.shape[0], dtype=mpath.Path.code_type)
codes[:] = mpath.Path.LINETO
codes[0] = mpath.Path.MOVETO
codes[-1] = mpath.Path.CLOSEPOLY
self._paths.append(mpath.Path(xy, codes))
xy = np.concatenate([xy, xy[:1]])
self._paths.append(mpath.Path(xy, closed=True))
else:
self._paths.append(mpath.Path(xy))
else:
Expand Down
78 changes: 23 additions & 55 deletions lib/matplotlib/markers.py
Original file line number Diff line number Diff line change
Expand Up @@ -410,23 +410,15 @@ def _set_pixel(self):
def _set_point(self):
self._set_circle(reduction=self._point_size_reduction)

_triangle_path = Path(
[[0.0, 1.0], [-1.0, -1.0], [1.0, -1.0], [0.0, 1.0]],
[Path.MOVETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY])
_triangle_path = Path([[0, 1], [-1, -1], [1, -1], [0, 1]], closed=True)
# Going down halfway looks to small. Golden ratio is too far.
_triangle_path_u = Path(
[[0.0, 1.0], [-3 / 5., -1 / 5.], [3 / 5., -1 / 5.], [0.0, 1.0]],
[Path.MOVETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY])
_triangle_path_u = Path([[0, 1], [-3/5, -1/5], [3/5, -1/5], [0, 1]],
closed=True)
_triangle_path_d = Path(
[[-3 / 5., -1 / 5.], [3 / 5., -1 / 5.], [1.0, -1.0], [-1.0, -1.0],
[-3 / 5., -1 / 5.]],
[Path.MOVETO, Path.LINETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY])
_triangle_path_l = Path(
[[0.0, 1.0], [0.0, -1.0], [-1.0, -1.0], [0.0, 1.0]],
[Path.MOVETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY])
_triangle_path_r = Path(
[[0.0, 1.0], [0.0, -1.0], [1.0, -1.0], [0.0, 1.0]],
[Path.MOVETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY])
[[-3/5, -1/5], [3/5, -1/5], [1, -1], [-1, -1], [-3/5, -1/5]],
closed=True)
_triangle_path_l = Path([[0, 1], [0, -1], [-1, -1], [0, 1]], closed=True)
_triangle_path_r = Path([[0, 1], [0, -1], [1, -1], [0, 1]], closed=True)

def _set_triangle(self, rot, skip):
self._transform = Affine2D().scale(0.5).rotate_deg(rot)
Expand Down Expand Up @@ -505,10 +497,8 @@ def _set_diamond(self):
if not self._half_fill():
self._path = Path.unit_rectangle()
else:
self._path = Path([[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 0.0]])
self._alt_path = Path([[0.0, 0.0], [0.0, 1.0],
[1.0, 1.0], [0.0, 0.0]])

self._path = Path([[0, 0], [1, 0], [1, 1], [0, 0]])
self._alt_path = Path([[0, 0], [0, 1], [1, 1], [0, 0]])
if fs == 'bottom':
rotate = 270.
elif fs == 'top':
Expand All @@ -517,10 +507,8 @@ def _set_diamond(self):
rotate = 180.
else:
rotate = 0.

self._transform.rotate_deg(rotate)
self._alt_transform = self._transform

self._joinstyle = 'miter'

def _set_thin_diamond(self):
Expand Down Expand Up @@ -815,24 +803,13 @@ def _set_x(self):
self._filled = False
self._path = self._x_path

_plus_filled_path = Path([(1/3, 0), (2/3, 0), (2/3, 1/3),
(1, 1/3), (1, 2/3), (2/3, 2/3),
(2/3, 1), (1/3, 1), (1/3, 2/3),
(0, 2/3), (0, 1/3), (1/3, 1/3),
(1/3, 0)],
[Path.MOVETO, Path.LINETO, Path.LINETO,
Path.LINETO, Path.LINETO, Path.LINETO,
Path.LINETO, Path.LINETO, Path.LINETO,
Path.LINETO, Path.LINETO, Path.LINETO,
Path.CLOSEPOLY])

_plus_filled_path_t = Path([(1, 1/2), (1, 2/3), (2/3, 2/3),
(2/3, 1), (1/3, 1), (1/3, 2/3),
(0, 2/3), (0, 1/2), (1, 1/2)],
[Path.MOVETO, Path.LINETO, Path.LINETO,
Path.LINETO, Path.LINETO, Path.LINETO,
Path.LINETO, Path.LINETO,
Path.CLOSEPOLY])
_plus_filled_path = Path(
[(1/3, 0), (2/3, 0), (2/3, 1/3), (1, 1/3), (1, 2/3), (2/3, 2/3),
(2/3, 1), (1/3, 1), (1/3, 2/3), (0, 2/3), (0, 1/3), (1/3, 1/3),
(1/3, 0)], closed=True)
_plus_filled_path_t = Path(
[(1, 1/2), (1, 2/3), (2/3, 2/3), (2/3, 1), (1/3, 1), (1/3, 2/3),
(0, 2/3), (0, 1/2), (1, 1/2)], closed=True)

def _set_plus_filled(self):
self._transform = Affine2D().translate(-0.5, -0.5)
Expand All @@ -858,22 +835,13 @@ def _set_plus_filled(self):
self._transform.rotate_deg(rotate)
self._alt_transform.rotate_deg(rotate_alt)

_x_filled_path = Path([(0.25, 0), (0.5, 0.25), (0.75, 0), (1, 0.25),
(0.75, 0.5), (1, 0.75), (0.75, 1), (0.5, 0.75),
(0.25, 1), (0, 0.75), (0.25, 0.5), (0, 0.25),
(0.25, 0)],
[Path.MOVETO, Path.LINETO, Path.LINETO,
Path.LINETO, Path.LINETO, Path.LINETO,
Path.LINETO, Path.LINETO, Path.LINETO,
Path.LINETO, Path.LINETO, Path.LINETO,
Path.CLOSEPOLY])

_x_filled_path_t = Path([(0.75, 0.5), (1, 0.75), (0.75, 1),
(0.5, 0.75), (0.25, 1), (0, 0.75),
(0.25, 0.5), (0.75, 0.5)],
[Path.MOVETO, Path.LINETO, Path.LINETO,
Path.LINETO, Path.LINETO, Path.LINETO,
Path.LINETO, Path.CLOSEPOLY])
_x_filled_path = Path(
[(0.25, 0), (0.5, 0.25), (0.75, 0), (1, 0.25), (0.75, 0.5), (1, 0.75),
(0.75, 1), (0.5, 0.75), (0.25, 1), (0, 0.75), (0.25, 0.5), (0, 0.25),
(0.25, 0)], closed=True)
_x_filled_path_t = Path(
[(0.75, 0.5), (1, 0.75), (0.75, 1), (0.5, 0.75), (0.25, 1), (0, 0.75),
(0.25, 0.5), (0.75, 0.5)], closed=True)

def _set_x_filled(self):
self._transform = Affine2D().translate(-0.5, -0.5)
Expand Down
88 changes: 29 additions & 59 deletions lib/matplotlib/patches.py
Original file line number Diff line number Diff line change
Expand Up @@ -1991,17 +1991,13 @@ def __init__(self, pad=0.3):

def transmute(self, x0, y0, width, height, mutation_size):
pad = mutation_size * self.pad

# width and height with padding added.
width, height = width + 2*pad, height + 2*pad

width, height = width + 2 * pad, height + 2 * pad
# boundary of the padded box
x0, y0 = x0 - pad, y0 - pad,
x0, y0 = x0 - pad, y0 - pad
x1, y1 = x0 + width, y0 + height

vertices = [(x0, y0), (x1, y0), (x1, y1), (x0, y1), (x0, y0)]
codes = [Path.MOVETO] + [Path.LINETO] * 3 + [Path.CLOSEPOLY]
return Path(vertices, codes)
return Path([(x0, y0), (x1, y0), (x1, y1), (x0, y1), (x0, y0)],
closed=True)

@_register_style(_style_list)
class Circle(_Base):
Expand All @@ -2020,9 +2016,8 @@ def __init__(self, pad=0.3):
def transmute(self, x0, y0, width, height, mutation_size):
pad = mutation_size * self.pad
width, height = width + 2 * pad, height + 2 * pad

# boundary of the padded box
x0, y0 = x0 - pad, y0 - pad,
x0, y0 = x0 - pad, y0 - pad
return Path.circle((x0 + width / 2, y0 + height / 2),
max(width, height) / 2)

Expand All @@ -2043,31 +2038,21 @@ def __init__(self, pad=0.3):
def transmute(self, x0, y0, width, height, mutation_size):
# padding
pad = mutation_size * self.pad

# width and height with padding added.
width, height = width + 2. * pad, height + 2. * pad

width, height = width + 2 * pad, height + 2 * pad
# boundary of the padded box
x0, y0 = x0 - pad, y0 - pad,
x1, y1 = x0 + width, y0 + height

dx = (y1 - y0) / 2.
dxx = dx * .5
# adjust x0. 1.4 <- sqrt(2)
x0 = x0 + pad / 1.4

cp = [(x0 + dxx, y0), (x1, y0), (x1, y1), (x0 + dxx, y1),
(x0 + dxx, y1 + dxx), (x0 - dx, y0 + dx),
(x0 + dxx, y0 - dxx), # arrow
(x0 + dxx, y0), (x0 + dxx, y0)]

com = [Path.MOVETO, Path.LINETO, Path.LINETO, Path.LINETO,
Path.LINETO, Path.LINETO, Path.LINETO,
Path.LINETO, Path.CLOSEPOLY]

path = Path(cp, com)
dx = (y1 - y0) / 2
dxx = dx / 2
x0 = x0 + pad / 1.4 # adjust by ~sqrt(2)

return path
return Path([(x0 + dxx, y0), (x1, y0), (x1, y1), (x0 + dxx, y1),
(x0 + dxx, y1 + dxx), (x0 - dx, y0 + dx),
(x0 + dxx, y0 - dxx), # arrow
(x0 + dxx, y0), (x0 + dxx, y0)],
closed=True)

@_register_style(_style_list)
class RArrow(LArrow):
Expand Down Expand Up @@ -2106,42 +2091,27 @@ def __init__(self, pad=0.3):
super().__init__()

def transmute(self, x0, y0, width, height, mutation_size):

# padding
pad = mutation_size * self.pad

# width and height with padding added.
# The width is padded by the arrows, so we don't need to pad it.
height = height + 2. * pad

height = height + 2 * pad
# boundary of the padded box
x0, y0 = x0 - pad, y0 - pad
x1, y1 = x0 + width, y0 + height

dx = (y1 - y0) / 2
dxx = dx * .5
# adjust x0. 1.4 <- sqrt(2)
x0 = x0 + pad / 1.4

cp = [(x0 + dxx, y0), (x1, y0), # bot-segment
(x1, y0 - dxx), (x1 + dx + dxx, y0 + dx),
(x1, y1 + dxx), # right-arrow
(x1, y1), (x0 + dxx, y1), # top-segment
(x0 + dxx, y1 + dxx), (x0 - dx, y0 + dx),
(x0 + dxx, y0 - dxx), # left-arrow
(x0 + dxx, y0), (x0 + dxx, y0)] # close-poly

com = [Path.MOVETO, Path.LINETO,
Path.LINETO, Path.LINETO,
Path.LINETO,
Path.LINETO, Path.LINETO,
Path.LINETO, Path.LINETO,
Path.LINETO,
Path.LINETO, Path.CLOSEPOLY]

path = Path(cp, com)

return path
dxx = dx / 2
x0 = x0 + pad / 1.4 # adjust by ~sqrt(2)

return Path([(x0 + dxx, y0), (x1, y0), # bot-segment
(x1, y0 - dxx), (x1 + dx + dxx, y0 + dx),
(x1, y1 + dxx), # right-arrow
(x1, y1), (x0 + dxx, y1), # top-segment
(x0 + dxx, y1 + dxx), (x0 - dx, y0 + dx),
(x0 + dxx, y0 - dxx), # left-arrow
(x0 + dxx, y0), (x0 + dxx, y0)], # close-poly
closed=True)

@_register_style(_style_list)
class Round(_Base):
Expand Down Expand Up @@ -2171,7 +2141,7 @@ def transmute(self, x0, y0, width, height, mutation_size):
else:
dr = pad

width, height = width + 2. * pad, height + 2. * pad
width, height = width + 2 * pad, height + 2 * pad

x0, y0 = x0 - pad, y0 - pad,
x1, y1 = x0 + width, y0 + height
Expand Down Expand Up @@ -2232,8 +2202,8 @@ def transmute(self, x0, y0, width, height, mutation_size):
else:
dr = pad / 2.

width, height = (width + 2. * pad - 2 * dr,
height + 2. * pad - 2 * dr)
width = width + 2 * pad - 2 * dr
height = height + 2 * pad - 2 * dr

x0, y0 = x0 - pad + dr, y0 - pad + dr,
x1, y1 = x0 + width, y0 + height
Expand Down
24 changes: 7 additions & 17 deletions lib/matplotlib/path.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,9 @@ def __init__(self, vertices, codes=None, _interpolation_steps=1,
intended for public use.
closed : bool, optional
If *codes* is None and closed is True, vertices will be treated as
line segments of a closed polygon.
line segments of a closed polygon. Note that the last vertex will
then be ignored (as the corresponding code will be set to
CLOSEPOLY).
readonly : bool, optional
Makes the path behave in an immutable way and sets the vertices
and codes as read-only arrays.
Expand Down Expand Up @@ -635,12 +637,8 @@ def unit_rectangle(cls):
Return a `Path` instance of the unit rectangle from (0, 0) to (1, 1).
"""
if cls._unit_rectangle is None:
cls._unit_rectangle = \
cls([[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0],
[0.0, 0.0]],
[cls.MOVETO, cls.LINETO, cls.LINETO, cls.LINETO,
cls.CLOSEPOLY],
readonly=True)
cls._unit_rectangle = cls([[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]],
closed=True, readonly=True)
return cls._unit_rectangle

_unit_regular_polygons = WeakValueDictionary()
Expand All @@ -661,11 +659,7 @@ def unit_regular_polygon(cls, numVertices):
# "points-up".
+ np.pi / 2)
verts = np.column_stack((np.cos(theta), np.sin(theta)))
codes = np.empty(numVertices + 1)
codes[0] = cls.MOVETO
codes[1:-1] = cls.LINETO
codes[-1] = cls.CLOSEPOLY
path = cls(verts, codes, readonly=True)
path = cls(verts, closed=True, readonly=True)
if numVertices <= 16:
cls._unit_regular_polygons[numVertices] = path
return path
Expand All @@ -691,11 +685,7 @@ def unit_regular_star(cls, numVertices, innerCircle=0.5):
r = np.ones(ns2 + 1)
r[1::2] = innerCircle
verts = (r * np.vstack((np.cos(theta), np.sin(theta)))).T
codes = np.empty(ns2 + 1)
codes[0] = cls.MOVETO
codes[1:-1] = cls.LINETO
codes[-1] = cls.CLOSEPOLY
path = cls(verts, codes, readonly=True)
path = cls(verts, closed=True, readonly=True)
if numVertices <= 16:
cls._unit_regular_stars[(numVertices, innerCircle)] = path
return path
Expand Down
7 changes: 3 additions & 4 deletions lib/matplotlib/tests/test_patches.py
Original file line number Diff line number Diff line change
Expand Up @@ -319,16 +319,15 @@ def test_patch_str():
assert str(p) == "FancyBboxPatch((1, 2), width=3, height=4)"

# Further nice __str__ which cannot be `eval`uated:
path_data = [([1, 2], mpath.Path.MOVETO), ([2, 2], mpath.Path.LINETO),
([1, 2], mpath.Path.CLOSEPOLY)]
p = mpatches.PathPatch(mpath.Path(*zip(*path_data)))
path = mpath.Path([(1, 2), (2, 2), (1, 2)], closed=True)
p = mpatches.PathPatch(path)
assert str(p) == "PathPatch3((1, 2) ...)"

data = [[1, 2], [2, 2], [1, 2]]
p = mpatches.Polygon(data)
assert str(p) == "Polygon3((1, 2) ...)"

p = mpatches.FancyArrowPatch(path=mpath.Path(*zip(*path_data)))
p = mpatches.FancyArrowPatch(path=path)
assert str(p)[:27] == "FancyArrowPatch(Path(array("

p = mpatches.FancyArrowPatch((1, 2), (3, 4))
Expand Down
Loading