Skip to content

Commit

Permalink
Deprecate offset_position="data".
Browse files Browse the repository at this point in the history
The `offset_position` property of collections is currently set to "data"
only for hexbin(), but one can do away with it by just setting the
correct offsetTrans instead -- which this PR does.  The advantage of
doing so is that the correct offsetTrans only needs to be implemented
once, whereas support for `offset_position` needs to be implemented for
each renderer class separately (including at the C-level for the Agg
backend).

Note that the *offset_position* argument to `draw_path_collection` is
not pending removal because its removal would require coordination with
third-party backends; the plan is to just always set it to "screen"
after the deprecation period.

AffineDeltaTransform can be used as a replacement for
`offset_position="data"`.  This API is experimental.
  • Loading branch information
anntzer committed Apr 27, 2020
1 parent f091a4d commit 4a569ce
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 16 deletions.
12 changes: 12 additions & 0 deletions doc/api/api_changes_3.3/deprecations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -475,3 +475,15 @@ is deprecated; use the explicit defaults of 1 and 0, respectively, instead.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
... is deprecated. Scale ``Figure.dpi_scale_trans`` by 1/72 to achieve the
same effect.

``offset_position`` property of `.Collection`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The ``offset_position`` property of `.Collection` is deprecated. In the
future, `.Collection`\s will always behave as if ``offset_position`` is set to
"screen" (the default).

Support for passing ``offset_position="data"`` to the ``draw_path_collection``
of all renderer classes is deprecated.

`.transforms.AffineDeltaTransform` can be used as a replacement. This API is
experimental and may change in the future.
3 changes: 1 addition & 2 deletions lib/matplotlib/axes/_axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -4816,8 +4816,7 @@ def reduce_C_function(C: array) -> float
edgecolors=edgecolors,
linewidths=linewidths,
offsets=offsets,
transOffset=mtransforms.IdentityTransform(),
offset_position="data"
transOffset=mtransforms.AffineDeltaTransform(self.transData),
)

