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