Thanks to visit codestin.com
Credit goes to github.com

Skip to content

FigureCanvasCairo can init RendererCairo; kill RendererCairo subclasses. #21981

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions doc/api/next_api_changes/deprecations/21981-AL.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
``RendererGTK3Cairo`` and ``RendererGTK4Cairo``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
... have been deprecated. Use ``RendererCairo`` instead, which has gained the
``set_context`` method.
31 changes: 21 additions & 10 deletions lib/matplotlib/backends/backend_cairo.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This used to make a new renderer, now it gets the cached one. Why should we not be worried about this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realized that I forgot to update self._renderer.dpi (now fixed), but the point is that other than the dpi, the width/height, and the surface, there's no other state on the renderer (the graphicscontext is reset between draws), and all of these always get reset manually before each draw.

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
Expand Down Expand Up @@ -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()
Expand Down
6 changes: 2 additions & 4 deletions lib/matplotlib/backends/backend_gtk3cairo.py
Original file line number Diff line number Diff line change
@@ -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)
Expand All @@ -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()):
Expand Down
6 changes: 2 additions & 4 deletions lib/matplotlib/backends/backend_gtk4cairo.py
Original file line number Diff line number Diff line change
@@ -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)
Expand All @@ -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()):
Expand Down
5 changes: 1 addition & 4 deletions lib/matplotlib/backends/backend_qt5cairo.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
from .backend_qtcairo import (
_BackendQTCairo, FigureCanvasQTCairo,
FigureCanvasCairo, FigureCanvasQT,
RendererCairo
)
_BackendQTCairo, FigureCanvasQTCairo, FigureCanvasCairo, FigureCanvasQT)


@_BackendQTCairo.export
Expand Down
3 changes: 1 addition & 2 deletions lib/matplotlib/backends/backend_qtcairo.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
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


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):
Expand Down
6 changes: 1 addition & 5 deletions lib/matplotlib/backends/backend_tkcairo.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
10 changes: 1 addition & 9 deletions lib/matplotlib/backends/backend_wxcairo.py
Original file line number Diff line number Diff line change
@@ -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)
Expand All @@ -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)
Expand Down