diff --git a/doc/api/api_changes_3.3/deprecations.rst b/doc/api/api_changes_3.3/deprecations.rst index 2ae4da6cfd77..52351888d377 100644 --- a/doc/api/api_changes_3.3/deprecations.rst +++ b/doc/api/api_changes_3.3/deprecations.rst @@ -392,6 +392,11 @@ NavigationToolbar2QT.ctx ~~~~~~~~~~~~~~~~~~~~~~~~ This attribute is deprecated. +NavigationToolbar2Wx attributes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The ``prevZoomRect``, ``retinaFix``, ``savedRetinaImage``, ``wxoverlay``, +``zoomAxes``, ``zoomStartX``, and ``zoomStartY`` attributes are deprecated. + NavigationToolbar2.press and .release ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ These methods were called when pressing or releasing a mouse button, diff --git a/lib/matplotlib/backends/backend_wx.py b/lib/matplotlib/backends/backend_wx.py index d48739d4152c..a5ab3ca50f97 100644 --- a/lib/matplotlib/backends/backend_wx.py +++ b/lib/matplotlib/backends/backend_wx.py @@ -1126,12 +1126,20 @@ def __init__(self, canvas): NavigationToolbar2.__init__(self, canvas) self._idle = True - self.prevZoomRect = None + self._prevZoomRect = None # for now, use alternate zoom-rectangle drawing on all # Macs. N.B. In future versions of wx it may be possible to # detect Retina displays with window.GetContentScaleFactor() # and/or dc.GetContentScaleFactor() - self.retinaFix = 'wxMac' in wx.PlatformInfo + self._retinaFix = 'wxMac' in wx.PlatformInfo + + prevZoomRect = cbook._deprecate_privatize_attribute("3.3") + retinaFix = cbook._deprecate_privatize_attribute("3.3") + savedRetinaImage = cbook._deprecate_privatize_attribute("3.3") + wxoverlay = cbook._deprecate_privatize_attribute("3.3") + zoomAxes = cbook._deprecate_privatize_attribute("3.3") + zoomStartX = cbook._deprecate_privatize_attribute("3.3") + zoomStartY = cbook._deprecate_privatize_attribute("3.3") def get_canvas(self, frame, fig): return type(self.canvas)(frame, -1, fig) @@ -1201,53 +1209,53 @@ def set_cursor(self, cursor): def press_zoom(self, event): super().press_zoom(event) if self.mode.name == 'ZOOM': - if not self.retinaFix: - self.wxoverlay = wx.Overlay() + if not self._retinaFix: + self._wxoverlay = wx.Overlay() else: if event.inaxes is not None: - self.savedRetinaImage = self.canvas.copy_from_bbox( + self._savedRetinaImage = self.canvas.copy_from_bbox( event.inaxes.bbox) - self.zoomStartX = event.xdata - self.zoomStartY = event.ydata - self.zoomAxes = event.inaxes + self._zoomStartX = event.xdata + self._zoomStartY = event.ydata + self._zoomAxes = event.inaxes def release_zoom(self, event): super().release_zoom(event) if self.mode.name == 'ZOOM': # When the mouse is released we reset the overlay and it # restores the former content to the window. - if not self.retinaFix: - self.wxoverlay.Reset() - del self.wxoverlay + if not self._retinaFix: + self._wxoverlay.Reset() + del self._wxoverlay else: - del self.savedRetinaImage - if self.prevZoomRect: - self.prevZoomRect.pop(0).remove() - self.prevZoomRect = None - if self.zoomAxes: - self.zoomAxes = None + del self._savedRetinaImage + if self._prevZoomRect: + self._prevZoomRect.pop(0).remove() + self._prevZoomRect = None + if self._zoomAxes: + self._zoomAxes = None def draw_rubberband(self, event, x0, y0, x1, y1): - if self.retinaFix: # On Macs, use the following code + if self._retinaFix: # On Macs, use the following code # wx.DCOverlay does not work properly on Retina displays. rubberBandColor = '#C0C0FF' - if self.prevZoomRect: - self.prevZoomRect.pop(0).remove() - self.canvas.restore_region(self.savedRetinaImage) - X0, X1 = self.zoomStartX, event.xdata - Y0, Y1 = self.zoomStartY, event.ydata + if self._prevZoomRect: + self._prevZoomRect.pop(0).remove() + self.canvas.restore_region(self._savedRetinaImage) + X0, X1 = self._zoomStartX, event.xdata + Y0, Y1 = self._zoomStartY, event.ydata lineX = (X0, X0, X1, X1, X0) lineY = (Y0, Y1, Y1, Y0, Y0) - self.prevZoomRect = self.zoomAxes.plot( + self._prevZoomRect = self._zoomAxes.plot( lineX, lineY, '-', color=rubberBandColor) - self.zoomAxes.draw_artist(self.prevZoomRect[0]) - self.canvas.blit(self.zoomAxes.bbox) + self._zoomAxes.draw_artist(self._prevZoomRect[0]) + self.canvas.blit(self._zoomAxes.bbox) return # Use an Overlay to draw a rubberband-like bounding box. dc = wx.ClientDC(self.canvas) - odc = wx.DCOverlay(self.wxoverlay, dc) + odc = wx.DCOverlay(self._wxoverlay, dc) odc.Clear() # Mac's DC is already the same as a GCDC, and it causes @@ -1439,14 +1447,14 @@ def set_cursor(self, cursor): class RubberbandWx(backend_tools.RubberbandBase): def __init__(self, *args, **kwargs): backend_tools.RubberbandBase.__init__(self, *args, **kwargs) - self.wxoverlay = None + self._wxoverlay = None def draw_rubberband(self, x0, y0, x1, y1): # Use an Overlay to draw a rubberband-like bounding box. - if self.wxoverlay is None: - self.wxoverlay = wx.Overlay() + if self._wxoverlay is None: + self._wxoverlay = wx.Overlay() dc = wx.ClientDC(self.canvas) - odc = wx.DCOverlay(self.wxoverlay, dc) + odc = wx.DCOverlay(self._wxoverlay, dc) odc.Clear() dc = wx.GCDC(dc) @@ -1477,10 +1485,10 @@ def draw_rubberband(self, x0, y0, x1, y1): dc.DrawRectangle(rect) def remove_rubberband(self): - if self.wxoverlay is None: + if self._wxoverlay is None: return - self.wxoverlay.Reset() - self.wxoverlay = None + self._wxoverlay.Reset() + self._wxoverlay = None else: # on Mac OS retina displays DCOverlay does not work diff --git a/lib/matplotlib/cbook/__init__.py b/lib/matplotlib/cbook/__init__.py index 57fe140da7bf..22d72854ce2f 100644 --- a/lib/matplotlib/cbook/__init__.py +++ b/lib/matplotlib/cbook/__init__.py @@ -31,7 +31,7 @@ from .deprecation import ( deprecated, warn_deprecated, _rename_parameter, _delete_parameter, _make_keyword_only, - _deprecate_method_override, + _deprecate_method_override, _deprecate_privatize_attribute, _suppress_matplotlib_deprecation_warning, MatplotlibDeprecationWarning, mplDeprecation) diff --git a/lib/matplotlib/cbook/deprecation.py b/lib/matplotlib/cbook/deprecation.py index d62173cf2f77..bdb98eb6a39a 100644 --- a/lib/matplotlib/cbook/deprecation.py +++ b/lib/matplotlib/cbook/deprecation.py @@ -251,6 +251,29 @@ def wrapper(*args, **kwargs): return deprecate +class _deprecate_privatize_attribute: + """ + Helper to deprecate public access to an attribute. + + This helper should only be used at class scope, as follows:: + + class Foo: + attr = _deprecate_privatize_attribute(*args, **kwargs) + + where *all* parameters are forwarded to `deprecated`. This form makes + ``attr`` a property which forwards access to ``self._attr`` (same name but + with a leading underscore), with a deprecation warning. Note that the + attribute name is derived from *the name this helper is assigned to*. + """ + + def __init__(self, *args, **kwargs): + self.deprecator = deprecated(*args, **kwargs) + + def __set_name__(self, owner, name): + setattr(owner, name, self.deprecator( + property(lambda self: getattr(self, f"_{name}")), name=name)) + + def _rename_parameter(since, old, new, func=None): """ Decorator indicating that parameter *old* of *func* is renamed to *new*.