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