From de1a72fff808a8786479195ac48eca6707c35c37 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Wed, 6 Oct 2021 10:27:27 +0200 Subject: [PATCH] FigureCanvasCairo can init RendererCairo; kill RendererCairo subclasses. Initialization of RendererCairo is duplicated across all FigureCanvasCairo subclasses (and also in FigureCanvasCairo itself), so just move it to a single place (in a delayed-init property to avoid having to play around multiple inheritance and GUI frameworks). RendererCairoGTK{3,4} simply add a set_context method, which can just as well be defined on the base RendererCairo class (which after all already defines set_ctx_from_surface for the benefit of {qt,tk,wx}cairo). --- .../deprecations/21981-AL.rst | 4 +++ lib/matplotlib/backends/backend_cairo.py | 31 +++++++++++++------ lib/matplotlib/backends/backend_gtk3cairo.py | 6 ++-- lib/matplotlib/backends/backend_gtk4cairo.py | 6 ++-- lib/matplotlib/backends/backend_qt5cairo.py | 5 +-- lib/matplotlib/backends/backend_qtcairo.py | 3 +- lib/matplotlib/backends/backend_tkcairo.py | 6 +--- lib/matplotlib/backends/backend_wxcairo.py | 10 +----- 8 files changed, 33 insertions(+), 38 deletions(-) create mode 100644 doc/api/next_api_changes/deprecations/21981-AL.rst diff --git a/doc/api/next_api_changes/deprecations/21981-AL.rst b/doc/api/next_api_changes/deprecations/21981-AL.rst new file mode 100644 index 000000000000..4c4d6535b5c6 --- /dev/null +++ b/doc/api/next_api_changes/deprecations/21981-AL.rst @@ -0,0 +1,4 @@ +``RendererGTK3Cairo`` and ``RendererGTK4Cairo`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +... have been deprecated. Use ``RendererCairo`` instead, which has gained the +``set_context`` method. diff --git a/lib/matplotlib/backends/backend_cairo.py b/lib/matplotlib/backends/backend_cairo.py index 05a760542f4f..555ecc1d2f85 100644 --- a/lib/matplotlib/backends/backend_cairo.py +++ b/lib/matplotlib/backends/backend_cairo.py @@ -133,6 +133,9 @@ def __init__(self, dpi): cairo.ImageSurface(cairo.FORMAT_ARGB32, 1, 1)) super().__init__() + def set_context(self, ctx): + self.gc.ctx = _to_context(ctx) + def set_ctx_from_surface(self, surface): self.gc.ctx = cairo.Context(surface) # Although it may appear natural to automatically call @@ -414,6 +417,15 @@ def __init__(self, slices, data): class FigureCanvasCairo(FigureCanvasBase): + @property + def _renderer(self): + # In theory, _renderer should be set in __init__, but GUI canvas + # subclasses (FigureCanvasFooCairo) don't always interact well with + # multiple inheritance (FigureCanvasFoo inits but doesn't super-init + # FigureCanvasCairo), so initialize it in the getter instead. + if not hasattr(self, "_cached_renderer"): + self._cached_renderer = RendererCairo(self.figure.dpi) + return self._cached_renderer def copy_from_bbox(self, bbox): surface = self._renderer.gc.ctx.get_target() @@ -462,12 +474,12 @@ def print_rgba(self, fobj): print_raw = print_rgba def _get_printed_image_surface(self): + self._renderer.dpi = self.figure.dpi width, height = self.get_width_height() - renderer = RendererCairo(self.figure.dpi) - renderer.set_width_height(width, height) + self._renderer.set_width_height(width, height) surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height) - renderer.set_ctx_from_surface(surface) - self.figure.draw(renderer) + self._renderer.set_ctx_from_surface(surface) + self.figure.draw(self._renderer) return surface @_check_savefig_extra_args @@ -506,18 +518,17 @@ def _save(self, fmt, fobj, *, orientation='portrait'): else: raise ValueError("Unknown format: {!r}".format(fmt)) - # surface.set_dpi() can be used - renderer = RendererCairo(self.figure.dpi) - renderer.set_width_height(width_in_points, height_in_points) - renderer.set_ctx_from_surface(surface) - ctx = renderer.gc.ctx + self._renderer.dpi = self.figure.dpi + self._renderer.set_width_height(width_in_points, height_in_points) + self._renderer.set_ctx_from_surface(surface) + ctx = self._renderer.gc.ctx if orientation == 'landscape': ctx.rotate(np.pi / 2) ctx.translate(0, -height_in_points) # Perhaps add an '%%Orientation: Landscape' comment? - self.figure.draw(renderer) + self.figure.draw(self._renderer) ctx.show_page() surface.finish() diff --git a/lib/matplotlib/backends/backend_gtk3cairo.py b/lib/matplotlib/backends/backend_gtk3cairo.py index 2e8558a66b2c..bed912899675 100644 --- a/lib/matplotlib/backends/backend_gtk3cairo.py +++ b/lib/matplotlib/backends/backend_gtk3cairo.py @@ -1,9 +1,11 @@ from contextlib import nullcontext +from .. import _api from . import backend_cairo, backend_gtk3 from .backend_gtk3 import Gtk, _BackendGTK3 +@_api.deprecated("3.6") class RendererGTK3Cairo(backend_cairo.RendererCairo): def set_context(self, ctx): self.gc.ctx = backend_cairo._to_context(ctx) @@ -12,10 +14,6 @@ def set_context(self, ctx): class FigureCanvasGTK3Cairo(backend_gtk3.FigureCanvasGTK3, backend_cairo.FigureCanvasCairo): - def __init__(self, figure): - super().__init__(figure) - self._renderer = RendererGTK3Cairo(self.figure.dpi) - def on_draw_event(self, widget, ctx): with (self.toolbar._wait_cursor_for_draw_cm() if self.toolbar else nullcontext()): diff --git a/lib/matplotlib/backends/backend_gtk4cairo.py b/lib/matplotlib/backends/backend_gtk4cairo.py index 05ddef53bd92..5a5b4c7e45b8 100644 --- a/lib/matplotlib/backends/backend_gtk4cairo.py +++ b/lib/matplotlib/backends/backend_gtk4cairo.py @@ -1,9 +1,11 @@ from contextlib import nullcontext +from .. import _api from . import backend_cairo, backend_gtk4 from .backend_gtk4 import Gtk, _BackendGTK4 +@_api.deprecated("3.6") class RendererGTK4Cairo(backend_cairo.RendererCairo): def set_context(self, ctx): self.gc.ctx = backend_cairo._to_context(ctx) @@ -13,10 +15,6 @@ class FigureCanvasGTK4Cairo(backend_gtk4.FigureCanvasGTK4, backend_cairo.FigureCanvasCairo): _context_is_scaled = True - def __init__(self, figure): - super().__init__(figure) - self._renderer = RendererGTK4Cairo(self.figure.dpi) - def on_draw_event(self, widget, ctx): with (self.toolbar._wait_cursor_for_draw_cm() if self.toolbar else nullcontext()): diff --git a/lib/matplotlib/backends/backend_qt5cairo.py b/lib/matplotlib/backends/backend_qt5cairo.py index 51eae512c654..98c033d511a7 100644 --- a/lib/matplotlib/backends/backend_qt5cairo.py +++ b/lib/matplotlib/backends/backend_qt5cairo.py @@ -1,8 +1,5 @@ from .backend_qtcairo import ( - _BackendQTCairo, FigureCanvasQTCairo, - FigureCanvasCairo, FigureCanvasQT, - RendererCairo -) + _BackendQTCairo, FigureCanvasQTCairo, FigureCanvasCairo, FigureCanvasQT) @_BackendQTCairo.export diff --git a/lib/matplotlib/backends/backend_qtcairo.py b/lib/matplotlib/backends/backend_qtcairo.py index 8d6def2d79e5..7f77546b02cc 100644 --- a/lib/matplotlib/backends/backend_qtcairo.py +++ b/lib/matplotlib/backends/backend_qtcairo.py @@ -1,6 +1,6 @@ import ctypes -from .backend_cairo import cairo, FigureCanvasCairo, RendererCairo +from .backend_cairo import cairo, FigureCanvasCairo from .backend_qt import QtCore, QtGui, _BackendQT, FigureCanvasQT from .qt_compat import QT_API, _enum, _setDevicePixelRatio @@ -8,7 +8,6 @@ class FigureCanvasQTCairo(FigureCanvasQT, FigureCanvasCairo): def __init__(self, figure=None): super().__init__(figure=figure) - self._renderer = RendererCairo(self.figure.dpi) self._renderer.set_width_height(-1, -1) # Invalid values. def draw(self): diff --git a/lib/matplotlib/backends/backend_tkcairo.py b/lib/matplotlib/backends/backend_tkcairo.py index b4099db24828..a132cab6b78e 100644 --- a/lib/matplotlib/backends/backend_tkcairo.py +++ b/lib/matplotlib/backends/backend_tkcairo.py @@ -3,15 +3,11 @@ import numpy as np from . import _backend_tk -from .backend_cairo import cairo, FigureCanvasCairo, RendererCairo +from .backend_cairo import cairo, FigureCanvasCairo from ._backend_tk import _BackendTk, FigureCanvasTk class FigureCanvasTkCairo(FigureCanvasCairo, FigureCanvasTk): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self._renderer = RendererCairo(self.figure.dpi) - def draw(self): width = int(self.figure.bbox.width) height = int(self.figure.bbox.height) diff --git a/lib/matplotlib/backends/backend_wxcairo.py b/lib/matplotlib/backends/backend_wxcairo.py index 38f072695432..0ff10d9b27d7 100644 --- a/lib/matplotlib/backends/backend_wxcairo.py +++ b/lib/matplotlib/backends/backend_wxcairo.py @@ -1,6 +1,6 @@ import wx.lib.wxcairo as wxcairo -from .backend_cairo import cairo, FigureCanvasCairo, RendererCairo +from .backend_cairo import cairo, FigureCanvasCairo from .backend_wx import ( _BackendWx, _FigureCanvasWxBase, FigureFrameWx, NavigationToolbar2Wx as NavigationToolbar2WxCairo) @@ -21,14 +21,6 @@ class FigureCanvasWxCairo(_FigureCanvasWxBase, FigureCanvasCairo): we give a hint as to our preferred minimum size. """ - def __init__(self, parent, id, figure): - # _FigureCanvasWxBase should be fixed to have the same signature as - # every other FigureCanvas and use cooperative inheritance, but in the - # meantime the following will make do. - _FigureCanvasWxBase.__init__(self, parent, id, figure) - FigureCanvasCairo.__init__(self, figure) - self._renderer = RendererCairo(self.figure.dpi) - def draw(self, drawDC=None): size = self.figure.bbox.size.astype(int) surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, *size)