##// END OF EJS Templates
Backport PR #13162: print_figure return base64 str instead of bytes
Matthias Bussonnier -
Show More
@@ -1,391 +1,417 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Pylab (matplotlib) support utilities."""
2 """Pylab (matplotlib) support utilities."""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
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
11 from IPython.utils.decorators import flag_calls
13 from IPython.utils.decorators import flag_calls
12
14
13 # If user specifies a GUI, that dictates the backend, otherwise we read the
15 # If user specifies a GUI, that dictates the backend, otherwise we read the
14 # user's mpl default from the mpl rc structure
16 # user's mpl default from the mpl rc structure
15 backends = {
17 backends = {
16 "tk": "TkAgg",
18 "tk": "TkAgg",
17 "gtk": "GTKAgg",
19 "gtk": "GTKAgg",
18 "gtk3": "GTK3Agg",
20 "gtk3": "GTK3Agg",
19 "gtk4": "GTK4Agg",
21 "gtk4": "GTK4Agg",
20 "wx": "WXAgg",
22 "wx": "WXAgg",
21 "qt4": "Qt4Agg",
23 "qt4": "Qt4Agg",
22 "qt5": "Qt5Agg",
24 "qt5": "Qt5Agg",
23 "qt6": "QtAgg",
25 "qt6": "QtAgg",
24 "qt": "Qt5Agg",
26 "qt": "Qt5Agg",
25 "osx": "MacOSX",
27 "osx": "MacOSX",
26 "nbagg": "nbAgg",
28 "nbagg": "nbAgg",
27 "notebook": "nbAgg",
29 "notebook": "nbAgg",
28 "agg": "agg",
30 "agg": "agg",
29 "svg": "svg",
31 "svg": "svg",
30 "pdf": "pdf",
32 "pdf": "pdf",
31 "ps": "ps",
33 "ps": "ps",
32 "inline": "module://matplotlib_inline.backend_inline",
34 "inline": "module://matplotlib_inline.backend_inline",
33 "ipympl": "module://ipympl.backend_nbagg",
35 "ipympl": "module://ipympl.backend_nbagg",
34 "widget": "module://ipympl.backend_nbagg",
36 "widget": "module://ipympl.backend_nbagg",
35 }
37 }
36
38
37 # We also need a reverse backends2guis mapping that will properly choose which
39 # We also need a reverse backends2guis mapping that will properly choose which
38 # GUI support to activate based on the desired matplotlib backend. For the
40 # GUI support to activate based on the desired matplotlib backend. For the
39 # most part it's just a reverse of the above dict, but we also need to add a
41 # most part it's just a reverse of the above dict, but we also need to add a
40 # few others that map to the same GUI manually:
42 # few others that map to the same GUI manually:
41 backend2gui = dict(zip(backends.values(), backends.keys()))
43 backend2gui = dict(zip(backends.values(), backends.keys()))
42 # Our tests expect backend2gui to just return 'qt'
44 # Our tests expect backend2gui to just return 'qt'
43 backend2gui['Qt4Agg'] = 'qt'
45 backend2gui['Qt4Agg'] = 'qt'
44 # In the reverse mapping, there are a few extra valid matplotlib backends that
46 # In the reverse mapping, there are a few extra valid matplotlib backends that
45 # map to the same GUI support
47 # map to the same GUI support
46 backend2gui["GTK"] = backend2gui["GTKCairo"] = "gtk"
48 backend2gui["GTK"] = backend2gui["GTKCairo"] = "gtk"
47 backend2gui["GTK3Cairo"] = "gtk3"
49 backend2gui["GTK3Cairo"] = "gtk3"
48 backend2gui["GTK4Cairo"] = "gtk4"
50 backend2gui["GTK4Cairo"] = "gtk4"
49 backend2gui["WX"] = "wx"
51 backend2gui["WX"] = "wx"
50 backend2gui["CocoaAgg"] = "osx"
52 backend2gui["CocoaAgg"] = "osx"
51 # And some backends that don't need GUI integration
53 # And some backends that don't need GUI integration
52 del backend2gui["nbAgg"]
54 del backend2gui["nbAgg"]
53 del backend2gui["agg"]
55 del backend2gui["agg"]
54 del backend2gui["svg"]
56 del backend2gui["svg"]
55 del backend2gui["pdf"]
57 del backend2gui["pdf"]
56 del backend2gui["ps"]
58 del backend2gui["ps"]
57 del backend2gui["module://matplotlib_inline.backend_inline"]
59 del backend2gui["module://matplotlib_inline.backend_inline"]
58
60
59 #-----------------------------------------------------------------------------
61 #-----------------------------------------------------------------------------
60 # Matplotlib utilities
62 # Matplotlib utilities
61 #-----------------------------------------------------------------------------
63 #-----------------------------------------------------------------------------
62
64
63
65
64 def getfigs(*fig_nums):
66 def getfigs(*fig_nums):
65 """Get a list of matplotlib figures by figure numbers.
67 """Get a list of matplotlib figures by figure numbers.
66
68
67 If no arguments are given, all available figures are returned. If the
69 If no arguments are given, all available figures are returned. If the
68 argument list contains references to invalid figures, a warning is printed
70 argument list contains references to invalid figures, a warning is printed
69 but the function continues pasting further figures.
71 but the function continues pasting further figures.
70
72
71 Parameters
73 Parameters
72 ----------
74 ----------
73 figs : tuple
75 figs : tuple
74 A tuple of ints giving the figure numbers of the figures to return.
76 A tuple of ints giving the figure numbers of the figures to return.
75 """
77 """
76 from matplotlib._pylab_helpers import Gcf
78 from matplotlib._pylab_helpers import Gcf
77 if not fig_nums:
79 if not fig_nums:
78 fig_managers = Gcf.get_all_fig_managers()
80 fig_managers = Gcf.get_all_fig_managers()
79 return [fm.canvas.figure for fm in fig_managers]
81 return [fm.canvas.figure for fm in fig_managers]
80 else:
82 else:
81 figs = []
83 figs = []
82 for num in fig_nums:
84 for num in fig_nums:
83 f = Gcf.figs.get(num)
85 f = Gcf.figs.get(num)
84 if f is None:
86 if f is None:
85 print('Warning: figure %s not available.' % num)
87 print('Warning: figure %s not available.' % num)
86 else:
88 else:
87 figs.append(f.canvas.figure)
89 figs.append(f.canvas.figure)
88 return figs
90 return figs
89
91
90
92
91 def figsize(sizex, sizey):
93 def figsize(sizex, sizey):
92 """Set the default figure size to be [sizex, sizey].
94 """Set the default figure size to be [sizex, sizey].
93
95
94 This is just an easy to remember, convenience wrapper that sets::
96 This is just an easy to remember, convenience wrapper that sets::
95
97
96 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
98 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
97 """
99 """
98 import matplotlib
100 import matplotlib
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'``,
106 in which case it will be unicode.
108 in which case it will be unicode.
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.
113 if not fig.axes and not fig.lines:
121 if not fig.axes and not fig.lines:
114 return
122 return
115
123
116 dpi = fig.dpi
124 dpi = fig.dpi
117 if fmt == 'retina':
125 if fmt == 'retina':
118 dpi = dpi * 2
126 dpi = dpi * 2
119 fmt = 'png'
127 fmt = 'png'
120
128
121 # build keyword args
129 # build keyword args
122 kw = {
130 kw = {
123 "format":fmt,
131 "format":fmt,
124 "facecolor":fig.get_facecolor(),
132 "facecolor":fig.get_facecolor(),
125 "edgecolor":fig.get_edgecolor(),
133 "edgecolor":fig.get_edgecolor(),
126 "dpi":dpi,
134 "dpi":dpi,
127 "bbox_inches":bbox_inches,
135 "bbox_inches":bbox_inches,
128 }
136 }
129 # **kwargs get higher priority
137 # **kwargs get higher priority
130 kw.update(kwargs)
138 kw.update(kwargs)
131
139
132 bytes_io = BytesIO()
140 bytes_io = BytesIO()
133 if fig.canvas is None:
141 if fig.canvas is None:
134 from matplotlib.backend_bases import FigureCanvasBase
142 from matplotlib.backend_bases import FigureCanvasBase
135 FigureCanvasBase(fig)
143 FigureCanvasBase(fig)
136
144
137 fig.canvas.print_figure(bytes_io, **kw)
145 fig.canvas.print_figure(bytes_io, **kw)
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):
157 """Factory to return a matplotlib-enabled runner for %run.
177 """Factory to return a matplotlib-enabled runner for %run.
158
178
159 Parameters
179 Parameters
160 ----------
180 ----------
161 safe_execfile : function
181 safe_execfile : function
162 This must be a function with the same interface as the
182 This must be a function with the same interface as the
163 :meth:`safe_execfile` method of IPython.
183 :meth:`safe_execfile` method of IPython.
164
184
165 Returns
185 Returns
166 -------
186 -------
167 A function suitable for use as the ``runner`` argument of the %run magic
187 A function suitable for use as the ``runner`` argument of the %run magic
168 function.
188 function.
169 """
189 """
170
190
171 def mpl_execfile(fname,*where,**kw):
191 def mpl_execfile(fname,*where,**kw):
172 """matplotlib-aware wrapper around safe_execfile.
192 """matplotlib-aware wrapper around safe_execfile.
173
193
174 Its interface is identical to that of the :func:`execfile` builtin.
194 Its interface is identical to that of the :func:`execfile` builtin.
175
195
176 This is ultimately a call to execfile(), but wrapped in safeties to
196 This is ultimately a call to execfile(), but wrapped in safeties to
177 properly handle interactive rendering."""
197 properly handle interactive rendering."""
178
198
179 import matplotlib
199 import matplotlib
180 import matplotlib.pyplot as plt
200 import matplotlib.pyplot as plt
181
201
182 #print '*** Matplotlib runner ***' # dbg
202 #print '*** Matplotlib runner ***' # dbg
183 # turn off rendering until end of script
203 # turn off rendering until end of script
184 is_interactive = matplotlib.rcParams['interactive']
204 is_interactive = matplotlib.rcParams['interactive']
185 matplotlib.interactive(False)
205 matplotlib.interactive(False)
186 safe_execfile(fname,*where,**kw)
206 safe_execfile(fname,*where,**kw)
187 matplotlib.interactive(is_interactive)
207 matplotlib.interactive(is_interactive)
188 # make rendering call now, if the user tried to do it
208 # make rendering call now, if the user tried to do it
189 if plt.draw_if_interactive.called:
209 if plt.draw_if_interactive.called:
190 plt.draw()
210 plt.draw()
191 plt.draw_if_interactive.called = False
211 plt.draw_if_interactive.called = False
192
212
193 # re-draw everything that is stale
213 # re-draw everything that is stale
194 try:
214 try:
195 da = plt.draw_all
215 da = plt.draw_all
196 except AttributeError:
216 except AttributeError:
197 pass
217 pass
198 else:
218 else:
199 da()
219 da()
200
220
201 return mpl_execfile
221 return mpl_execfile
202
222
203
223
204 def _reshow_nbagg_figure(fig):
224 def _reshow_nbagg_figure(fig):
205 """reshow an nbagg figure"""
225 """reshow an nbagg figure"""
206 try:
226 try:
207 reshow = fig.canvas.manager.reshow
227 reshow = fig.canvas.manager.reshow
208 except AttributeError:
228 except AttributeError:
209 raise NotImplementedError()
229 raise NotImplementedError()
210 else:
230 else:
211 reshow()
231 reshow()
212
232
213
233
214 def select_figure_formats(shell, formats, **kwargs):
234 def select_figure_formats(shell, formats, **kwargs):
215 """Select figure formats for the inline backend.
235 """Select figure formats for the inline backend.
216
236
217 Parameters
237 Parameters
218 ==========
238 ==========
219 shell : InteractiveShell
239 shell : InteractiveShell
220 The main IPython instance.
240 The main IPython instance.
221 formats : str or set
241 formats : str or set
222 One or a set of figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
242 One or a set of figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
223 **kwargs : any
243 **kwargs : any
224 Extra keyword arguments to be passed to fig.canvas.print_figure.
244 Extra keyword arguments to be passed to fig.canvas.print_figure.
225 """
245 """
226 import matplotlib
246 import matplotlib
227 from matplotlib.figure import Figure
247 from matplotlib.figure import Figure
228
248
229 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
249 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
230 png_formatter = shell.display_formatter.formatters['image/png']
250 png_formatter = shell.display_formatter.formatters['image/png']
231 jpg_formatter = shell.display_formatter.formatters['image/jpeg']
251 jpg_formatter = shell.display_formatter.formatters['image/jpeg']
232 pdf_formatter = shell.display_formatter.formatters['application/pdf']
252 pdf_formatter = shell.display_formatter.formatters['application/pdf']
233
253
234 if isinstance(formats, str):
254 if isinstance(formats, str):
235 formats = {formats}
255 formats = {formats}
236 # cast in case of list / tuple
256 # cast in case of list / tuple
237 formats = set(formats)
257 formats = set(formats)
238
258
239 [ f.pop(Figure, None) for f in shell.display_formatter.formatters.values() ]
259 [ f.pop(Figure, None) for f in shell.display_formatter.formatters.values() ]
240 mplbackend = matplotlib.get_backend().lower()
260 mplbackend = matplotlib.get_backend().lower()
241 if mplbackend == 'nbagg' or mplbackend == 'module://ipympl.backend_nbagg':
261 if mplbackend == 'nbagg' or mplbackend == 'module://ipympl.backend_nbagg':
242 formatter = shell.display_formatter.ipython_display_formatter
262 formatter = shell.display_formatter.ipython_display_formatter
243 formatter.for_type(Figure, _reshow_nbagg_figure)
263 formatter.for_type(Figure, _reshow_nbagg_figure)
244
264
245 supported = {'png', 'png2x', 'retina', 'jpg', 'jpeg', 'svg', 'pdf'}
265 supported = {'png', 'png2x', 'retina', 'jpg', 'jpeg', 'svg', 'pdf'}
246 bad = formats.difference(supported)
266 bad = formats.difference(supported)
247 if bad:
267 if bad:
248 bs = "%s" % ','.join([repr(f) for f in bad])
268 bs = "%s" % ','.join([repr(f) for f in bad])
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
265 #-----------------------------------------------------------------------------
291 #-----------------------------------------------------------------------------
266
292
267
293
268 def find_gui_and_backend(gui=None, gui_select=None):
294 def find_gui_and_backend(gui=None, gui_select=None):
269 """Given a gui string return the gui and mpl backend.
295 """Given a gui string return the gui and mpl backend.
270
296
271 Parameters
297 Parameters
272 ----------
298 ----------
273 gui : str
299 gui : str
274 Can be one of ('tk','gtk','wx','qt','qt4','inline','agg').
300 Can be one of ('tk','gtk','wx','qt','qt4','inline','agg').
275 gui_select : str
301 gui_select : str
276 Can be one of ('tk','gtk','wx','qt','qt4','inline').
302 Can be one of ('tk','gtk','wx','qt','qt4','inline').
277 This is any gui already selected by the shell.
303 This is any gui already selected by the shell.
278
304
279 Returns
305 Returns
280 -------
306 -------
281 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
307 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
282 'WXAgg','Qt4Agg','module://matplotlib_inline.backend_inline','agg').
308 'WXAgg','Qt4Agg','module://matplotlib_inline.backend_inline','agg').
283 """
309 """
284
310
285 import matplotlib
311 import matplotlib
286
312
287 if gui and gui != 'auto':
313 if gui and gui != 'auto':
288 # select backend based on requested gui
314 # select backend based on requested gui
289 backend = backends[gui]
315 backend = backends[gui]
290 if gui == 'agg':
316 if gui == 'agg':
291 gui = None
317 gui = None
292 else:
318 else:
293 # We need to read the backend from the original data structure, *not*
319 # We need to read the backend from the original data structure, *not*
294 # from mpl.rcParams, since a prior invocation of %matplotlib may have
320 # from mpl.rcParams, since a prior invocation of %matplotlib may have
295 # overwritten that.
321 # overwritten that.
296 # WARNING: this assumes matplotlib 1.1 or newer!!
322 # WARNING: this assumes matplotlib 1.1 or newer!!
297 backend = matplotlib.rcParamsOrig['backend']
323 backend = matplotlib.rcParamsOrig['backend']
298 # In this case, we need to find what the appropriate gui selection call
324 # In this case, we need to find what the appropriate gui selection call
299 # should be for IPython, so we can activate inputhook accordingly
325 # should be for IPython, so we can activate inputhook accordingly
300 gui = backend2gui.get(backend, None)
326 gui = backend2gui.get(backend, None)
301
327
302 # If we have already had a gui active, we need it and inline are the
328 # If we have already had a gui active, we need it and inline are the
303 # ones allowed.
329 # ones allowed.
304 if gui_select and gui != gui_select:
330 if gui_select and gui != gui_select:
305 gui = gui_select
331 gui = gui_select
306 backend = backends[gui]
332 backend = backends[gui]
307
333
308 return gui, backend
334 return gui, backend
309
335
310
336
311 def activate_matplotlib(backend):
337 def activate_matplotlib(backend):
312 """Activate the given backend and set interactive to True."""
338 """Activate the given backend and set interactive to True."""
313
339
314 import matplotlib
340 import matplotlib
315 matplotlib.interactive(True)
341 matplotlib.interactive(True)
316
342
317 # Matplotlib had a bug where even switch_backend could not force
343 # Matplotlib had a bug where even switch_backend could not force
318 # the rcParam to update. This needs to be set *before* the module
344 # the rcParam to update. This needs to be set *before* the module
319 # magic of switch_backend().
345 # magic of switch_backend().
320 matplotlib.rcParams['backend'] = backend
346 matplotlib.rcParams['backend'] = backend
321
347
322 # Due to circular imports, pyplot may be only partially initialised
348 # Due to circular imports, pyplot may be only partially initialised
323 # when this function runs.
349 # when this function runs.
324 # So avoid needing matplotlib attribute-lookup to access pyplot.
350 # So avoid needing matplotlib attribute-lookup to access pyplot.
325 from matplotlib import pyplot as plt
351 from matplotlib import pyplot as plt
326
352
327 plt.switch_backend(backend)
353 plt.switch_backend(backend)
328
354
329 plt.show._needmain = False
355 plt.show._needmain = False
330 # We need to detect at runtime whether show() is called by the user.
356 # We need to detect at runtime whether show() is called by the user.
331 # For this, we wrap it into a decorator which adds a 'called' flag.
357 # For this, we wrap it into a decorator which adds a 'called' flag.
332 plt.draw_if_interactive = flag_calls(plt.draw_if_interactive)
358 plt.draw_if_interactive = flag_calls(plt.draw_if_interactive)
333
359
334
360
335 def import_pylab(user_ns, import_all=True):
361 def import_pylab(user_ns, import_all=True):
336 """Populate the namespace with pylab-related values.
362 """Populate the namespace with pylab-related values.
337
363
338 Imports matplotlib, pylab, numpy, and everything from pylab and numpy.
364 Imports matplotlib, pylab, numpy, and everything from pylab and numpy.
339
365
340 Also imports a few names from IPython (figsize, display, getfigs)
366 Also imports a few names from IPython (figsize, display, getfigs)
341
367
342 """
368 """
343
369
344 # Import numpy as np/pyplot as plt are conventions we're trying to
370 # Import numpy as np/pyplot as plt are conventions we're trying to
345 # somewhat standardize on. Making them available to users by default
371 # somewhat standardize on. Making them available to users by default
346 # will greatly help this.
372 # will greatly help this.
347 s = ("import numpy\n"
373 s = ("import numpy\n"
348 "import matplotlib\n"
374 "import matplotlib\n"
349 "from matplotlib import pylab, mlab, pyplot\n"
375 "from matplotlib import pylab, mlab, pyplot\n"
350 "np = numpy\n"
376 "np = numpy\n"
351 "plt = pyplot\n"
377 "plt = pyplot\n"
352 )
378 )
353 exec(s, user_ns)
379 exec(s, user_ns)
354
380
355 if import_all:
381 if import_all:
356 s = ("from matplotlib.pylab import *\n"
382 s = ("from matplotlib.pylab import *\n"
357 "from numpy import *\n")
383 "from numpy import *\n")
358 exec(s, user_ns)
384 exec(s, user_ns)
359
385
360 # IPython symbols to add
386 # IPython symbols to add
361 user_ns['figsize'] = figsize
387 user_ns['figsize'] = figsize
362 from IPython.core.display import display
388 from IPython.core.display import display
363 # Add display and getfigs to the user's namespace
389 # Add display and getfigs to the user's namespace
364 user_ns['display'] = display
390 user_ns['display'] = display
365 user_ns['getfigs'] = getfigs
391 user_ns['getfigs'] = getfigs
366
392
367
393
368 def configure_inline_support(shell, backend):
394 def configure_inline_support(shell, backend):
369 """
395 """
370 .. deprecated: 7.23
396 .. deprecated: 7.23
371
397
372 use `matplotlib_inline.backend_inline.configure_inline_support()`
398 use `matplotlib_inline.backend_inline.configure_inline_support()`
373
399
374 Configure an IPython shell object for matplotlib use.
400 Configure an IPython shell object for matplotlib use.
375
401
376 Parameters
402 Parameters
377 ----------
403 ----------
378 shell : InteractiveShell instance
404 shell : InteractiveShell instance
379
405
380 backend : matplotlib backend
406 backend : matplotlib backend
381 """
407 """
382 warnings.warn(
408 warnings.warn(
383 "`configure_inline_support` is deprecated since IPython 7.23, directly "
409 "`configure_inline_support` is deprecated since IPython 7.23, directly "
384 "use `matplotlib_inline.backend_inline.configure_inline_support()`",
410 "use `matplotlib_inline.backend_inline.configure_inline_support()`",
385 DeprecationWarning,
411 DeprecationWarning,
386 stacklevel=2,
412 stacklevel=2,
387 )
413 )
388
414
389 from matplotlib_inline.backend_inline import configure_inline_support as configure_inline_support_orig
415 from matplotlib_inline.backend_inline import configure_inline_support as configure_inline_support_orig
390
416
391 configure_inline_support_orig(shell, backend)
417 configure_inline_support_orig(shell, backend)
@@ -1,459 +1,461 b''
1 # Copyright (c) IPython Development Team.
1 # Copyright (c) IPython Development Team.
2 # Distributed under the terms of the Modified BSD License.
2 # Distributed under the terms of the Modified BSD License.
3
3
4 import json
4 import json
5 import os
5 import os
6 import warnings
6 import warnings
7
7
8 from unittest import mock
8 from unittest import mock
9
9
10 import nose.tools as nt
10 import nose.tools as nt
11
11
12 from IPython.core import display
12 from IPython.core import display
13 from IPython.core.getipython import get_ipython
13 from IPython.core.getipython import get_ipython
14 from IPython.utils.io import capture_output
14 from IPython.utils.io import capture_output
15 from IPython.utils.tempdir import NamedFileInTemporaryDirectory
15 from IPython.utils.tempdir import NamedFileInTemporaryDirectory
16 from IPython import paths as ipath
16 from IPython import paths as ipath
17 from IPython.testing.tools import AssertNotPrints
17 from IPython.testing.tools import AssertNotPrints
18
18
19 import IPython.testing.decorators as dec
19 import IPython.testing.decorators as dec
20
20
21 def test_image_size():
21 def test_image_size():
22 """Simple test for display.Image(args, width=x,height=y)"""
22 """Simple test for display.Image(args, width=x,height=y)"""
23 thisurl = 'http://www.google.fr/images/srpr/logo3w.png'
23 thisurl = 'http://www.google.fr/images/srpr/logo3w.png'
24 img = display.Image(url=thisurl, width=200, height=200)
24 img = display.Image(url=thisurl, width=200, height=200)
25 nt.assert_equal(u'<img src="%s" width="200" height="200"/>' % (thisurl), img._repr_html_())
25 nt.assert_equal(u'<img src="%s" width="200" height="200"/>' % (thisurl), img._repr_html_())
26 img = display.Image(url=thisurl, metadata={'width':200, 'height':200})
26 img = display.Image(url=thisurl, metadata={'width':200, 'height':200})
27 nt.assert_equal(u'<img src="%s" width="200" height="200"/>' % (thisurl), img._repr_html_())
27 nt.assert_equal(u'<img src="%s" width="200" height="200"/>' % (thisurl), img._repr_html_())
28 img = display.Image(url=thisurl, width=200)
28 img = display.Image(url=thisurl, width=200)
29 nt.assert_equal(u'<img src="%s" width="200"/>' % (thisurl), img._repr_html_())
29 nt.assert_equal(u'<img src="%s" width="200"/>' % (thisurl), img._repr_html_())
30 img = display.Image(url=thisurl)
30 img = display.Image(url=thisurl)
31 nt.assert_equal(u'<img src="%s"/>' % (thisurl), img._repr_html_())
31 nt.assert_equal(u'<img src="%s"/>' % (thisurl), img._repr_html_())
32 img = display.Image(url=thisurl, unconfined=True)
32 img = display.Image(url=thisurl, unconfined=True)
33 nt.assert_equal(u'<img src="%s" class="unconfined"/>' % (thisurl), img._repr_html_())
33 nt.assert_equal(u'<img src="%s" class="unconfined"/>' % (thisurl), img._repr_html_())
34
34
35
35
36 def test_image_mimes():
36 def test_image_mimes():
37 fmt = get_ipython().display_formatter.format
37 fmt = get_ipython().display_formatter.format
38 for format in display.Image._ACCEPTABLE_EMBEDDINGS:
38 for format in display.Image._ACCEPTABLE_EMBEDDINGS:
39 mime = display.Image._MIMETYPES[format]
39 mime = display.Image._MIMETYPES[format]
40 img = display.Image(b'garbage', format=format)
40 img = display.Image(b'garbage', format=format)
41 data, metadata = fmt(img)
41 data, metadata = fmt(img)
42 nt.assert_equal(sorted(data), sorted([mime, 'text/plain']))
42 nt.assert_equal(sorted(data), sorted([mime, 'text/plain']))
43
43
44
44
45 def test_geojson():
45 def test_geojson():
46
46
47 gj = display.GeoJSON(data={
47 gj = display.GeoJSON(data={
48 "type": "Feature",
48 "type": "Feature",
49 "geometry": {
49 "geometry": {
50 "type": "Point",
50 "type": "Point",
51 "coordinates": [-81.327, 296.038]
51 "coordinates": [-81.327, 296.038]
52 },
52 },
53 "properties": {
53 "properties": {
54 "name": "Inca City"
54 "name": "Inca City"
55 }
55 }
56 },
56 },
57 url_template="http://s3-eu-west-1.amazonaws.com/whereonmars.cartodb.net/{basemap_id}/{z}/{x}/{y}.png",
57 url_template="http://s3-eu-west-1.amazonaws.com/whereonmars.cartodb.net/{basemap_id}/{z}/{x}/{y}.png",
58 layer_options={
58 layer_options={
59 "basemap_id": "celestia_mars-shaded-16k_global",
59 "basemap_id": "celestia_mars-shaded-16k_global",
60 "attribution": "Celestia/praesepe",
60 "attribution": "Celestia/praesepe",
61 "minZoom": 0,
61 "minZoom": 0,
62 "maxZoom": 18,
62 "maxZoom": 18,
63 })
63 })
64 nt.assert_equal(u'<IPython.core.display.GeoJSON object>', str(gj))
64 nt.assert_equal(u'<IPython.core.display.GeoJSON object>', str(gj))
65
65
66 def test_retina_png():
66 def test_retina_png():
67 here = os.path.dirname(__file__)
67 here = os.path.dirname(__file__)
68 img = display.Image(os.path.join(here, "2x2.png"), retina=True)
68 img = display.Image(os.path.join(here, "2x2.png"), retina=True)
69 nt.assert_equal(img.height, 1)
69 nt.assert_equal(img.height, 1)
70 nt.assert_equal(img.width, 1)
70 nt.assert_equal(img.width, 1)
71 data, md = img._repr_png_()
71 data, md = img._repr_png_()
72 nt.assert_equal(md['width'], 1)
72 nt.assert_equal(md['width'], 1)
73 nt.assert_equal(md['height'], 1)
73 nt.assert_equal(md['height'], 1)
74
74
75 def test_embed_svg_url():
75 def test_embed_svg_url():
76 import gzip
76 import gzip
77 from io import BytesIO
77 from io import BytesIO
78 svg_data = b'<svg><circle x="0" y="0" r="1"/></svg>'
78 svg_data = b'<svg><circle x="0" y="0" r="1"/></svg>'
79 url = 'http://test.com/circle.svg'
79 url = 'http://test.com/circle.svg'
80
80
81 gzip_svg = BytesIO()
81 gzip_svg = BytesIO()
82 with gzip.open(gzip_svg, 'wb') as fp:
82 with gzip.open(gzip_svg, 'wb') as fp:
83 fp.write(svg_data)
83 fp.write(svg_data)
84 gzip_svg = gzip_svg.getvalue()
84 gzip_svg = gzip_svg.getvalue()
85
85
86 def mocked_urlopen(*args, **kwargs):
86 def mocked_urlopen(*args, **kwargs):
87 class MockResponse:
87 class MockResponse:
88 def __init__(self, svg):
88 def __init__(self, svg):
89 self._svg_data = svg
89 self._svg_data = svg
90 self.headers = {'content-type': 'image/svg+xml'}
90 self.headers = {'content-type': 'image/svg+xml'}
91
91
92 def read(self):
92 def read(self):
93 return self._svg_data
93 return self._svg_data
94
94
95 if args[0] == url:
95 if args[0] == url:
96 return MockResponse(svg_data)
96 return MockResponse(svg_data)
97 elif args[0] == url + 'z':
97 elif args[0] == url + 'z':
98 ret= MockResponse(gzip_svg)
98 ret= MockResponse(gzip_svg)
99 ret.headers['content-encoding']= 'gzip'
99 ret.headers['content-encoding']= 'gzip'
100 return ret
100 return ret
101 return MockResponse(None)
101 return MockResponse(None)
102
102
103 with mock.patch('urllib.request.urlopen', side_effect=mocked_urlopen):
103 with mock.patch('urllib.request.urlopen', side_effect=mocked_urlopen):
104 svg = display.SVG(url=url)
104 svg = display.SVG(url=url)
105 nt.assert_true(svg._repr_svg_().startswith('<svg'))
105 nt.assert_true(svg._repr_svg_().startswith('<svg'))
106 svg = display.SVG(url=url + 'z')
106 svg = display.SVG(url=url + 'z')
107 nt.assert_true(svg._repr_svg_().startswith('<svg'))
107 nt.assert_true(svg._repr_svg_().startswith('<svg'))
108
108
109 def test_retina_jpeg():
109 def test_retina_jpeg():
110 here = os.path.dirname(__file__)
110 here = os.path.dirname(__file__)
111 img = display.Image(os.path.join(here, "2x2.jpg"), retina=True)
111 img = display.Image(os.path.join(here, "2x2.jpg"), retina=True)
112 nt.assert_equal(img.height, 1)
112 nt.assert_equal(img.height, 1)
113 nt.assert_equal(img.width, 1)
113 nt.assert_equal(img.width, 1)
114 data, md = img._repr_jpeg_()
114 data, md = img._repr_jpeg_()
115 nt.assert_equal(md['width'], 1)
115 nt.assert_equal(md['width'], 1)
116 nt.assert_equal(md['height'], 1)
116 nt.assert_equal(md['height'], 1)
117
117
118 def test_base64image():
118 def test_base64image():
119 display.Image("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB94BCRQnOqNu0b4AAAAKSURBVAjXY2AAAAACAAHiIbwzAAAAAElFTkSuQmCC")
119 display.Image("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB94BCRQnOqNu0b4AAAAKSURBVAjXY2AAAAACAAHiIbwzAAAAAElFTkSuQmCC")
120
120
121 def test_image_filename_defaults():
121 def test_image_filename_defaults():
122 '''test format constraint, and validity of jpeg and png'''
122 '''test format constraint, and validity of jpeg and png'''
123 tpath = ipath.get_ipython_package_dir()
123 tpath = ipath.get_ipython_package_dir()
124 nt.assert_raises(ValueError, display.Image, filename=os.path.join(tpath, 'testing/tests/badformat.zip'),
124 nt.assert_raises(ValueError, display.Image, filename=os.path.join(tpath, 'testing/tests/badformat.zip'),
125 embed=True)
125 embed=True)
126 nt.assert_raises(ValueError, display.Image)
126 nt.assert_raises(ValueError, display.Image)
127 nt.assert_raises(ValueError, display.Image, data='this is not an image', format='badformat', embed=True)
127 nt.assert_raises(ValueError, display.Image, data='this is not an image', format='badformat', embed=True)
128 # check boths paths to allow packages to test at build and install time
128 # check boths paths to allow packages to test at build and install time
129 imgfile = os.path.join(tpath, 'core/tests/2x2.png')
129 imgfile = os.path.join(tpath, 'core/tests/2x2.png')
130 img = display.Image(filename=imgfile)
130 img = display.Image(filename=imgfile)
131 nt.assert_equal('png', img.format)
131 nt.assert_equal('png', img.format)
132 nt.assert_is_not_none(img._repr_png_())
132 nt.assert_is_not_none(img._repr_png_())
133 img = display.Image(filename=os.path.join(tpath, 'testing/tests/logo.jpg'), embed=False)
133 img = display.Image(filename=os.path.join(tpath, 'testing/tests/logo.jpg'), embed=False)
134 nt.assert_equal('jpeg', img.format)
134 nt.assert_equal('jpeg', img.format)
135 nt.assert_is_none(img._repr_jpeg_())
135 nt.assert_is_none(img._repr_jpeg_())
136
136
137 def _get_inline_config():
137 def _get_inline_config():
138 from matplotlib_inline.config import InlineBackend
138 from matplotlib_inline.config import InlineBackend
139 return InlineBackend.instance()
139 return InlineBackend.instance()
140
140
141
141
142 @dec.skip_without("ipykernel")
142 @dec.skip_without("ipykernel")
143 @dec.skip_without("matplotlib")
143 @dec.skip_without("matplotlib")
144 def test_set_matplotlib_close():
144 def test_set_matplotlib_close():
145 cfg = _get_inline_config()
145 cfg = _get_inline_config()
146 cfg.close_figures = False
146 cfg.close_figures = False
147 display.set_matplotlib_close()
147 display.set_matplotlib_close()
148 assert cfg.close_figures
148 assert cfg.close_figures
149 display.set_matplotlib_close(False)
149 display.set_matplotlib_close(False)
150 assert not cfg.close_figures
150 assert not cfg.close_figures
151
151
152 _fmt_mime_map = {
152 _fmt_mime_map = {
153 'png': 'image/png',
153 'png': 'image/png',
154 'jpeg': 'image/jpeg',
154 'jpeg': 'image/jpeg',
155 'pdf': 'application/pdf',
155 'pdf': 'application/pdf',
156 'retina': 'image/png',
156 'retina': 'image/png',
157 'svg': 'image/svg+xml',
157 'svg': 'image/svg+xml',
158 }
158 }
159
159
160 @dec.skip_without('matplotlib')
160 @dec.skip_without('matplotlib')
161 def test_set_matplotlib_formats():
161 def test_set_matplotlib_formats():
162 from matplotlib.figure import Figure
162 from matplotlib.figure import Figure
163 formatters = get_ipython().display_formatter.formatters
163 formatters = get_ipython().display_formatter.formatters
164 for formats in [
164 for formats in [
165 ('png',),
165 ('png',),
166 ('pdf', 'svg'),
166 ('pdf', 'svg'),
167 ('jpeg', 'retina', 'png'),
167 ('jpeg', 'retina', 'png'),
168 (),
168 (),
169 ]:
169 ]:
170 active_mimes = {_fmt_mime_map[fmt] for fmt in formats}
170 active_mimes = {_fmt_mime_map[fmt] for fmt in formats}
171 display.set_matplotlib_formats(*formats)
171 display.set_matplotlib_formats(*formats)
172 for mime, f in formatters.items():
172 for mime, f in formatters.items():
173 if mime in active_mimes:
173 if mime in active_mimes:
174 nt.assert_in(Figure, f)
174 nt.assert_in(Figure, f)
175 else:
175 else:
176 nt.assert_not_in(Figure, f)
176 nt.assert_not_in(Figure, f)
177
177
178
178
179 @dec.skip_without("ipykernel")
179 @dec.skip_without("ipykernel")
180 @dec.skip_without("matplotlib")
180 @dec.skip_without("matplotlib")
181 def test_set_matplotlib_formats_kwargs():
181 def test_set_matplotlib_formats_kwargs():
182 from matplotlib.figure import Figure
182 from matplotlib.figure import Figure
183 ip = get_ipython()
183 ip = get_ipython()
184 cfg = _get_inline_config()
184 cfg = _get_inline_config()
185 cfg.print_figure_kwargs.update(dict(foo='bar'))
185 cfg.print_figure_kwargs.update(dict(foo='bar'))
186 kwargs = dict(dpi=150)
186 kwargs = dict(dpi=150)
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 """
197 Test that display is available without import
199 Test that display is available without import
198
200
199 We don't really care if it's in builtin or anything else, but it should
201 We don't really care if it's in builtin or anything else, but it should
200 always be available.
202 always be available.
201 """
203 """
202 ip = get_ipython()
204 ip = get_ipython()
203 with AssertNotPrints('NameError'):
205 with AssertNotPrints('NameError'):
204 ip.run_cell('display')
206 ip.run_cell('display')
205 try:
207 try:
206 ip.run_cell('del display')
208 ip.run_cell('del display')
207 except NameError:
209 except NameError:
208 pass # it's ok, it might be in builtins
210 pass # it's ok, it might be in builtins
209 # even if deleted it should be back
211 # even if deleted it should be back
210 with AssertNotPrints('NameError'):
212 with AssertNotPrints('NameError'):
211 ip.run_cell('display')
213 ip.run_cell('display')
212
214
213 def test_textdisplayobj_pretty_repr():
215 def test_textdisplayobj_pretty_repr():
214 p = display.Pretty("This is a simple test")
216 p = display.Pretty("This is a simple test")
215 nt.assert_equal(repr(p), '<IPython.core.display.Pretty object>')
217 nt.assert_equal(repr(p), '<IPython.core.display.Pretty object>')
216 nt.assert_equal(p.data, 'This is a simple test')
218 nt.assert_equal(p.data, 'This is a simple test')
217
219
218 p._show_mem_addr = True
220 p._show_mem_addr = True
219 nt.assert_equal(repr(p), object.__repr__(p))
221 nt.assert_equal(repr(p), object.__repr__(p))
220
222
221 def test_displayobject_repr():
223 def test_displayobject_repr():
222 h = display.HTML('<br />')
224 h = display.HTML('<br />')
223 nt.assert_equal(repr(h), '<IPython.core.display.HTML object>')
225 nt.assert_equal(repr(h), '<IPython.core.display.HTML object>')
224 h._show_mem_addr = True
226 h._show_mem_addr = True
225 nt.assert_equal(repr(h), object.__repr__(h))
227 nt.assert_equal(repr(h), object.__repr__(h))
226 h._show_mem_addr = False
228 h._show_mem_addr = False
227 nt.assert_equal(repr(h), '<IPython.core.display.HTML object>')
229 nt.assert_equal(repr(h), '<IPython.core.display.HTML object>')
228
230
229 j = display.Javascript('')
231 j = display.Javascript('')
230 nt.assert_equal(repr(j), '<IPython.core.display.Javascript object>')
232 nt.assert_equal(repr(j), '<IPython.core.display.Javascript object>')
231 j._show_mem_addr = True
233 j._show_mem_addr = True
232 nt.assert_equal(repr(j), object.__repr__(j))
234 nt.assert_equal(repr(j), object.__repr__(j))
233 j._show_mem_addr = False
235 j._show_mem_addr = False
234 nt.assert_equal(repr(j), '<IPython.core.display.Javascript object>')
236 nt.assert_equal(repr(j), '<IPython.core.display.Javascript object>')
235
237
236 @mock.patch('warnings.warn')
238 @mock.patch('warnings.warn')
237 def test_encourage_iframe_over_html(m_warn):
239 def test_encourage_iframe_over_html(m_warn):
238 display.HTML()
240 display.HTML()
239 m_warn.assert_not_called()
241 m_warn.assert_not_called()
240
242
241 display.HTML('<br />')
243 display.HTML('<br />')
242 m_warn.assert_not_called()
244 m_warn.assert_not_called()
243
245
244 display.HTML('<html><p>Lots of content here</p><iframe src="http://a.com"></iframe>')
246 display.HTML('<html><p>Lots of content here</p><iframe src="http://a.com"></iframe>')
245 m_warn.assert_not_called()
247 m_warn.assert_not_called()
246
248
247 display.HTML('<iframe src="http://a.com"></iframe>')
249 display.HTML('<iframe src="http://a.com"></iframe>')
248 m_warn.assert_called_with('Consider using IPython.display.IFrame instead')
250 m_warn.assert_called_with('Consider using IPython.display.IFrame instead')
249
251
250 m_warn.reset_mock()
252 m_warn.reset_mock()
251 display.HTML('<IFRAME SRC="http://a.com"></IFRAME>')
253 display.HTML('<IFRAME SRC="http://a.com"></IFRAME>')
252 m_warn.assert_called_with('Consider using IPython.display.IFrame instead')
254 m_warn.assert_called_with('Consider using IPython.display.IFrame instead')
253
255
254 def test_progress():
256 def test_progress():
255 p = display.ProgressBar(10)
257 p = display.ProgressBar(10)
256 nt.assert_in('0/10',repr(p))
258 nt.assert_in('0/10',repr(p))
257 p.html_width = '100%'
259 p.html_width = '100%'
258 p.progress = 5
260 p.progress = 5
259 nt.assert_equal(p._repr_html_(), "<progress style='width:100%' max='10' value='5'></progress>")
261 nt.assert_equal(p._repr_html_(), "<progress style='width:100%' max='10' value='5'></progress>")
260
262
261 def test_progress_iter():
263 def test_progress_iter():
262 with capture_output(display=False) as captured:
264 with capture_output(display=False) as captured:
263 for i in display.ProgressBar(5):
265 for i in display.ProgressBar(5):
264 out = captured.stdout
266 out = captured.stdout
265 nt.assert_in('{0}/5'.format(i), out)
267 nt.assert_in('{0}/5'.format(i), out)
266 out = captured.stdout
268 out = captured.stdout
267 nt.assert_in('5/5', out)
269 nt.assert_in('5/5', out)
268
270
269 def test_json():
271 def test_json():
270 d = {'a': 5}
272 d = {'a': 5}
271 lis = [d]
273 lis = [d]
272 metadata = [
274 metadata = [
273 {'expanded': False, 'root': 'root'},
275 {'expanded': False, 'root': 'root'},
274 {'expanded': True, 'root': 'root'},
276 {'expanded': True, 'root': 'root'},
275 {'expanded': False, 'root': 'custom'},
277 {'expanded': False, 'root': 'custom'},
276 {'expanded': True, 'root': 'custom'},
278 {'expanded': True, 'root': 'custom'},
277 ]
279 ]
278 json_objs = [
280 json_objs = [
279 display.JSON(d),
281 display.JSON(d),
280 display.JSON(d, expanded=True),
282 display.JSON(d, expanded=True),
281 display.JSON(d, root='custom'),
283 display.JSON(d, root='custom'),
282 display.JSON(d, expanded=True, root='custom'),
284 display.JSON(d, expanded=True, root='custom'),
283 ]
285 ]
284 for j, md in zip(json_objs, metadata):
286 for j, md in zip(json_objs, metadata):
285 nt.assert_equal(j._repr_json_(), (d, md))
287 nt.assert_equal(j._repr_json_(), (d, md))
286
288
287 with warnings.catch_warnings(record=True) as w:
289 with warnings.catch_warnings(record=True) as w:
288 warnings.simplefilter("always")
290 warnings.simplefilter("always")
289 j = display.JSON(json.dumps(d))
291 j = display.JSON(json.dumps(d))
290 nt.assert_equal(len(w), 1)
292 nt.assert_equal(len(w), 1)
291 nt.assert_equal(j._repr_json_(), (d, metadata[0]))
293 nt.assert_equal(j._repr_json_(), (d, metadata[0]))
292
294
293 json_objs = [
295 json_objs = [
294 display.JSON(lis),
296 display.JSON(lis),
295 display.JSON(lis, expanded=True),
297 display.JSON(lis, expanded=True),
296 display.JSON(lis, root='custom'),
298 display.JSON(lis, root='custom'),
297 display.JSON(lis, expanded=True, root='custom'),
299 display.JSON(lis, expanded=True, root='custom'),
298 ]
300 ]
299 for j, md in zip(json_objs, metadata):
301 for j, md in zip(json_objs, metadata):
300 nt.assert_equal(j._repr_json_(), (lis, md))
302 nt.assert_equal(j._repr_json_(), (lis, md))
301
303
302 with warnings.catch_warnings(record=True) as w:
304 with warnings.catch_warnings(record=True) as w:
303 warnings.simplefilter("always")
305 warnings.simplefilter("always")
304 j = display.JSON(json.dumps(lis))
306 j = display.JSON(json.dumps(lis))
305 nt.assert_equal(len(w), 1)
307 nt.assert_equal(len(w), 1)
306 nt.assert_equal(j._repr_json_(), (lis, metadata[0]))
308 nt.assert_equal(j._repr_json_(), (lis, metadata[0]))
307
309
308 def test_video_embedding():
310 def test_video_embedding():
309 """use a tempfile, with dummy-data, to ensure that video embedding doesn't crash"""
311 """use a tempfile, with dummy-data, to ensure that video embedding doesn't crash"""
310 v = display.Video("http://ignored")
312 v = display.Video("http://ignored")
311 assert not v.embed
313 assert not v.embed
312 html = v._repr_html_()
314 html = v._repr_html_()
313 nt.assert_not_in('src="data:', html)
315 nt.assert_not_in('src="data:', html)
314 nt.assert_in('src="http://ignored"', html)
316 nt.assert_in('src="http://ignored"', html)
315
317
316 with nt.assert_raises(ValueError):
318 with nt.assert_raises(ValueError):
317 v = display.Video(b'abc')
319 v = display.Video(b'abc')
318
320
319 with NamedFileInTemporaryDirectory('test.mp4') as f:
321 with NamedFileInTemporaryDirectory('test.mp4') as f:
320 f.write(b'abc')
322 f.write(b'abc')
321 f.close()
323 f.close()
322
324
323 v = display.Video(f.name)
325 v = display.Video(f.name)
324 assert not v.embed
326 assert not v.embed
325 html = v._repr_html_()
327 html = v._repr_html_()
326 nt.assert_not_in('src="data:', html)
328 nt.assert_not_in('src="data:', html)
327
329
328 v = display.Video(f.name, embed=True)
330 v = display.Video(f.name, embed=True)
329 html = v._repr_html_()
331 html = v._repr_html_()
330 nt.assert_in('src="data:video/mp4;base64,YWJj"',html)
332 nt.assert_in('src="data:video/mp4;base64,YWJj"',html)
331
333
332 v = display.Video(f.name, embed=True, mimetype='video/other')
334 v = display.Video(f.name, embed=True, mimetype='video/other')
333 html = v._repr_html_()
335 html = v._repr_html_()
334 nt.assert_in('src="data:video/other;base64,YWJj"',html)
336 nt.assert_in('src="data:video/other;base64,YWJj"',html)
335
337
336 v = display.Video(b'abc', embed=True, mimetype='video/mp4')
338 v = display.Video(b'abc', embed=True, mimetype='video/mp4')
337 html = v._repr_html_()
339 html = v._repr_html_()
338 nt.assert_in('src="data:video/mp4;base64,YWJj"',html)
340 nt.assert_in('src="data:video/mp4;base64,YWJj"',html)
339
341
340 v = display.Video(u'YWJj', embed=True, mimetype='video/xyz')
342 v = display.Video(u'YWJj', embed=True, mimetype='video/xyz')
341 html = v._repr_html_()
343 html = v._repr_html_()
342 nt.assert_in('src="data:video/xyz;base64,YWJj"',html)
344 nt.assert_in('src="data:video/xyz;base64,YWJj"',html)
343
345
344 def test_html_metadata():
346 def test_html_metadata():
345 s = "<h1>Test</h1>"
347 s = "<h1>Test</h1>"
346 h = display.HTML(s, metadata={"isolated": True})
348 h = display.HTML(s, metadata={"isolated": True})
347 nt.assert_equal(h._repr_html_(), (s, {"isolated": True}))
349 nt.assert_equal(h._repr_html_(), (s, {"isolated": True}))
348
350
349 def test_display_id():
351 def test_display_id():
350 ip = get_ipython()
352 ip = get_ipython()
351 with mock.patch.object(ip.display_pub, 'publish') as pub:
353 with mock.patch.object(ip.display_pub, 'publish') as pub:
352 handle = display.display('x')
354 handle = display.display('x')
353 nt.assert_is(handle, None)
355 nt.assert_is(handle, None)
354 handle = display.display('y', display_id='secret')
356 handle = display.display('y', display_id='secret')
355 nt.assert_is_instance(handle, display.DisplayHandle)
357 nt.assert_is_instance(handle, display.DisplayHandle)
356 handle2 = display.display('z', display_id=True)
358 handle2 = display.display('z', display_id=True)
357 nt.assert_is_instance(handle2, display.DisplayHandle)
359 nt.assert_is_instance(handle2, display.DisplayHandle)
358 nt.assert_not_equal(handle.display_id, handle2.display_id)
360 nt.assert_not_equal(handle.display_id, handle2.display_id)
359
361
360 nt.assert_equal(pub.call_count, 3)
362 nt.assert_equal(pub.call_count, 3)
361 args, kwargs = pub.call_args_list[0]
363 args, kwargs = pub.call_args_list[0]
362 nt.assert_equal(args, ())
364 nt.assert_equal(args, ())
363 nt.assert_equal(kwargs, {
365 nt.assert_equal(kwargs, {
364 'data': {
366 'data': {
365 'text/plain': repr('x')
367 'text/plain': repr('x')
366 },
368 },
367 'metadata': {},
369 'metadata': {},
368 })
370 })
369 args, kwargs = pub.call_args_list[1]
371 args, kwargs = pub.call_args_list[1]
370 nt.assert_equal(args, ())
372 nt.assert_equal(args, ())
371 nt.assert_equal(kwargs, {
373 nt.assert_equal(kwargs, {
372 'data': {
374 'data': {
373 'text/plain': repr('y')
375 'text/plain': repr('y')
374 },
376 },
375 'metadata': {},
377 'metadata': {},
376 'transient': {
378 'transient': {
377 'display_id': handle.display_id,
379 'display_id': handle.display_id,
378 },
380 },
379 })
381 })
380 args, kwargs = pub.call_args_list[2]
382 args, kwargs = pub.call_args_list[2]
381 nt.assert_equal(args, ())
383 nt.assert_equal(args, ())
382 nt.assert_equal(kwargs, {
384 nt.assert_equal(kwargs, {
383 'data': {
385 'data': {
384 'text/plain': repr('z')
386 'text/plain': repr('z')
385 },
387 },
386 'metadata': {},
388 'metadata': {},
387 'transient': {
389 'transient': {
388 'display_id': handle2.display_id,
390 'display_id': handle2.display_id,
389 },
391 },
390 })
392 })
391
393
392
394
393 def test_update_display():
395 def test_update_display():
394 ip = get_ipython()
396 ip = get_ipython()
395 with mock.patch.object(ip.display_pub, 'publish') as pub:
397 with mock.patch.object(ip.display_pub, 'publish') as pub:
396 with nt.assert_raises(TypeError):
398 with nt.assert_raises(TypeError):
397 display.update_display('x')
399 display.update_display('x')
398 display.update_display('x', display_id='1')
400 display.update_display('x', display_id='1')
399 display.update_display('y', display_id='2')
401 display.update_display('y', display_id='2')
400 args, kwargs = pub.call_args_list[0]
402 args, kwargs = pub.call_args_list[0]
401 nt.assert_equal(args, ())
403 nt.assert_equal(args, ())
402 nt.assert_equal(kwargs, {
404 nt.assert_equal(kwargs, {
403 'data': {
405 'data': {
404 'text/plain': repr('x')
406 'text/plain': repr('x')
405 },
407 },
406 'metadata': {},
408 'metadata': {},
407 'transient': {
409 'transient': {
408 'display_id': '1',
410 'display_id': '1',
409 },
411 },
410 'update': True,
412 'update': True,
411 })
413 })
412 args, kwargs = pub.call_args_list[1]
414 args, kwargs = pub.call_args_list[1]
413 nt.assert_equal(args, ())
415 nt.assert_equal(args, ())
414 nt.assert_equal(kwargs, {
416 nt.assert_equal(kwargs, {
415 'data': {
417 'data': {
416 'text/plain': repr('y')
418 'text/plain': repr('y')
417 },
419 },
418 'metadata': {},
420 'metadata': {},
419 'transient': {
421 'transient': {
420 'display_id': '2',
422 'display_id': '2',
421 },
423 },
422 'update': True,
424 'update': True,
423 })
425 })
424
426
425
427
426 def test_display_handle():
428 def test_display_handle():
427 ip = get_ipython()
429 ip = get_ipython()
428 handle = display.DisplayHandle()
430 handle = display.DisplayHandle()
429 nt.assert_is_instance(handle.display_id, str)
431 nt.assert_is_instance(handle.display_id, str)
430 handle = display.DisplayHandle('my-id')
432 handle = display.DisplayHandle('my-id')
431 nt.assert_equal(handle.display_id, 'my-id')
433 nt.assert_equal(handle.display_id, 'my-id')
432 with mock.patch.object(ip.display_pub, 'publish') as pub:
434 with mock.patch.object(ip.display_pub, 'publish') as pub:
433 handle.display('x')
435 handle.display('x')
434 handle.update('y')
436 handle.update('y')
435
437
436 args, kwargs = pub.call_args_list[0]
438 args, kwargs = pub.call_args_list[0]
437 nt.assert_equal(args, ())
439 nt.assert_equal(args, ())
438 nt.assert_equal(kwargs, {
440 nt.assert_equal(kwargs, {
439 'data': {
441 'data': {
440 'text/plain': repr('x')
442 'text/plain': repr('x')
441 },
443 },
442 'metadata': {},
444 'metadata': {},
443 'transient': {
445 'transient': {
444 'display_id': handle.display_id,
446 'display_id': handle.display_id,
445 }
447 }
446 })
448 })
447 args, kwargs = pub.call_args_list[1]
449 args, kwargs = pub.call_args_list[1]
448 nt.assert_equal(args, ())
450 nt.assert_equal(args, ())
449 nt.assert_equal(kwargs, {
451 nt.assert_equal(kwargs, {
450 'data': {
452 'data': {
451 'text/plain': repr('y')
453 'text/plain': repr('y')
452 },
454 },
453 'metadata': {},
455 'metadata': {},
454 'transient': {
456 'transient': {
455 'display_id': handle.display_id,
457 'display_id': handle.display_id,
456 },
458 },
457 'update': True,
459 'update': True,
458 })
460 })
459
461
@@ -1,259 +1,265 b''
1 """Tests for pylab tools module.
1 """Tests for pylab tools module.
2 """
2 """
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
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')
12 from matplotlib.figure import Figure
13 from matplotlib.figure import Figure
13
14
14 from nose import SkipTest
15 from nose import SkipTest
15 import nose.tools as nt
16 import nose.tools as nt
16
17
17 from matplotlib import pyplot as plt
18 from matplotlib import pyplot as plt
18 import matplotlib_inline
19 import matplotlib_inline
19 import numpy as np
20 import numpy as np
20
21
21 from IPython.core.getipython import get_ipython
22 from IPython.core.getipython import get_ipython
22 from IPython.core.interactiveshell import InteractiveShell
23 from IPython.core.interactiveshell import InteractiveShell
23 from IPython.core.display import _PNG, _JPEG
24 from IPython.core.display import _PNG, _JPEG
24 from .. import pylabtools as pt
25 from .. import pylabtools as pt
25
26
26 from IPython.testing import decorators as dec
27 from IPython.testing import decorators as dec
27
28
28
29
29 def test_figure_to_svg():
30 def test_figure_to_svg():
30 # simple empty-figure test
31 # simple empty-figure test
31 fig = plt.figure()
32 fig = plt.figure()
32 nt.assert_equal(pt.print_figure(fig, 'svg'), None)
33 nt.assert_equal(pt.print_figure(fig, 'svg'), None)
33
34
34 plt.close('all')
35 plt.close('all')
35
36
36 # simple check for at least svg-looking output
37 # simple check for at least svg-looking output
37 fig = plt.figure()
38 fig = plt.figure()
38 ax = fig.add_subplot(1,1,1)
39 ax = fig.add_subplot(1,1,1)
39 ax.plot([1,2,3])
40 ax.plot([1,2,3])
40 plt.draw()
41 plt.draw()
41 svg = pt.print_figure(fig, 'svg')[:100].lower()
42 svg = pt.print_figure(fig, 'svg')[:100].lower()
42 nt.assert_in(u'doctype svg', svg)
43 nt.assert_in(u'doctype svg', svg)
43
44
44 def _check_pil_jpeg_bytes():
45 def _check_pil_jpeg_bytes():
45 """Skip if PIL can't write JPEGs to BytesIO objects"""
46 """Skip if PIL can't write JPEGs to BytesIO objects"""
46 # PIL's JPEG plugin can't write to BytesIO objects
47 # PIL's JPEG plugin can't write to BytesIO objects
47 # Pillow fixes this
48 # Pillow fixes this
48 from PIL import Image
49 from PIL import Image
49 buf = BytesIO()
50 buf = BytesIO()
50 img = Image.new("RGB", (4,4))
51 img = Image.new("RGB", (4,4))
51 try:
52 try:
52 img.save(buf, 'jpeg')
53 img.save(buf, 'jpeg')
53 except Exception as e:
54 except Exception as e:
54 ename = e.__class__.__name__
55 ename = e.__class__.__name__
55 raise SkipTest("PIL can't write JPEG to BytesIO: %s: %s" % (ename, e))
56 raise SkipTest("PIL can't write JPEG to BytesIO: %s: %s" % (ename, e))
56
57
57 @dec.skip_without("PIL.Image")
58 @dec.skip_without("PIL.Image")
58 def test_figure_to_jpeg():
59 def test_figure_to_jpeg():
59 _check_pil_jpeg_bytes()
60 _check_pil_jpeg_bytes()
60 # simple check for at least jpeg-looking output
61 # simple check for at least jpeg-looking output
61 fig = plt.figure()
62 fig = plt.figure()
62 ax = fig.add_subplot(1,1,1)
63 ax = fig.add_subplot(1,1,1)
63 ax.plot([1,2,3])
64 ax.plot([1,2,3])
64 plt.draw()
65 plt.draw()
65 jpeg = pt.print_figure(fig, 'jpeg', pil_kwargs={'optimize': 50})[:100].lower()
66 jpeg = pt.print_figure(fig, 'jpeg', pil_kwargs={'optimize': 50})[:100].lower()
66 assert jpeg.startswith(_JPEG)
67 assert jpeg.startswith(_JPEG)
67
68
68 def test_retina_figure():
69 def test_retina_figure():
69 # simple empty-figure test
70 # simple empty-figure test
70 fig = plt.figure()
71 fig = plt.figure()
71 nt.assert_equal(pt.retina_figure(fig), None)
72 nt.assert_equal(pt.retina_figure(fig), None)
72 plt.close('all')
73 plt.close('all')
73
74
74 fig = plt.figure()
75 fig = plt.figure()
75 ax = fig.add_subplot(1,1,1)
76 ax = fig.add_subplot(1,1,1)
76 ax.plot([1,2,3])
77 ax.plot([1,2,3])
77 plt.draw()
78 plt.draw()
78 png, md = pt.retina_figure(fig)
79 png, md = pt.retina_figure(fig)
79 assert png.startswith(_PNG)
80 assert png.startswith(_PNG)
80 nt.assert_in('width', md)
81 nt.assert_in('width', md)
81 nt.assert_in('height', md)
82 nt.assert_in('height', md)
82
83
83 _fmt_mime_map = {
84 _fmt_mime_map = {
84 'png': 'image/png',
85 'png': 'image/png',
85 'jpeg': 'image/jpeg',
86 'jpeg': 'image/jpeg',
86 'pdf': 'application/pdf',
87 'pdf': 'application/pdf',
87 'retina': 'image/png',
88 'retina': 'image/png',
88 'svg': 'image/svg+xml',
89 'svg': 'image/svg+xml',
89 }
90 }
90
91
91 def test_select_figure_formats_str():
92 def test_select_figure_formats_str():
92 ip = get_ipython()
93 ip = get_ipython()
93 for fmt, active_mime in _fmt_mime_map.items():
94 for fmt, active_mime in _fmt_mime_map.items():
94 pt.select_figure_formats(ip, fmt)
95 pt.select_figure_formats(ip, fmt)
95 for mime, f in ip.display_formatter.formatters.items():
96 for mime, f in ip.display_formatter.formatters.items():
96 if mime == active_mime:
97 if mime == active_mime:
97 nt.assert_in(Figure, f)
98 nt.assert_in(Figure, f)
98 else:
99 else:
99 nt.assert_not_in(Figure, f)
100 nt.assert_not_in(Figure, f)
100
101
101 def test_select_figure_formats_kwargs():
102 def test_select_figure_formats_kwargs():
102 ip = get_ipython()
103 ip = get_ipython()
103 kwargs = dict(quality=10, bbox_inches='tight')
104 kwargs = dict(quality=10, bbox_inches='tight')
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()
112 ax = fig.add_subplot(1,1,1)
116 ax = fig.add_subplot(1,1,1)
113 ax.plot([1,2,3])
117 ax.plot([1,2,3])
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()
121 for fmts in [
127 for fmts in [
122 {'png', 'svg'},
128 {'png', 'svg'},
123 ['png'],
129 ['png'],
124 ('jpeg', 'pdf', 'retina'),
130 ('jpeg', 'pdf', 'retina'),
125 {'svg'},
131 {'svg'},
126 ]:
132 ]:
127 active_mimes = {_fmt_mime_map[fmt] for fmt in fmts}
133 active_mimes = {_fmt_mime_map[fmt] for fmt in fmts}
128 pt.select_figure_formats(ip, fmts)
134 pt.select_figure_formats(ip, fmts)
129 for mime, f in ip.display_formatter.formatters.items():
135 for mime, f in ip.display_formatter.formatters.items():
130 if mime in active_mimes:
136 if mime in active_mimes:
131 nt.assert_in(Figure, f)
137 nt.assert_in(Figure, f)
132 else:
138 else:
133 nt.assert_not_in(Figure, f)
139 nt.assert_not_in(Figure, f)
134
140
135 def test_select_figure_formats_bad():
141 def test_select_figure_formats_bad():
136 ip = get_ipython()
142 ip = get_ipython()
137 with nt.assert_raises(ValueError):
143 with nt.assert_raises(ValueError):
138 pt.select_figure_formats(ip, 'foo')
144 pt.select_figure_formats(ip, 'foo')
139 with nt.assert_raises(ValueError):
145 with nt.assert_raises(ValueError):
140 pt.select_figure_formats(ip, {'png', 'foo'})
146 pt.select_figure_formats(ip, {'png', 'foo'})
141 with nt.assert_raises(ValueError):
147 with nt.assert_raises(ValueError):
142 pt.select_figure_formats(ip, ['retina', 'pdf', 'bar', 'bad'])
148 pt.select_figure_formats(ip, ['retina', 'pdf', 'bar', 'bad'])
143
149
144 def test_import_pylab():
150 def test_import_pylab():
145 ns = {}
151 ns = {}
146 pt.import_pylab(ns, import_all=False)
152 pt.import_pylab(ns, import_all=False)
147 nt.assert_true('plt' in ns)
153 nt.assert_true('plt' in ns)
148 nt.assert_equal(ns['np'], np)
154 nt.assert_equal(ns['np'], np)
149
155
150 class TestPylabSwitch(object):
156 class TestPylabSwitch(object):
151 class Shell(InteractiveShell):
157 class Shell(InteractiveShell):
152 def enable_gui(self, gui):
158 def enable_gui(self, gui):
153 pass
159 pass
154
160
155 def setup(self):
161 def setup(self):
156 import matplotlib
162 import matplotlib
157 def act_mpl(backend):
163 def act_mpl(backend):
158 matplotlib.rcParams['backend'] = backend
164 matplotlib.rcParams['backend'] = backend
159
165
160 # Save rcParams since they get modified
166 # Save rcParams since they get modified
161 self._saved_rcParams = matplotlib.rcParams
167 self._saved_rcParams = matplotlib.rcParams
162 self._saved_rcParamsOrig = matplotlib.rcParamsOrig
168 self._saved_rcParamsOrig = matplotlib.rcParamsOrig
163 matplotlib.rcParams = dict(backend='Qt4Agg')
169 matplotlib.rcParams = dict(backend='Qt4Agg')
164 matplotlib.rcParamsOrig = dict(backend='Qt4Agg')
170 matplotlib.rcParamsOrig = dict(backend='Qt4Agg')
165
171
166 # Mock out functions
172 # Mock out functions
167 self._save_am = pt.activate_matplotlib
173 self._save_am = pt.activate_matplotlib
168 pt.activate_matplotlib = act_mpl
174 pt.activate_matplotlib = act_mpl
169 self._save_ip = pt.import_pylab
175 self._save_ip = pt.import_pylab
170 pt.import_pylab = lambda *a,**kw:None
176 pt.import_pylab = lambda *a,**kw:None
171 self._save_cis = matplotlib_inline.backend_inline.configure_inline_support
177 self._save_cis = matplotlib_inline.backend_inline.configure_inline_support
172 matplotlib_inline.backend_inline.configure_inline_support = (
178 matplotlib_inline.backend_inline.configure_inline_support = (
173 lambda *a, **kw: None
179 lambda *a, **kw: None
174 )
180 )
175
181
176 def teardown(self):
182 def teardown(self):
177 pt.activate_matplotlib = self._save_am
183 pt.activate_matplotlib = self._save_am
178 pt.import_pylab = self._save_ip
184 pt.import_pylab = self._save_ip
179 matplotlib_inline.backend_inline.configure_inline_support = self._save_cis
185 matplotlib_inline.backend_inline.configure_inline_support = self._save_cis
180 import matplotlib
186 import matplotlib
181 matplotlib.rcParams = self._saved_rcParams
187 matplotlib.rcParams = self._saved_rcParams
182 matplotlib.rcParamsOrig = self._saved_rcParamsOrig
188 matplotlib.rcParamsOrig = self._saved_rcParamsOrig
183
189
184 def test_qt(self):
190 def test_qt(self):
185 s = self.Shell()
191 s = self.Shell()
186 gui, backend = s.enable_matplotlib(None)
192 gui, backend = s.enable_matplotlib(None)
187 nt.assert_equal(gui, 'qt')
193 nt.assert_equal(gui, 'qt')
188 nt.assert_equal(s.pylab_gui_select, 'qt')
194 nt.assert_equal(s.pylab_gui_select, 'qt')
189
195
190 gui, backend = s.enable_matplotlib('inline')
196 gui, backend = s.enable_matplotlib('inline')
191 nt.assert_equal(gui, 'inline')
197 nt.assert_equal(gui, 'inline')
192 nt.assert_equal(s.pylab_gui_select, 'qt')
198 nt.assert_equal(s.pylab_gui_select, 'qt')
193
199
194 gui, backend = s.enable_matplotlib('qt')
200 gui, backend = s.enable_matplotlib('qt')
195 nt.assert_equal(gui, 'qt')
201 nt.assert_equal(gui, 'qt')
196 nt.assert_equal(s.pylab_gui_select, 'qt')
202 nt.assert_equal(s.pylab_gui_select, 'qt')
197
203
198 gui, backend = s.enable_matplotlib('inline')
204 gui, backend = s.enable_matplotlib('inline')
199 nt.assert_equal(gui, 'inline')
205 nt.assert_equal(gui, 'inline')
200 nt.assert_equal(s.pylab_gui_select, 'qt')
206 nt.assert_equal(s.pylab_gui_select, 'qt')
201
207
202 gui, backend = s.enable_matplotlib()
208 gui, backend = s.enable_matplotlib()
203 nt.assert_equal(gui, 'qt')
209 nt.assert_equal(gui, 'qt')
204 nt.assert_equal(s.pylab_gui_select, 'qt')
210 nt.assert_equal(s.pylab_gui_select, 'qt')
205
211
206 def test_inline(self):
212 def test_inline(self):
207 s = self.Shell()
213 s = self.Shell()
208 gui, backend = s.enable_matplotlib('inline')
214 gui, backend = s.enable_matplotlib('inline')
209 nt.assert_equal(gui, 'inline')
215 nt.assert_equal(gui, 'inline')
210 nt.assert_equal(s.pylab_gui_select, None)
216 nt.assert_equal(s.pylab_gui_select, None)
211
217
212 gui, backend = s.enable_matplotlib('inline')
218 gui, backend = s.enable_matplotlib('inline')
213 nt.assert_equal(gui, 'inline')
219 nt.assert_equal(gui, 'inline')
214 nt.assert_equal(s.pylab_gui_select, None)
220 nt.assert_equal(s.pylab_gui_select, None)
215
221
216 gui, backend = s.enable_matplotlib('qt')
222 gui, backend = s.enable_matplotlib('qt')
217 nt.assert_equal(gui, 'qt')
223 nt.assert_equal(gui, 'qt')
218 nt.assert_equal(s.pylab_gui_select, 'qt')
224 nt.assert_equal(s.pylab_gui_select, 'qt')
219
225
220 def test_inline_twice(self):
226 def test_inline_twice(self):
221 "Using '%matplotlib inline' twice should not reset formatters"
227 "Using '%matplotlib inline' twice should not reset formatters"
222
228
223 ip = self.Shell()
229 ip = self.Shell()
224 gui, backend = ip.enable_matplotlib('inline')
230 gui, backend = ip.enable_matplotlib('inline')
225 nt.assert_equal(gui, 'inline')
231 nt.assert_equal(gui, 'inline')
226
232
227 fmts = {'png'}
233 fmts = {'png'}
228 active_mimes = {_fmt_mime_map[fmt] for fmt in fmts}
234 active_mimes = {_fmt_mime_map[fmt] for fmt in fmts}
229 pt.select_figure_formats(ip, fmts)
235 pt.select_figure_formats(ip, fmts)
230
236
231 gui, backend = ip.enable_matplotlib('inline')
237 gui, backend = ip.enable_matplotlib('inline')
232 nt.assert_equal(gui, 'inline')
238 nt.assert_equal(gui, 'inline')
233
239
234 for mime, f in ip.display_formatter.formatters.items():
240 for mime, f in ip.display_formatter.formatters.items():
235 if mime in active_mimes:
241 if mime in active_mimes:
236 nt.assert_in(Figure, f)
242 nt.assert_in(Figure, f)
237 else:
243 else:
238 nt.assert_not_in(Figure, f)
244 nt.assert_not_in(Figure, f)
239
245
240 def test_qt_gtk(self):
246 def test_qt_gtk(self):
241 s = self.Shell()
247 s = self.Shell()
242 gui, backend = s.enable_matplotlib('qt')
248 gui, backend = s.enable_matplotlib('qt')
243 nt.assert_equal(gui, 'qt')
249 nt.assert_equal(gui, 'qt')
244 nt.assert_equal(s.pylab_gui_select, 'qt')
250 nt.assert_equal(s.pylab_gui_select, 'qt')
245
251
246 gui, backend = s.enable_matplotlib('gtk')
252 gui, backend = s.enable_matplotlib('gtk')
247 nt.assert_equal(gui, 'qt')
253 nt.assert_equal(gui, 'qt')
248 nt.assert_equal(s.pylab_gui_select, 'qt')
254 nt.assert_equal(s.pylab_gui_select, 'qt')
249
255
250
256
251 def test_no_gui_backends():
257 def test_no_gui_backends():
252 for k in ['agg', 'svg', 'pdf', 'ps']:
258 for k in ['agg', 'svg', 'pdf', 'ps']:
253 assert k not in pt.backend2gui
259 assert k not in pt.backend2gui
254
260
255
261
256 def test_figure_no_canvas():
262 def test_figure_no_canvas():
257 fig = Figure()
263 fig = Figure()
258 fig.canvas = None
264 fig.canvas = None
259 pt.print_figure(fig)
265 pt.print_figure(fig)
General Comments 0
You need to be logged in to leave comments. Login now