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