8000 Merge consecutive rasterizations · matplotlib/matplotlib@2f67719 · GitHub
[go: up one dir, main page]

Skip to content

Commit 2f67719

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 3232f58 commit 2f67719

File tree

4 files changed

+37
-12
lines changed

4 files changed

+37
-12
lines changed

lib/matplotlib/artist.py

Lines changed: 4 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

@@ -869,6 +871,8 @@ def set_rasterized(self, rasterized):
869871
870872
Defaults to None, which implies the backend's default behavior.
871873
874+
Will also cause child artists to be rasterized.
875+
872876
Parameters
873877
----------
874878
rasterized : bool or None

lib/matplotlib/backend_bases.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,9 +680,22 @@ def stop_rasterizing(self):
680680
Switch back to the vector renderer and draw the contents of the raster
681681
renderer as an image on the vector renderer.
682682
683+
Note that for nested draw calls, this may not stop the rasterization,
684+
only decrement a depth counter. Also this should not write the bitmap
685+
to the output, as it may be possible to accumulate and merge it with
686+
the next draw call. See `flush_rasterizing`.
687+
683688
Used by `.MixedModeRenderer`.
684689
"""
685690

691+
def flush_rasterizing(self):
692+
"""
693+
This will be called before a non-raster draw and after the final
694+
artist has been drawn to allow the accumulated bitmap to be flushed
695+
to the output.
696+
"""
697+
pass
698+
686699
def start_filter(self):
687700
"""
688701
Switch to a temporary renderer for image filtering effects.

lib/matplotlib/backends/backend_mixed.py

Lines changed: 19 additions & 11 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,24 +85,36 @@ 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
"""
95-
Exit "raster" mode. All of the drawing that was done since
96-
the last `start_rasterizing` call will be copied to the
97-
vector backend by calling draw_image.
97+
Exit "raster" mode. The accumulated bitmap will not be copied to
98+
the output until `flush_rasterizing` is called.
9899
99100
If `start_rasterizing` has been called multiple times,
100101
`stop_rasterizing` must be called the same number of times before
101102
"raster" mode is exited.
102103
"""
103104
self._rasterizing -= 1
104-
if self._rasterizing == 0:
105+
106+
if self._bbox_inches_restore: # when tight bbox is used
107+
r = process_figure_for_rasterizing(self.figure,
108+
self._bbox_inches_restore,
109+
self._figdpi)
110+
self._bbox_inches_restore = r
111+
112+
def flush_rasterizing(self):
113+
"""
114+
All of the drawing that was done since the last `start_rasterizing`
115+
call will be copied to the vector backend by calling draw_image.
116+
"""
117+
if self._rasterizing == 0 and self._rasterizing_unflushed:
105118
self._renderer = self._vector_renderer
106119

107120
height = self._height * self.dpi
@@ -122,12 +135,7 @@ def stop_rasterizing(self):
122135
image)
123136
self._raster_renderer = None
124137
self._rasterizing = False
138+
self._rasterizing_unflushed = False
125139

126140
# restore the figure dpi.
127141
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
@@ -1735,7 +1735,7 @@ def draw(self, renderer):
17351735
self.patch.draw(renderer)
17361736
mimage._draw_list_compositing_images(
17371737
renderer, self, artists, self.suppressComposite)
1738-
1738+
renderer.flush_rasterizing()
17391739
renderer.close_group('figure')
17401740
finally:
17411741
self.stale = False

0 commit comments

Comments
 (0)
0