##// END OF EJS Templates
enable retina matplotlib figures
MinRK -
Show More
@@ -1,370 +1,391 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Pylab (matplotlib) support utilities.
2 """Pylab (matplotlib) support utilities.
3
3
4 Authors
4 Authors
5 -------
5 -------
6
6
7 * Fernando Perez.
7 * Fernando Perez.
8 * Brian Granger
8 * Brian Granger
9 """
9 """
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Copyright (C) 2009-2011 The IPython Development Team
12 # Copyright (C) 2009-2011 The IPython Development Team
13 #
13 #
14 # Distributed under the terms of the BSD License. The full license is in
14 # Distributed under the terms of the BSD License. The full license is in
15 # the file COPYING, distributed as part of this software.
15 # the file COPYING, distributed as part of this software.
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Imports
19 # Imports
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 import struct
22 import sys
23 import sys
23 from io import BytesIO
24 from io import BytesIO
24
25
25 from IPython.utils.decorators import flag_calls
26 from IPython.utils.decorators import flag_calls
26
27
27 # If user specifies a GUI, that dictates the backend, otherwise we read the
28 # If user specifies a GUI, that dictates the backend, otherwise we read the
28 # user's mpl default from the mpl rc structure
29 # user's mpl default from the mpl rc structure
29 backends = {'tk': 'TkAgg',
30 backends = {'tk': 'TkAgg',
30 'gtk': 'GTKAgg',
31 'gtk': 'GTKAgg',
31 'wx': 'WXAgg',
32 'wx': 'WXAgg',
32 'qt': 'Qt4Agg', # qt3 not supported
33 'qt': 'Qt4Agg', # qt3 not supported
33 'qt4': 'Qt4Agg',
34 'qt4': 'Qt4Agg',
34 'osx': 'MacOSX',
35 'osx': 'MacOSX',
35 'inline' : 'module://IPython.kernel.zmq.pylab.backend_inline'}
36 'inline' : 'module://IPython.kernel.zmq.pylab.backend_inline'}
36
37
37 # We also need a reverse backends2guis mapping that will properly choose which
38 # We also need a reverse backends2guis mapping that will properly choose which
38 # GUI support to activate based on the desired matplotlib backend. For the
39 # GUI support to activate based on the desired matplotlib backend. For the
39 # most part it's just a reverse of the above dict, but we also need to add a
40 # most part it's just a reverse of the above dict, but we also need to add a
40 # few others that map to the same GUI manually:
41 # few others that map to the same GUI manually:
41 backend2gui = dict(zip(backends.values(), backends.keys()))
42 backend2gui = dict(zip(backends.values(), backends.keys()))
42 # In the reverse mapping, there are a few extra valid matplotlib backends that
43 # In the reverse mapping, there are a few extra valid matplotlib backends that
43 # map to the same GUI support
44 # map to the same GUI support
44 backend2gui['GTK'] = backend2gui['GTKCairo'] = 'gtk'
45 backend2gui['GTK'] = backend2gui['GTKCairo'] = 'gtk'
45 backend2gui['WX'] = 'wx'
46 backend2gui['WX'] = 'wx'
46 backend2gui['CocoaAgg'] = 'osx'
47 backend2gui['CocoaAgg'] = 'osx'
47
48
48 #-----------------------------------------------------------------------------
49 #-----------------------------------------------------------------------------
49 # Matplotlib utilities
50 # Matplotlib utilities
50 #-----------------------------------------------------------------------------
51 #-----------------------------------------------------------------------------
51
52
52
53
53 def getfigs(*fig_nums):
54 def getfigs(*fig_nums):
54 """Get a list of matplotlib figures by figure numbers.
55 """Get a list of matplotlib figures by figure numbers.
55
56
56 If no arguments are given, all available figures are returned. If the
57 If no arguments are given, all available figures are returned. If the
57 argument list contains references to invalid figures, a warning is printed
58 argument list contains references to invalid figures, a warning is printed
58 but the function continues pasting further figures.
59 but the function continues pasting further figures.
59
60
60 Parameters
61 Parameters
61 ----------
62 ----------
62 figs : tuple
63 figs : tuple
63 A tuple of ints giving the figure numbers of the figures to return.
64 A tuple of ints giving the figure numbers of the figures to return.
64 """
65 """
65 from matplotlib._pylab_helpers import Gcf
66 from matplotlib._pylab_helpers import Gcf
66 if not fig_nums:
67 if not fig_nums:
67 fig_managers = Gcf.get_all_fig_managers()
68 fig_managers = Gcf.get_all_fig_managers()
68 return [fm.canvas.figure for fm in fig_managers]
69 return [fm.canvas.figure for fm in fig_managers]
69 else:
70 else:
70 figs = []
71 figs = []
71 for num in fig_nums:
72 for num in fig_nums:
72 f = Gcf.figs.get(num)
73 f = Gcf.figs.get(num)
73 if f is None:
74 if f is None:
74 print('Warning: figure %s not available.' % num)
75 print('Warning: figure %s not available.' % num)
75 else:
76 else:
76 figs.append(f.canvas.figure)
77 figs.append(f.canvas.figure)
77 return figs
78 return figs
78
79
79
80
80 def figsize(sizex, sizey):
81 def figsize(sizex, sizey):
81 """Set the default figure size to be [sizex, sizey].
82 """Set the default figure size to be [sizex, sizey].
82
83
83 This is just an easy to remember, convenience wrapper that sets::
84 This is just an easy to remember, convenience wrapper that sets::
84
85
85 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
86 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
86 """
87 """
87 import matplotlib
88 import matplotlib
88 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
89 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
89
90
90
91
91 def print_figure(fig, fmt='png'):
92 def print_figure(fig, fmt='png'):
92 """Convert a figure to svg or png for inline display."""
93 """Convert a figure to svg or png for inline display."""
94 from matplotlib import rcParams
93 # When there's an empty figure, we shouldn't return anything, otherwise we
95 # When there's an empty figure, we shouldn't return anything, otherwise we
94 # get big blank areas in the qt console.
96 # get big blank areas in the qt console.
95 if not fig.axes and not fig.lines:
97 if not fig.axes and not fig.lines:
96 return
98 return
97
99
98 fc = fig.get_facecolor()
100 fc = fig.get_facecolor()
99 ec = fig.get_edgecolor()
101 ec = fig.get_edgecolor()
100 bytes_io = BytesIO()
102 bytes_io = BytesIO()
103 dpi = rcParams['savefig.dpi']
104 if fmt == 'retina':
105 dpi = dpi * 2
101 fig.canvas.print_figure(bytes_io, format=fmt, bbox_inches='tight',
106 fig.canvas.print_figure(bytes_io, format=fmt, bbox_inches='tight',
102 facecolor=fc, edgecolor=ec)
107 facecolor=fc, edgecolor=ec, dpi=dpi)
103 data = bytes_io.getvalue()
108 data = bytes_io.getvalue()
104 return data
109 return data
105
110
111 def pngxy(data):
112 """read the width/height from a PNG header"""
113 ihdr = data.index(b'IHDR')
114 # next 8 bytes are width/height
115 w4h4 = data[ihdr+4:ihdr+12]
116 return struct.unpack('>ii', w4h4)
117
118 def retina_figure(fig):
119 """format a figure as a pixel-doubled (retina) PNG"""
120 pngdata = print_figure(fig, fmt='retina')
121 w, h = pngxy(pngdata)
122 metadata = dict(width=w//2, height=h//2)
123 return pngdata, metadata
106
124
107 # We need a little factory function here to create the closure where
125 # We need a little factory function here to create the closure where
108 # safe_execfile can live.
126 # safe_execfile can live.
109 def mpl_runner(safe_execfile):
127 def mpl_runner(safe_execfile):
110 """Factory to return a matplotlib-enabled runner for %run.
128 """Factory to return a matplotlib-enabled runner for %run.
111
129
112 Parameters
130 Parameters
113 ----------
131 ----------
114 safe_execfile : function
132 safe_execfile : function
115 This must be a function with the same interface as the
133 This must be a function with the same interface as the
116 :meth:`safe_execfile` method of IPython.
134 :meth:`safe_execfile` method of IPython.
117
135
118 Returns
136 Returns
119 -------
137 -------
120 A function suitable for use as the ``runner`` argument of the %run magic
138 A function suitable for use as the ``runner`` argument of the %run magic
121 function.
139 function.
122 """
140 """
123
141
124 def mpl_execfile(fname,*where,**kw):
142 def mpl_execfile(fname,*where,**kw):
125 """matplotlib-aware wrapper around safe_execfile.
143 """matplotlib-aware wrapper around safe_execfile.
126
144
127 Its interface is identical to that of the :func:`execfile` builtin.
145 Its interface is identical to that of the :func:`execfile` builtin.
128
146
129 This is ultimately a call to execfile(), but wrapped in safeties to
147 This is ultimately a call to execfile(), but wrapped in safeties to
130 properly handle interactive rendering."""
148 properly handle interactive rendering."""
131
149
132 import matplotlib
150 import matplotlib
133 import matplotlib.pylab as pylab
151 import matplotlib.pylab as pylab
134
152
135 #print '*** Matplotlib runner ***' # dbg
153 #print '*** Matplotlib runner ***' # dbg
136 # turn off rendering until end of script
154 # turn off rendering until end of script
137 is_interactive = matplotlib.rcParams['interactive']
155 is_interactive = matplotlib.rcParams['interactive']
138 matplotlib.interactive(False)
156 matplotlib.interactive(False)
139 safe_execfile(fname,*where,**kw)
157 safe_execfile(fname,*where,**kw)
140 matplotlib.interactive(is_interactive)
158 matplotlib.interactive(is_interactive)
141 # make rendering call now, if the user tried to do it
159 # make rendering call now, if the user tried to do it
142 if pylab.draw_if_interactive.called:
160 if pylab.draw_if_interactive.called:
143 pylab.draw()
161 pylab.draw()
144 pylab.draw_if_interactive.called = False
162 pylab.draw_if_interactive.called = False
145
163
146 return mpl_execfile
164 return mpl_execfile
147
165
148
166
149 def select_figure_format(shell, fmt):
167 def select_figure_format(shell, fmt):
150 """Select figure format for inline backend, either 'png' or 'svg'.
168 """Select figure format for inline backend, can be 'png', 'retina', or 'svg'.
151
169
152 Using this method ensures only one figure format is active at a time.
170 Using this method ensures only one figure format is active at a time.
153 """
171 """
154 from matplotlib.figure import Figure
172 from matplotlib.figure import Figure
155 from IPython.kernel.zmq.pylab import backend_inline
173 from IPython.kernel.zmq.pylab import backend_inline
156
174
157 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
175 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
158 png_formatter = shell.display_formatter.formatters['image/png']
176 png_formatter = shell.display_formatter.formatters['image/png']
159
177
160 if fmt=='png':
178 if fmt == 'png':
161 svg_formatter.type_printers.pop(Figure, None)
179 svg_formatter.type_printers.pop(Figure, None)
162 png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png'))
180 png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png'))
163 elif fmt=='svg':
181 elif fmt in ('png2x', 'retina'):
182 svg_formatter.type_printers.pop(Figure, None)
183 png_formatter.for_type(Figure, retina_figure)
184 elif fmt == 'svg':
164 png_formatter.type_printers.pop(Figure, None)
185 png_formatter.type_printers.pop(Figure, None)
165 svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg'))
186 svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg'))
166 else:
187 else:
167 raise ValueError("supported formats are: 'png', 'svg', not %r"%fmt)
188 raise ValueError("supported formats are: 'png', 'retina', 'svg', not %r" % fmt)
168
189
169 # set the format to be used in the backend()
190 # set the format to be used in the backend()
170 backend_inline._figure_format = fmt
191 backend_inline._figure_format = fmt
171
192
172 #-----------------------------------------------------------------------------
193 #-----------------------------------------------------------------------------
173 # Code for initializing matplotlib and importing pylab
194 # Code for initializing matplotlib and importing pylab
174 #-----------------------------------------------------------------------------
195 #-----------------------------------------------------------------------------
175
196
176
197
177 def find_gui_and_backend(gui=None, gui_select=None):
198 def find_gui_and_backend(gui=None, gui_select=None):
178 """Given a gui string return the gui and mpl backend.
199 """Given a gui string return the gui and mpl backend.
179
200
180 Parameters
201 Parameters
181 ----------
202 ----------
182 gui : str
203 gui : str
183 Can be one of ('tk','gtk','wx','qt','qt4','inline').
204 Can be one of ('tk','gtk','wx','qt','qt4','inline').
184 gui_select : str
205 gui_select : str
185 Can be one of ('tk','gtk','wx','qt','qt4','inline').
206 Can be one of ('tk','gtk','wx','qt','qt4','inline').
186 This is any gui already selected by the shell.
207 This is any gui already selected by the shell.
187
208
188 Returns
209 Returns
189 -------
210 -------
190 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
211 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
191 'WXAgg','Qt4Agg','module://IPython.kernel.zmq.pylab.backend_inline').
212 'WXAgg','Qt4Agg','module://IPython.kernel.zmq.pylab.backend_inline').
192 """
213 """
193
214
194 import matplotlib
215 import matplotlib
195
216
196 if gui and gui != 'auto':
217 if gui and gui != 'auto':
197 # select backend based on requested gui
218 # select backend based on requested gui
198 backend = backends[gui]
219 backend = backends[gui]
199 else:
220 else:
200 backend = matplotlib.rcParams['backend']
221 backend = matplotlib.rcParams['backend']
201 # In this case, we need to find what the appropriate gui selection call
222 # In this case, we need to find what the appropriate gui selection call
202 # should be for IPython, so we can activate inputhook accordingly
223 # should be for IPython, so we can activate inputhook accordingly
203 gui = backend2gui.get(backend, None)
224 gui = backend2gui.get(backend, None)
204
225
205 # If we have already had a gui active, we need it and inline are the
226 # If we have already had a gui active, we need it and inline are the
206 # ones allowed.
227 # ones allowed.
207 if gui_select and gui != gui_select:
228 if gui_select and gui != gui_select:
208 gui = gui_select
229 gui = gui_select
209 backend = backends[gui]
230 backend = backends[gui]
210
231
211 return gui, backend
232 return gui, backend
212
233
213
234
214 def activate_matplotlib(backend):
235 def activate_matplotlib(backend):
215 """Activate the given backend and set interactive to True."""
236 """Activate the given backend and set interactive to True."""
216
237
217 import matplotlib
238 import matplotlib
218 matplotlib.interactive(True)
239 matplotlib.interactive(True)
219
240
220 # Matplotlib had a bug where even switch_backend could not force
241 # Matplotlib had a bug where even switch_backend could not force
221 # the rcParam to update. This needs to be set *before* the module
242 # the rcParam to update. This needs to be set *before* the module
222 # magic of switch_backend().
243 # magic of switch_backend().
223 matplotlib.rcParams['backend'] = backend
244 matplotlib.rcParams['backend'] = backend
224
245
225 import matplotlib.pyplot
246 import matplotlib.pyplot
226 matplotlib.pyplot.switch_backend(backend)
247 matplotlib.pyplot.switch_backend(backend)
227
248
228 # This must be imported last in the matplotlib series, after
249 # This must be imported last in the matplotlib series, after
229 # backend/interactivity choices have been made
250 # backend/interactivity choices have been made
230 import matplotlib.pylab as pylab
251 import matplotlib.pylab as pylab
231
252
232 pylab.show._needmain = False
253 pylab.show._needmain = False
233 # We need to detect at runtime whether show() is called by the user.
254 # We need to detect at runtime whether show() is called by the user.
234 # For this, we wrap it into a decorator which adds a 'called' flag.
255 # For this, we wrap it into a decorator which adds a 'called' flag.
235 pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive)
256 pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive)
236
257
237
258
238 def import_pylab(user_ns, import_all=True):
259 def import_pylab(user_ns, import_all=True):
239 """Import the standard pylab symbols into user_ns."""
260 """Import the standard pylab symbols into user_ns."""
240
261
241 # Import numpy as np/pyplot as plt are conventions we're trying to
262 # Import numpy as np/pyplot as plt are conventions we're trying to
242 # somewhat standardize on. Making them available to users by default
263 # somewhat standardize on. Making them available to users by default
243 # will greatly help this.
264 # will greatly help this.
244 s = ("import numpy\n"
265 s = ("import numpy\n"
245 "import matplotlib\n"
266 "import matplotlib\n"
246 "from matplotlib import pylab, mlab, pyplot\n"
267 "from matplotlib import pylab, mlab, pyplot\n"
247 "np = numpy\n"
268 "np = numpy\n"
248 "plt = pyplot\n"
269 "plt = pyplot\n"
249 )
270 )
250 exec s in user_ns
271 exec s in user_ns
251
272
252 if import_all:
273 if import_all:
253 s = ("from matplotlib.pylab import *\n"
274 s = ("from matplotlib.pylab import *\n"
254 "from numpy import *\n")
275 "from numpy import *\n")
255 exec s in user_ns
276 exec s in user_ns
256
277
257
278
258 def configure_inline_support(shell, backend, user_ns=None):
279 def configure_inline_support(shell, backend, user_ns=None):
259 """Configure an IPython shell object for matplotlib use.
280 """Configure an IPython shell object for matplotlib use.
260
281
261 Parameters
282 Parameters
262 ----------
283 ----------
263 shell : InteractiveShell instance
284 shell : InteractiveShell instance
264
285
265 backend : matplotlib backend
286 backend : matplotlib backend
266
287
267 user_ns : dict
288 user_ns : dict
268 A namespace where all configured variables will be placed. If not given,
289 A namespace where all configured variables will be placed. If not given,
269 the `user_ns` attribute of the shell object is used.
290 the `user_ns` attribute of the shell object is used.
270 """
291 """
271 # If using our svg payload backend, register the post-execution
292 # If using our svg payload backend, register the post-execution
272 # function that will pick up the results for display. This can only be
293 # function that will pick up the results for display. This can only be
273 # done with access to the real shell object.
294 # done with access to the real shell object.
274
295
275 # Note: if we can't load the inline backend, then there's no point
296 # Note: if we can't load the inline backend, then there's no point
276 # continuing (such as in terminal-only shells in environments without
297 # continuing (such as in terminal-only shells in environments without
277 # zeromq available).
298 # zeromq available).
278 try:
299 try:
279 from IPython.kernel.zmq.pylab.backend_inline import InlineBackend
300 from IPython.kernel.zmq.pylab.backend_inline import InlineBackend
280 except ImportError:
301 except ImportError:
281 return
302 return
282 from matplotlib import pyplot
303 from matplotlib import pyplot
283
304
284 user_ns = shell.user_ns if user_ns is None else user_ns
305 user_ns = shell.user_ns if user_ns is None else user_ns
285
306
286 cfg = InlineBackend.instance(config=shell.config)
307 cfg = InlineBackend.instance(config=shell.config)
287 cfg.shell = shell
308 cfg.shell = shell
288 if cfg not in shell.configurables:
309 if cfg not in shell.configurables:
289 shell.configurables.append(cfg)
310 shell.configurables.append(cfg)
290
311
291 if backend == backends['inline']:
312 if backend == backends['inline']:
292 from IPython.kernel.zmq.pylab.backend_inline import flush_figures
313 from IPython.kernel.zmq.pylab.backend_inline import flush_figures
293 shell.register_post_execute(flush_figures)
314 shell.register_post_execute(flush_figures)
294
315
295 # Save rcParams that will be overwrittern
316 # Save rcParams that will be overwrittern
296 shell._saved_rcParams = dict()
317 shell._saved_rcParams = dict()
297 for k in cfg.rc:
318 for k in cfg.rc:
298 shell._saved_rcParams[k] = pyplot.rcParams[k]
319 shell._saved_rcParams[k] = pyplot.rcParams[k]
299 # load inline_rc
320 # load inline_rc
300 pyplot.rcParams.update(cfg.rc)
321 pyplot.rcParams.update(cfg.rc)
301 # Add 'figsize' to pyplot and to the user's namespace
322 # Add 'figsize' to pyplot and to the user's namespace
302 user_ns['figsize'] = pyplot.figsize = figsize
323 user_ns['figsize'] = pyplot.figsize = figsize
303 else:
324 else:
304 from IPython.kernel.zmq.pylab.backend_inline import flush_figures
325 from IPython.kernel.zmq.pylab.backend_inline import flush_figures
305 if flush_figures in shell._post_execute:
326 if flush_figures in shell._post_execute:
306 shell._post_execute.pop(flush_figures)
327 shell._post_execute.pop(flush_figures)
307 if hasattr(shell, '_saved_rcParams'):
328 if hasattr(shell, '_saved_rcParams'):
308 pyplot.rcParams.update(shell._saved_rcParams)
329 pyplot.rcParams.update(shell._saved_rcParams)
309 del shell._saved_rcParams
330 del shell._saved_rcParams
310
331
311 # Setup the default figure format
332 # Setup the default figure format
312 fmt = cfg.figure_format
333 fmt = cfg.figure_format
313 select_figure_format(shell, fmt)
334 select_figure_format(shell, fmt)
314
335
315 # The old pastefig function has been replaced by display
336 # The old pastefig function has been replaced by display
316 from IPython.core.display import display
337 from IPython.core.display import display
317 # Add display and getfigs to the user's namespace
338 # Add display and getfigs to the user's namespace
318 user_ns['display'] = display
339 user_ns['display'] = display
319 user_ns['getfigs'] = getfigs
340 user_ns['getfigs'] = getfigs
320
341
321
342
322 def pylab_activate(user_ns, gui=None, import_all=True, shell=None, welcome_message=False):
343 def pylab_activate(user_ns, gui=None, import_all=True, shell=None, welcome_message=False):
323 """Activate pylab mode in the user's namespace.
344 """Activate pylab mode in the user's namespace.
324
345
325 Loads and initializes numpy, matplotlib and friends for interactive use.
346 Loads and initializes numpy, matplotlib and friends for interactive use.
326
347
327 Parameters
348 Parameters
328 ----------
349 ----------
329 user_ns : dict
350 user_ns : dict
330 Namespace where the imports will occur.
351 Namespace where the imports will occur.
331
352
332 gui : optional, string
353 gui : optional, string
333 A valid gui name following the conventions of the %gui magic.
354 A valid gui name following the conventions of the %gui magic.
334
355
335 import_all : optional, boolean
356 import_all : optional, boolean
336 If true, an 'import *' is done from numpy and pylab.
357 If true, an 'import *' is done from numpy and pylab.
337
358
338 welcome_message : optional, boolean
359 welcome_message : optional, boolean
339 If true, print a welcome message about pylab, which includes the backend
360 If true, print a welcome message about pylab, which includes the backend
340 being used.
361 being used.
341
362
342 Returns
363 Returns
343 -------
364 -------
344 The actual gui used (if not given as input, it was obtained from matplotlib
365 The actual gui used (if not given as input, it was obtained from matplotlib
345 itself, and will be needed next to configure IPython's gui integration.
366 itself, and will be needed next to configure IPython's gui integration.
346 """
367 """
347 pylab_gui_select = shell.pylab_gui_select if shell is not None else None
368 pylab_gui_select = shell.pylab_gui_select if shell is not None else None
348 # Try to find the appropriate gui and backend for the settings
369 # Try to find the appropriate gui and backend for the settings
349 gui, backend = find_gui_and_backend(gui, pylab_gui_select)
370 gui, backend = find_gui_and_backend(gui, pylab_gui_select)
350 if shell is not None and gui != 'inline':
371 if shell is not None and gui != 'inline':
351 # If we have our first gui selection, store it
372 # If we have our first gui selection, store it
352 if pylab_gui_select is None:
373 if pylab_gui_select is None:
353 shell.pylab_gui_select = gui
374 shell.pylab_gui_select = gui
354 # Otherwise if they are different
375 # Otherwise if they are different
355 elif gui != pylab_gui_select:
376 elif gui != pylab_gui_select:
356 print ('Warning: Cannot change to a different GUI toolkit: %s.'
377 print ('Warning: Cannot change to a different GUI toolkit: %s.'
357 ' Using %s instead.' % (gui, pylab_gui_select))
378 ' Using %s instead.' % (gui, pylab_gui_select))
358 gui, backend = find_gui_and_backend(pylab_gui_select)
379 gui, backend = find_gui_and_backend(pylab_gui_select)
359 activate_matplotlib(backend)
380 activate_matplotlib(backend)
360 import_pylab(user_ns, import_all)
381 import_pylab(user_ns, import_all)
361 if shell is not None:
382 if shell is not None:
362 configure_inline_support(shell, backend, user_ns)
383 configure_inline_support(shell, backend, user_ns)
363 if welcome_message:
384 if welcome_message:
364 print """
385 print """
365 Welcome to pylab, a matplotlib-based Python environment [backend: %s].
386 Welcome to pylab, a matplotlib-based Python environment [backend: %s].
366 For more information, type 'help(pylab)'.""" % backend
387 For more information, type 'help(pylab)'.""" % backend
367 # flush stdout, just to be safe
388 # flush stdout, just to be safe
368 sys.stdout.flush()
389 sys.stdout.flush()
369
390
370 return gui
391 return gui
@@ -1,215 +1,215 b''
1 """Produce SVG versions of active plots for display by the rich Qt frontend.
1 """Produce SVG versions of active plots for display by the rich Qt frontend.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Imports
4 # Imports
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 from __future__ import print_function
6 from __future__ import print_function
7
7
8 # Standard library imports
8 # Standard library imports
9 import sys
9 import sys
10
10
11 # Third-party imports
11 # Third-party imports
12 import matplotlib
12 import matplotlib
13 from matplotlib.backends.backend_agg import new_figure_manager, FigureCanvasAgg
13 from matplotlib.backends.backend_agg import new_figure_manager, FigureCanvasAgg
14 from matplotlib._pylab_helpers import Gcf
14 from matplotlib._pylab_helpers import Gcf
15
15
16 # Local imports.
16 # Local imports.
17 from IPython.config.configurable import SingletonConfigurable
17 from IPython.config.configurable import SingletonConfigurable
18 from IPython.core.display import display
18 from IPython.core.display import display
19 from IPython.core.displaypub import publish_display_data
19 from IPython.core.displaypub import publish_display_data
20 from IPython.core.pylabtools import print_figure, select_figure_format
20 from IPython.core.pylabtools import print_figure, select_figure_format
21 from IPython.utils.traitlets import Dict, Instance, CaselessStrEnum, CBool
21 from IPython.utils.traitlets import Dict, Instance, CaselessStrEnum, Bool
22 from IPython.utils.warn import warn
22 from IPython.utils.warn import warn
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # Configurable for inline backend options
25 # Configurable for inline backend options
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 # inherit from InlineBackendConfig for deprecation purposes
27 # inherit from InlineBackendConfig for deprecation purposes
28 class InlineBackendConfig(SingletonConfigurable):
28 class InlineBackendConfig(SingletonConfigurable):
29 pass
29 pass
30
30
31 class InlineBackend(InlineBackendConfig):
31 class InlineBackend(InlineBackendConfig):
32 """An object to store configuration of the inline backend."""
32 """An object to store configuration of the inline backend."""
33
33
34 def _config_changed(self, name, old, new):
34 def _config_changed(self, name, old, new):
35 # warn on change of renamed config section
35 # warn on change of renamed config section
36 if new.InlineBackendConfig != old.InlineBackendConfig:
36 if new.InlineBackendConfig != old.InlineBackendConfig:
37 warn("InlineBackendConfig has been renamed to InlineBackend")
37 warn("InlineBackendConfig has been renamed to InlineBackend")
38 super(InlineBackend, self)._config_changed(name, old, new)
38 super(InlineBackend, self)._config_changed(name, old, new)
39
39
40 # The typical default figure size is too large for inline use,
40 # The typical default figure size is too large for inline use,
41 # so we shrink the figure size to 6x4, and tweak fonts to
41 # so we shrink the figure size to 6x4, and tweak fonts to
42 # make that fit.
42 # make that fit.
43 rc = Dict({'figure.figsize': (6.0,4.0),
43 rc = Dict({'figure.figsize': (6.0,4.0),
44 # play nicely with white background in the Qt and notebook frontend
44 # play nicely with white background in the Qt and notebook frontend
45 'figure.facecolor': 'white',
45 'figure.facecolor': 'white',
46 'figure.edgecolor': 'white',
46 'figure.edgecolor': 'white',
47 # 12pt labels get cutoff on 6x4 logplots, so use 10pt.
47 # 12pt labels get cutoff on 6x4 logplots, so use 10pt.
48 'font.size': 10,
48 'font.size': 10,
49 # 72 dpi matches SVG/qtconsole
49 # 72 dpi matches SVG/qtconsole
50 # this only affects PNG export, as SVG has no dpi setting
50 # this only affects PNG export, as SVG has no dpi setting
51 'savefig.dpi': 72,
51 'savefig.dpi': 72,
52 # 10pt still needs a little more room on the xlabel:
52 # 10pt still needs a little more room on the xlabel:
53 'figure.subplot.bottom' : .125
53 'figure.subplot.bottom' : .125
54 }, config=True,
54 }, config=True,
55 help="""Subset of matplotlib rcParams that should be different for the
55 help="""Subset of matplotlib rcParams that should be different for the
56 inline backend."""
56 inline backend."""
57 )
57 )
58
58
59 figure_format = CaselessStrEnum(['svg', 'png'], default_value='png', config=True,
59 figure_format = CaselessStrEnum(['svg', 'png', 'retina'], default_value='png', config=True,
60 help="The image format for figures with the inline backend.")
60 help="The image format for figures with the inline backend.")
61
61
62 def _figure_format_changed(self, name, old, new):
62 def _figure_format_changed(self, name, old, new):
63 if self.shell is None:
63 if self.shell is None:
64 return
64 return
65 else:
65 else:
66 select_figure_format(self.shell, new)
66 select_figure_format(self.shell, new)
67
67
68 close_figures = CBool(True, config=True,
68 close_figures = Bool(True, config=True,
69 help="""Close all figures at the end of each cell.
69 help="""Close all figures at the end of each cell.
70
70
71 When True, ensures that each cell starts with no active figures, but it
71 When True, ensures that each cell starts with no active figures, but it
72 also means that one must keep track of references in order to edit or
72 also means that one must keep track of references in order to edit or
73 redraw figures in subsequent cells. This mode is ideal for the notebook,
73 redraw figures in subsequent cells. This mode is ideal for the notebook,
74 where residual plots from other cells might be surprising.
74 where residual plots from other cells might be surprising.
75
75
76 When False, one must call figure() to create new figures. This means
76 When False, one must call figure() to create new figures. This means
77 that gcf() and getfigs() can reference figures created in other cells,
77 that gcf() and getfigs() can reference figures created in other cells,
78 and the active figure can continue to be edited with pylab/pyplot
78 and the active figure can continue to be edited with pylab/pyplot
79 methods that reference the current active figure. This mode facilitates
79 methods that reference the current active figure. This mode facilitates
80 iterative editing of figures, and behaves most consistently with
80 iterative editing of figures, and behaves most consistently with
81 other matplotlib backends, but figure barriers between cells must
81 other matplotlib backends, but figure barriers between cells must
82 be explicit.
82 be explicit.
83 """)
83 """)
84
84
85 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
85 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
86
86
87
87
88 #-----------------------------------------------------------------------------
88 #-----------------------------------------------------------------------------
89 # Functions
89 # Functions
90 #-----------------------------------------------------------------------------
90 #-----------------------------------------------------------------------------
91
91
92 def show(close=None):
92 def show(close=None):
93 """Show all figures as SVG/PNG payloads sent to the IPython clients.
93 """Show all figures as SVG/PNG payloads sent to the IPython clients.
94
94
95 Parameters
95 Parameters
96 ----------
96 ----------
97 close : bool, optional
97 close : bool, optional
98 If true, a ``plt.close('all')`` call is automatically issued after
98 If true, a ``plt.close('all')`` call is automatically issued after
99 sending all the figures. If this is set, the figures will entirely
99 sending all the figures. If this is set, the figures will entirely
100 removed from the internal list of figures.
100 removed from the internal list of figures.
101 """
101 """
102 if close is None:
102 if close is None:
103 close = InlineBackend.instance().close_figures
103 close = InlineBackend.instance().close_figures
104 try:
104 try:
105 for figure_manager in Gcf.get_all_fig_managers():
105 for figure_manager in Gcf.get_all_fig_managers():
106 display(figure_manager.canvas.figure)
106 display(figure_manager.canvas.figure)
107 finally:
107 finally:
108 show._to_draw = []
108 show._to_draw = []
109 if close:
109 if close:
110 matplotlib.pyplot.close('all')
110 matplotlib.pyplot.close('all')
111
111
112
112
113
113
114 # This flag will be reset by draw_if_interactive when called
114 # This flag will be reset by draw_if_interactive when called
115 show._draw_called = False
115 show._draw_called = False
116 # list of figures to draw when flush_figures is called
116 # list of figures to draw when flush_figures is called
117 show._to_draw = []
117 show._to_draw = []
118
118
119
119
120 def draw_if_interactive():
120 def draw_if_interactive():
121 """
121 """
122 Is called after every pylab drawing command
122 Is called after every pylab drawing command
123 """
123 """
124 # signal that the current active figure should be sent at the end of
124 # signal that the current active figure should be sent at the end of
125 # execution. Also sets the _draw_called flag, signaling that there will be
125 # execution. Also sets the _draw_called flag, signaling that there will be
126 # something to send. At the end of the code execution, a separate call to
126 # something to send. At the end of the code execution, a separate call to
127 # flush_figures() will act upon these values
127 # flush_figures() will act upon these values
128
128
129 fig = Gcf.get_active().canvas.figure
129 fig = Gcf.get_active().canvas.figure
130
130
131 # Hack: matplotlib FigureManager objects in interacive backends (at least
131 # Hack: matplotlib FigureManager objects in interacive backends (at least
132 # in some of them) monkeypatch the figure object and add a .show() method
132 # in some of them) monkeypatch the figure object and add a .show() method
133 # to it. This applies the same monkeypatch in order to support user code
133 # to it. This applies the same monkeypatch in order to support user code
134 # that might expect `.show()` to be part of the official API of figure
134 # that might expect `.show()` to be part of the official API of figure
135 # objects.
135 # objects.
136 # For further reference:
136 # For further reference:
137 # https://github.com/ipython/ipython/issues/1612
137 # https://github.com/ipython/ipython/issues/1612
138 # https://github.com/matplotlib/matplotlib/issues/835
138 # https://github.com/matplotlib/matplotlib/issues/835
139
139
140 if not hasattr(fig, 'show'):
140 if not hasattr(fig, 'show'):
141 # Queue up `fig` for display
141 # Queue up `fig` for display
142 fig.show = lambda *a: display(fig)
142 fig.show = lambda *a: display(fig)
143
143
144 # If matplotlib was manually set to non-interactive mode, this function
144 # If matplotlib was manually set to non-interactive mode, this function
145 # should be a no-op (otherwise we'll generate duplicate plots, since a user
145 # should be a no-op (otherwise we'll generate duplicate plots, since a user
146 # who set ioff() manually expects to make separate draw/show calls).
146 # who set ioff() manually expects to make separate draw/show calls).
147 if not matplotlib.is_interactive():
147 if not matplotlib.is_interactive():
148 return
148 return
149
149
150 # ensure current figure will be drawn, and each subsequent call
150 # ensure current figure will be drawn, and each subsequent call
151 # of draw_if_interactive() moves the active figure to ensure it is
151 # of draw_if_interactive() moves the active figure to ensure it is
152 # drawn last
152 # drawn last
153 try:
153 try:
154 show._to_draw.remove(fig)
154 show._to_draw.remove(fig)
155 except ValueError:
155 except ValueError:
156 # ensure it only appears in the draw list once
156 # ensure it only appears in the draw list once
157 pass
157 pass
158 # Queue up the figure for drawing in next show() call
158 # Queue up the figure for drawing in next show() call
159 show._to_draw.append(fig)
159 show._to_draw.append(fig)
160 show._draw_called = True
160 show._draw_called = True
161
161
162
162
163 def flush_figures():
163 def flush_figures():
164 """Send all figures that changed
164 """Send all figures that changed
165
165
166 This is meant to be called automatically and will call show() if, during
166 This is meant to be called automatically and will call show() if, during
167 prior code execution, there had been any calls to draw_if_interactive.
167 prior code execution, there had been any calls to draw_if_interactive.
168
168
169 This function is meant to be used as a post_execute callback in IPython,
169 This function is meant to be used as a post_execute callback in IPython,
170 so user-caused errors are handled with showtraceback() instead of being
170 so user-caused errors are handled with showtraceback() instead of being
171 allowed to raise. If this function is not called from within IPython,
171 allowed to raise. If this function is not called from within IPython,
172 then these exceptions will raise.
172 then these exceptions will raise.
173 """
173 """
174 if not show._draw_called:
174 if not show._draw_called:
175 return
175 return
176
176
177 if InlineBackend.instance().close_figures:
177 if InlineBackend.instance().close_figures:
178 # ignore the tracking, just draw and close all figures
178 # ignore the tracking, just draw and close all figures
179 try:
179 try:
180 return show(True)
180 return show(True)
181 except Exception as e:
181 except Exception as e:
182 # safely show traceback if in IPython, else raise
182 # safely show traceback if in IPython, else raise
183 try:
183 try:
184 get_ipython
184 get_ipython
185 except NameError:
185 except NameError:
186 raise e
186 raise e
187 else:
187 else:
188 get_ipython().showtraceback()
188 get_ipython().showtraceback()
189 return
189 return
190 try:
190 try:
191 # exclude any figures that were closed:
191 # exclude any figures that were closed:
192 active = set([fm.canvas.figure for fm in Gcf.get_all_fig_managers()])
192 active = set([fm.canvas.figure for fm in Gcf.get_all_fig_managers()])
193 for fig in [ fig for fig in show._to_draw if fig in active ]:
193 for fig in [ fig for fig in show._to_draw if fig in active ]:
194 try:
194 try:
195 display(fig)
195 display(fig)
196 except Exception as e:
196 except Exception as e:
197 # safely show traceback if in IPython, else raise
197 # safely show traceback if in IPython, else raise
198 try:
198 try:
199 get_ipython
199 get_ipython
200 except NameError:
200 except NameError:
201 raise e
201 raise e
202 else:
202 else:
203 get_ipython().showtraceback()
203 get_ipython().showtraceback()
204 break
204 break
205 finally:
205 finally:
206 # clear flags for next round
206 # clear flags for next round
207 show._to_draw = []
207 show._to_draw = []
208 show._draw_called = False
208 show._draw_called = False
209
209
210
210
211 # Changes to matplotlib in version 1.2 requires a mpl backend to supply a default
211 # Changes to matplotlib in version 1.2 requires a mpl backend to supply a default
212 # figurecanvas. This is set here to a Agg canvas
212 # figurecanvas. This is set here to a Agg canvas
213 # See https://github.com/matplotlib/matplotlib/pull/1125
213 # See https://github.com/matplotlib/matplotlib/pull/1125
214 FigureCanvas = FigureCanvasAgg
214 FigureCanvas = FigureCanvasAgg
215
215
General Comments 0
You need to be logged in to leave comments. Login now