Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit db06f62

Browse files
committed
Improve autoscaling for high order Bezier curves
1 parent 6d6dd38 commit db06f62

File tree

2 files changed

+49
-0
lines changed

2 files changed

+49
-0
lines changed

lib/matplotlib/axes/_base.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2116,6 +2116,8 @@ def _update_patch_limits(self, patch):
21162116
((not patch.get_width()) and (not patch.get_height()))):
21172117
return
21182118
p = patch.get_path()
2119+
p = p._replace_bezier_control_points_with_extrema()
2120+
# Don't include CLOSEPOLY and STOP vertices in the path
21192121
vertices = p.vertices if p.codes is None else p.vertices[np.isin(
21202122
p.codes, (mpath.Path.CLOSEPOLY, mpath.Path.STOP), invert=True)]
21212123
if vertices.size > 0:

lib/matplotlib/path.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,53 @@ def iter_bezier(self, **kwargs):
461461
raise ValueError("Invalid Path.code_type: " + str(code))
462462
prev_vert = verts[-2:]
463463

464+
def _replace_bezier_control_points_with_extrema(self):
465+
"""
466+
Return a new version of this path, with any control points for Bezier
467+
segments replaced with any extrema for that segment.
468+
469+
This is helpful when autoscaling. We don't want to include the control
470+
points, which are often far away from the actual curve, but in order to
471+
calculate a bounding box for the whole curve we need to include any
472+
extrema as well as start and end points for each Bezier segment.
473+
474+
Notes
475+
-----
476+
If there are no curved Bezier segments, the current object is returned.
477+
"""
478+
# Shortcut case where there are no curved segments
479+
if not np.any(np.isin(self.codes, (Path.CURVE3, Path.CURVE4))):
480+
return self
481+
482+
vertices = np.array([[], []]).T
483+
codes = []
484+
for bez_segment, code in self.iter_bezier():
485+
verts = bez_segment._cpoints
486+
487+
# For low order segments (straight lines or points), just add
488+
# the vertices
489+
if code in (Path.MOVETO, Path.LINETO, Path.CLOSEPOLY):
490+
# Ignore the (already added) vertex at the start of this
491+
# segment
492+
if code in (Path.LINETO, Path.CLOSEPOLY):
493+
verts = verts[1]
494+
codes += [code] * self.NUM_VERTICES_FOR_CODE[code]
495+
# For higher order segments, calculate the extrema
496+
elif code in (Path.CURVE3, Path.CURVE4):
497+
_, t = bez_segment.axis_aligned_extrema()
498+
if len(t):
499+
extrema = bez_segment(t)
500+
verts = np.vstack((verts[0], extrema, verts[-1]))
501+
else:
502+
verts = np.vstack((verts[0], verts[-1]))
503+
504+
# Add extrema to the start and end points
505+
codes += [Path.LINETO] * verts.shape[0]
506+
507+
vertices = np.vstack((vertices, verts))
508+
# Construct path
509+
return Path(vertices, codes)
510+
464511
@_api.delete_parameter("3.3", "quantize")
465512
def cleaned(self, transform=None, remove_nans=False, clip=None,
466513
quantize=False, simplify=False, curves=False,

0 commit comments

Comments
 (0)