Spaces:
Running
Running
| import numpy as np | |
| from matplotlib import cbook | |
| from .backend_agg import RendererAgg | |
| from matplotlib._tight_bbox import process_figure_for_rasterizing | |
| class MixedModeRenderer: | |
| """ | |
| A helper class to implement a renderer that switches between | |
| vector and raster drawing. An example may be a PDF writer, where | |
| most things are drawn with PDF vector commands, but some very | |
| complex objects, such as quad meshes, are rasterised and then | |
| output as images. | |
| """ | |
| def __init__(self, figure, width, height, dpi, vector_renderer, | |
| raster_renderer_class=None, | |
| bbox_inches_restore=None): | |
| """ | |
| Parameters | |
| ---------- | |
| figure : `~matplotlib.figure.Figure` | |
| The figure instance. | |
| width : float | |
| The width of the canvas in logical units | |
| height : float | |
| The height of the canvas in logical units | |
| dpi : float | |
| The dpi of the canvas | |
| vector_renderer : `~matplotlib.backend_bases.RendererBase` | |
| An instance of a subclass of | |
| `~matplotlib.backend_bases.RendererBase` that will be used for the | |
| vector drawing. | |
| raster_renderer_class : `~matplotlib.backend_bases.RendererBase` | |
| The renderer class to use for the raster drawing. If not provided, | |
| this will use the Agg backend (which is currently the only viable | |
| option anyway.) | |
| """ | |
| if raster_renderer_class is None: | |
| raster_renderer_class = RendererAgg | |
| self._raster_renderer_class = raster_renderer_class | |
| self._width = width | |
| self._height = height | |
| self.dpi = dpi | |
| self._vector_renderer = vector_renderer | |
| self._raster_renderer = None | |
| # A reference to the figure is needed as we need to change | |
| # the figure dpi before and after the rasterization. Although | |
| # this looks ugly, I couldn't find a better solution. -JJL | |
| self.figure = figure | |
| self._figdpi = figure.dpi | |
| self._bbox_inches_restore = bbox_inches_restore | |
| self._renderer = vector_renderer | |
| def __getattr__(self, attr): | |
| # Proxy everything that hasn't been overridden to the base | |
| # renderer. Things that *are* overridden can call methods | |
| # on self._renderer directly, but must not cache/store | |
| # methods (because things like RendererAgg change their | |
| # methods on the fly in order to optimise proxying down | |
| # to the underlying C implementation). | |
| return getattr(self._renderer, attr) | |
| def start_rasterizing(self): | |
| """ | |
| Enter "raster" mode. All subsequent drawing commands (until | |
| `stop_rasterizing` is called) will be drawn with the raster backend. | |
| """ | |
| # change the dpi of the figure temporarily. | |
| self.figure.dpi = self.dpi | |
| if self._bbox_inches_restore: # when tight bbox is used | |
| r = process_figure_for_rasterizing(self.figure, | |
| self._bbox_inches_restore) | |
| self._bbox_inches_restore = r | |
| self._raster_renderer = self._raster_renderer_class( | |
| self._width*self.dpi, self._height*self.dpi, self.dpi) | |
| self._renderer = self._raster_renderer | |
| def stop_rasterizing(self): | |
| """ | |
| Exit "raster" mode. All of the drawing that was done since | |
| the last `start_rasterizing` call will be copied to the | |
| vector backend by calling draw_image. | |
| """ | |
| self._renderer = self._vector_renderer | |
| height = self._height * self.dpi | |
| img = np.asarray(self._raster_renderer.buffer_rgba()) | |
| slice_y, slice_x = cbook._get_nonzero_slices(img[..., 3]) | |
| cropped_img = img[slice_y, slice_x] | |
| if cropped_img.size: | |
| gc = self._renderer.new_gc() | |
| # TODO: If the mixedmode resolution differs from the figure's | |
| # dpi, the image must be scaled (dpi->_figdpi). Not all | |
| # backends support this. | |
| self._renderer.draw_image( | |
| gc, | |
| slice_x.start * self._figdpi / self.dpi, | |
| (height - slice_y.stop) * self._figdpi / self.dpi, | |
| cropped_img[::-1]) | |
| self._raster_renderer = None | |
| # restore the figure dpi. | |
| self.figure.dpi = self._figdpi | |
| if self._bbox_inches_restore: # when tight bbox is used | |
| r = process_figure_for_rasterizing(self.figure, | |
| self._bbox_inches_restore, | |
| self._figdpi) | |
| self._bbox_inches_restore = r | |