Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 6fe8b98

Browse filesBrowse files
committed
refactor Bezier so it doesn't depend on Path
1 parent db55918 commit 6fe8b98
Copy full SHA for 6fe8b98

File tree

Expand file treeCollapse file tree

5 files changed

+116
-96
lines changed
Filter options
Expand file treeCollapse file tree

5 files changed

+116
-96
lines changed

‎doc/api/next_api_changes/deprecations.rst

Copy file name to clipboardExpand all lines: doc/api/next_api_changes/deprecations.rst
+7-7Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -374,10 +374,10 @@ also be accessible as ``toolbar.parent()``.
374374

375375
Path helpers in :mod:`.bezier`
376376
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
377-
378-
``bezier.make_path_regular`` is deprecated. Use ``Path.cleaned()`` (or
379-
``Path.cleaned(curves=True)``, etc.) instead (but note that these methods add a
380-
``STOP`` code at the end of the path).
381-
382-
``bezier.concatenate_paths`` is deprecated. Use ``Path.make_compound_path()``
383-
instead.
377+
- ``bezier.make_path_regular`` is deprecated. Use ``Path.cleaned()`` (or
378+
``Path.cleaned(curves=True)``, etc.) instead (but note that these methods add
379+
a ``STOP`` code at the end of the path).
380+
- ``bezier.concatenate_paths`` is deprecated. Use ``Path.make_compound_path()``
381+
instead.
382+
- ``bezier.split_path_inout`` (use ``Path.split_path_inout`` instead)
383+
- ``bezier.inside_circle()`` (no replacement)

‎doc/api/next_api_changes/removals.rst

Copy file name to clipboardExpand all lines: doc/api/next_api_changes/removals.rst
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ Classes, methods and attributes
103103

104104
- ``image.BboxImage.interp_at_native`` property (no replacement)
105105
- ``lines.Line2D.verticalOffset`` property (no replacement)
106-
- ``bezier.find_r_to_boundary_of_closedpath()`` (no relacement)
106+
- ``bezier.find_r_to_boundary_of_closedpath()`` (no replacement)
107107

108108
- ``quiver.Quiver.color()`` (use ``Quiver.get_facecolor()`` instead)
109109
- ``quiver.Quiver.keyvec`` property (no replacement)

‎lib/matplotlib/bezier.py

Copy file name to clipboardExpand all lines: lib/matplotlib/bezier.py
+17-73Lines changed: 17 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@
77
import numpy as np
88

99
import matplotlib.cbook as cbook
10-
from matplotlib.path import Path
1110

1211

1312
class NonIntersectingPathException(ValueError):
1413
pass
1514

15+
1616
# some functions
1717

1818

@@ -68,6 +68,15 @@ def get_normal_points(cx, cy, cos_t, sin_t, length):
6868
return x1, y1, x2, y2
6969

7070

71+
@cbook.deprecated("3.3", alternative="Path.split_path_inout()")
72+
def split_path_inout(path, inside, tolerance=0.01, reorder_inout=False):
73+
"""
74+
Divide a path into two segments at the point where ``inside(x, y)``
75+
becomes False.
76+
"""
77+
return path.split_path_inout(inside, tolerance, reorder_inout)
78+
79+
7180
# BEZIER routines
7281

