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