You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			120 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Python
		
	
			
		
		
	
	
			120 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Python
		
	
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
 |