7382
# subdividing bezier curve
@@ -222,69 +231,7 @@ def split_bezier_intersecting_with_closedpath(
222231
return _left, _right
223232

224233

225-
# matplotlib specific
226-
227-
228-
def split_path_inout(path, inside, tolerance=0.01, reorder_inout=False):
229-
"""
230-
Divide a path into two segments at the point where ``inside(x, y)`` becomes
231-
False.
232-
"""
233-
path_iter = path.iter_segments()
234-
235-
ctl_points, command = next(path_iter)
236-
begin_inside = inside(ctl_points[-2:]) # true if begin point is inside
237-
238-
ctl_points_old = ctl_points
239-
240-
iold = 0
241-
i = 1
242-
243-
for ctl_points, command in path_iter:
244-
iold = i
245-
i += len(ctl_points) // 2
246-
if inside(ctl_points[-2:]) != begin_inside:
247-
bezier_path = np.concatenate([ctl_points_old[-2:], ctl_points])
248-
break
249-
ctl_points_old = ctl_points
250-
else:
251-
raise ValueError("The path does not intersect with the patch")
252-
253-
bp = bezier_path.reshape((-1, 2))
254-
left, right = split_bezier_intersecting_with_closedpath(
255-
bp, inside, tolerance)
256-
if len(left) == 2:
257-
codes_left = [Path.LINETO]
258-
codes_right = [Path.MOVETO, Path.LINETO]
259-
elif len(left) == 3:
260-
codes_left = [Path.CURVE3, Path.CURVE3]
261-
codes_right = [Path.MOVETO, Path.CURVE3, Path.CURVE3]
262-
elif len(left) == 4:
263-
codes_left = [Path.CURVE4, Path.CURVE4, Path.CURVE4]
264-
codes_right = [Path.MOVETO, Path.CURVE4, Path.CURVE4, Path.CURVE4]
265-
else:
266-
raise AssertionError("This should never be reached")
267-
268-
verts_left = left[1:]
269-
verts_right = right[:]
270-
271-
if path.codes is None:
272-
path_in = Path(np.concatenate([path.vertices[:i], verts_left]))
273-
path_out = Path(np.concatenate([verts_right, path.vertices[i:]]))
274-
275-
else:
276-
path_in = Path(np.concatenate([path.vertices[:iold], verts_left]),
277-
np.concatenate([path.codes[:iold], codes_left]))
278-
279-
path_out = Path(np.concatenate([verts_right, path.vertices[i:]]),
280-
np.concatenate([codes_right, path.codes[i:]]))
281-
282-
if reorder_inout and not begin_inside:
283-
path_in, path_out = path_out, path_in
284-
285-
return path_in, path_out
286-
287-
234+
@cbook.deprecated("3.3")
288235
def inside_circle(cx, cy, r):
289236
"""
290237
Return a function that checks whether a point is in a circle with center
@@ -294,16 +241,13 @@ def inside_circle(cx, cy, r):
294241
295242
f(xy: Tuple[float, float]) -> bool
296243
"""
297-
r2 = r ** 2
298-
299-
def _f(xy):
300-
x, y = xy
301-
return (x - cx) ** 2 + (y - cy) ** 2 < r2
302-
return _f
244+
from .patches import _inside_circle
245+
return _inside_circle(cx, cy, r)
303246

304247

305248
# quadratic Bezier lines
306249

250+
307251
def get_cos_sin(x0, y0, x1, y1):
308252
dx, dy = x1 - x0, y1 - y0
309253
d = (dx * dx + dy * dy) ** .5
@@ -486,6 +430,7 @@ def make_path_regular(p):
486430
with ``codes`` set to (MOVETO, LINETO, LINETO, ..., LINETO); otherwise
487431
return *p* itself.
488432
"""
433+
from .path import Path
489434
c = p.codes
490435
if c is None:
491436
c = np.full(len(p.vertices), Path.LINETO, dtype=Path.code_type)
@@ -498,6 +443,5 @@ def make_path_regular(p):
498443
@cbook.deprecated("3.3", alternative="Path.make_compound_path()")
499444
def concatenate_paths(paths):
500445
"""Concatenate a list of paths into a single path."""
501-
vertices = np.concatenate([p.vertices for p in paths])
502-
codes = np.concatenate([make_path_regular(p).codes for p in paths])
503-
return Path(vertices, codes)
446+
from .path import Path
447+
return Path.make_compound_path(*paths)

‎lib/matplotlib/patches.py

Copy file name to clipboardExpand all lines: lib/matplotlib/patches.py
+29-14Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,28 @@
1010
import matplotlib as mpl
1111
from . import artist, cbook, colors, docstring, lines as mlines, transforms
1212
from .bezier import (
13-
NonIntersectingPathException, get_cos_sin, get_intersection,
14-
get_parallels, inside_circle, make_wedged_bezier2,
15-
split_bezier_intersecting_with_closedpath, split_path_inout)
13+
NonIntersectingPathException, get_cos_sin, get_intersection, get_parallels,
14+
make_wedged_bezier2, split_bezier_intersecting_with_closedpath)
1615
from .path import Path
1716

1817

18+
def _inside_circle(cx, cy, r):
19+
"""
20+
Return a function that checks whether a point is in a circle with center
21+
(*cx*, *cy*) and radius *r*.
22+
23+
The returned function has the signature::
24+
25+
f(xy: Tuple[float, float]) -> bool
26+
"""
27+
r2 = r ** 2
28+
29+
def _f(xy):
30+
x, y = xy
31+
return (x - cx) ** 2 + (y - cy) ** 2 < r2
32+
return _f
33+
34+
1935
@cbook._define_aliases({
2036
"antialiased": ["aa"],
2137
"edgecolor": ["ec"],
@@ -2428,7 +2444,7 @@ def insideA(xy_display):
24282444
return patchA.contains(xy_event)[0]
24292445

24302446
try:
2431-
left, right = split_path_inout(path, insideA)
2447+
left, right = path.split_path_inout(insideA)
24322448
except ValueError:
24332449
right = path
24342450

@@ -2440,7 +2456,7 @@ def insideB(xy_display):
24402456
return patchB.contains(xy_event)[0]
24412457

24422458
try:
2443-
left, right = split_path_inout(path, insideB)
2459+
left, right = path.split_path_inout(insideB)
24442460
except ValueError:
24452461
left = path
24462462

@@ -2453,15 +2469,15 @@ def _shrink(self, path, shrinkA, shrinkB):
24532469
Shrink the path by fixed size (in points) with shrinkA and shrinkB.
24542470
"""
24552471
if shrinkA:
2456-
insideA = inside_circle(*path.vertices[0], shrinkA)
2472+
insideA = _inside_circle(*path.vertices[0], shrinkA)
24572473
try:
2458-
left, path = split_path_inout(path, insideA)
2474+
left, path = path.split_path_inout(insideA)
24592475
except ValueError:
24602476
pass
24612477
if shrinkB:
2462-
insideB = inside_circle(*path.vertices[-1], shrinkB)
2478+
insideB = _inside_circle(*path.vertices[-1], shrinkB)
24632479
try:
2464-
path, right = split_path_inout(path, insideB)
2480+
path, right = path.split_path_inout(insideB)
24652481
except ValueError:
24662482
pass
24672483
return path
@@ -2886,7 +2902,6 @@ def __call__(self, path, mutation_size, linewidth,
28862902
The __call__ method is a thin wrapper around the transmute method
28872903
and takes care of the aspect ratio.
28882904
"""
2889-
28902905
if aspect_ratio is not None:
28912906
# Squeeze the given height by the aspect_ratio
28922907
vertices = path.vertices / [1, aspect_ratio]
@@ -3351,7 +3366,7 @@ def transmute(self, path, mutation_size, linewidth):
33513366

33523367
# divide the path into a head and a tail
33533368
head_length = self.head_length * mutation_size
3354-
in_f = inside_circle(x2, y2, head_length)
3369+
in_f = _inside_circle(x2, y2, head_length)
33553370
arrow_path = [(x0, y0), (x1, y1), (x2, y2)]
33563371

33573372
try:
@@ -3434,7 +3449,7 @@ def transmute(self, path, mutation_size, linewidth):
34343449
arrow_path = [(x0, y0), (x1, y1), (x2, y2)]
34353450

34363451
# path for head
3437-
in_f = inside_circle(x2, y2, head_length)
3452+
in_f = _inside_circle(x2, y2, head_length)
34383453
try:
34393454
path_out, path_in = split_bezier_intersecting_with_closedpath(
34403455
arrow_path, in_f, tolerance=0.01)
@@ -3449,7 +3464,7 @@ def transmute(self, path, mutation_size, linewidth):
34493464
path_head = path_in
34503465

34513466
# path for head
3452-
in_f = inside_circle(x2, y2, head_length * .8)
3467+
in_f = _inside_circle(x2, y2, head_length * .8)
34533468
path_out, path_in = split_bezier_intersecting_with_closedpath(
34543469
arrow_path, in_f, tolerance=0.01)
34553470
path_tail = path_out
@@ -3467,7 +3482,7 @@ def transmute(self, path, mutation_size, linewidth):
34673482
w1=1., wm=0.6, w2=0.3)
34683483

34693484
# path for head
3470-
in_f = inside_circle(x0, y0, tail_width * .3)
3485+
in_f = _inside_circle(x0, y0, tail_width * .3)
34713486
path_in, path_out = split_bezier_intersecting_with_closedpath(
34723487
arrow_path, in_f, tolerance=0.01)
34733488
tail_start = path_in[-1]

‎lib/matplotlib/path.py

Copy file name to clipboardExpand all lines: lib/matplotlib/path.py
+62-1Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import matplotlib as mpl
1818
from . import _path, cbook
1919
from .cbook import _to_unmasked_float_array, simple_linear_interpolation
20+
from .bezier import split_bezier_intersecting_with_closedpath
2021

2122

2223
class Path:
@@ -586,6 +587,65 @@ def interpolated(self, steps):
586587
new_codes = None
587588
return Path(vertices, new_codes)
588589

590+
def split_path_inout(self, inside, tolerance=0.01, reorder_inout=False):
591+
"""
592+
Divide a path into two segments at the point where ``inside(x, y)``
593+
becomes False.
594+
"""
595+
path_iter = self.iter_segments()
596+
597+
ctl_points, command = next(path_iter)
598+
begin_inside = inside(ctl_points[-2:]) # true if begin point is inside
599+
600+
ctl_points_old = ctl_points
601+
602+
iold = 0
603+
i = 1
604+
605+
for ctl_points, command in path_iter:
606+
iold = i
607+
i += len(ctl_points) // 2
608+
if inside(ctl_points[-2:]) != begin_inside:
609+
bezier_path = np.concatenate([ctl_points_old[-2:], ctl_points])
610+
break
611+
ctl_points_old = ctl_points
612+
else:
613+
raise ValueError("The path does not intersect with the patch")
614+
615+
bp = bezier_path.reshape((-1, 2))
616+
left, right = split_bezier_intersecting_with_closedpath(
617+
bp, inside, tolerance)
618+
if len(left) == 2:
619+
codes_left = [Path.LINETO]
620+
codes_right = [Path.MOVETO, Path.LINETO]
621+
elif len(left) == 3:
622+
codes_left = [Path.CURVE3, Path.CURVE3]
623+
codes_right = [Path.MOVETO, Path.CURVE3, Path.CURVE3]
624+
elif len(left) == 4:
625+
codes_left = [Path.CURVE4, Path.CURVE4, Path.CURVE4]
626+
codes_right = [Path.MOVETO, Path.CURVE4, Path.CURVE4, Path.CURVE4]
627+
else:
628+
raise AssertionError("This should never be reached")
629+
630+
verts_left = left[1:]
631+
verts_right = right[:]
632+
633+
if self.codes is None:
634+
path_in = Path(np.concatenate([self.vertices[:i], verts_left]))
635+
path_out = Path(np.concatenate([verts_right, self.vertices[i:]]))
636+
637+
else:
638+
path_in = Path(np.concatenate([self.vertices[:iold], verts_left]),
639+
np.concatenate([self.codes[:iold], codes_left]))
640+
641+
path_out = Path(np.concatenate([verts_right, self.vertices[i:]]),
642+
np.concatenate([codes_right, self.codes[i:]]))
643+
644+
if reorder_inout and not begin_inside:
645+
path_in, path_out = path_out, path_in
646+
647+
return path_in, path_out
648+
589649
def to_polygons(self, transform=None, width=0, height=0, closed_only=True):
590650
"""
591651
Convert this path to a list of polygons or polylines. Each
@@ -648,7 +708,8 @@ def unit_rectangle(cls):
648708
def unit_regular_polygon(cls, numVertices):
649709
"""
650710
Return a :class:`Path` instance for a unit regular polygon with the
651-
given *numVertices* and radius of 1.0, centered at (0, 0).
711+
given *numVertices* such that the circumscribing circle has radius 1.0,
712+
centered at (0, 0).
652713
"""
653714
if numVertices <= 16:
654715
path = cls._unit_regular_polygons.get(numVertices)

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.