Skip to content

Commit 3ae9d44

Browse files
committed
Merge consecutive rasterizations
In vector output it is possible to flag artists to be rasterized. In many cases with multiple rasterized objects there can be significant file size savings by combining the rendered bitmaps into a single bitmap. This achieved by splitting some of the work of the renderers stop_rasterizing() out into a flush_rasterizing() function. This gets called when for a non-rasterized artist, and does the flushing only if needed. It must also be called after every element in the Figure has been drawn to finalize any remaining rasterized elements. This fixes #17149
1 parent f6b8891 commit 3ae9d44

File tree

4 files changed

+19
-9
lines changed

4 files changed

+19
-9
lines changed

lib/matplotlib/artist.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ def draw_wrapper(artist, renderer, *args, **kwargs):
3535
try:
3636
if artist.get_rasterized():
3737
renderer.start_rasterizing()
38+
else:
39+
renderer.flush_rasterizing()
3840
if artist.get_agg_filter() is not None:
3941
renderer.start_filter()
4042

lib/matplotlib/backend_bases.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,9 @@ def stop_rasterizing(self):
685685
Used by `.MixedModeRenderer`.
686686
"""
687687

688+
def flush_rasterizing(self):
689+
pass
690+
688691
def start_filter(self):
689692
"""
690693
Switch to a temporary renderer for image filtering effects.

lib/matplotlib/backends/backend_mixed.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ def __init__(self, figure, width, height, dpi, vector_renderer,
5353

5454
self._raster_renderer = None
5555
self._rasterizing = 0
56+
self._rasterizing_unflushed = False
5657

5758
# A reference to the figure is needed as we need to change
5859
# the figure dpi before and after the rasterization. Although
@@ -84,11 +85,12 @@ def start_rasterizing(self):
8485
r = process_figure_for_rasterizing(self.figure,
8586
self._bbox_inches_restore)
8687
self._bbox_inches_restore = r
87-
if self._rasterizing == 0:
88+
if self._rasterizing == 0 and not self._rasterizing_unflushed:
8889
self._raster_renderer = self._raster_renderer_class(
8990
self._width*self.dpi, self._height*self.dpi, self.dpi)
9091
self._renderer = self._raster_renderer
9192
self._rasterizing += 1
93+
self._rasterizing_unflushed = True
9294

9395
def stop_rasterizing(self):
9496
"""
@@ -101,7 +103,15 @@ def stop_rasterizing(self):
101103
"raster" mode is exited.
102104
"""
103105
self._rasterizing -= 1
104-
if self._rasterizing == 0:
106+
107+
if self._bbox_inches_restore: # when tight bbox is used
108+
r = process_figure_for_rasterizing(self.figure,
109+
self._bbox_inches_restore,
110+
self._figdpi)
111+
self._bbox_inches_restore = r
112+
113+
def flush_rasterizing(self):
114+
if self._rasterizing == 0 and self._rasterizing_unflushed:
105115
self._renderer = self._vector_renderer
106116

107117
height = self._height * self.dpi
@@ -122,12 +132,7 @@ def stop_rasterizing(self):
122132
image)
123133
self._raster_renderer = None
124134
self._rasterizing = False
135+
self._rasterizing_unflushed = False
125136

126137
# restore the figure dpi.
127138
self.figure.set_dpi(self._figdpi)
128-
129-
if self._bbox_inches_restore: # when tight bbox is used
130-
r = process_figure_for_rasterizing(self.figure,
131-
self._bbox_inches_restore,
132-
self._figdpi)
133-
self._bbox_inches_restore = r

lib/matplotlib/figure.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1730,7 +1730,7 @@ def draw(self, renderer):
17301730
self.patch.draw(renderer)
17311731
mimage._draw_list_compositing_images(
17321732
renderer, self, artists, self.suppressComposite)
1733-
1733+
renderer.flush_rasterizing()
17341734
renderer.close_group('figure')
17351735
finally:
17361736
self.stale = False

0 commit comments

Comments
 (0)