##// END OF EJS Templates
Add code to de-init the inline backend....
Ryan May -
Show More
@@ -1,334 +1,346 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
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Copyright (C) 2009-2011 The IPython Development Team
12 # Copyright (C) 2009-2011 The IPython Development Team
13 #
13 #
14 # Distributed under the terms of the BSD License. The full license is in
14 # Distributed under the terms of the BSD License. The full license is in
15 # the file COPYING, distributed as part of this software.
15 # the file COPYING, distributed as part of this software.
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Imports
19 # Imports
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 import sys
22 import sys
23 from io import BytesIO
23 from io import BytesIO
24
24
25 from IPython.utils.decorators import flag_calls
25 from IPython.utils.decorators import flag_calls
26
26
27 # If user specifies a GUI, that dictates the backend, otherwise we read the
27 # If user specifies a GUI, that dictates the backend, otherwise we read the
28 # user's mpl default from the mpl rc structure
28 # user's mpl default from the mpl rc structure
29 backends = {'tk': 'TkAgg',
29 backends = {'tk': 'TkAgg',
30 'gtk': 'GTKAgg',
30 'gtk': 'GTKAgg',
31 'wx': 'WXAgg',
31 'wx': 'WXAgg',
32 'qt': 'Qt4Agg', # qt3 not supported
32 'qt': 'Qt4Agg', # qt3 not supported
33 'qt4': 'Qt4Agg',
33 'qt4': 'Qt4Agg',
34 'osx': 'MacOSX',
34 'osx': 'MacOSX',
35 'inline' : 'module://IPython.zmq.pylab.backend_inline'}
35 'inline' : 'module://IPython.zmq.pylab.backend_inline'}
36
36
37 # We also need a reverse backends2guis mapping that will properly choose which
37 # 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
38 # 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
39 # 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:
40 # few others that map to the same GUI manually:
41 backend2gui = dict(zip(backends.values(), backends.keys()))
41 backend2gui = dict(zip(backends.values(), backends.keys()))
42 # In the reverse mapping, there are a few extra valid matplotlib backends that
42 # In the reverse mapping, there are a few extra valid matplotlib backends that
43 # map to the same GUI support
43 # map to the same GUI support
44 backend2gui['GTK'] = backend2gui['GTKCairo'] = 'gtk'
44 backend2gui['GTK'] = backend2gui['GTKCairo'] = 'gtk'
45 backend2gui['WX'] = 'wx'
45 backend2gui['WX'] = 'wx'
46 backend2gui['CocoaAgg'] = 'osx'
46 backend2gui['CocoaAgg'] = 'osx'
47
47
48 #-----------------------------------------------------------------------------
48 #-----------------------------------------------------------------------------
49 # Matplotlib utilities
49 # Matplotlib utilities
50 #-----------------------------------------------------------------------------
50 #-----------------------------------------------------------------------------
51
51
52
52
53 def getfigs(*fig_nums):
53 def getfigs(*fig_nums):
54 """Get a list of matplotlib figures by figure numbers.
54 """Get a list of matplotlib figures by figure numbers.
55
55
56 If no arguments are given, all available figures are returned. If the
56 If no arguments are given, all available figures are returned. If the
57 argument list contains references to invalid figures, a warning is printed
57 argument list contains references to invalid figures, a warning is printed
58 but the function continues pasting further figures.
58 but the function continues pasting further figures.
59
59
60 Parameters
60 Parameters
61 ----------
61 ----------
62 figs : tuple
62 figs : tuple
63 A tuple of ints giving the figure numbers of the figures to return.
63 A tuple of ints giving the figure numbers of the figures to return.
64 """
64 """
65 from matplotlib._pylab_helpers import Gcf
65 from matplotlib._pylab_helpers import Gcf
66 if not fig_nums:
66 if not fig_nums:
67 fig_managers = Gcf.get_all_fig_managers()
67 fig_managers = Gcf.get_all_fig_managers()
68 return [fm.canvas.figure for fm in fig_managers]
68 return [fm.canvas.figure for fm in fig_managers]
69 else:
69 else:
70 figs = []
70 figs = []
71 for num in fig_nums:
71 for num in fig_nums:
72 f = Gcf.figs.get(num)
72 f = Gcf.figs.get(num)
73 if f is None:
73 if f is None:
74 print('Warning: figure %s not available.' % num)
74 print('Warning: figure %s not available.' % num)
75 else:
75 else:
76 figs.append(f.canvas.figure)
76 figs.append(f.canvas.figure)
77 return figs
77 return figs
78
78
79
79
80 def figsize(sizex, sizey):
80 def figsize(sizex, sizey):
81 """Set the default figure size to be [sizex, sizey].
81 """Set the default figure size to be [sizex, sizey].
82
82
83 This is just an easy to remember, convenience wrapper that sets::
83 This is just an easy to remember, convenience wrapper that sets::
84
84
85 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
85 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
86 """
86 """
87 import matplotlib
87 import matplotlib
88 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
88 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
89
89
90
90
91 def print_figure(fig, fmt='png'):
91 def print_figure(fig, fmt='png'):
92 """Convert a figure to svg or png for inline display."""
92 """Convert a figure to svg or png for inline display."""
93 # When there's an empty figure, we shouldn't return anything, otherwise we
93 # When there's an empty figure, we shouldn't return anything, otherwise we
94 # get big blank areas in the qt console.
94 # get big blank areas in the qt console.
95 if not fig.axes and not fig.lines:
95 if not fig.axes and not fig.lines:
96 return
96 return
97
97
98 fc = fig.get_facecolor()
98 fc = fig.get_facecolor()
99 ec = fig.get_edgecolor()
99 ec = fig.get_edgecolor()
100 bytes_io = BytesIO()
100 bytes_io = BytesIO()
101 fig.canvas.print_figure(bytes_io, format=fmt, bbox_inches='tight',
101 fig.canvas.print_figure(bytes_io, format=fmt, bbox_inches='tight',
102 facecolor=fc, edgecolor=ec)
102 facecolor=fc, edgecolor=ec)
103 data = bytes_io.getvalue()
103 data = bytes_io.getvalue()
104 return data
104 return data
105
105
106
106
107 # We need a little factory function here to create the closure where
107 # We need a little factory function here to create the closure where
108 # safe_execfile can live.
108 # safe_execfile can live.
109 def mpl_runner(safe_execfile):
109 def mpl_runner(safe_execfile):
110 """Factory to return a matplotlib-enabled runner for %run.
110 """Factory to return a matplotlib-enabled runner for %run.
111
111
112 Parameters
112 Parameters
113 ----------
113 ----------
114 safe_execfile : function
114 safe_execfile : function
115 This must be a function with the same interface as the
115 This must be a function with the same interface as the
116 :meth:`safe_execfile` method of IPython.
116 :meth:`safe_execfile` method of IPython.
117
117
118 Returns
118 Returns
119 -------
119 -------
120 A function suitable for use as the ``runner`` argument of the %run magic
120 A function suitable for use as the ``runner`` argument of the %run magic
121 function.
121 function.
122 """
122 """
123
123
124 def mpl_execfile(fname,*where,**kw):
124 def mpl_execfile(fname,*where,**kw):
125 """matplotlib-aware wrapper around safe_execfile.
125 """matplotlib-aware wrapper around safe_execfile.
126
126
127 Its interface is identical to that of the :func:`execfile` builtin.
127 Its interface is identical to that of the :func:`execfile` builtin.
128
128
129 This is ultimately a call to execfile(), but wrapped in safeties to
129 This is ultimately a call to execfile(), but wrapped in safeties to
130 properly handle interactive rendering."""
130 properly handle interactive rendering."""
131
131
132 import matplotlib
132 import matplotlib
133 import matplotlib.pylab as pylab
133 import matplotlib.pylab as pylab
134
134
135 #print '*** Matplotlib runner ***' # dbg
135 #print '*** Matplotlib runner ***' # dbg
136 # turn off rendering until end of script
136 # turn off rendering until end of script
137 is_interactive = matplotlib.rcParams['interactive']
137 is_interactive = matplotlib.rcParams['interactive']
138 matplotlib.interactive(False)
138 matplotlib.interactive(False)
139 safe_execfile(fname,*where,**kw)
139 safe_execfile(fname,*where,**kw)
140 matplotlib.interactive(is_interactive)
140 matplotlib.interactive(is_interactive)
141 # make rendering call now, if the user tried to do it
141 # make rendering call now, if the user tried to do it
142 if pylab.draw_if_interactive.called:
142 if pylab.draw_if_interactive.called:
143 pylab.draw()
143 pylab.draw()
144 pylab.draw_if_interactive.called = False
144 pylab.draw_if_interactive.called = False
145
145
146 return mpl_execfile
146 return mpl_execfile
147
147
148
148
149 def select_figure_format(shell, fmt):
149 def select_figure_format(shell, fmt):
150 """Select figure format for inline backend, either 'png' or 'svg'.
150 """Select figure format for inline backend, either 'png' or 'svg'.
151
151
152 Using this method ensures only one figure format is active at a time.
152 Using this method ensures only one figure format is active at a time.
153 """
153 """
154 from matplotlib.figure import Figure
154 from matplotlib.figure import Figure
155 from IPython.zmq.pylab import backend_inline
155 from IPython.zmq.pylab import backend_inline
156
156
157 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
157 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
158 png_formatter = shell.display_formatter.formatters['image/png']
158 png_formatter = shell.display_formatter.formatters['image/png']
159
159
160 if fmt=='png':
160 if fmt=='png':
161 svg_formatter.type_printers.pop(Figure, None)
161 svg_formatter.type_printers.pop(Figure, None)
162 png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png'))
162 png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png'))
163 elif fmt=='svg':
163 elif fmt=='svg':
164 png_formatter.type_printers.pop(Figure, None)
164 png_formatter.type_printers.pop(Figure, None)
165 svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg'))
165 svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg'))
166 else:
166 else:
167 raise ValueError("supported formats are: 'png', 'svg', not %r"%fmt)
167 raise ValueError("supported formats are: 'png', 'svg', not %r"%fmt)
168
168
169 # set the format to be used in the backend()
169 # set the format to be used in the backend()
170 backend_inline._figure_format = fmt
170 backend_inline._figure_format = fmt
171
171
172 #-----------------------------------------------------------------------------
172 #-----------------------------------------------------------------------------
173 # Code for initializing matplotlib and importing pylab
173 # Code for initializing matplotlib and importing pylab
174 #-----------------------------------------------------------------------------
174 #-----------------------------------------------------------------------------
175
175
176
176
177 def find_gui_and_backend(gui=None):
177 def find_gui_and_backend(gui=None):
178 """Given a gui string return the gui and mpl backend.
178 """Given a gui string return the gui and mpl backend.
179
179
180 Parameters
180 Parameters
181 ----------
181 ----------
182 gui : str
182 gui : str
183 Can be one of ('tk','gtk','wx','qt','qt4','inline').
183 Can be one of ('tk','gtk','wx','qt','qt4','inline').
184
184
185 Returns
185 Returns
186 -------
186 -------
187 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
187 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
188 'WXAgg','Qt4Agg','module://IPython.zmq.pylab.backend_inline').
188 'WXAgg','Qt4Agg','module://IPython.zmq.pylab.backend_inline').
189 """
189 """
190
190
191 import matplotlib
191 import matplotlib
192
192
193 if gui and gui != 'auto':
193 if gui and gui != 'auto':
194 # select backend based on requested gui
194 # select backend based on requested gui
195 backend = backends[gui]
195 backend = backends[gui]
196 else:
196 else:
197 backend = matplotlib.rcParams['backend']
197 backend = matplotlib.rcParams['backend']
198 # In this case, we need to find what the appropriate gui selection call
198 # In this case, we need to find what the appropriate gui selection call
199 # should be for IPython, so we can activate inputhook accordingly
199 # should be for IPython, so we can activate inputhook accordingly
200 gui = backend2gui.get(backend, None)
200 gui = backend2gui.get(backend, None)
201 return gui, backend
201 return gui, backend
202
202
203
203
204 def activate_matplotlib(backend):
204 def activate_matplotlib(backend):
205 """Activate the given backend and set interactive to True."""
205 """Activate the given backend and set interactive to True."""
206
206
207 import matplotlib
207 import matplotlib
208 matplotlib.interactive(True)
208 matplotlib.interactive(True)
209
209
210 # Matplotlib had a bug where even switch_backend could not force
210 # Matplotlib had a bug where even switch_backend could not force
211 # the rcParam to update. This needs to be set *before* the module
211 # the rcParam to update. This needs to be set *before* the module
212 # magic of switch_backend().
212 # magic of switch_backend().
213 matplotlib.rcParams['backend'] = backend
213 matplotlib.rcParams['backend'] = backend
214
214
215 import matplotlib.pyplot
215 import matplotlib.pyplot
216 matplotlib.pyplot.switch_backend(backend)
216 matplotlib.pyplot.switch_backend(backend)
217
217
218 # This must be imported last in the matplotlib series, after
218 # This must be imported last in the matplotlib series, after
219 # backend/interactivity choices have been made
219 # backend/interactivity choices have been made
220 import matplotlib.pylab as pylab
220 import matplotlib.pylab as pylab
221
221
222 pylab.show._needmain = False
222 pylab.show._needmain = False
223 # We need to detect at runtime whether show() is called by the user.
223 # We need to detect at runtime whether show() is called by the user.
224 # For this, we wrap it into a decorator which adds a 'called' flag.
224 # For this, we wrap it into a decorator which adds a 'called' flag.
225 pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive)
225 pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive)
226
226
227
227
228 def import_pylab(user_ns, import_all=True):
228 def import_pylab(user_ns, import_all=True):
229 """Import the standard pylab symbols into user_ns."""
229 """Import the standard pylab symbols into user_ns."""
230
230
231 # Import numpy as np/pyplot as plt are conventions we're trying to
231 # Import numpy as np/pyplot as plt are conventions we're trying to
232 # somewhat standardize on. Making them available to users by default
232 # somewhat standardize on. Making them available to users by default
233 # will greatly help this.
233 # will greatly help this.
234 s = ("import numpy\n"
234 s = ("import numpy\n"
235 "import matplotlib\n"
235 "import matplotlib\n"
236 "from matplotlib import pylab, mlab, pyplot\n"
236 "from matplotlib import pylab, mlab, pyplot\n"
237 "np = numpy\n"
237 "np = numpy\n"
238 "plt = pyplot\n"
238 "plt = pyplot\n"
239 )
239 )
240 exec s in user_ns
240 exec s in user_ns
241
241
242 if import_all:
242 if import_all:
243 s = ("from matplotlib.pylab import *\n"
243 s = ("from matplotlib.pylab import *\n"
244 "from numpy import *\n")
244 "from numpy import *\n")
245 exec s in user_ns
245 exec s in user_ns
246
246
247
247
248 def configure_inline_support(shell, backend, user_ns=None):
248 def configure_inline_support(shell, backend, user_ns=None):
249 """Configure an IPython shell object for matplotlib use.
249 """Configure an IPython shell object for matplotlib use.
250
250
251 Parameters
251 Parameters
252 ----------
252 ----------
253 shell : InteractiveShell instance
253 shell : InteractiveShell instance
254
254
255 backend : matplotlib backend
255 backend : matplotlib backend
256
256
257 user_ns : dict
257 user_ns : dict
258 A namespace where all configured variables will be placed. If not given,
258 A namespace where all configured variables will be placed. If not given,
259 the `user_ns` attribute of the shell object is used.
259 the `user_ns` attribute of the shell object is used.
260 """
260 """
261 # If using our svg payload backend, register the post-execution
261 # If using our svg payload backend, register the post-execution
262 # function that will pick up the results for display. This can only be
262 # function that will pick up the results for display. This can only be
263 # done with access to the real shell object.
263 # done with access to the real shell object.
264
264
265 # Note: if we can't load the inline backend, then there's no point
265 # Note: if we can't load the inline backend, then there's no point
266 # continuing (such as in terminal-only shells in environments without
266 # continuing (such as in terminal-only shells in environments without
267 # zeromq available).
267 # zeromq available).
268 try:
268 try:
269 from IPython.zmq.pylab.backend_inline import InlineBackend
269 from IPython.zmq.pylab.backend_inline import InlineBackend
270 except ImportError:
270 except ImportError:
271 return
271 return
272 from matplotlib import pyplot
272
273
273 user_ns = shell.user_ns if user_ns is None else user_ns
274 user_ns = shell.user_ns if user_ns is None else user_ns
274
275
275 cfg = InlineBackend.instance(config=shell.config)
276 cfg = InlineBackend.instance(config=shell.config)
276 cfg.shell = shell
277 cfg.shell = shell
277 if cfg not in shell.configurables:
278 if cfg not in shell.configurables:
278 shell.configurables.append(cfg)
279 shell.configurables.append(cfg)
279
280
280 if backend == backends['inline']:
281 if backend == backends['inline']:
281 from IPython.zmq.pylab.backend_inline import flush_figures
282 from IPython.zmq.pylab.backend_inline import flush_figures
282 from matplotlib import pyplot
283 shell.register_post_execute(flush_figures)
283 shell.register_post_execute(flush_figures)
284
285 # Save rcParams that will be overwrittern
286 shell._saved_rcParams = dict()
287 for k in cfg.rc:
288 shell._saved_rcParams[k] = pyplot.rcParams[k]
284 # load inline_rc
289 # load inline_rc
285 pyplot.rcParams.update(cfg.rc)
290 pyplot.rcParams.update(cfg.rc)
286 # Add 'figsize' to pyplot and to the user's namespace
291 # Add 'figsize' to pyplot and to the user's namespace
287 user_ns['figsize'] = pyplot.figsize = figsize
292 user_ns['figsize'] = pyplot.figsize = figsize
293 else:
294 from IPython.zmq.pylab.backend_inline import flush_figures
295 if flush_figures in shell._post_execute:
296 shell._post_execute.pop(flush_figures)
297 if hasattr(shell, '_saved_rcParams'):
298 pyplot.rcParams.update(shell._saved_rcParams)
299 del shell._saved_rcParams
288
300
289 # Setup the default figure format
301 # Setup the default figure format
290 fmt = cfg.figure_format
302 fmt = cfg.figure_format
291 select_figure_format(shell, fmt)
303 select_figure_format(shell, fmt)
292
304
293 # The old pastefig function has been replaced by display
305 # The old pastefig function has been replaced by display
294 from IPython.core.display import display
306 from IPython.core.display import display
295 # Add display and getfigs to the user's namespace
307 # Add display and getfigs to the user's namespace
296 user_ns['display'] = display
308 user_ns['display'] = display
297 user_ns['getfigs'] = getfigs
309 user_ns['getfigs'] = getfigs
298
310
299
311
300 def pylab_activate(user_ns, gui=None, import_all=True, shell=None):
312 def pylab_activate(user_ns, gui=None, import_all=True, shell=None):
301 """Activate pylab mode in the user's namespace.
313 """Activate pylab mode in the user's namespace.
302
314
303 Loads and initializes numpy, matplotlib and friends for interactive use.
315 Loads and initializes numpy, matplotlib and friends for interactive use.
304
316
305 Parameters
317 Parameters
306 ----------
318 ----------
307 user_ns : dict
319 user_ns : dict
308 Namespace where the imports will occur.
320 Namespace where the imports will occur.
309
321
310 gui : optional, string
322 gui : optional, string
311 A valid gui name following the conventions of the %gui magic.
323 A valid gui name following the conventions of the %gui magic.
312
324
313 import_all : optional, boolean
325 import_all : optional, boolean
314 If true, an 'import *' is done from numpy and pylab.
326 If true, an 'import *' is done from numpy and pylab.
315
327
316 Returns
328 Returns
317 -------
329 -------
318 The actual gui used (if not given as input, it was obtained from matplotlib
330 The actual gui used (if not given as input, it was obtained from matplotlib
319 itself, and will be needed next to configure IPython's gui integration.
331 itself, and will be needed next to configure IPython's gui integration.
320 """
332 """
321 gui, backend = find_gui_and_backend(gui)
333 gui, backend = find_gui_and_backend(gui)
322 activate_matplotlib(backend)
334 activate_matplotlib(backend)
323 import_pylab(user_ns, import_all)
335 import_pylab(user_ns, import_all)
324 if shell is not None:
336 if shell is not None:
325 configure_inline_support(shell, backend, user_ns)
337 configure_inline_support(shell, backend, user_ns)
326
338
327 print """
339 print """
328 Welcome to pylab, a matplotlib-based Python environment [backend: %s].
340 Welcome to pylab, a matplotlib-based Python environment [backend: %s].
329 For more information, type 'help(pylab)'.""" % backend
341 For more information, type 'help(pylab)'.""" % backend
330 # flush stdout, just to be safe
342 # flush stdout, just to be safe
331 sys.stdout.flush()
343 sys.stdout.flush()
332
344
333 return gui
345 return gui
334
346
General Comments 0
You need to be logged in to leave comments. Login now