Skip to content

Commit f17e491

Browse files
authored
Merge pull request #20146 from QuLogic/fix-clippath
Don't clip clip paths to Figure bbox.
2 parents 8e69c9b + 3d4e498 commit f17e491

File tree

2 files changed

+25
-5
lines changed

2 files changed

+25
-5
lines changed

lib/matplotlib/tests/test_artist.py

+20-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import matplotlib.transforms as mtransforms
1313
import matplotlib.collections as mcollections
1414
import matplotlib.artist as martist
15-
from matplotlib.testing.decorators import image_comparison
15+
from matplotlib.testing.decorators import check_figures_equal, image_comparison
1616

1717

1818
def test_patch_transform_of_none():
@@ -121,6 +121,25 @@ def test_clipping():
121121
ax1.set_ylim([-3, 3])
122122

123123

124+
@check_figures_equal(extensions=['png'])
125+
def test_clipping_zoom(fig_test, fig_ref):
126+
# This test places the Axes and sets its limits such that the clip path is
127+
# outside the figure entirely. This should not break the clip path.
128+
ax_test = fig_test.add_axes([0, 0, 1, 1])
129+
l, = ax_test.plot([-3, 3], [-3, 3])
130+
# Explicit Path instead of a Rectangle uses clip path processing, instead
131+
# of a clip box optimization.
132+
p = mpath.Path([[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]])
133+
p = mpatches.PathPatch(p, transform=ax_test.transData)
134+
l.set_clip_path(p)
135+
136+
ax_ref = fig_ref.add_axes([0, 0, 1, 1])
137+
ax_ref.plot([-3, 3], [-3, 3])
138+
139+
ax_ref.set(xlim=(0.5, 0.75), ylim=(0.5, 0.75))
140+
ax_test.set(xlim=(0.5, 0.75), ylim=(0.5, 0.75))
141+
142+
124143
def test_cull_markers():
125144
x = np.random.random(20000)
126145
y = np.random.random(20000)

src/_backend_agg.cpp

+5-4
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,10 @@ bool RendererAgg::render_clippath(py::PathIterator &clippath,
134134
{
135135
typedef agg::conv_transform<py::PathIterator> transformed_path_t;
136136
typedef PathNanRemover<transformed_path_t> nan_removed_t;
137-
typedef PathClipper<nan_removed_t> clipped_t;
138-
typedef PathSnapper<clipped_t> snapped_t;
137+
/* Unlike normal Paths, the clip path cannot be clipped to the Figure bbox,
138+
* because it needs to remain a complete closed path, so there is no
139+
* PathClipper<nan_removed_t> step. */
140+
typedef PathSnapper<nan_removed_t> snapped_t;
139141
typedef PathSimplifier<snapped_t> simplify_t;
140142
typedef agg::conv_curve<simplify_t> curve_t;
141143

@@ -151,8 +153,7 @@ bool RendererAgg::render_clippath(py::PathIterator &clippath,
151153
rendererBaseAlphaMask.clear(agg::gray8(0, 0));
152154
transformed_path_t transformed_clippath(clippath, trans);
153155
nan_removed_t nan_removed_clippath(transformed_clippath, true, clippath.has_curves());
154-
clipped_t clipped_clippath(nan_removed_clippath, !clippath.has_curves(), width, height);
155-
snapped_t snapped_clippath(clipped_clippath, snap_mode, clippath.total_vertices(), 0.0);
156+
snapped_t snapped_clippath(nan_removed_clippath, snap_mode, clippath.total_vertices(), 0.0);
156157
simplify_t simplified_clippath(snapped_clippath,
157158
clippath.should_simplify() && !clippath.has_curves(),
158159
clippath.simplify_threshold());

0 commit comments

Comments
 (0)