Skip to content

Commit f71d7cd

Browse files
committed
Improve autoscaling for high order Bezier curves
1 parent ac2a145 commit f71d7cd

File tree

3 files changed

+39
-5
lines changed

3 files changed

+39
-5
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Improved autoscaling for bezier curves
2+
--------------------------------------
3+
Bezier curves are now autoscaled to their extents - previously they were
4+
autoscaled to their ends and control points, which in some cases led to
5+
unnecessarily large limits.

lib/matplotlib/axes/_base.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import matplotlib.image as mimage
2323
import matplotlib.lines as mlines
2424
import matplotlib.patches as mpatches
25-
import matplotlib.path as mpath
2625
from matplotlib.rcsetup import cycler, validate_axisbelow
2726
import matplotlib.spines as mspines
2827
import matplotlib.table as mtable
@@ -2375,10 +2374,18 @@ def _update_patch_limits(self, patch):
23752374
((not patch.get_width()) and (not patch.get_height()))):
23762375
return
23772376
p = patch.get_path()
2378-
vertices = p.vertices if p.codes is None else p.vertices[np.isin(
2379-
p.codes, (mpath.Path.CLOSEPOLY, mpath.Path.STOP), invert=True)]
2380-
if not vertices.size:
2381-
return
2377+
# Get all vertices on the path
2378+
# Loop through each sement to get extrema for Bezier curve sections
2379+
vertices = []
2380+
for curve, code in p.iter_bezier():
2381+
# Get distance along the curve of any extrema
2382+
_, dzeros = curve.axis_aligned_extrema()
2383+
# Calculate vertcies of start, end and any extrema in between
2384+
vertices.append(curve([0, *dzeros, 1]))
2385+
2386+
if len(vertices):
2387+
vertices = np.row_stack(vertices)
2388+
23822389
patch_trf = patch.get_transform()
23832390
updatex, updatey = patch_trf.contains_branch_seperately(self.transData)
23842391
if not (updatex or updatey):

lib/matplotlib/tests/test_axes.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import matplotlib.font_manager as mfont_manager
2525
import matplotlib.markers as mmarkers
2626
import matplotlib.patches as mpatches
27+
import matplotlib.path as mpath
2728
import matplotlib.pyplot as plt
2829
import matplotlib.ticker as mticker
2930
import matplotlib.transforms as mtransforms
@@ -7340,3 +7341,24 @@ def test_clim():
73407341
clim = (7, 8)
73417342
norm = plot_method(clim=clim).norm
73427343
assert (norm.vmin, norm.vmax) == clim
7344+
7345+
7346+
def test_bezier_autoscale():
7347+
# Check that bezier curves autoscale to their curves, and not their
7348+
# control points
7349+
verts = [[-1, 0],
7350+
[0, -1],
7351+
[1, 0],
7352+
[1, 0]]
7353+
codes = [mpath.Path.MOVETO,
7354+
mpath.Path.CURVE3,
7355+
mpath.Path.CURVE3,
7356+
mpath.Path.CLOSEPOLY]
7357+
p = mpath.Path(verts, codes)
7358+
7359+
fig, ax = plt.subplots()
7360+
ax.add_patch(mpatches.PathPatch(p))
7361+
ax.autoscale()
7362+
# Bottom ylim should be at the edge of the curve (-0.5), and not include
7363+
# the control point (at -1)
7364+
assert ax.get_ylim()[0] == -0.5

0 commit comments

Comments
 (0)