##// END OF EJS Templates
Merge pull request #9998 from tacaswell/mnt_remove_unneeded_pylab_imports...
Min RK -
r22946:b041e69a merge
parent child Browse files
Show More
@@ -1,401 +1,409 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 # And some backends that don't need GUI integration
43 43 del backend2gui['nbAgg']
44 44 del backend2gui['agg']
45 45 del backend2gui['module://ipykernel.pylab.backend_inline']
46 46
47 47 #-----------------------------------------------------------------------------
48 48 # Matplotlib utilities
49 49 #-----------------------------------------------------------------------------
50 50
51 51
52 52 def getfigs(*fig_nums):
53 53 """Get a list of matplotlib figures by figure numbers.
54 54
55 55 If no arguments are given, all available figures are returned. If the
56 56 argument list contains references to invalid figures, a warning is printed
57 57 but the function continues pasting further figures.
58 58
59 59 Parameters
60 60 ----------
61 61 figs : tuple
62 62 A tuple of ints giving the figure numbers of the figures to return.
63 63 """
64 64 from matplotlib._pylab_helpers import Gcf
65 65 if not fig_nums:
66 66 fig_managers = Gcf.get_all_fig_managers()
67 67 return [fm.canvas.figure for fm in fig_managers]
68 68 else:
69 69 figs = []
70 70 for num in fig_nums:
71 71 f = Gcf.figs.get(num)
72 72 if f is None:
73 73 print('Warning: figure %s not available.' % num)
74 74 else:
75 75 figs.append(f.canvas.figure)
76 76 return figs
77 77
78 78
79 79 def figsize(sizex, sizey):
80 80 """Set the default figure size to be [sizex, sizey].
81 81
82 82 This is just an easy to remember, convenience wrapper that sets::
83 83
84 84 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
85 85 """
86 86 import matplotlib
87 87 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
88 88
89 89
90 90 def print_figure(fig, fmt='png', bbox_inches='tight', **kwargs):
91 91 """Print a figure to an image, and return the resulting file data
92 92
93 93 Returned data will be bytes unless ``fmt='svg'``,
94 94 in which case it will be unicode.
95 95
96 96 Any keyword args are passed to fig.canvas.print_figure,
97 97 such as ``quality`` or ``bbox_inches``.
98 98 """
99 99 from matplotlib import rcParams
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 = dict(
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 = dict(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 import matplotlib.pylab as pylab
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 if pylab.draw_if_interactive.called:
175 pylab.draw()
176 pylab.draw_if_interactive.called = False
174 if plt.draw_if_interactive.called:
175 plt.draw()
176 plt.draw_if_interactive.called = False
177
178 # re-draw everything that is stale
179 try:
180 da = plt.draw_all
181 except AttributeError:
182 pass
183 else:
184 da()
177 185
178 186 return mpl_execfile
179 187
180 188
181 189 def _reshow_nbagg_figure(fig):
182 190 """reshow an nbagg figure"""
183 191 try:
184 192 reshow = fig.canvas.manager.reshow
185 193 except AttributeError:
186 194 raise NotImplementedError()
187 195 else:
188 196 reshow()
189 197
190 198
191 199 def select_figure_formats(shell, formats, **kwargs):
192 200 """Select figure formats for the inline backend.
193 201
194 202 Parameters
195 203 ==========
196 204 shell : InteractiveShell
197 205 The main IPython instance.
198 206 formats : str or set
199 207 One or a set of figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
200 208 **kwargs : any
201 209 Extra keyword arguments to be passed to fig.canvas.print_figure.
202 210 """
203 211 import matplotlib
204 212 from matplotlib.figure import Figure
205 213
206 214 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
207 215 png_formatter = shell.display_formatter.formatters['image/png']
208 216 jpg_formatter = shell.display_formatter.formatters['image/jpeg']
209 217 pdf_formatter = shell.display_formatter.formatters['application/pdf']
210 218
211 219 if isinstance(formats, py3compat.string_types):
212 220 formats = {formats}
213 221 # cast in case of list / tuple
214 222 formats = set(formats)
215 223
216 224 [ f.pop(Figure, None) for f in shell.display_formatter.formatters.values() ]
217 225
218 226 if matplotlib.get_backend().lower() == 'nbagg':
219 227 formatter = shell.display_formatter.ipython_display_formatter
220 228 formatter.for_type(Figure, _reshow_nbagg_figure)
221 229
222 230 supported = {'png', 'png2x', 'retina', 'jpg', 'jpeg', 'svg', 'pdf'}
223 231 bad = formats.difference(supported)
224 232 if bad:
225 233 bs = "%s" % ','.join([repr(f) for f in bad])
226 234 gs = "%s" % ','.join([repr(f) for f in supported])
227 235 raise ValueError("supported formats are: %s not %s" % (gs, bs))
228 236
229 237 if 'png' in formats:
230 238 png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png', **kwargs))
231 239 if 'retina' in formats or 'png2x' in formats:
232 240 png_formatter.for_type(Figure, lambda fig: retina_figure(fig, **kwargs))
233 241 if 'jpg' in formats or 'jpeg' in formats:
234 242 jpg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'jpg', **kwargs))
235 243 if 'svg' in formats:
236 244 svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg', **kwargs))
237 245 if 'pdf' in formats:
238 246 pdf_formatter.for_type(Figure, lambda fig: print_figure(fig, 'pdf', **kwargs))
239 247
240 248 #-----------------------------------------------------------------------------
241 249 # Code for initializing matplotlib and importing pylab
242 250 #-----------------------------------------------------------------------------
243 251
244 252
245 253 def find_gui_and_backend(gui=None, gui_select=None):
246 254 """Given a gui string return the gui and mpl backend.
247 255
248 256 Parameters
249 257 ----------
250 258 gui : str
251 259 Can be one of ('tk','gtk','wx','qt','qt4','inline','agg').
252 260 gui_select : str
253 261 Can be one of ('tk','gtk','wx','qt','qt4','inline').
254 262 This is any gui already selected by the shell.
255 263
256 264 Returns
257 265 -------
258 266 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
259 267 'WXAgg','Qt4Agg','module://ipykernel.pylab.backend_inline','agg').
260 268 """
261 269
262 270 import matplotlib
263 271
264 272 if gui and gui != 'auto':
265 273 # select backend based on requested gui
266 274 backend = backends[gui]
267 275 if gui == 'agg':
268 276 gui = None
269 277 else:
270 278 # We need to read the backend from the original data structure, *not*
271 279 # from mpl.rcParams, since a prior invocation of %matplotlib may have
272 280 # overwritten that.
273 281 # WARNING: this assumes matplotlib 1.1 or newer!!
274 282 backend = matplotlib.rcParamsOrig['backend']
275 283 # In this case, we need to find what the appropriate gui selection call
276 284 # should be for IPython, so we can activate inputhook accordingly
277 285 gui = backend2gui.get(backend, None)
278 286
279 287 # If we have already had a gui active, we need it and inline are the
280 288 # ones allowed.
281 289 if gui_select and gui != gui_select:
282 290 gui = gui_select
283 291 backend = backends[gui]
284 292
285 293 return gui, backend
286 294
287 295
288 296 def activate_matplotlib(backend):
289 297 """Activate the given backend and set interactive to True."""
290 298
291 299 import matplotlib
292 300 matplotlib.interactive(True)
293 301
294 302 # Matplotlib had a bug where even switch_backend could not force
295 303 # the rcParam to update. This needs to be set *before* the module
296 304 # magic of switch_backend().
297 305 matplotlib.rcParams['backend'] = backend
298 306
299 307 import matplotlib.pyplot
300 308 matplotlib.pyplot.switch_backend(backend)
301 309
302 310 # This must be imported last in the matplotlib series, after
303 311 # backend/interactivity choices have been made
304 import matplotlib.pylab as pylab
312 import matplotlib.pyplot as plt
305 313
306 pylab.show._needmain = False
314 plt.show._needmain = False
307 315 # We need to detect at runtime whether show() is called by the user.
308 316 # For this, we wrap it into a decorator which adds a 'called' flag.
309 pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive)
317 plt.draw_if_interactive = flag_calls(plt.draw_if_interactive)
310 318
311 319
312 320 def import_pylab(user_ns, import_all=True):
313 321 """Populate the namespace with pylab-related values.
314 322
315 323 Imports matplotlib, pylab, numpy, and everything from pylab and numpy.
316 324
317 325 Also imports a few names from IPython (figsize, display, getfigs)
318 326
319 327 """
320 328
321 329 # Import numpy as np/pyplot as plt are conventions we're trying to
322 330 # somewhat standardize on. Making them available to users by default
323 331 # will greatly help this.
324 332 s = ("import numpy\n"
325 333 "import matplotlib\n"
326 334 "from matplotlib import pylab, mlab, pyplot\n"
327 335 "np = numpy\n"
328 336 "plt = pyplot\n"
329 337 )
330 338 exec(s, user_ns)
331 339
332 340 if import_all:
333 341 s = ("from matplotlib.pylab import *\n"
334 342 "from numpy import *\n")
335 343 exec(s, user_ns)
336 344
337 345 # IPython symbols to add
338 346 user_ns['figsize'] = figsize
339 347 from IPython.core.display import display
340 348 # Add display and getfigs to the user's namespace
341 349 user_ns['display'] = display
342 350 user_ns['getfigs'] = getfigs
343 351
344 352
345 353 def configure_inline_support(shell, backend):
346 354 """Configure an IPython shell object for matplotlib use.
347 355
348 356 Parameters
349 357 ----------
350 358 shell : InteractiveShell instance
351 359
352 360 backend : matplotlib backend
353 361 """
354 362 # If using our svg payload backend, register the post-execution
355 363 # function that will pick up the results for display. This can only be
356 364 # done with access to the real shell object.
357 365
358 366 # Note: if we can't load the inline backend, then there's no point
359 367 # continuing (such as in terminal-only shells in environments without
360 368 # zeromq available).
361 369 try:
362 370 from ipykernel.pylab.backend_inline import InlineBackend
363 371 except ImportError:
364 372 return
365 373 import matplotlib
366 374
367 375 cfg = InlineBackend.instance(parent=shell)
368 376 cfg.shell = shell
369 377 if cfg not in shell.configurables:
370 378 shell.configurables.append(cfg)
371 379
372 380 if backend == backends['inline']:
373 381 from ipykernel.pylab.backend_inline import flush_figures
374 382 shell.events.register('post_execute', flush_figures)
375 383
376 384 # Save rcParams that will be overwrittern
377 385 shell._saved_rcParams = dict()
378 386 for k in cfg.rc:
379 387 shell._saved_rcParams[k] = matplotlib.rcParams[k]
380 388 # load inline_rc
381 389 matplotlib.rcParams.update(cfg.rc)
382 390 new_backend_name = "inline"
383 391 else:
384 392 from ipykernel.pylab.backend_inline import flush_figures
385 393 try:
386 394 shell.events.unregister('post_execute', flush_figures)
387 395 except ValueError:
388 396 pass
389 397 if hasattr(shell, '_saved_rcParams'):
390 398 matplotlib.rcParams.update(shell._saved_rcParams)
391 399 del shell._saved_rcParams
392 400 new_backend_name = "other"
393 401
394 402 # only enable the formats once -> don't change the enabled formats (which the user may
395 403 # has changed) when getting another "%matplotlib inline" call.
396 404 # See https://github.com/ipython/ipykernel/issues/29
397 405 cur_backend = getattr(configure_inline_support, "current_backend", "unset")
398 406 if new_backend_name != cur_backend:
399 407 # Setup the default figure format
400 408 select_figure_formats(shell, cfg.figure_formats, **cfg.print_figure_kwargs)
401 409 configure_inline_support.current_backend = new_backend_name
General Comments 0
You need to be logged in to leave comments. Login now