##// END OF EJS Templates
Backport PR #13162: print_figure return base64 str instead of bytes
Matthias Bussonnier -
Show More
@@ -5,6 +5,8 b''
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7 from io import BytesIO
8 from binascii import b2a_base64
9 from functools import partial
8 10 import warnings
9 11
10 12 from IPython.core.display import _pngxy
@@ -99,7 +101,7 b' def figsize(sizex, sizey):'
99 101 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
100 102
101 103
102 def print_figure(fig, fmt='png', bbox_inches='tight', **kwargs):
104 def print_figure(fig, fmt="png", bbox_inches="tight", base64=False, **kwargs):
103 105 """Print a figure to an image, and return the resulting file data
104 106
105 107 Returned data will be bytes unless ``fmt='svg'``,
@@ -107,6 +109,12 b" def print_figure(fig, fmt='png', bbox_inches='tight', **kwargs):"
107 109
108 110 Any keyword args are passed to fig.canvas.print_figure,
109 111 such as ``quality`` or ``bbox_inches``.
112
113 If `base64` is True, return base64-encoded str instead of raw bytes
114 for binary-encoded image formats
115
116 .. versionadded: 7.29
117 base64 argument
110 118 """
111 119 # When there's an empty figure, we shouldn't return anything, otherwise we
112 120 # get big blank areas in the qt console.
@@ -138,19 +146,31 b" def print_figure(fig, fmt='png', bbox_inches='tight', **kwargs):"
138 146 data = bytes_io.getvalue()
139 147 if fmt == 'svg':
140 148 data = data.decode('utf-8')
149 elif base64:
150 data = b2a_base64(data).decode("ascii")
141 151 return data
142 152
143 def retina_figure(fig, **kwargs):
144 """format a figure as a pixel-doubled (retina) PNG"""
145 pngdata = print_figure(fig, fmt='retina', **kwargs)
153 def retina_figure(fig, base64=False, **kwargs):
154 """format a figure as a pixel-doubled (retina) PNG
155
156 If `base64` is True, return base64-encoded str instead of raw bytes
157 for binary-encoded image formats
158
159 .. versionadded: 7.29
160 base64 argument
161 """
162 pngdata = print_figure(fig, fmt="retina", base64=False, **kwargs)
146 163 # Make sure that retina_figure acts just like print_figure and returns
147 164 # None when the figure is empty.
148 165 if pngdata is None:
149 166 return
150 167 w, h = _pngxy(pngdata)
151 168 metadata = {"width": w//2, "height":h//2}
169 if base64:
170 pngdata = b2a_base64(pngdata).decode("ascii")
152 171 return pngdata, metadata
153 172
173
154 174 # We need a little factory function here to create the closure where
155 175 # safe_execfile can live.
156 176 def mpl_runner(safe_execfile):
@@ -249,16 +269,22 b' def select_figure_formats(shell, formats, **kwargs):'
249 269 gs = "%s" % ','.join([repr(f) for f in supported])
250 270 raise ValueError("supported formats are: %s not %s" % (gs, bs))
251 271
252 if 'png' in formats:
253 png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png', **kwargs))
254 if 'retina' in formats or 'png2x' in formats:
255 png_formatter.for_type(Figure, lambda fig: retina_figure(fig, **kwargs))
256 if 'jpg' in formats or 'jpeg' in formats:
257 jpg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'jpg', **kwargs))
258 if 'svg' in formats:
259 svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg', **kwargs))
260 if 'pdf' in formats:
261 pdf_formatter.for_type(Figure, lambda fig: print_figure(fig, 'pdf', **kwargs))
272 if "png" in formats:
273 png_formatter.for_type(
274 Figure, partial(print_figure, fmt="png", base64=True, **kwargs)
275 )
276 if "retina" in formats or "png2x" in formats:
277 png_formatter.for_type(Figure, partial(retina_figure, base64=True, **kwargs))
278 if "jpg" in formats or "jpeg" in formats:
279 jpg_formatter.for_type(
280 Figure, partial(print_figure, fmt="jpg", base64=True, **kwargs)
281 )
282 if "svg" in formats:
283 svg_formatter.for_type(Figure, partial(print_figure, fmt="svg", **kwargs))
284 if "pdf" in formats:
285 pdf_formatter.for_type(
286 Figure, partial(print_figure, fmt="pdf", base64=True, **kwargs)
287 )
262 288
263 289 #-----------------------------------------------------------------------------
264 290 # Code for initializing matplotlib and importing pylab
@@ -187,10 +187,12 b' def test_set_matplotlib_formats_kwargs():'
187 187 display.set_matplotlib_formats('png', **kwargs)
188 188 formatter = ip.display_formatter.formatters['image/png']
189 189 f = formatter.lookup_by_type(Figure)
190 cell = f.__closure__[0].cell_contents
190 formatter_kwargs = f.keywords
191 191 expected = kwargs
192 expected["base64"] = True
193 expected["fmt"] = "png"
192 194 expected.update(cfg.print_figure_kwargs)
193 nt.assert_equal(cell, expected)
195 nt.assert_equal(formatter_kwargs, expected)
194 196
195 197 def test_display_available():
196 198 """
@@ -5,7 +5,8 b''
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7
8 from io import UnsupportedOperation, BytesIO
8 from binascii import a2b_base64
9 from io import BytesIO
9 10
10 11 import matplotlib
11 12 matplotlib.use('Agg')
@@ -104,8 +105,11 b' def test_select_figure_formats_kwargs():'
104 105 pt.select_figure_formats(ip, 'png', **kwargs)
105 106 formatter = ip.display_formatter.formatters['image/png']
106 107 f = formatter.lookup_by_type(Figure)
107 cell = f.__closure__[0].cell_contents
108 nt.assert_equal(cell, kwargs)
108 cell = f.keywords
109 expected = kwargs
110 expected["base64"] = True
111 expected["fmt"] = "png"
112 assert cell == expected
109 113
110 114 # check that the formatter doesn't raise
111 115 fig = plt.figure()
@@ -114,7 +118,9 b' def test_select_figure_formats_kwargs():'
114 118 plt.draw()
115 119 formatter.enabled = True
116 120 png = formatter(fig)
117 assert png.startswith(_PNG)
121 assert isinstance(png, str)
122 png_bytes = a2b_base64(png)
123 assert png_bytes.startswith(_PNG)
118 124
119 125 def test_select_figure_formats_set():
120 126 ip = get_ipython()
General Comments 0
You need to be logged in to leave comments. Login now