##// END OF EJS Templates
Avoid calling inline config if no shell - per @minrk feedback on #1052
Fernando Perez -
Show More
@@ -1,345 +1,343 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:
95 if not fig.axes:
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 fig.set_facecolor('white')
100 fig.set_facecolor('white')
101 fig.set_edgecolor('white')
101 fig.set_edgecolor('white')
102 try:
102 try:
103 bytes_io = BytesIO()
103 bytes_io = BytesIO()
104 fig.canvas.print_figure(bytes_io, format=fmt, bbox_inches='tight')
104 fig.canvas.print_figure(bytes_io, format=fmt, bbox_inches='tight')
105 data = bytes_io.getvalue()
105 data = bytes_io.getvalue()
106 finally:
106 finally:
107 fig.set_facecolor(fc)
107 fig.set_facecolor(fc)
108 fig.set_edgecolor(ec)
108 fig.set_edgecolor(ec)
109 return data
109 return data
110
110
111
111
112 # We need a little factory function here to create the closure where
112 # We need a little factory function here to create the closure where
113 # safe_execfile can live.
113 # safe_execfile can live.
114 def mpl_runner(safe_execfile):
114 def mpl_runner(safe_execfile):
115 """Factory to return a matplotlib-enabled runner for %run.
115 """Factory to return a matplotlib-enabled runner for %run.
116
116
117 Parameters
117 Parameters
118 ----------
118 ----------
119 safe_execfile : function
119 safe_execfile : function
120 This must be a function with the same interface as the
120 This must be a function with the same interface as the
121 :meth:`safe_execfile` method of IPython.
121 :meth:`safe_execfile` method of IPython.
122
122
123 Returns
123 Returns
124 -------
124 -------
125 A function suitable for use as the ``runner`` argument of the %run magic
125 A function suitable for use as the ``runner`` argument of the %run magic
126 function.
126 function.
127 """
127 """
128
128
129 def mpl_execfile(fname,*where,**kw):
129 def mpl_execfile(fname,*where,**kw):
130 """matplotlib-aware wrapper around safe_execfile.
130 """matplotlib-aware wrapper around safe_execfile.
131
131
132 Its interface is identical to that of the :func:`execfile` builtin.
132 Its interface is identical to that of the :func:`execfile` builtin.
133
133
134 This is ultimately a call to execfile(), but wrapped in safeties to
134 This is ultimately a call to execfile(), but wrapped in safeties to
135 properly handle interactive rendering."""
135 properly handle interactive rendering."""
136
136
137 import matplotlib
137 import matplotlib
138 import matplotlib.pylab as pylab
138 import matplotlib.pylab as pylab
139
139
140 #print '*** Matplotlib runner ***' # dbg
140 #print '*** Matplotlib runner ***' # dbg
141 # turn off rendering until end of script
141 # turn off rendering until end of script
142 is_interactive = matplotlib.rcParams['interactive']
142 is_interactive = matplotlib.rcParams['interactive']
143 matplotlib.interactive(False)
143 matplotlib.interactive(False)
144 safe_execfile(fname,*where,**kw)
144 safe_execfile(fname,*where,**kw)
145 matplotlib.interactive(is_interactive)
145 matplotlib.interactive(is_interactive)
146 # make rendering call now, if the user tried to do it
146 # make rendering call now, if the user tried to do it
147 if pylab.draw_if_interactive.called:
147 if pylab.draw_if_interactive.called:
148 pylab.draw()
148 pylab.draw()
149 pylab.draw_if_interactive.called = False
149 pylab.draw_if_interactive.called = False
150
150
151 return mpl_execfile
151 return mpl_execfile
152
152
153
153
154 def select_figure_format(shell, fmt):
154 def select_figure_format(shell, fmt):
155 """Select figure format for inline backend, either 'png' or 'svg'.
155 """Select figure format for inline backend, either 'png' or 'svg'.
156
156
157 Using this method ensures only one figure format is active at a time.
157 Using this method ensures only one figure format is active at a time.
158 """
158 """
159 from matplotlib.figure import Figure
159 from matplotlib.figure import Figure
160 from IPython.zmq.pylab import backend_inline
160 from IPython.zmq.pylab import backend_inline
161
161
162 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
162 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
163 png_formatter = shell.display_formatter.formatters['image/png']
163 png_formatter = shell.display_formatter.formatters['image/png']
164
164
165 if fmt=='png':
165 if fmt=='png':
166 svg_formatter.type_printers.pop(Figure, None)
166 svg_formatter.type_printers.pop(Figure, None)
167 png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png'))
167 png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png'))
168 elif fmt=='svg':
168 elif fmt=='svg':
169 png_formatter.type_printers.pop(Figure, None)
169 png_formatter.type_printers.pop(Figure, None)
170 svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg'))
170 svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg'))
171 else:
171 else:
172 raise ValueError("supported formats are: 'png', 'svg', not %r"%fmt)
172 raise ValueError("supported formats are: 'png', 'svg', not %r"%fmt)
173
173
174 # set the format to be used in the backend()
174 # set the format to be used in the backend()
175 backend_inline._figure_format = fmt
175 backend_inline._figure_format = fmt
176
176
177 #-----------------------------------------------------------------------------
177 #-----------------------------------------------------------------------------
178 # Code for initializing matplotlib and importing pylab
178 # Code for initializing matplotlib and importing pylab
179 #-----------------------------------------------------------------------------
179 #-----------------------------------------------------------------------------
180
180
181
181
182 def find_gui_and_backend(gui=None):
182 def find_gui_and_backend(gui=None):
183 """Given a gui string return the gui and mpl backend.
183 """Given a gui string return the gui and mpl backend.
184
184
185 Parameters
185 Parameters
186 ----------
186 ----------
187 gui : str
187 gui : str
188 Can be one of ('tk','gtk','wx','qt','qt4','inline').
188 Can be one of ('tk','gtk','wx','qt','qt4','inline').
189
189
190 Returns
190 Returns
191 -------
191 -------
192 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
192 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
193 'WXAgg','Qt4Agg','module://IPython.zmq.pylab.backend_inline').
193 'WXAgg','Qt4Agg','module://IPython.zmq.pylab.backend_inline').
194 """
194 """
195
195
196 import matplotlib
196 import matplotlib
197
197
198 if gui and gui != 'auto':
198 if gui and gui != 'auto':
199 # select backend based on requested gui
199 # select backend based on requested gui
200 backend = backends[gui]
200 backend = backends[gui]
201 else:
201 else:
202 backend = matplotlib.rcParams['backend']
202 backend = matplotlib.rcParams['backend']
203 # In this case, we need to find what the appropriate gui selection call
203 # In this case, we need to find what the appropriate gui selection call
204 # should be for IPython, so we can activate inputhook accordingly
204 # should be for IPython, so we can activate inputhook accordingly
205 gui = backend2gui.get(backend, None)
205 gui = backend2gui.get(backend, None)
206 return gui, backend
206 return gui, backend
207
207
208
208
209 def activate_matplotlib(backend):
209 def activate_matplotlib(backend):
210 """Activate the given backend and set interactive to True."""
210 """Activate the given backend and set interactive to True."""
211
211
212 import matplotlib
212 import matplotlib
213 if backend.startswith('module://'):
213 if backend.startswith('module://'):
214 # Work around bug in matplotlib: matplotlib.use converts the
214 # Work around bug in matplotlib: matplotlib.use converts the
215 # backend_id to lowercase even if a module name is specified!
215 # backend_id to lowercase even if a module name is specified!
216 matplotlib.rcParams['backend'] = backend
216 matplotlib.rcParams['backend'] = backend
217 else:
217 else:
218 matplotlib.use(backend)
218 matplotlib.use(backend)
219 matplotlib.interactive(True)
219 matplotlib.interactive(True)
220
220
221 # This must be imported last in the matplotlib series, after
221 # This must be imported last in the matplotlib series, after
222 # backend/interactivity choices have been made
222 # backend/interactivity choices have been made
223 import matplotlib.pylab as pylab
223 import matplotlib.pylab as pylab
224
224
225 # XXX For now leave this commented out, but depending on discussions with
225 # XXX For now leave this commented out, but depending on discussions with
226 # mpl-dev, we may be able to allow interactive switching...
226 # mpl-dev, we may be able to allow interactive switching...
227 #import matplotlib.pyplot
227 #import matplotlib.pyplot
228 #matplotlib.pyplot.switch_backend(backend)
228 #matplotlib.pyplot.switch_backend(backend)
229
229
230 pylab.show._needmain = False
230 pylab.show._needmain = False
231 # We need to detect at runtime whether show() is called by the user.
231 # We need to detect at runtime whether show() is called by the user.
232 # For this, we wrap it into a decorator which adds a 'called' flag.
232 # For this, we wrap it into a decorator which adds a 'called' flag.
233 pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive)
233 pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive)
234
234
235
235
236 def import_pylab(user_ns, import_all=True):
236 def import_pylab(user_ns, import_all=True):
237 """Import the standard pylab symbols into user_ns."""
237 """Import the standard pylab symbols into user_ns."""
238
238
239 # Import numpy as np/pyplot as plt are conventions we're trying to
239 # Import numpy as np/pyplot as plt are conventions we're trying to
240 # somewhat standardize on. Making them available to users by default
240 # somewhat standardize on. Making them available to users by default
241 # will greatly help this.
241 # will greatly help this.
242 s = ("import numpy\n"
242 s = ("import numpy\n"
243 "import matplotlib\n"
243 "import matplotlib\n"
244 "from matplotlib import pylab, mlab, pyplot\n"
244 "from matplotlib import pylab, mlab, pyplot\n"
245 "np = numpy\n"
245 "np = numpy\n"
246 "plt = pyplot\n"
246 "plt = pyplot\n"
247 )
247 )
248 exec s in user_ns
248 exec s in user_ns
249
249
250 if import_all:
250 if import_all:
251 s = ("from matplotlib.pylab import *\n"
251 s = ("from matplotlib.pylab import *\n"
252 "from numpy import *\n")
252 "from numpy import *\n")
253 exec s in user_ns
253 exec s in user_ns
254
254
255
255
256 def configure_inline_support(shell, backend, user_ns=None):
256 def configure_inline_support(shell, backend, user_ns=None):
257 """Configure an IPython shell object for matplotlib use.
257 """Configure an IPython shell object for matplotlib use.
258
258
259 Parameters
259 Parameters
260 ----------
260 ----------
261 shell : InteractiveShell instance
261 shell : InteractiveShell instance
262 If None, this function returns immediately.
262 If None, this function returns immediately.
263
263
264 backend : matplotlib backend
264 backend : matplotlib backend
265
265
266 user_ns : dict
266 user_ns : dict
267 A namespace where all configured variables will be placed. If not given,
267 A namespace where all configured variables will be placed. If not given,
268 the `user_ns` attribute of the shell object is used.
268 the `user_ns` attribute of the shell object is used.
269 """
269 """
270 if shell is None:
271 return
272
273 # If using our svg payload backend, register the post-execution
270 # If using our svg payload backend, register the post-execution
274 # function that will pick up the results for display. This can only be
271 # function that will pick up the results for display. This can only be
275 # done with access to the real shell object.
272 # done with access to the real shell object.
276
273
277 # Note: if we can't load the inline backend, then there's no point
274 # Note: if we can't load the inline backend, then there's no point
278 # continuing (such as in terminal-only shells in environments without
275 # continuing (such as in terminal-only shells in environments without
279 # zeromq available).
276 # zeromq available).
280 try:
277 try:
281 from IPython.zmq.pylab.backend_inline import InlineBackend
278 from IPython.zmq.pylab.backend_inline import InlineBackend
282 except ImportError:
279 except ImportError:
283 return
280 return
284
281
285 user_ns = shell.user_ns if user_ns is None else user_ns
282 user_ns = shell.user_ns if user_ns is None else user_ns
286
283
287 cfg = InlineBackend.instance(config=shell.config)
284 cfg = InlineBackend.instance(config=shell.config)
288 cfg.shell = shell
285 cfg.shell = shell
289 if cfg not in shell.configurables:
286 if cfg not in shell.configurables:
290 shell.configurables.append(cfg)
287 shell.configurables.append(cfg)
291
288
292 if backend == backends['inline']:
289 if backend == backends['inline']:
293 from IPython.zmq.pylab.backend_inline import flush_figures
290 from IPython.zmq.pylab.backend_inline import flush_figures
294 from matplotlib import pyplot
291 from matplotlib import pyplot
295 shell.register_post_execute(flush_figures)
292 shell.register_post_execute(flush_figures)
296 # load inline_rc
293 # load inline_rc
297 pyplot.rcParams.update(cfg.rc)
294 pyplot.rcParams.update(cfg.rc)
298 # Add 'figsize' to pyplot and to the user's namespace
295 # Add 'figsize' to pyplot and to the user's namespace
299 user_ns['figsize'] = pyplot.figsize = figsize
296 user_ns['figsize'] = pyplot.figsize = figsize
300
297
301 # Setup the default figure format
298 # Setup the default figure format
302 fmt = cfg.figure_format
299 fmt = cfg.figure_format
303 select_figure_format(shell, fmt)
300 select_figure_format(shell, fmt)
304
301
305 # The old pastefig function has been replaced by display
302 # The old pastefig function has been replaced by display
306 from IPython.core.display import display
303 from IPython.core.display import display
307 # Add display and getfigs to the user's namespace
304 # Add display and getfigs to the user's namespace
308 user_ns['display'] = display
305 user_ns['display'] = display
309 user_ns['getfigs'] = getfigs
306 user_ns['getfigs'] = getfigs
310
307
311
308
312 def pylab_activate(user_ns, gui=None, import_all=True, shell=None):
309 def pylab_activate(user_ns, gui=None, import_all=True, shell=None):
313 """Activate pylab mode in the user's namespace.
310 """Activate pylab mode in the user's namespace.
314
311
315 Loads and initializes numpy, matplotlib and friends for interactive use.
312 Loads and initializes numpy, matplotlib and friends for interactive use.
316
313
317 Parameters
314 Parameters
318 ----------
315 ----------
319 user_ns : dict
316 user_ns : dict
320 Namespace where the imports will occur.
317 Namespace where the imports will occur.
321
318
322 gui : optional, string
319 gui : optional, string
323 A valid gui name following the conventions of the %gui magic.
320 A valid gui name following the conventions of the %gui magic.
324
321
325 import_all : optional, boolean
322 import_all : optional, boolean
326 If true, an 'import *' is done from numpy and pylab.
323 If true, an 'import *' is done from numpy and pylab.
327
324
328 Returns
325 Returns
329 -------
326 -------
330 The actual gui used (if not given as input, it was obtained from matplotlib
327 The actual gui used (if not given as input, it was obtained from matplotlib
331 itself, and will be needed next to configure IPython's gui integration.
328 itself, and will be needed next to configure IPython's gui integration.
332 """
329 """
333 gui, backend = find_gui_and_backend(gui)
330 gui, backend = find_gui_and_backend(gui)
334 activate_matplotlib(backend)
331 activate_matplotlib(backend)
335 import_pylab(user_ns, import_all)
332 import_pylab(user_ns, import_all)
333 if shell is not None:
336 configure_inline_support(shell, backend, user_ns)
334 configure_inline_support(shell, backend, user_ns)
337
335
338 print """
336 print """
339 Welcome to pylab, a matplotlib-based Python environment [backend: %s].
337 Welcome to pylab, a matplotlib-based Python environment [backend: %s].
340 For more information, type 'help(pylab)'.""" % backend
338 For more information, type 'help(pylab)'.""" % backend
341 # flush stdout, just to be safe
339 # flush stdout, just to be safe
342 sys.stdout.flush()
340 sys.stdout.flush()
343
341
344 return gui
342 return gui
345
343
General Comments 0
You need to be logged in to leave comments. Login now