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