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