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