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