##// END OF EJS Templates
Display figures with no axes but lines, which are also valid.
Fernando Perez -
Show More
@@ -1,342 +1,342 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 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 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
262
263 backend : matplotlib backend
263 backend : matplotlib backend
264
264
265 user_ns : dict
265 user_ns : dict
266 A namespace where all configured variables will be placed. If not given,
266 A namespace where all configured variables will be placed. If not given,
267 the `user_ns` attribute of the shell object is used.
267 the `user_ns` attribute of the shell object is used.
268 """
268 """
269 # If using our svg payload backend, register the post-execution
269 # If using our svg payload backend, register the post-execution
270 # function that will pick up the results for display. This can only be
270 # function that will pick up the results for display. This can only be
271 # done with access to the real shell object.
271 # done with access to the real shell object.
272
272
273 # Note: if we can't load the inline backend, then there's no point
273 # Note: if we can't load the inline backend, then there's no point
274 # continuing (such as in terminal-only shells in environments without
274 # continuing (such as in terminal-only shells in environments without
275 # zeromq available).
275 # zeromq available).
276 try:
276 try:
277 from IPython.zmq.pylab.backend_inline import InlineBackend
277 from IPython.zmq.pylab.backend_inline import InlineBackend
278 except ImportError:
278 except ImportError:
279 return
279 return
280
280
281 user_ns = shell.user_ns if user_ns is None else user_ns
281 user_ns = shell.user_ns if user_ns is None else user_ns
282
282
283 cfg = InlineBackend.instance(config=shell.config)
283 cfg = InlineBackend.instance(config=shell.config)
284 cfg.shell = shell
284 cfg.shell = shell
285 if cfg not in shell.configurables:
285 if cfg not in shell.configurables:
286 shell.configurables.append(cfg)
286 shell.configurables.append(cfg)
287
287
288 if backend == backends['inline']:
288 if backend == backends['inline']:
289 from IPython.zmq.pylab.backend_inline import flush_figures
289 from IPython.zmq.pylab.backend_inline import flush_figures
290 from matplotlib import pyplot
290 from matplotlib import pyplot
291 shell.register_post_execute(flush_figures)
291 shell.register_post_execute(flush_figures)
292 # load inline_rc
292 # load inline_rc
293 pyplot.rcParams.update(cfg.rc)
293 pyplot.rcParams.update(cfg.rc)
294 # Add 'figsize' to pyplot and to the user's namespace
294 # Add 'figsize' to pyplot and to the user's namespace
295 user_ns['figsize'] = pyplot.figsize = figsize
295 user_ns['figsize'] = pyplot.figsize = figsize
296
296
297 # Setup the default figure format
297 # Setup the default figure format
298 fmt = cfg.figure_format
298 fmt = cfg.figure_format
299 select_figure_format(shell, fmt)
299 select_figure_format(shell, fmt)
300
300
301 # The old pastefig function has been replaced by display
301 # The old pastefig function has been replaced by display
302 from IPython.core.display import display
302 from IPython.core.display import display
303 # Add display and getfigs to the user's namespace
303 # Add display and getfigs to the user's namespace
304 user_ns['display'] = display
304 user_ns['display'] = display
305 user_ns['getfigs'] = getfigs
305 user_ns['getfigs'] = getfigs
306
306
307
307
308 def pylab_activate(user_ns, gui=None, import_all=True, shell=None):
308 def pylab_activate(user_ns, gui=None, import_all=True, shell=None):
309 """Activate pylab mode in the user's namespace.
309 """Activate pylab mode in the user's namespace.
310
310
311 Loads and initializes numpy, matplotlib and friends for interactive use.
311 Loads and initializes numpy, matplotlib and friends for interactive use.
312
312
313 Parameters
313 Parameters
314 ----------
314 ----------
315 user_ns : dict
315 user_ns : dict
316 Namespace where the imports will occur.
316 Namespace where the imports will occur.
317
317
318 gui : optional, string
318 gui : optional, string
319 A valid gui name following the conventions of the %gui magic.
319 A valid gui name following the conventions of the %gui magic.
320
320
321 import_all : optional, boolean
321 import_all : optional, boolean
322 If true, an 'import *' is done from numpy and pylab.
322 If true, an 'import *' is done from numpy and pylab.
323
323
324 Returns
324 Returns
325 -------
325 -------
326 The actual gui used (if not given as input, it was obtained from matplotlib
326 The actual gui used (if not given as input, it was obtained from matplotlib
327 itself, and will be needed next to configure IPython's gui integration.
327 itself, and will be needed next to configure IPython's gui integration.
328 """
328 """
329 gui, backend = find_gui_and_backend(gui)
329 gui, backend = find_gui_and_backend(gui)
330 activate_matplotlib(backend)
330 activate_matplotlib(backend)
331 import_pylab(user_ns, import_all)
331 import_pylab(user_ns, import_all)
332 if shell is not None:
332 if shell is not None:
333 configure_inline_support(shell, backend, user_ns)
333 configure_inline_support(shell, backend, user_ns)
334
334
335 print """
335 print """
336 Welcome to pylab, a matplotlib-based Python environment [backend: %s].
336 Welcome to pylab, a matplotlib-based Python environment [backend: %s].
337 For more information, type 'help(pylab)'.""" % backend
337 For more information, type 'help(pylab)'.""" % backend
338 # flush stdout, just to be safe
338 # flush stdout, just to be safe
339 sys.stdout.flush()
339 sys.stdout.flush()
340
340
341 return gui
341 return gui
342
342
General Comments 0
You need to be logged in to leave comments. Login now