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