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