8000 Backport PR #22946: FIX: Handle no-offsets in collection datalim (alt… · matplotlib/matplotlib@b262b11 · GitHub
[go: up one dir, main page]

Skip to content

Commit b262b11

Browse files
timhoffmgreglucas
authored andcommitted
Backport PR #22946: FIX: Handle no-offsets in collection datalim (alternative)
1 parent 930bb82 commit b262b11

File tree

2 files changed

+42
-32
lines changed

2 files changed

+42
-32
lines changed

lib/matplotlib/collections.py

Lines changed: 30 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ class Collection(artist.Artist, cm.ScalarMappable):
6161
mappable will be used to set the ``facecolors`` and ``edgecolors``,
6262
ignoring those that were manually passed in.
6363
"""
64-
_offsets = np.zeros((0, 2))
6564
#: Either a list of 3x3 arrays or an Nx3x3 array (representing N
6665
#: transforms), suitable for the `all_transforms` argument to
6766
#: `~matplotlib.backend_bases.RendererBase.draw_path_collection`;
@@ -193,15 +192,11 @@ def __init__(self,
193192
else:
194193
self._joinstyle = None
195194

196-
# default to zeros
197-
self._offsets = np.zeros((1, 2))
198-
199195
if offsets is not None:
200196
offsets = np.asanyarray(offsets, float)
201197
# Broadcast (2,) -> (1, 2) but nothing else.
202198
if offsets.shape == (2,):
203199
offsets = offsets[None, :]
204-
self._offsets = offsets
205200
elif transOffset is not None:
206201
_api.warn_deprecated(
207202
'3.5',
@@ -215,6 +210,7 @@ def __init__(self,
215210
'explicitly.')
216211
transOffset = None
217212

213+
self._offsets = offsets
218214
self._transOffset = transOffset
219215

220216
self._path_effects = None
@@ -273,9 +269,12 @@ def get_datalim(self, transData):
273269
# if there are offsets but in some coords other than data,
274270
# then don't use them for autoscaling.
275271
return transforms.Bbox.null()
276-
offsets = self._offsets
272+
offsets = self.get_offsets()
277273

278274
paths = self.get_paths()
275+
if not len(paths):
276+
# No paths to transform
277+
return transforms.Bbox.null()
279278

280279
if not transform.is_affine:
281280
paths = [transform.transform_path_non_affine(p) for p in paths]
@@ -284,22 +283,22 @@ def get_datalim(self, transData):
284283
# transforms.get_affine().contains_branch(transData). But later,
285284
# be careful to only apply the affine part that remains.
286285

287-
if isinstance(offsets, np.ma.MaskedArray):
288-
offsets = offsets.filled(np.nan)
286+
if any(transform.contains_branch_seperately(transData)):
287+
if isinstance(offsets, np.ma.MaskedArray):
288+
offsets = offsets.filled(np.nan)
289289
# get_path_collection_extents handles nan but not masked arrays
290-
291-
if len(paths) and len(offsets):
292-
if any(transform.contains_branch_seperately(transData)):
293-
# collections that are just in data units (like quiver)
294-
# can properly have the axes limits set by their shape +
295-
# offset. LineCollections that have no offsets can
296-
# also use this algorithm (like streamplot).
297-
return mpath.get_path_collection_extents(
298-
transform.get_affine() - transData, paths,
299-
self.get_transforms(),
300-
transOffset.transform_non_affine(offsets),
301-
transOffset.get_affine().frozen())
302-
290+
# collections that are just in data units (like quiver)
291+
# can properly have the axes limits set by their shape +
292+
# offset. LineCollections that have no offsets can
293+
# also use this algorithm (like streamplot).
294+
return mpath.get_path_collection_extents(
295+
transform.get_affine() - transData, paths,
296+
self.get_transforms(),
297+
transOffset.transform_non_affine(offsets),
298+
transOffset.get_affine().frozen())
299+
300+
# NOTE: None is the default case where no offsets were passed in
301+
if self._offsets is not None:
303302
# this is for collections that have their paths (shapes)
304303
# in physical, axes-relative, or figure-relative units
305304
# (i.e. like scatter). We can't uniquely set limits based on
@@ -325,7 +324,7 @@ def _prepare_points(self):
325324

326325
transform = self.get_transform()
327326
transOffset = self.get_offset_transform()
328-
offsets = self._offsets
327+
offsets = self.get_offsets()
329328
paths = self.get_paths()
330329

331330
if self.have_units():
@@ -336,10 +335,9 @@ def _prepare_points(self):
336335
xs = self.convert_xunits(xs)
337336
ys = self.convert_yunits(ys)
338337
paths.append(mpath.Path(np.column_stack([xs, ys]), path.codes))
339-
if offsets.size:
340-
xs = self.convert_xunits(offsets[:, 0])
341-
ys = self.convert_yunits(offsets[:, 1])
342-
offsets = np.column_stack([xs, ys])
338+
xs = self.convert_xunits(offsets[:, 0])
339+
ys = self.convert_yunits(offsets[:, 1])
340+
offsets = np.column_stack([xs, ys])
343341

344342
if not transform.is_affine:
345343
paths = [transform.transform_path_non_affine(path)
@@ -569,7 +567,8 @@ def set_offsets(self, offsets):
569567

570568
def get_offsets(self):
571569
"""Return the offsets for the collection."""
572-
return self._offsets
570+
# Default to zeros in the no-offset (None) case
571+
return np.zeros((1, 2)) if self._offsets is None else self._offsets
573572

574573
def _get_default_linewidth(self):
575574
# This may be overridden in a subclass.
@@ -2166,13 +2165,12 @@ def draw(self, renderer):
21662165
renderer.open_group(self.__class__.__name__, self.get_gid())
21672166
transform = self.get_transform()
21682167
transOffset = self.get_offset_transform()
2169-
offsets = self._offsets
2168+
offsets = self.get_offsets()
21702169

21712170
if self.have_units():
2172-
if len(self._offsets):
2173-
xs = self.convert_xunits(self._offsets[:, 0])
2174-
ys = self.convert_yunits(self._offsets[:, 1])
2175-
offsets = np.column_stack([xs, ys])
2171+
xs = self.convert_xunits(offsets[:, 0])
2172+
ys = self.convert_yunits(offsets[:, 1])
2173+
offsets = np.column_stack([xs, ys])
21762174

21772175
self.update_scalarmappable()
21782176

lib/matplotlib/tests/test_collections.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import matplotlib.pyplot as plt
1010
import matplotlib.collections as mcollections
1111
import matplotlib.colors as mcolors
12+
import matplotlib.path as mpath
1213
import matplotlib.transforms as mtransforms
1314
from matplotlib.collections import (Collection, LineCollection,
1415
EventCollection, PolyCollection)
@@ -291,6 +292,17 @@ def test_null_collection_datalim():
291292
mtransforms.Bbox.null().get_points())
292293

293294

295+
def test_no_offsets_datalim():
296+
# A collection with no offsets and a non transData
297+
# transform should return a null bbox
298+
ax = plt.axes()
299+
coll = mcollections.PathCollection([mpath.Path([(0, 0), (1, 0)])])
300+
ax.add_collection(coll)
301+
coll_data_lim = coll.get_datalim(mtransforms.IdentityTransform())
302+
assert_array_equal(coll_data_lim.get_points(),
303+
mtransforms.Bbox.null().get_points())
304+
305+
294306
def test_add_collection():
295307
# Test if data limits are unchanged by adding an empty collection.
296308
# GitHub issue #1490, pull #1497.

0 commit comments

Comments
 (0)
0