##// END OF EJS Templates
print_figure returns unicode for svg
MinRK -
Show More
@@ -1,376 +1,382 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Pylab (matplotlib) support utilities.
2 """Pylab (matplotlib) support utilities.
3
3
4 Authors
4 Authors
5 -------
5 -------
6
6
7 * Fernando Perez.
7 * Fernando Perez.
8 * Brian Granger
8 * Brian Granger
9 """
9 """
10 from __future__ import print_function
10 from __future__ import print_function
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Copyright (C) 2009 The IPython Development Team
13 # Copyright (C) 2009 The IPython Development Team
14 #
14 #
15 # Distributed under the terms of the BSD License. The full license is in
15 # Distributed under the terms of the BSD License. The full license is in
16 # the file COPYING, distributed as part of this software.
16 # the file COPYING, distributed as part of this software.
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Imports
20 # Imports
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22
22
23 import sys
23 import sys
24 from io import BytesIO
24 from io import BytesIO
25
25
26 from IPython.core.display import _pngxy
26 from IPython.core.display import _pngxy
27 from IPython.utils.decorators import flag_calls
27 from IPython.utils.decorators import flag_calls
28 from IPython.utils import py3compat
28 from IPython.utils import py3compat
29
29
30 # If user specifies a GUI, that dictates the backend, otherwise we read the
30 # If user specifies a GUI, that dictates the backend, otherwise we read the
31 # user's mpl default from the mpl rc structure
31 # user's mpl default from the mpl rc structure
32 backends = {'tk': 'TkAgg',
32 backends = {'tk': 'TkAgg',
33 'gtk': 'GTKAgg',
33 'gtk': 'GTKAgg',
34 'gtk3': 'GTK3Agg',
34 'gtk3': 'GTK3Agg',
35 'wx': 'WXAgg',
35 'wx': 'WXAgg',
36 'qt': 'Qt4Agg', # qt3 not supported
36 'qt': 'Qt4Agg', # qt3 not supported
37 'qt4': 'Qt4Agg',
37 'qt4': 'Qt4Agg',
38 'osx': 'MacOSX',
38 'osx': 'MacOSX',
39 'inline' : 'module://IPython.kernel.zmq.pylab.backend_inline'}
39 'inline' : 'module://IPython.kernel.zmq.pylab.backend_inline'}
40
40
41 # We also need a reverse backends2guis mapping that will properly choose which
41 # We also need a reverse backends2guis mapping that will properly choose which
42 # GUI support to activate based on the desired matplotlib backend. For the
42 # GUI support to activate based on the desired matplotlib backend. For the
43 # most part it's just a reverse of the above dict, but we also need to add a
43 # most part it's just a reverse of the above dict, but we also need to add a
44 # few others that map to the same GUI manually:
44 # few others that map to the same GUI manually:
45 backend2gui = dict(zip(backends.values(), backends.keys()))
45 backend2gui = dict(zip(backends.values(), backends.keys()))
46 # Our tests expect backend2gui to just return 'qt'
46 # Our tests expect backend2gui to just return 'qt'
47 backend2gui['Qt4Agg'] = 'qt'
47 backend2gui['Qt4Agg'] = 'qt'
48 # In the reverse mapping, there are a few extra valid matplotlib backends that
48 # In the reverse mapping, there are a few extra valid matplotlib backends that
49 # map to the same GUI support
49 # map to the same GUI support
50 backend2gui['GTK'] = backend2gui['GTKCairo'] = 'gtk'
50 backend2gui['GTK'] = backend2gui['GTKCairo'] = 'gtk'
51 backend2gui['GTK3Cairo'] = 'gtk3'
51 backend2gui['GTK3Cairo'] = 'gtk3'
52 backend2gui['WX'] = 'wx'
52 backend2gui['WX'] = 'wx'
53 backend2gui['CocoaAgg'] = 'osx'
53 backend2gui['CocoaAgg'] = 'osx'
54
54
55 #-----------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
56 # Matplotlib utilities
56 # Matplotlib utilities
57 #-----------------------------------------------------------------------------
57 #-----------------------------------------------------------------------------
58
58
59
59
60 def getfigs(*fig_nums):
60 def getfigs(*fig_nums):
61 """Get a list of matplotlib figures by figure numbers.
61 """Get a list of matplotlib figures by figure numbers.
62
62
63 If no arguments are given, all available figures are returned. If the
63 If no arguments are given, all available figures are returned. If the
64 argument list contains references to invalid figures, a warning is printed
64 argument list contains references to invalid figures, a warning is printed
65 but the function continues pasting further figures.
65 but the function continues pasting further figures.
66
66
67 Parameters
67 Parameters
68 ----------
68 ----------
69 figs : tuple
69 figs : tuple
70 A tuple of ints giving the figure numbers of the figures to return.
70 A tuple of ints giving the figure numbers of the figures to return.
71 """
71 """
72 from matplotlib._pylab_helpers import Gcf
72 from matplotlib._pylab_helpers import Gcf
73 if not fig_nums:
73 if not fig_nums:
74 fig_managers = Gcf.get_all_fig_managers()
74 fig_managers = Gcf.get_all_fig_managers()
75 return [fm.canvas.figure for fm in fig_managers]
75 return [fm.canvas.figure for fm in fig_managers]
76 else:
76 else:
77 figs = []
77 figs = []
78 for num in fig_nums:
78 for num in fig_nums:
79 f = Gcf.figs.get(num)
79 f = Gcf.figs.get(num)
80 if f is None:
80 if f is None:
81 print('Warning: figure %s not available.' % num)
81 print('Warning: figure %s not available.' % num)
82 else:
82 else:
83 figs.append(f.canvas.figure)
83 figs.append(f.canvas.figure)
84 return figs
84 return figs
85
85
86
86
87 def figsize(sizex, sizey):
87 def figsize(sizex, sizey):
88 """Set the default figure size to be [sizex, sizey].
88 """Set the default figure size to be [sizex, sizey].
89
89
90 This is just an easy to remember, convenience wrapper that sets::
90 This is just an easy to remember, convenience wrapper that sets::
91
91
92 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
92 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
93 """
93 """
94 import matplotlib
94 import matplotlib
95 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
95 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
96
96
97
97
98 def print_figure(fig, fmt='png', bbox_inches='tight', **kwargs):
98 def print_figure(fig, fmt='png', bbox_inches='tight', **kwargs):
99 """Print a figure to an image, and return the resulting bytes
99 """Print a figure to an image, and return the resulting file data
100
101 Returned data will be bytes unless ``fmt='svg'``,
102 in which case it will be unicode.
100
103
101 Any keyword args are passed to fig.canvas.print_figure,
104 Any keyword args are passed to fig.canvas.print_figure,
102 such as ``quality`` or ``bbox_inches``.
105 such as ``quality`` or ``bbox_inches``.
103 """
106 """
104 from matplotlib import rcParams
107 from matplotlib import rcParams
105 # When there's an empty figure, we shouldn't return anything, otherwise we
108 # When there's an empty figure, we shouldn't return anything, otherwise we
106 # get big blank areas in the qt console.
109 # get big blank areas in the qt console.
107 if not fig.axes and not fig.lines:
110 if not fig.axes and not fig.lines:
108 return
111 return
109
112
110 dpi = rcParams['savefig.dpi']
113 dpi = rcParams['savefig.dpi']
111 if fmt == 'retina':
114 if fmt == 'retina':
112 dpi = dpi * 2
115 dpi = dpi * 2
113 fmt = 'png'
116 fmt = 'png'
114
117
115 # build keyword args
118 # build keyword args
116 kw = dict(
119 kw = dict(
117 format=fmt,
120 format=fmt,
118 fc=fig.get_facecolor(),
121 fc=fig.get_facecolor(),
119 ec=fig.get_edgecolor(),
122 ec=fig.get_edgecolor(),
120 dpi=dpi,
123 dpi=dpi,
121 bbox_inches=bbox_inches,
124 bbox_inches=bbox_inches,
122 )
125 )
123 # **kwargs get higher priority
126 # **kwargs get higher priority
124 kw.update(kwargs)
127 kw.update(kwargs)
125
128
126 bytes_io = BytesIO()
129 bytes_io = BytesIO()
127 fig.canvas.print_figure(bytes_io, **kw)
130 fig.canvas.print_figure(bytes_io, **kw)
128 return bytes_io.getvalue()
131 data = bytes_io.getvalue()
132 if fmt == 'svg':
133 data = data.decode('utf-8')
134 return data
129
135
130 def retina_figure(fig, **kwargs):
136 def retina_figure(fig, **kwargs):
131 """format a figure as a pixel-doubled (retina) PNG"""
137 """format a figure as a pixel-doubled (retina) PNG"""
132 pngdata = print_figure(fig, fmt='retina', **kwargs)
138 pngdata = print_figure(fig, fmt='retina', **kwargs)
133 w, h = _pngxy(pngdata)
139 w, h = _pngxy(pngdata)
134 metadata = dict(width=w//2, height=h//2)
140 metadata = dict(width=w//2, height=h//2)
135 return pngdata, metadata
141 return pngdata, metadata
136
142
137 # We need a little factory function here to create the closure where
143 # We need a little factory function here to create the closure where
138 # safe_execfile can live.
144 # safe_execfile can live.
139 def mpl_runner(safe_execfile):
145 def mpl_runner(safe_execfile):
140 """Factory to return a matplotlib-enabled runner for %run.
146 """Factory to return a matplotlib-enabled runner for %run.
141
147
142 Parameters
148 Parameters
143 ----------
149 ----------
144 safe_execfile : function
150 safe_execfile : function
145 This must be a function with the same interface as the
151 This must be a function with the same interface as the
146 :meth:`safe_execfile` method of IPython.
152 :meth:`safe_execfile` method of IPython.
147
153
148 Returns
154 Returns
149 -------
155 -------
150 A function suitable for use as the ``runner`` argument of the %run magic
156 A function suitable for use as the ``runner`` argument of the %run magic
151 function.
157 function.
152 """
158 """
153
159
154 def mpl_execfile(fname,*where,**kw):
160 def mpl_execfile(fname,*where,**kw):
155 """matplotlib-aware wrapper around safe_execfile.
161 """matplotlib-aware wrapper around safe_execfile.
156
162
157 Its interface is identical to that of the :func:`execfile` builtin.
163 Its interface is identical to that of the :func:`execfile` builtin.
158
164
159 This is ultimately a call to execfile(), but wrapped in safeties to
165 This is ultimately a call to execfile(), but wrapped in safeties to
160 properly handle interactive rendering."""
166 properly handle interactive rendering."""
161
167
162 import matplotlib
168 import matplotlib
163 import matplotlib.pylab as pylab
169 import matplotlib.pylab as pylab
164
170
165 #print '*** Matplotlib runner ***' # dbg
171 #print '*** Matplotlib runner ***' # dbg
166 # turn off rendering until end of script
172 # turn off rendering until end of script
167 is_interactive = matplotlib.rcParams['interactive']
173 is_interactive = matplotlib.rcParams['interactive']
168 matplotlib.interactive(False)
174 matplotlib.interactive(False)
169 safe_execfile(fname,*where,**kw)
175 safe_execfile(fname,*where,**kw)
170 matplotlib.interactive(is_interactive)
176 matplotlib.interactive(is_interactive)
171 # make rendering call now, if the user tried to do it
177 # make rendering call now, if the user tried to do it
172 if pylab.draw_if_interactive.called:
178 if pylab.draw_if_interactive.called:
173 pylab.draw()
179 pylab.draw()
174 pylab.draw_if_interactive.called = False
180 pylab.draw_if_interactive.called = False
175
181
176 return mpl_execfile
182 return mpl_execfile
177
183
178
184
179 def select_figure_formats(shell, formats, **kwargs):
185 def select_figure_formats(shell, formats, **kwargs):
180 """Select figure formats for the inline backend.
186 """Select figure formats for the inline backend.
181
187
182 Parameters
188 Parameters
183 ==========
189 ==========
184 shell : InteractiveShell
190 shell : InteractiveShell
185 The main IPython instance.
191 The main IPython instance.
186 formats : str or set
192 formats : str or set
187 One or a set of figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
193 One or a set of figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
188 **kwargs : any
194 **kwargs : any
189 Extra keyword arguments to be passed to fig.canvas.print_figure.
195 Extra keyword arguments to be passed to fig.canvas.print_figure.
190 """
196 """
191 from matplotlib.figure import Figure
197 from matplotlib.figure import Figure
192 from IPython.kernel.zmq.pylab import backend_inline
198 from IPython.kernel.zmq.pylab import backend_inline
193
199
194 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
200 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
195 png_formatter = shell.display_formatter.formatters['image/png']
201 png_formatter = shell.display_formatter.formatters['image/png']
196 jpg_formatter = shell.display_formatter.formatters['image/jpeg']
202 jpg_formatter = shell.display_formatter.formatters['image/jpeg']
197 pdf_formatter = shell.display_formatter.formatters['application/pdf']
203 pdf_formatter = shell.display_formatter.formatters['application/pdf']
198
204
199 if isinstance(formats, py3compat.string_types):
205 if isinstance(formats, py3compat.string_types):
200 formats = {formats}
206 formats = {formats}
201 # cast in case of list / tuple
207 # cast in case of list / tuple
202 formats = set(formats)
208 formats = set(formats)
203
209
204 [ f.pop(Figure, None) for f in shell.display_formatter.formatters.values() ]
210 [ f.pop(Figure, None) for f in shell.display_formatter.formatters.values() ]
205
211
206 supported = {'png', 'png2x', 'retina', 'jpg', 'jpeg', 'svg', 'pdf'}
212 supported = {'png', 'png2x', 'retina', 'jpg', 'jpeg', 'svg', 'pdf'}
207 bad = formats.difference(supported)
213 bad = formats.difference(supported)
208 if bad:
214 if bad:
209 bs = "%s" % ','.join([repr(f) for f in bad])
215 bs = "%s" % ','.join([repr(f) for f in bad])
210 gs = "%s" % ','.join([repr(f) for f in supported])
216 gs = "%s" % ','.join([repr(f) for f in supported])
211 raise ValueError("supported formats are: %s not %s" % (gs, bs))
217 raise ValueError("supported formats are: %s not %s" % (gs, bs))
212
218
213 if 'png' in formats:
219 if 'png' in formats:
214 png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png', **kwargs))
220 png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png', **kwargs))
215 if 'retina' in formats or 'png2x' in formats:
221 if 'retina' in formats or 'png2x' in formats:
216 png_formatter.for_type(Figure, lambda fig: retina_figure(fig, **kwargs))
222 png_formatter.for_type(Figure, lambda fig: retina_figure(fig, **kwargs))
217 if 'jpg' in formats or 'jpeg' in formats:
223 if 'jpg' in formats or 'jpeg' in formats:
218 jpg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'jpg', **kwargs))
224 jpg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'jpg', **kwargs))
219 if 'svg' in formats:
225 if 'svg' in formats:
220 svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg', **kwargs))
226 svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg', **kwargs))
221 if 'pdf' in formats:
227 if 'pdf' in formats:
222 pdf_formatter.for_type(Figure, lambda fig: print_figure(fig, 'pdf', **kwargs))
228 pdf_formatter.for_type(Figure, lambda fig: print_figure(fig, 'pdf', **kwargs))
223
229
224 #-----------------------------------------------------------------------------
230 #-----------------------------------------------------------------------------
225 # Code for initializing matplotlib and importing pylab
231 # Code for initializing matplotlib and importing pylab
226 #-----------------------------------------------------------------------------
232 #-----------------------------------------------------------------------------
227
233
228
234
229 def find_gui_and_backend(gui=None, gui_select=None):
235 def find_gui_and_backend(gui=None, gui_select=None):
230 """Given a gui string return the gui and mpl backend.
236 """Given a gui string return the gui and mpl backend.
231
237
232 Parameters
238 Parameters
233 ----------
239 ----------
234 gui : str
240 gui : str
235 Can be one of ('tk','gtk','wx','qt','qt4','inline').
241 Can be one of ('tk','gtk','wx','qt','qt4','inline').
236 gui_select : str
242 gui_select : str
237 Can be one of ('tk','gtk','wx','qt','qt4','inline').
243 Can be one of ('tk','gtk','wx','qt','qt4','inline').
238 This is any gui already selected by the shell.
244 This is any gui already selected by the shell.
239
245
240 Returns
246 Returns
241 -------
247 -------
242 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
248 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
243 'WXAgg','Qt4Agg','module://IPython.kernel.zmq.pylab.backend_inline').
249 'WXAgg','Qt4Agg','module://IPython.kernel.zmq.pylab.backend_inline').
244 """
250 """
245
251
246 import matplotlib
252 import matplotlib
247
253
248 if gui and gui != 'auto':
254 if gui and gui != 'auto':
249 # select backend based on requested gui
255 # select backend based on requested gui
250 backend = backends[gui]
256 backend = backends[gui]
251 else:
257 else:
252 # We need to read the backend from the original data structure, *not*
258 # We need to read the backend from the original data structure, *not*
253 # from mpl.rcParams, since a prior invocation of %matplotlib may have
259 # from mpl.rcParams, since a prior invocation of %matplotlib may have
254 # overwritten that.
260 # overwritten that.
255 # WARNING: this assumes matplotlib 1.1 or newer!!
261 # WARNING: this assumes matplotlib 1.1 or newer!!
256 backend = matplotlib.rcParamsOrig['backend']
262 backend = matplotlib.rcParamsOrig['backend']
257 # In this case, we need to find what the appropriate gui selection call
263 # In this case, we need to find what the appropriate gui selection call
258 # should be for IPython, so we can activate inputhook accordingly
264 # should be for IPython, so we can activate inputhook accordingly
259 gui = backend2gui.get(backend, None)
265 gui = backend2gui.get(backend, None)
260
266
261 # If we have already had a gui active, we need it and inline are the
267 # If we have already had a gui active, we need it and inline are the
262 # ones allowed.
268 # ones allowed.
263 if gui_select and gui != gui_select:
269 if gui_select and gui != gui_select:
264 gui = gui_select
270 gui = gui_select
265 backend = backends[gui]
271 backend = backends[gui]
266
272
267 return gui, backend
273 return gui, backend
268
274
269
275
270 def activate_matplotlib(backend):
276 def activate_matplotlib(backend):
271 """Activate the given backend and set interactive to True."""
277 """Activate the given backend and set interactive to True."""
272
278
273 import matplotlib
279 import matplotlib
274 matplotlib.interactive(True)
280 matplotlib.interactive(True)
275
281
276 # Matplotlib had a bug where even switch_backend could not force
282 # Matplotlib had a bug where even switch_backend could not force
277 # the rcParam to update. This needs to be set *before* the module
283 # the rcParam to update. This needs to be set *before* the module
278 # magic of switch_backend().
284 # magic of switch_backend().
279 matplotlib.rcParams['backend'] = backend
285 matplotlib.rcParams['backend'] = backend
280
286
281 import matplotlib.pyplot
287 import matplotlib.pyplot
282 matplotlib.pyplot.switch_backend(backend)
288 matplotlib.pyplot.switch_backend(backend)
283
289
284 # This must be imported last in the matplotlib series, after
290 # This must be imported last in the matplotlib series, after
285 # backend/interactivity choices have been made
291 # backend/interactivity choices have been made
286 import matplotlib.pylab as pylab
292 import matplotlib.pylab as pylab
287
293
288 pylab.show._needmain = False
294 pylab.show._needmain = False
289 # We need to detect at runtime whether show() is called by the user.
295 # We need to detect at runtime whether show() is called by the user.
290 # For this, we wrap it into a decorator which adds a 'called' flag.
296 # For this, we wrap it into a decorator which adds a 'called' flag.
291 pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive)
297 pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive)
292
298
293
299
294 def import_pylab(user_ns, import_all=True):
300 def import_pylab(user_ns, import_all=True):
295 """Populate the namespace with pylab-related values.
301 """Populate the namespace with pylab-related values.
296
302
297 Imports matplotlib, pylab, numpy, and everything from pylab and numpy.
303 Imports matplotlib, pylab, numpy, and everything from pylab and numpy.
298
304
299 Also imports a few names from IPython (figsize, display, getfigs)
305 Also imports a few names from IPython (figsize, display, getfigs)
300
306
301 """
307 """
302
308
303 # Import numpy as np/pyplot as plt are conventions we're trying to
309 # Import numpy as np/pyplot as plt are conventions we're trying to
304 # somewhat standardize on. Making them available to users by default
310 # somewhat standardize on. Making them available to users by default
305 # will greatly help this.
311 # will greatly help this.
306 s = ("import numpy\n"
312 s = ("import numpy\n"
307 "import matplotlib\n"
313 "import matplotlib\n"
308 "from matplotlib import pylab, mlab, pyplot\n"
314 "from matplotlib import pylab, mlab, pyplot\n"
309 "np = numpy\n"
315 "np = numpy\n"
310 "plt = pyplot\n"
316 "plt = pyplot\n"
311 )
317 )
312 exec(s, user_ns)
318 exec(s, user_ns)
313
319
314 if import_all:
320 if import_all:
315 s = ("from matplotlib.pylab import *\n"
321 s = ("from matplotlib.pylab import *\n"
316 "from numpy import *\n")
322 "from numpy import *\n")
317 exec(s, user_ns)
323 exec(s, user_ns)
318
324
319 # IPython symbols to add
325 # IPython symbols to add
320 user_ns['figsize'] = figsize
326 user_ns['figsize'] = figsize
321 from IPython.core.display import display
327 from IPython.core.display import display
322 # Add display and getfigs to the user's namespace
328 # Add display and getfigs to the user's namespace
323 user_ns['display'] = display
329 user_ns['display'] = display
324 user_ns['getfigs'] = getfigs
330 user_ns['getfigs'] = getfigs
325
331
326
332
327 def configure_inline_support(shell, backend):
333 def configure_inline_support(shell, backend):
328 """Configure an IPython shell object for matplotlib use.
334 """Configure an IPython shell object for matplotlib use.
329
335
330 Parameters
336 Parameters
331 ----------
337 ----------
332 shell : InteractiveShell instance
338 shell : InteractiveShell instance
333
339
334 backend : matplotlib backend
340 backend : matplotlib backend
335 """
341 """
336 # If using our svg payload backend, register the post-execution
342 # If using our svg payload backend, register the post-execution
337 # function that will pick up the results for display. This can only be
343 # function that will pick up the results for display. This can only be
338 # done with access to the real shell object.
344 # done with access to the real shell object.
339
345
340 # Note: if we can't load the inline backend, then there's no point
346 # Note: if we can't load the inline backend, then there's no point
341 # continuing (such as in terminal-only shells in environments without
347 # continuing (such as in terminal-only shells in environments without
342 # zeromq available).
348 # zeromq available).
343 try:
349 try:
344 from IPython.kernel.zmq.pylab.backend_inline import InlineBackend
350 from IPython.kernel.zmq.pylab.backend_inline import InlineBackend
345 except ImportError:
351 except ImportError:
346 return
352 return
347 from matplotlib import pyplot
353 from matplotlib import pyplot
348
354
349 cfg = InlineBackend.instance(parent=shell)
355 cfg = InlineBackend.instance(parent=shell)
350 cfg.shell = shell
356 cfg.shell = shell
351 if cfg not in shell.configurables:
357 if cfg not in shell.configurables:
352 shell.configurables.append(cfg)
358 shell.configurables.append(cfg)
353
359
354 if backend == backends['inline']:
360 if backend == backends['inline']:
355 from IPython.kernel.zmq.pylab.backend_inline import flush_figures
361 from IPython.kernel.zmq.pylab.backend_inline import flush_figures
356 shell.events.register('post_execute', flush_figures)
362 shell.events.register('post_execute', flush_figures)
357
363
358 # Save rcParams that will be overwrittern
364 # Save rcParams that will be overwrittern
359 shell._saved_rcParams = dict()
365 shell._saved_rcParams = dict()
360 for k in cfg.rc:
366 for k in cfg.rc:
361 shell._saved_rcParams[k] = pyplot.rcParams[k]
367 shell._saved_rcParams[k] = pyplot.rcParams[k]
362 # load inline_rc
368 # load inline_rc
363 pyplot.rcParams.update(cfg.rc)
369 pyplot.rcParams.update(cfg.rc)
364 else:
370 else:
365 from IPython.kernel.zmq.pylab.backend_inline import flush_figures
371 from IPython.kernel.zmq.pylab.backend_inline import flush_figures
366 try:
372 try:
367 shell.events.unregister('post_execute', flush_figures)
373 shell.events.unregister('post_execute', flush_figures)
368 except ValueError:
374 except ValueError:
369 pass
375 pass
370 if hasattr(shell, '_saved_rcParams'):
376 if hasattr(shell, '_saved_rcParams'):
371 pyplot.rcParams.update(shell._saved_rcParams)
377 pyplot.rcParams.update(shell._saved_rcParams)
372 del shell._saved_rcParams
378 del shell._saved_rcParams
373
379
374 # Setup the default figure format
380 # Setup the default figure format
375 select_figure_formats(shell, cfg.figure_formats, **cfg.print_figure_kwargs)
381 select_figure_formats(shell, cfg.figure_formats, **cfg.print_figure_kwargs)
376
382
@@ -1,241 +1,241 b''
1 """Tests for pylab tools module.
1 """Tests for pylab tools module.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2011, the IPython Development Team.
4 # Copyright (c) 2011, the IPython Development Team.
5 #
5 #
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7 #
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 from __future__ import print_function
14 from __future__ import print_function
15
15
16 from io import UnsupportedOperation, BytesIO
16 from io import UnsupportedOperation, BytesIO
17
17
18 import matplotlib
18 import matplotlib
19 matplotlib.use('Agg')
19 matplotlib.use('Agg')
20 from matplotlib.figure import Figure
20 from matplotlib.figure import Figure
21
21
22 from nose import SkipTest
22 from nose import SkipTest
23 import nose.tools as nt
23 import nose.tools as nt
24
24
25 from matplotlib import pyplot as plt
25 from matplotlib import pyplot as plt
26 import numpy as np
26 import numpy as np
27
27
28 # Our own imports
28 # Our own imports
29 from IPython.core.getipython import get_ipython
29 from IPython.core.getipython import get_ipython
30 from IPython.core.interactiveshell import InteractiveShell
30 from IPython.core.interactiveshell import InteractiveShell
31 from IPython.core.display import _PNG, _JPEG
31 from IPython.core.display import _PNG, _JPEG
32 from .. import pylabtools as pt
32 from .. import pylabtools as pt
33
33
34 from IPython.testing import decorators as dec
34 from IPython.testing import decorators as dec
35
35
36 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
37 # Globals and constants
37 # Globals and constants
38 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
39
39
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41 # Local utilities
41 # Local utilities
42 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43
43
44 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
45 # Classes and functions
45 # Classes and functions
46 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
47
47
48 def test_figure_to_svg():
48 def test_figure_to_svg():
49 # simple empty-figure test
49 # simple empty-figure test
50 fig = plt.figure()
50 fig = plt.figure()
51 nt.assert_equal(pt.print_figure(fig, 'svg'), None)
51 nt.assert_equal(pt.print_figure(fig, 'svg'), None)
52
52
53 plt.close('all')
53 plt.close('all')
54
54
55 # simple check for at least svg-looking output
55 # simple check for at least svg-looking output
56 fig = plt.figure()
56 fig = plt.figure()
57 ax = fig.add_subplot(1,1,1)
57 ax = fig.add_subplot(1,1,1)
58 ax.plot([1,2,3])
58 ax.plot([1,2,3])
59 plt.draw()
59 plt.draw()
60 svg = pt.print_figure(fig, 'svg')[:100].lower()
60 svg = pt.print_figure(fig, 'svg')[:100].lower()
61 nt.assert_in(b'doctype svg', svg)
61 nt.assert_in(u'doctype svg', svg)
62
62
63 def _check_pil_jpeg_bytes():
63 def _check_pil_jpeg_bytes():
64 """Skip if PIL can't write JPEGs to BytesIO objects"""
64 """Skip if PIL can't write JPEGs to BytesIO objects"""
65 # PIL's JPEG plugin can't write to BytesIO objects
65 # PIL's JPEG plugin can't write to BytesIO objects
66 # Pillow fixes this
66 # Pillow fixes this
67 from PIL import Image
67 from PIL import Image
68 buf = BytesIO()
68 buf = BytesIO()
69 img = Image.new("RGB", (4,4))
69 img = Image.new("RGB", (4,4))
70 try:
70 try:
71 img.save(buf, 'jpeg')
71 img.save(buf, 'jpeg')
72 except Exception as e:
72 except Exception as e:
73 ename = e.__class__.__name__
73 ename = e.__class__.__name__
74 raise SkipTest("PIL can't write JPEG to BytesIO: %s: %s" % (ename, e))
74 raise SkipTest("PIL can't write JPEG to BytesIO: %s: %s" % (ename, e))
75
75
76 @dec.skip_without("PIL.Image")
76 @dec.skip_without("PIL.Image")
77 def test_figure_to_jpeg():
77 def test_figure_to_jpeg():
78 _check_pil_jpeg_bytes()
78 _check_pil_jpeg_bytes()
79 # simple check for at least jpeg-looking output
79 # simple check for at least jpeg-looking output
80 fig = plt.figure()
80 fig = plt.figure()
81 ax = fig.add_subplot(1,1,1)
81 ax = fig.add_subplot(1,1,1)
82 ax.plot([1,2,3])
82 ax.plot([1,2,3])
83 plt.draw()
83 plt.draw()
84 jpeg = pt.print_figure(fig, 'jpeg', quality=50)[:100].lower()
84 jpeg = pt.print_figure(fig, 'jpeg', quality=50)[:100].lower()
85 assert jpeg.startswith(_JPEG)
85 assert jpeg.startswith(_JPEG)
86
86
87 def test_retina_figure():
87 def test_retina_figure():
88 fig = plt.figure()
88 fig = plt.figure()
89 ax = fig.add_subplot(1,1,1)
89 ax = fig.add_subplot(1,1,1)
90 ax.plot([1,2,3])
90 ax.plot([1,2,3])
91 plt.draw()
91 plt.draw()
92 png, md = pt.retina_figure(fig)
92 png, md = pt.retina_figure(fig)
93 assert png.startswith(_PNG)
93 assert png.startswith(_PNG)
94 nt.assert_in('width', md)
94 nt.assert_in('width', md)
95 nt.assert_in('height', md)
95 nt.assert_in('height', md)
96
96
97 _fmt_mime_map = {
97 _fmt_mime_map = {
98 'png': 'image/png',
98 'png': 'image/png',
99 'jpeg': 'image/jpeg',
99 'jpeg': 'image/jpeg',
100 'pdf': 'application/pdf',
100 'pdf': 'application/pdf',
101 'retina': 'image/png',
101 'retina': 'image/png',
102 'svg': 'image/svg+xml',
102 'svg': 'image/svg+xml',
103 }
103 }
104
104
105 def test_select_figure_formats_str():
105 def test_select_figure_formats_str():
106 ip = get_ipython()
106 ip = get_ipython()
107 for fmt, active_mime in _fmt_mime_map.items():
107 for fmt, active_mime in _fmt_mime_map.items():
108 pt.select_figure_formats(ip, fmt)
108 pt.select_figure_formats(ip, fmt)
109 for mime, f in ip.display_formatter.formatters.items():
109 for mime, f in ip.display_formatter.formatters.items():
110 if mime == active_mime:
110 if mime == active_mime:
111 nt.assert_in(Figure, f)
111 nt.assert_in(Figure, f)
112 else:
112 else:
113 nt.assert_not_in(Figure, f)
113 nt.assert_not_in(Figure, f)
114
114
115 def test_select_figure_formats_kwargs():
115 def test_select_figure_formats_kwargs():
116 ip = get_ipython()
116 ip = get_ipython()
117 kwargs = dict(quality=10, bbox_inches='tight')
117 kwargs = dict(quality=10, bbox_inches='tight')
118 pt.select_figure_formats(ip, 'png', **kwargs)
118 pt.select_figure_formats(ip, 'png', **kwargs)
119 formatter = ip.display_formatter.formatters['image/png']
119 formatter = ip.display_formatter.formatters['image/png']
120 f = formatter.lookup_by_type(Figure)
120 f = formatter.lookup_by_type(Figure)
121 cell = f.__closure__[0].cell_contents
121 cell = f.__closure__[0].cell_contents
122 nt.assert_equal(cell, kwargs)
122 nt.assert_equal(cell, kwargs)
123
123
124 # check that the formatter doesn't raise
124 # check that the formatter doesn't raise
125 fig = plt.figure()
125 fig = plt.figure()
126 ax = fig.add_subplot(1,1,1)
126 ax = fig.add_subplot(1,1,1)
127 ax.plot([1,2,3])
127 ax.plot([1,2,3])
128 plt.draw()
128 plt.draw()
129 formatter.enabled = True
129 formatter.enabled = True
130 png = formatter(fig)
130 png = formatter(fig)
131 assert png.startswith(_PNG)
131 assert png.startswith(_PNG)
132
132
133 def test_select_figure_formats_set():
133 def test_select_figure_formats_set():
134 ip = get_ipython()
134 ip = get_ipython()
135 for fmts in [
135 for fmts in [
136 {'png', 'svg'},
136 {'png', 'svg'},
137 ['png'],
137 ['png'],
138 ('jpeg', 'pdf', 'retina'),
138 ('jpeg', 'pdf', 'retina'),
139 {'svg'},
139 {'svg'},
140 ]:
140 ]:
141 active_mimes = {_fmt_mime_map[fmt] for fmt in fmts}
141 active_mimes = {_fmt_mime_map[fmt] for fmt in fmts}
142 pt.select_figure_formats(ip, fmts)
142 pt.select_figure_formats(ip, fmts)
143 for mime, f in ip.display_formatter.formatters.items():
143 for mime, f in ip.display_formatter.formatters.items():
144 if mime in active_mimes:
144 if mime in active_mimes:
145 nt.assert_in(Figure, f)
145 nt.assert_in(Figure, f)
146 else:
146 else:
147 nt.assert_not_in(Figure, f)
147 nt.assert_not_in(Figure, f)
148
148
149 def test_select_figure_formats_bad():
149 def test_select_figure_formats_bad():
150 ip = get_ipython()
150 ip = get_ipython()
151 with nt.assert_raises(ValueError):
151 with nt.assert_raises(ValueError):
152 pt.select_figure_formats(ip, 'foo')
152 pt.select_figure_formats(ip, 'foo')
153 with nt.assert_raises(ValueError):
153 with nt.assert_raises(ValueError):
154 pt.select_figure_formats(ip, {'png', 'foo'})
154 pt.select_figure_formats(ip, {'png', 'foo'})
155 with nt.assert_raises(ValueError):
155 with nt.assert_raises(ValueError):
156 pt.select_figure_formats(ip, ['retina', 'pdf', 'bar', 'bad'])
156 pt.select_figure_formats(ip, ['retina', 'pdf', 'bar', 'bad'])
157
157
158 def test_import_pylab():
158 def test_import_pylab():
159 ns = {}
159 ns = {}
160 pt.import_pylab(ns, import_all=False)
160 pt.import_pylab(ns, import_all=False)
161 nt.assert_true('plt' in ns)
161 nt.assert_true('plt' in ns)
162 nt.assert_equal(ns['np'], np)
162 nt.assert_equal(ns['np'], np)
163
163
164 class TestPylabSwitch(object):
164 class TestPylabSwitch(object):
165 class Shell(InteractiveShell):
165 class Shell(InteractiveShell):
166 def enable_gui(self, gui):
166 def enable_gui(self, gui):
167 pass
167 pass
168
168
169 def setup(self):
169 def setup(self):
170 import matplotlib
170 import matplotlib
171 def act_mpl(backend):
171 def act_mpl(backend):
172 matplotlib.rcParams['backend'] = backend
172 matplotlib.rcParams['backend'] = backend
173
173
174 # Save rcParams since they get modified
174 # Save rcParams since they get modified
175 self._saved_rcParams = matplotlib.rcParams
175 self._saved_rcParams = matplotlib.rcParams
176 self._saved_rcParamsOrig = matplotlib.rcParamsOrig
176 self._saved_rcParamsOrig = matplotlib.rcParamsOrig
177 matplotlib.rcParams = dict(backend='Qt4Agg')
177 matplotlib.rcParams = dict(backend='Qt4Agg')
178 matplotlib.rcParamsOrig = dict(backend='Qt4Agg')
178 matplotlib.rcParamsOrig = dict(backend='Qt4Agg')
179
179
180 # Mock out functions
180 # Mock out functions
181 self._save_am = pt.activate_matplotlib
181 self._save_am = pt.activate_matplotlib
182 pt.activate_matplotlib = act_mpl
182 pt.activate_matplotlib = act_mpl
183 self._save_ip = pt.import_pylab
183 self._save_ip = pt.import_pylab
184 pt.import_pylab = lambda *a,**kw:None
184 pt.import_pylab = lambda *a,**kw:None
185 self._save_cis = pt.configure_inline_support
185 self._save_cis = pt.configure_inline_support
186 pt.configure_inline_support = lambda *a,**kw:None
186 pt.configure_inline_support = lambda *a,**kw:None
187
187
188 def teardown(self):
188 def teardown(self):
189 pt.activate_matplotlib = self._save_am
189 pt.activate_matplotlib = self._save_am
190 pt.import_pylab = self._save_ip
190 pt.import_pylab = self._save_ip
191 pt.configure_inline_support = self._save_cis
191 pt.configure_inline_support = self._save_cis
192 import matplotlib
192 import matplotlib
193 matplotlib.rcParams = self._saved_rcParams
193 matplotlib.rcParams = self._saved_rcParams
194 matplotlib.rcParamsOrig = self._saved_rcParamsOrig
194 matplotlib.rcParamsOrig = self._saved_rcParamsOrig
195
195
196 def test_qt(self):
196 def test_qt(self):
197 s = self.Shell()
197 s = self.Shell()
198 gui, backend = s.enable_matplotlib(None)
198 gui, backend = s.enable_matplotlib(None)
199 nt.assert_equal(gui, 'qt')
199 nt.assert_equal(gui, 'qt')
200 nt.assert_equal(s.pylab_gui_select, 'qt')
200 nt.assert_equal(s.pylab_gui_select, 'qt')
201
201
202 gui, backend = s.enable_matplotlib('inline')
202 gui, backend = s.enable_matplotlib('inline')
203 nt.assert_equal(gui, 'inline')
203 nt.assert_equal(gui, 'inline')
204 nt.assert_equal(s.pylab_gui_select, 'qt')
204 nt.assert_equal(s.pylab_gui_select, 'qt')
205
205
206 gui, backend = s.enable_matplotlib('qt')
206 gui, backend = s.enable_matplotlib('qt')
207 nt.assert_equal(gui, 'qt')
207 nt.assert_equal(gui, 'qt')
208 nt.assert_equal(s.pylab_gui_select, 'qt')
208 nt.assert_equal(s.pylab_gui_select, 'qt')
209
209
210 gui, backend = s.enable_matplotlib('inline')
210 gui, backend = s.enable_matplotlib('inline')
211 nt.assert_equal(gui, 'inline')
211 nt.assert_equal(gui, 'inline')
212 nt.assert_equal(s.pylab_gui_select, 'qt')
212 nt.assert_equal(s.pylab_gui_select, 'qt')
213
213
214 gui, backend = s.enable_matplotlib()
214 gui, backend = s.enable_matplotlib()
215 nt.assert_equal(gui, 'qt')
215 nt.assert_equal(gui, 'qt')
216 nt.assert_equal(s.pylab_gui_select, 'qt')
216 nt.assert_equal(s.pylab_gui_select, 'qt')
217
217
218 def test_inline(self):
218 def test_inline(self):
219 s = self.Shell()
219 s = self.Shell()
220 gui, backend = s.enable_matplotlib('inline')
220 gui, backend = s.enable_matplotlib('inline')
221 nt.assert_equal(gui, 'inline')
221 nt.assert_equal(gui, 'inline')
222 nt.assert_equal(s.pylab_gui_select, None)
222 nt.assert_equal(s.pylab_gui_select, None)
223
223
224 gui, backend = s.enable_matplotlib('inline')
224 gui, backend = s.enable_matplotlib('inline')
225 nt.assert_equal(gui, 'inline')
225 nt.assert_equal(gui, 'inline')
226 nt.assert_equal(s.pylab_gui_select, None)
226 nt.assert_equal(s.pylab_gui_select, None)
227
227
228 gui, backend = s.enable_matplotlib('qt')
228 gui, backend = s.enable_matplotlib('qt')
229 nt.assert_equal(gui, 'qt')
229 nt.assert_equal(gui, 'qt')
230 nt.assert_equal(s.pylab_gui_select, 'qt')
230 nt.assert_equal(s.pylab_gui_select, 'qt')
231
231
232 def test_qt_gtk(self):
232 def test_qt_gtk(self):
233 s = self.Shell()
233 s = self.Shell()
234 gui, backend = s.enable_matplotlib('qt')
234 gui, backend = s.enable_matplotlib('qt')
235 nt.assert_equal(gui, 'qt')
235 nt.assert_equal(gui, 'qt')
236 nt.assert_equal(s.pylab_gui_select, 'qt')
236 nt.assert_equal(s.pylab_gui_select, 'qt')
237
237
238 gui, backend = s.enable_matplotlib('gtk')
238 gui, backend = s.enable_matplotlib('gtk')
239 nt.assert_equal(gui, 'qt')
239 nt.assert_equal(gui, 'qt')
240 nt.assert_equal(s.pylab_gui_select, 'qt')
240 nt.assert_equal(s.pylab_gui_select, 'qt')
241
241
General Comments 0
You need to be logged in to leave comments. Login now