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