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