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