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