Coverage for /usr/lib/python3/dist-packages/matplotlib/backends/backend_mixed.py: 54%
41 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
1import numpy as np
3from matplotlib import cbook
4from .backend_agg import RendererAgg
5from matplotlib._tight_bbox import process_figure_for_rasterizing
8class MixedModeRenderer:
9 """
10 A helper class to implement a renderer that switches between
11 vector and raster drawing. An example may be a PDF writer, where
12 most things are drawn with PDF vector commands, but some very
13 complex objects, such as quad meshes, are rasterised and then
14 output as images.
15 """
16 def __init__(self, figure, width, height, dpi, vector_renderer,
17 raster_renderer_class=None,
18 bbox_inches_restore=None):
19 """
20 Parameters
21 ----------
22 figure : `matplotlib.figure.Figure`
23 The figure instance.
24 width : scalar
25 The width of the canvas in logical units
26 height : scalar
27 The height of the canvas in logical units
28 dpi : float
29 The dpi of the canvas
30 vector_renderer : `matplotlib.backend_bases.RendererBase`
31 An instance of a subclass of
32 `~matplotlib.backend_bases.RendererBase` that will be used for the
33 vector drawing.
34 raster_renderer_class : `matplotlib.backend_bases.RendererBase`
35 The renderer class to use for the raster drawing. If not provided,
36 this will use the Agg backend (which is currently the only viable
37 option anyway.)
39 """
40 if raster_renderer_class is None:
41 raster_renderer_class = RendererAgg
43 self._raster_renderer_class = raster_renderer_class
44 self._width = width
45 self._height = height
46 self.dpi = dpi
48 self._vector_renderer = vector_renderer
50 self._raster_renderer = None
52 # A reference to the figure is needed as we need to change
53 # the figure dpi before and after the rasterization. Although
54 # this looks ugly, I couldn't find a better solution. -JJL
55 self.figure = figure
56 self._figdpi = figure.dpi
58 self._bbox_inches_restore = bbox_inches_restore
60 self._renderer = vector_renderer
62 def __getattr__(self, attr):
63 # Proxy everything that hasn't been overridden to the base
64 # renderer. Things that *are* overridden can call methods
65 # on self._renderer directly, but must not cache/store
66 # methods (because things like RendererAgg change their
67 # methods on the fly in order to optimise proxying down
68 # to the underlying C implementation).
69 return getattr(self._renderer, attr)
71 def start_rasterizing(self):
72 """
73 Enter "raster" mode. All subsequent drawing commands (until
74 `stop_rasterizing` is called) will be drawn with the raster backend.
75 """
76 # change the dpi of the figure temporarily.
77 self.figure.dpi = self.dpi
78 if self._bbox_inches_restore: # when tight bbox is used
79 r = process_figure_for_rasterizing(self.figure,
80 self._bbox_inches_restore)
81 self._bbox_inches_restore = r
83 self._raster_renderer = self._raster_renderer_class(
84 self._width*self.dpi, self._height*self.dpi, self.dpi)
85 self._renderer = self._raster_renderer
87 def stop_rasterizing(self):
88 """
89 Exit "raster" mode. All of the drawing that was done since
90 the last `start_rasterizing` call will be copied to the
91 vector backend by calling draw_image.
92 """
94 self._renderer = self._vector_renderer
96 height = self._height * self.dpi
97 img = np.asarray(self._raster_renderer.buffer_rgba())
98 slice_y, slice_x = cbook._get_nonzero_slices(img[..., 3])
99 cropped_img = img[slice_y, slice_x]
100 if cropped_img.size:
101 gc = self._renderer.new_gc()
102 # TODO: If the mixedmode resolution differs from the figure's
103 # dpi, the image must be scaled (dpi->_figdpi). Not all
104 # backends support this.
105 self._renderer.draw_image(
106 gc,
107 slice_x.start * self._figdpi / self.dpi,
108 (height - slice_y.stop) * self._figdpi / self.dpi,
109 cropped_img[::-1])
110 self._raster_renderer = None
112 # restore the figure dpi.
113 self.figure.dpi = self._figdpi
115 if self._bbox_inches_restore: # when tight bbox is used
116 r = process_figure_for_rasterizing(self.figure,
117 self._bbox_inches_restore,
118 self._figdpi)
119 self._bbox_inches_restore = r