diff --git a/lib/matplotlib/backends/backend_mixed.py b/lib/matplotlib/backends/backend_mixed.py index 7bfc51bceb2e..575030a45b67 100644 --- a/lib/matplotlib/backends/backend_mixed.py +++ b/lib/matplotlib/backends/backend_mixed.py @@ -62,27 +62,16 @@ def __init__(self, figure, width, height, dpi, vector_renderer, self._bbox_inches_restore = bbox_inches_restore - self._set_current_renderer(vector_renderer) - - _methods = """ - close_group draw_image draw_markers draw_path - draw_path_collection draw_quad_mesh draw_tex draw_text - finalize flipy get_canvas_width_height get_image_magnification - get_texmanager get_text_width_height_descent new_gc open_group - option_image_nocomposite points_to_pixels strip_math - start_filter stop_filter draw_gouraud_triangle - draw_gouraud_triangles option_scale_image - _text2path _get_text_path_transform height width - """.split() - - def _set_current_renderer(self, renderer): - self._renderer = renderer - - for method in self._methods: - if hasattr(renderer, method): - setattr(self, method, getattr(renderer, method)) - renderer.start_rasterizing = self.start_rasterizing - renderer.stop_rasterizing = self.stop_rasterizing + 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): """ @@ -105,7 +94,7 @@ def start_rasterizing(self): if self._rasterizing == 0: self._raster_renderer = self._raster_renderer_class( self._width*self.dpi, self._height*self.dpi, self.dpi) - self._set_current_renderer(self._raster_renderer) + self._renderer = self._raster_renderer self._rasterizing += 1 def stop_rasterizing(self): @@ -119,7 +108,7 @@ def stop_rasterizing(self): """ self._rasterizing -= 1 if self._rasterizing == 0: - self._set_current_renderer(self._vector_renderer) + self._renderer = self._vector_renderer height = self._height * self.dpi buffer, bounds = self._raster_renderer.tostring_rgba_minimized() diff --git a/lib/matplotlib/tests/baseline_images/test_agg_filter/agg_filter_alpha.pdf b/lib/matplotlib/tests/baseline_images/test_agg_filter/agg_filter_alpha.pdf new file mode 100644 index 000000000000..46275f180bc4 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_agg_filter/agg_filter_alpha.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_agg_filter/agg_filter_alpha.png b/lib/matplotlib/tests/baseline_images/test_agg_filter/agg_filter_alpha.png new file mode 100644 index 000000000000..dce047707da8 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_agg_filter/agg_filter_alpha.png differ diff --git a/lib/matplotlib/tests/test_agg_filter.py b/lib/matplotlib/tests/test_agg_filter.py new file mode 100644 index 000000000000..913034636603 --- /dev/null +++ b/lib/matplotlib/tests/test_agg_filter.py @@ -0,0 +1,30 @@ +import numpy as np + +import matplotlib.pyplot as plt +from matplotlib.testing.decorators import image_comparison + + +@image_comparison(baseline_images=['agg_filter_alpha'], + extensions=['png', 'pdf']) +def test_agg_filter_alpha(): + ax = plt.axes() + x, y = np.mgrid[0:7, 0:8] + data = x**2 - y**2 + mesh = ax.pcolormesh(data, cmap='Reds', zorder=5) + + def manual_alpha(im, dpi): + im[:, :, 3] *= 0.6 + print('CALLED') + return im, 0, 0 + + # Note: Doing alpha like this is not the same as setting alpha on + # the mesh itself. Currently meshes are drawn as independent patches, + # and we see fine borders around the blocks of color. See the SO + # question for an example: https://stackoverflow.com/questions/20678817 + mesh.set_agg_filter(manual_alpha) + + # Currently we must enable rasterization for this to have an effect in + # the PDF backend. + mesh.set_rasterized(True) + + ax.plot([0, 4, 7], [1, 3, 8])