##// END OF EJS Templates
specify default bbox_inches in print_figure explicitly...
MinRK -
Show More
@@ -1,372 +1,373 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 def print_figure(fig, fmt='png', **kwargs):
98 def print_figure(fig, fmt='png', bbox_inches='tight', **kwargs):
99 99 """Print a figure to an image, and return the resulting bytes
100 100
101 Any extra keyword args are passed to fig.canvas.print_figure,
101 Any 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 bbox_inches=bbox_inches,
121 122 )
122 123 # **kwargs get higher priority
123 124 kw.update(kwargs)
124 125
125 126 bytes_io = BytesIO()
126 127 fig.canvas.print_figure(bytes_io, **kw)
127 128 return bytes_io.getvalue()
128 129
129 130 def retina_figure(fig, **kwargs):
130 131 """format a figure as a pixel-doubled (retina) PNG"""
131 132 pngdata = print_figure(fig, fmt='retina', **kwargs)
132 133 w, h = _pngxy(pngdata)
133 134 metadata = dict(width=w//2, height=h//2)
134 135 return pngdata, metadata
135 136
136 137 # We need a little factory function here to create the closure where
137 138 # safe_execfile can live.
138 139 def mpl_runner(safe_execfile):
139 140 """Factory to return a matplotlib-enabled runner for %run.
140 141
141 142 Parameters
142 143 ----------
143 144 safe_execfile : function
144 145 This must be a function with the same interface as the
145 146 :meth:`safe_execfile` method of IPython.
146 147
147 148 Returns
148 149 -------
149 150 A function suitable for use as the ``runner`` argument of the %run magic
150 151 function.
151 152 """
152 153
153 154 def mpl_execfile(fname,*where,**kw):
154 155 """matplotlib-aware wrapper around safe_execfile.
155 156
156 157 Its interface is identical to that of the :func:`execfile` builtin.
157 158
158 159 This is ultimately a call to execfile(), but wrapped in safeties to
159 160 properly handle interactive rendering."""
160 161
161 162 import matplotlib
162 163 import matplotlib.pylab as pylab
163 164
164 165 #print '*** Matplotlib runner ***' # dbg
165 166 # turn off rendering until end of script
166 167 is_interactive = matplotlib.rcParams['interactive']
167 168 matplotlib.interactive(False)
168 169 safe_execfile(fname,*where,**kw)
169 170 matplotlib.interactive(is_interactive)
170 171 # make rendering call now, if the user tried to do it
171 172 if pylab.draw_if_interactive.called:
172 173 pylab.draw()
173 174 pylab.draw_if_interactive.called = False
174 175
175 176 return mpl_execfile
176 177
177 178
178 179 def select_figure_formats(shell, formats, **kwargs):
179 180 """Select figure formats for the inline backend.
180 181
181 182 Parameters
182 183 ==========
183 184 shell : InteractiveShell
184 185 The main IPython instance.
185 186 formats : str or set
186 187 One or a set of figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
187 188 **kwargs : any
188 189 Extra keyword arguments to be passed to fig.canvas.print_figure.
189 190 """
190 191 from matplotlib.figure import Figure
191 192 from IPython.kernel.zmq.pylab import backend_inline
192 193
193 194 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
194 195 png_formatter = shell.display_formatter.formatters['image/png']
195 196 jpg_formatter = shell.display_formatter.formatters['image/jpeg']
196 197 pdf_formatter = shell.display_formatter.formatters['application/pdf']
197 198
198 199 if isinstance(formats, py3compat.string_types):
199 200 formats = {formats}
200 201 # cast in case of list / tuple
201 202 formats = set(formats)
202 203
203 204 [ f.pop(Figure, None) for f in shell.display_formatter.formatters.values() ]
204 205
205 206 supported = {'png', 'png2x', 'retina', 'jpg', 'jpeg', 'svg', 'pdf'}
206 207 bad = formats.difference(supported)
207 208 if bad:
208 209 s = "{%s}" % ",".join([repr(f) for f in bad])
209 210 raise ValueError("supported formats are: 'png', 'retina', 'svg', 'jpg', 'pdf' not %s" % s)
210 211
211 212 if 'png' in formats:
212 213 png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png', **kwargs))
213 214 if 'retina' in formats or 'png2x' in formats:
214 215 png_formatter.for_type(Figure, lambda fig: retina_figure(fig, **kwargs))
215 216 if 'jpg' in formats or 'jpeg' in formats:
216 217 jpg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'jpg', **kwargs))
217 218 if 'svg' in formats:
218 219 svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg', **kwargs))
219 220 if 'pdf' in formats:
220 221 pdf_formatter.for_type(Figure, lambda fig: print_figure(fig, 'pdf', **kwargs))
221 222
222 223 #-----------------------------------------------------------------------------
223 224 # Code for initializing matplotlib and importing pylab
224 225 #-----------------------------------------------------------------------------
225 226
226 227
227 228 def find_gui_and_backend(gui=None, gui_select=None):
228 229 """Given a gui string return the gui and mpl backend.
229 230
230 231 Parameters
231 232 ----------
232 233 gui : str
233 234 Can be one of ('tk','gtk','wx','qt','qt4','inline').
234 235 gui_select : str
235 236 Can be one of ('tk','gtk','wx','qt','qt4','inline').
236 237 This is any gui already selected by the shell.
237 238
238 239 Returns
239 240 -------
240 241 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
241 242 'WXAgg','Qt4Agg','module://IPython.kernel.zmq.pylab.backend_inline').
242 243 """
243 244
244 245 import matplotlib
245 246
246 247 if gui and gui != 'auto':
247 248 # select backend based on requested gui
248 249 backend = backends[gui]
249 250 else:
250 251 # We need to read the backend from the original data structure, *not*
251 252 # from mpl.rcParams, since a prior invocation of %matplotlib may have
252 253 # overwritten that.
253 254 # WARNING: this assumes matplotlib 1.1 or newer!!
254 255 backend = matplotlib.rcParamsOrig['backend']
255 256 # In this case, we need to find what the appropriate gui selection call
256 257 # should be for IPython, so we can activate inputhook accordingly
257 258 gui = backend2gui.get(backend, None)
258 259
259 260 # If we have already had a gui active, we need it and inline are the
260 261 # ones allowed.
261 262 if gui_select and gui != gui_select:
262 263 gui = gui_select
263 264 backend = backends[gui]
264 265
265 266 return gui, backend
266 267
267 268
268 269 def activate_matplotlib(backend):
269 270 """Activate the given backend and set interactive to True."""
270 271
271 272 import matplotlib
272 273 matplotlib.interactive(True)
273 274
274 275 # Matplotlib had a bug where even switch_backend could not force
275 276 # the rcParam to update. This needs to be set *before* the module
276 277 # magic of switch_backend().
277 278 matplotlib.rcParams['backend'] = backend
278 279
279 280 import matplotlib.pyplot
280 281 matplotlib.pyplot.switch_backend(backend)
281 282
282 283 # This must be imported last in the matplotlib series, after
283 284 # backend/interactivity choices have been made
284 285 import matplotlib.pylab as pylab
285 286
286 287 pylab.show._needmain = False
287 288 # We need to detect at runtime whether show() is called by the user.
288 289 # For this, we wrap it into a decorator which adds a 'called' flag.
289 290 pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive)
290 291
291 292
292 293 def import_pylab(user_ns, import_all=True):
293 294 """Populate the namespace with pylab-related values.
294 295
295 296 Imports matplotlib, pylab, numpy, and everything from pylab and numpy.
296 297
297 298 Also imports a few names from IPython (figsize, display, getfigs)
298 299
299 300 """
300 301
301 302 # Import numpy as np/pyplot as plt are conventions we're trying to
302 303 # somewhat standardize on. Making them available to users by default
303 304 # will greatly help this.
304 305 s = ("import numpy\n"
305 306 "import matplotlib\n"
306 307 "from matplotlib import pylab, mlab, pyplot\n"
307 308 "np = numpy\n"
308 309 "plt = pyplot\n"
309 310 )
310 311 exec(s, user_ns)
311 312
312 313 if import_all:
313 314 s = ("from matplotlib.pylab import *\n"
314 315 "from numpy import *\n")
315 316 exec(s, user_ns)
316 317
317 318 # IPython symbols to add
318 319 user_ns['figsize'] = figsize
319 320 from IPython.core.display import display
320 321 # Add display and getfigs to the user's namespace
321 322 user_ns['display'] = display
322 323 user_ns['getfigs'] = getfigs
323 324
324 325
325 326 def configure_inline_support(shell, backend):
326 327 """Configure an IPython shell object for matplotlib use.
327 328
328 329 Parameters
329 330 ----------
330 331 shell : InteractiveShell instance
331 332
332 333 backend : matplotlib backend
333 334 """
334 335 # If using our svg payload backend, register the post-execution
335 336 # function that will pick up the results for display. This can only be
336 337 # done with access to the real shell object.
337 338
338 339 # Note: if we can't load the inline backend, then there's no point
339 340 # continuing (such as in terminal-only shells in environments without
340 341 # zeromq available).
341 342 try:
342 343 from IPython.kernel.zmq.pylab.backend_inline import InlineBackend
343 344 except ImportError:
344 345 return
345 346 from matplotlib import pyplot
346 347
347 348 cfg = InlineBackend.instance(parent=shell)
348 349 cfg.shell = shell
349 350 if cfg not in shell.configurables:
350 351 shell.configurables.append(cfg)
351 352
352 353 if backend == backends['inline']:
353 354 from IPython.kernel.zmq.pylab.backend_inline import flush_figures
354 355 shell.register_post_execute(flush_figures)
355 356
356 357 # Save rcParams that will be overwrittern
357 358 shell._saved_rcParams = dict()
358 359 for k in cfg.rc:
359 360 shell._saved_rcParams[k] = pyplot.rcParams[k]
360 361 # load inline_rc
361 362 pyplot.rcParams.update(cfg.rc)
362 363 else:
363 364 from IPython.kernel.zmq.pylab.backend_inline import flush_figures
364 365 if flush_figures in shell._post_execute:
365 366 shell._post_execute.pop(flush_figures)
366 367 if hasattr(shell, '_saved_rcParams'):
367 368 pyplot.rcParams.update(shell._saved_rcParams)
368 369 del shell._saved_rcParams
369 370
370 371 # Setup the default figure format
371 372 select_figure_formats(shell, cfg.figure_formats, **cfg.print_figure_kwargs)
372 373
General Comments 0
You need to be logged in to leave comments. Login now