Skip to content

Commit fe23120

Browse files
authored
Merge pull request #2734 from greglucas/fix/circular-boundary-pan-flood
Fix boundary flooding when panning axes with a non-data-transform boundary
2 parents dc75743 + 0e0b302 commit fe23120

2 files changed

Lines changed: 45 additions & 6 deletions

File tree

‎lib/cartopy/mpl/geoaxes.py‎

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ def __init__(self, axes, **kwargs):
203203
self._original_path = mpath.Path(np.empty((0, 2)))
204204
super().__init__(self._original_path, **kwargs)
205205
self._axes = axes
206+
self._boundary_in_data_coords = True
206207

207208
# We need to use a TransformWrapper as our transform so that we can
208209
# update the transform without breaking others' references to this one.
@@ -214,14 +215,19 @@ def set_transform(self, transform):
214215

215216
def set_boundary(self, path, transform):
216217
self._original_path = cpath._ensure_path_closed(path)
218+
# viewLim is in data coordinates, so only clip to it when the
219+
# boundary itself is in data coordinates.
220+
self._boundary_in_data_coords = transform is self._axes.transData
217221
self.set_transform(transform)
218222
self.stale = True
219223

220224
def _adjust_location(self):
221225
if self.stale:
222-
self.set_path(
223-
cpath._ensure_path_closed(
224-
self._original_path.clip_to_bbox(self.axes.viewLim)))
226+
path = self._original_path
227+
if self._boundary_in_data_coords:
228+
path = cpath._ensure_path_closed(
229+
path.clip_to_bbox(self.axes.viewLim))
230+
self.set_path(path)
225231
# Some places in matplotlib's transform stack cache the actual
226232
# path so we trigger an update by invalidating the transform.
227233
self._trans_wrap.invalidate()
@@ -235,20 +241,24 @@ def draw(self, renderer, *args, **kwargs):
235241
class GeoSpine(mspines.Spine):
236242
def __init__(self, axes, **kwargs):
237243
self._original_path = mpath.Path(np.empty((0, 2)))
244+
self._boundary_in_data_coords = True
238245
kwargs.setdefault('clip_on', False)
239246
super().__init__(axes, 'geo', self._original_path, **kwargs)
240247

241248
def set_boundary(self, path, transform):
242249
# Make sure path is closed (required by "Path.clip_to_bbox")
243250
self._original_path = cpath._ensure_path_closed(path)
251+
self._boundary_in_data_coords = transform is self.axes.transData
244252
self.set_transform(transform)
245253
self.stale = True
246254

247255
def _adjust_location(self):
248256
if self.stale:
249-
self._path = cpath._ensure_path_closed(
250-
self._original_path.clip_to_bbox(self.axes.viewLim)
251-
)
257+
path = self._original_path
258+
if self._boundary_in_data_coords:
259+
path = cpath._ensure_path_closed(
260+
path.clip_to_bbox(self.axes.viewLim))
261+
self._path = path
252262

253263
def get_window_extent(self, renderer=None):
254264
# make sure the location is updated so that transforms etc are

‎lib/cartopy/tests/mpl/test_axes.py‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,35 @@ def test_geoaxes_set_boundary_clipping():
156156
return fig
157157

158158

159+
def test_geoaxes_set_boundary_survives_panning():
160+
"""A transAxes boundary must survive panning far from the initial view."""
161+
fig = plt.figure()
162+
ax = fig.add_subplot(1, 1, 1, projection=ccrs.SouthPolarStereo())
163+
ax.set_extent([-180, 180, -90, -60], ccrs.PlateCarree())
164+
circle = mpath.Path.circle(center=(0.5, 0.5), radius=0.5)
165+
ax.set_boundary(circle, transform=ax.transAxes)
166+
167+
xlim0 = ax.get_xlim()
168+
ylim0 = ax.get_ylim()
169+
width = xlim0[1] - xlim0[0]
170+
height = ylim0[1] - ylim0[0]
171+
172+
# Pan well past the initial view.
173+
ax.set_xlim(xlim0[0] - width, xlim0[1] - width)
174+
ax.set_ylim(ylim0[0] + height, ylim0[1] + height)
175+
176+
fig.draw_without_rendering()
177+
178+
for artist in (ax.patch, ax.spines['geo']):
179+
path = artist.get_path()
180+
assert len(path.vertices) > 0
181+
bbox = path.get_extents()
182+
assert bbox.x0 == pytest.approx(0, abs=1e-9)
183+
assert bbox.x1 == pytest.approx(1, abs=1e-9)
184+
assert bbox.y0 == pytest.approx(0, abs=1e-9)
185+
assert bbox.y1 == pytest.approx(1, abs=1e-9)
186+
187+
159188
def test_shared_axes_zoom_propagation():
160189
fig = plt.figure()
161190
proj = ccrs.PlateCarree()

0 commit comments

Comments
 (0)