# Set normalizer if bins is 'log'
Expand Down
11 changes: 9 additions & 2 deletions lib/matplotlib/backend_bases.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,8 +205,10 @@ def draw_path_collection(self, gc, master_transform, paths, all_transforms,
*linestyles* and *antialiaseds*. *offsets* is a list of
offsets to apply to each of the paths. The offsets in
*offsets* are first transformed by *offsetTrans* before being
applied. *offset_position* may be either "screen" or "data"
depending on the space that the offsets are in.
applied.
*offset_position* may be either "screen" or "data" depending on the
space that the offsets are in; "data" is deprecated.
This provides a fallback implementation of
:meth:`draw_path_collection` that makes multiple calls to
Expand Down Expand Up @@ -380,6 +382,11 @@ def _iter_collection(self, gc, master_transform, all_transforms,
Naa = len(antialiaseds)
Nurls = len(urls)

if offset_position == "data":
cbook.warn_deprecated(
"3.3", message="Support for offset_position='data' is "
"deprecated since %(since)s and will be removed %(removal)s.")

if (Nfacecolors == 0 and Nedgecolors == 0) or Npaths == 0:
return
if Noffsets:
Expand Down
17 changes: 16 additions & 1 deletion lib/matplotlib/backends/backend_agg.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,9 @@ def _update_methods(self):
self.draw_gouraud_triangles = self._renderer.draw_gouraud_triangles
self.draw_image = self._renderer.draw_image
self.draw_markers = self._renderer.draw_markers
self.draw_path_collection = self._renderer.draw_path_collection
# This is its own method for the duration of the deprecation of
# offset_position = "data".
# self.draw_path_collection = self._renderer.draw_path_collection
self.draw_quad_mesh = self._renderer.draw_quad_mesh
self.copy_from_bbox = self._renderer.copy_from_bbox
self.get_content_extents = self._renderer.get_content_extents
Expand Down Expand Up @@ -155,6 +157,19 @@ def draw_path(self, gc, path, transform, rgbFace=None):
raise OverflowError("Exceeded cell block limit (set "
"'agg.path.chunksize' rcparam)") from err

def draw_path_collection(self, gc, master_transform, paths, all_transforms,
offsets, offsetTrans, facecolors, edgecolors,
linewidths, linestyles, antialiaseds, urls,
offset_position):
if offset_position == "data":
cbook.warn_deprecated(
"3.3", message="Support for offset_position='data' is "
"deprecated since %(since)s and will be removed %(removal)s.")
return self._renderer.draw_path_collection(
gc, master_transform, paths, all_transforms, offsets, offsetTrans,
facecolors, edgecolors, linewidths, linestyles, antialiaseds, urls,
offset_position)

def draw_mathtext(self, gc, x, y, s, prop, angle):
"""Draw mathtext using :mod:`matplotlib.mathtext`."""
ox, oy, width, height, descent, font_image, used_characters = \
Expand Down
17 changes: 11 additions & 6 deletions lib/matplotlib/collections.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class Collection(artist.Artist, cm.ScalarMappable):
- *antialiaseds*: None
- *offsets*: None
- *transOffset*: transforms.IdentityTransform()
- *offset_position*: 'screen' (default) or 'data'
- *offset_position* (deprecated): 'screen' (default) or 'data' (deprecated)
- *norm*: None (optional for `matplotlib.cm.ScalarMappable`)
- *cmap*: None (optional for `matplotlib.cm.ScalarMappable`)
- *hatch*: None
Expand All @@ -59,8 +59,8 @@ class Collection(artist.Artist, cm.ScalarMappable):
rendering (default no offsets). If offset_position is 'screen'
(default) the offset is applied after the master transform has
been applied, that is, the offsets are in screen coordinates. If
offset_position is 'data', the offset is applied before the master
transform, i.e., the offsets are in data coordinates.
offset_position is 'data' (deprecated), the offset is applied before the
master transform, i.e., the offsets are in data coordinates.
If any of *edgecolors*, *facecolors*, *linewidths*, *antialiaseds* are
None, they default to their `.rcParams` patch setting, in sequence form.
Expand All @@ -85,6 +85,7 @@ class Collection(artist.Artist, cm.ScalarMappable):
# subclass-by-subclass basis.
_edge_default = False

@cbook._delete_parameter("3.3", "offset_position")
def __init__(self,
edgecolors=None,
facecolors=None,
Expand Down Expand Up @@ -130,7 +131,9 @@ def __init__(self,
self.set_pickradius(pickradius)
self.set_urls(urls)
self.set_hatch(hatch)
self.set_offset_position(offset_position)
self._offset_position = "screen"
if offset_position != "screen":
self.set_offset_position(offset_position) # emit deprecation.
self.set_zorder(zorder)

if capstyle:
Expand Down Expand Up @@ -404,7 +407,7 @@ def contains(self, mouseevent):
self._picker is not True # the bool, not just nonzero or 1
else self._pickradius)

if self.axes and self.get_offset_position() == "data":
if self.axes:
self.axes._unstale_viewLim()

transform, transOffset, offsets, paths = self._prepare_points()
Expand All @@ -413,7 +416,7 @@ def contains(self, mouseevent):
mouseevent.x, mouseevent.y, pickradius,
transform.frozen(), paths, self.get_transforms(),
offsets, transOffset, pickradius <= 0,
self.get_offset_position())
self._offset_position)

return len(ind) > 0, dict(ind=ind)

Expand Down Expand Up @@ -494,6 +497,7 @@ def get_offsets(self):
else:
return self._uniform_offsets

@cbook.deprecated("3.3")
def set_offset_position(self, offset_position):
"""
Set how offsets are applied. If *offset_position* is 'screen'
Expand All @@ -511,6 +515,7 @@ def set_offset_position(self, offset_position):
self._offset_position = offset_position
self.stale = True

@cbook.deprecated("3.3")
def get_offset_position(self):
"""
Return how offsets are applied for the collection. If
Expand Down
11 changes: 6 additions & 5 deletions lib/matplotlib/tests/test_backend_bases.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,12 @@ def check(master_transform, paths, all_transforms,
master_transform, paths, all_transforms))
gc = rb.new_gc()
ids = [path_id for xo, yo, path_id, gc0, rgbFace in
rb._iter_collection(gc, master_transform, all_transforms,
range(len(raw_paths)), offsets,
transforms.IdentityTransform(),
facecolors, edgecolors, [], [], [False],
[], 'data')]
rb._iter_collection(
gc, master_transform, all_transforms,
range(len(raw_paths)), offsets,
transforms.AffineDeltaTransform(master_transform),
facecolors, edgecolors, [], [], [False],
[], 'screen')]
uses = rb._iter_collection_uses_per_path(
paths, all_transforms, offsets, facecolors, edgecolors)
if raw_paths:
Expand Down
30 changes: 30 additions & 0 deletions lib/matplotlib/transforms.py
Original file line number Diff line number Diff line change
Expand Up @@ -2617,6 +2617,36 @@ def get_matrix(self):
return self._mtx


class AffineDeltaTransform(Affine2DBase):
r"""
A transform wrapper for transforming displacements between pairs of points.
This class is intended to be used to transform displacements ("position
deltas") between pairs of points (e.g., as the ``offset_transform``
of `.Collection`\s): given a transform ``t`` such that ``t =
AffineDeltaTransform(t) + offset``, ``AffineDeltaTransform``
satisfies ``AffineDeltaTransform(a - b) == AffineDeltaTransform(a) -
AffineDeltaTransform(b)``.
This is implemented by forcing the offset components of the transform
matrix to zero.
This class is experimental as of 3.3, and the API may change.
"""

def __init__(self, transform, **kwargs):
super().__init__(**kwargs)
self._base_transform = transform

__str__ = _make_str_method("_base_transform")

def get_matrix(self):
if self._invalid:
self._mtx = self._base_transform.get_matrix().copy()
self._mtx[:2, -1] = 0
return self._mtx


class TransformedPath(TransformNode):
"""
A `TransformedPath` caches a non-affine transformed copy of the
Expand Down

0 comments on commit 4a569ce

Please sign in to comment.