##// END OF EJS Templates
Fix support for raw GTK and WX matplotlib backends....
Fernando Perez -
Show More
@@ -1,300 +1,309 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 cStringIO import StringIO
22 from cStringIO import StringIO
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
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
39 # few others that map to the same GUI manually:
40 backend2gui = dict(zip(backends.values(), backends.keys()))
41 # In the reverse mapping, there are a few extra valid matplotlib backends that
42 # map to the same GUI support
43 backend2gui['GTK'] = backend2gui['GTKCairo'] = 'gtk'
44 backend2gui['WX'] = 'wx'
45 backend2gui['CocoaAgg'] = 'osx'
46
36 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
37 # Matplotlib utilities
48 # Matplotlib utilities
38 #-----------------------------------------------------------------------------
49 #-----------------------------------------------------------------------------
39
50
40
51
41 def getfigs(*fig_nums):
52 def getfigs(*fig_nums):
42 """Get a list of matplotlib figures by figure numbers.
53 """Get a list of matplotlib figures by figure numbers.
43
54
44 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
45 argument list contains references to invalid figures, a warning is printed
56 argument list contains references to invalid figures, a warning is printed
46 but the function continues pasting further figures.
57 but the function continues pasting further figures.
47
58
48 Parameters
59 Parameters
49 ----------
60 ----------
50 figs : tuple
61 figs : tuple
51 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.
52 """
63 """
53 from matplotlib._pylab_helpers import Gcf
64 from matplotlib._pylab_helpers import Gcf
54 if not fig_nums:
65 if not fig_nums:
55 fig_managers = Gcf.get_all_fig_managers()
66 fig_managers = Gcf.get_all_fig_managers()
56 return [fm.canvas.figure for fm in fig_managers]
67 return [fm.canvas.figure for fm in fig_managers]
57 else:
68 else:
58 figs = []
69 figs = []
59 for num in fig_nums:
70 for num in fig_nums:
60 f = Gcf.figs.get(num)
71 f = Gcf.figs.get(num)
61 if f is None:
72 if f is None:
62 print('Warning: figure %s not available.' % num)
73 print('Warning: figure %s not available.' % num)
63 else:
74 else:
64 figs.append(f.canvas.figure)
75 figs.append(f.canvas.figure)
65 return figs
76 return figs
66
77
67
78
68 def figsize(sizex, sizey):
79 def figsize(sizex, sizey):
69 """Set the default figure size to be [sizex, sizey].
80 """Set the default figure size to be [sizex, sizey].
70
81
71 This is just an easy to remember, convenience wrapper that sets::
82 This is just an easy to remember, convenience wrapper that sets::
72
83
73 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
84 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
74 """
85 """
75 import matplotlib
86 import matplotlib
76 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
87 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
77
88
78
89
79 def figure_to_svg(fig):
90 def figure_to_svg(fig):
80 """Convert a figure to svg for inline display."""
91 """Convert a figure to svg for inline display."""
81 # 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
82 # get big blank areas in the qt console.
93 # get big blank areas in the qt console.
83 if not fig.axes:
94 if not fig.axes:
84 return
95 return
85
96
86 fc = fig.get_facecolor()
97 fc = fig.get_facecolor()
87 ec = fig.get_edgecolor()
98 ec = fig.get_edgecolor()
88 fig.set_facecolor('white')
99 fig.set_facecolor('white')
89 fig.set_edgecolor('white')
100 fig.set_edgecolor('white')
90 try:
101 try:
91 string_io = StringIO()
102 string_io = StringIO()
92 fig.canvas.print_figure(string_io, format='svg')
103 fig.canvas.print_figure(string_io, format='svg')
93 svg = string_io.getvalue()
104 svg = string_io.getvalue()
94 finally:
105 finally:
95 fig.set_facecolor(fc)
106 fig.set_facecolor(fc)
96 fig.set_edgecolor(ec)
107 fig.set_edgecolor(ec)
97 return svg
108 return svg
98
109
99
110
100 # 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
101 # safe_execfile can live.
112 # safe_execfile can live.
102 def mpl_runner(safe_execfile):
113 def mpl_runner(safe_execfile):
103 """Factory to return a matplotlib-enabled runner for %run.
114 """Factory to return a matplotlib-enabled runner for %run.
104
115
105 Parameters
116 Parameters
106 ----------
117 ----------
107 safe_execfile : function
118 safe_execfile : function
108 This must be a function with the same interface as the
119 This must be a function with the same interface as the
109 :meth:`safe_execfile` method of IPython.
120 :meth:`safe_execfile` method of IPython.
110
121
111 Returns
122 Returns
112 -------
123 -------
113 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
114 function.
125 function.
115 """
126 """
116
127
117 def mpl_execfile(fname,*where,**kw):
128 def mpl_execfile(fname,*where,**kw):
118 """matplotlib-aware wrapper around safe_execfile.
129 """matplotlib-aware wrapper around safe_execfile.
119
130
120 Its interface is identical to that of the :func:`execfile` builtin.
131 Its interface is identical to that of the :func:`execfile` builtin.
121
132
122 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
123 properly handle interactive rendering."""
134 properly handle interactive rendering."""
124
135
125 import matplotlib
136 import matplotlib
126 import matplotlib.pylab as pylab
137 import matplotlib.pylab as pylab
127
138
128 #print '*** Matplotlib runner ***' # dbg
139 #print '*** Matplotlib runner ***' # dbg
129 # turn off rendering until end of script
140 # turn off rendering until end of script
130 is_interactive = matplotlib.rcParams['interactive']
141 is_interactive = matplotlib.rcParams['interactive']
131 matplotlib.interactive(False)
142 matplotlib.interactive(False)
132 safe_execfile(fname,*where,**kw)
143 safe_execfile(fname,*where,**kw)
133 matplotlib.interactive(is_interactive)
144 matplotlib.interactive(is_interactive)
134 # make rendering call now, if the user tried to do it
145 # make rendering call now, if the user tried to do it
135 if pylab.draw_if_interactive.called:
146 if pylab.draw_if_interactive.called:
136 pylab.draw()
147 pylab.draw()
137 pylab.draw_if_interactive.called = False
148 pylab.draw_if_interactive.called = False
138
149
139 return mpl_execfile
150 return mpl_execfile
140
151
141
152
142 #-----------------------------------------------------------------------------
153 #-----------------------------------------------------------------------------
143 # Code for initializing matplotlib and importing pylab
154 # Code for initializing matplotlib and importing pylab
144 #-----------------------------------------------------------------------------
155 #-----------------------------------------------------------------------------
145
156
146
157
147 def find_gui_and_backend(gui=None):
158 def find_gui_and_backend(gui=None):
148 """Given a gui string return the gui and mpl backend.
159 """Given a gui string return the gui and mpl backend.
149
160
150 Parameters
161 Parameters
151 ----------
162 ----------
152 gui : str
163 gui : str
153 Can be one of ('tk','gtk','wx','qt','qt4','inline').
164 Can be one of ('tk','gtk','wx','qt','qt4','inline').
154
165
155 Returns
166 Returns
156 -------
167 -------
157 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
168 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
158 'WXAgg','Qt4Agg','module://IPython.zmq.pylab.backend_inline').
169 'WXAgg','Qt4Agg','module://IPython.zmq.pylab.backend_inline').
159 """
170 """
160
171
161 import matplotlib
172 import matplotlib
162
173
163 if gui:
174 if gui:
164 # select backend based on requested gui
175 # select backend based on requested gui
165 backend = backends[gui]
176 backend = backends[gui]
166 else:
177 else:
167 backend = matplotlib.rcParams['backend']
178 backend = matplotlib.rcParams['backend']
168 # In this case, we need to find what the appropriate gui selection call
179 # In this case, we need to find what the appropriate gui selection call
169 # should be for IPython, so we can activate inputhook accordingly
180 # should be for IPython, so we can activate inputhook accordingly
170 g2b = backends # maps gui names to mpl backend names
181 gui = backend2gui.get(backend, None)
171 b2g = dict(zip(g2b.values(), g2b.keys())) # reverse dict
172 gui = b2g.get(backend, None)
173 return gui, backend
182 return gui, backend
174
183
175
184
176 def activate_matplotlib(backend):
185 def activate_matplotlib(backend):
177 """Activate the given backend and set interactive to True."""
186 """Activate the given backend and set interactive to True."""
178
187
179 import matplotlib
188 import matplotlib
180 if backend.startswith('module://'):
189 if backend.startswith('module://'):
181 # Work around bug in matplotlib: matplotlib.use converts the
190 # Work around bug in matplotlib: matplotlib.use converts the
182 # backend_id to lowercase even if a module name is specified!
191 # backend_id to lowercase even if a module name is specified!
183 matplotlib.rcParams['backend'] = backend
192 matplotlib.rcParams['backend'] = backend
184 else:
193 else:
185 matplotlib.use(backend)
194 matplotlib.use(backend)
186 matplotlib.interactive(True)
195 matplotlib.interactive(True)
187
196
188 # This must be imported last in the matplotlib series, after
197 # This must be imported last in the matplotlib series, after
189 # backend/interactivity choices have been made
198 # backend/interactivity choices have been made
190 import matplotlib.pylab as pylab
199 import matplotlib.pylab as pylab
191
200
192 # XXX For now leave this commented out, but depending on discussions with
201 # XXX For now leave this commented out, but depending on discussions with
193 # mpl-dev, we may be able to allow interactive switching...
202 # mpl-dev, we may be able to allow interactive switching...
194 #import matplotlib.pyplot
203 #import matplotlib.pyplot
195 #matplotlib.pyplot.switch_backend(backend)
204 #matplotlib.pyplot.switch_backend(backend)
196
205
197 pylab.show._needmain = False
206 pylab.show._needmain = False
198 # We need to detect at runtime whether show() is called by the user.
207 # We need to detect at runtime whether show() is called by the user.
199 # For this, we wrap it into a decorator which adds a 'called' flag.
208 # For this, we wrap it into a decorator which adds a 'called' flag.
200 pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive)
209 pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive)
201
210
202
211
203 def import_pylab(user_ns, backend, import_all=True, shell=None):
212 def import_pylab(user_ns, backend, import_all=True, shell=None):
204 """Import the standard pylab symbols into user_ns."""
213 """Import the standard pylab symbols into user_ns."""
205
214
206 # Import numpy as np/pyplot as plt are conventions we're trying to
215 # Import numpy as np/pyplot as plt are conventions we're trying to
207 # somewhat standardize on. Making them available to users by default
216 # somewhat standardize on. Making them available to users by default
208 # will greatly help this.
217 # will greatly help this.
209 s = ("import numpy\n"
218 s = ("import numpy\n"
210 "import matplotlib\n"
219 "import matplotlib\n"
211 "from matplotlib import pylab, mlab, pyplot\n"
220 "from matplotlib import pylab, mlab, pyplot\n"
212 "np = numpy\n"
221 "np = numpy\n"
213 "plt = pyplot\n"
222 "plt = pyplot\n"
214 )
223 )
215 exec s in user_ns
224 exec s in user_ns
216
225
217 if shell is not None:
226 if shell is not None:
218 exec s in shell.user_ns_hidden
227 exec s in shell.user_ns_hidden
219 # If using our svg payload backend, register the post-execution
228 # If using our svg payload backend, register the post-execution
220 # function that will pick up the results for display. This can only be
229 # function that will pick up the results for display. This can only be
221 # done with access to the real shell object.
230 # done with access to the real shell object.
222 if backend == backends['inline']:
231 if backend == backends['inline']:
223 from IPython.zmq.pylab.backend_inline import flush_svg
232 from IPython.zmq.pylab.backend_inline import flush_svg
224 from matplotlib import pyplot
233 from matplotlib import pyplot
225 shell.register_post_execute(flush_svg)
234 shell.register_post_execute(flush_svg)
226 # The typical default figure size is too large for inline use,
235 # The typical default figure size is too large for inline use,
227 # so we shrink the figure size to 6x4, and tweak fonts to
236 # so we shrink the figure size to 6x4, and tweak fonts to
228 # make that fit. This is configurable via Global.pylab_inline_rc,
237 # make that fit. This is configurable via Global.pylab_inline_rc,
229 # or rather it will be once the zmq kernel is hooked up to
238 # or rather it will be once the zmq kernel is hooked up to
230 # the config system.
239 # the config system.
231
240
232 default_rc = {
241 default_rc = {
233 'figure.figsize': (6.0,4.0),
242 'figure.figsize': (6.0,4.0),
234 # 12pt labels get cutoff on 6x4 logplots, so use 10pt.
243 # 12pt labels get cutoff on 6x4 logplots, so use 10pt.
235 'font.size': 10,
244 'font.size': 10,
236 # 10pt still needs a little more room on the xlabel:
245 # 10pt still needs a little more room on the xlabel:
237 'figure.subplot.bottom' : .125
246 'figure.subplot.bottom' : .125
238 }
247 }
239 rc = getattr(shell.config.Global, 'pylab_inline_rc', default_rc)
248 rc = getattr(shell.config.Global, 'pylab_inline_rc', default_rc)
240 pyplot.rcParams.update(rc)
249 pyplot.rcParams.update(rc)
241 shell.config.Global.pylab_inline_rc = rc
250 shell.config.Global.pylab_inline_rc = rc
242
251
243 # Add 'figsize' to pyplot and to the user's namespace
252 # Add 'figsize' to pyplot and to the user's namespace
244 user_ns['figsize'] = pyplot.figsize = figsize
253 user_ns['figsize'] = pyplot.figsize = figsize
245 shell.user_ns_hidden['figsize'] = figsize
254 shell.user_ns_hidden['figsize'] = figsize
246
255
247 # The old pastefig function has been replaced by display
256 # The old pastefig function has been replaced by display
248 # Always add this svg formatter so display works.
257 # Always add this svg formatter so display works.
249 from IPython.core.display import display, display_svg
258 from IPython.core.display import display, display_svg
250 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
259 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
251 svg_formatter.for_type_by_name(
260 svg_formatter.for_type_by_name(
252 'matplotlib.figure','Figure',figure_to_svg
261 'matplotlib.figure','Figure',figure_to_svg
253 )
262 )
254 # Add display and display_png to the user's namespace
263 # Add display and display_png to the user's namespace
255 user_ns['display'] = display
264 user_ns['display'] = display
256 shell.user_ns_hidden['display'] = display
265 shell.user_ns_hidden['display'] = display
257 user_ns['display_svg'] = display_svg
266 user_ns['display_svg'] = display_svg
258 shell.user_ns_hidden['display_svg'] = display_svg
267 shell.user_ns_hidden['display_svg'] = display_svg
259 user_ns['getfigs'] = getfigs
268 user_ns['getfigs'] = getfigs
260 shell.user_ns_hidden['getfigs'] = getfigs
269 shell.user_ns_hidden['getfigs'] = getfigs
261
270
262 if import_all:
271 if import_all:
263 s = ("from matplotlib.pylab import *\n"
272 s = ("from matplotlib.pylab import *\n"
264 "from numpy import *\n")
273 "from numpy import *\n")
265 exec s in user_ns
274 exec s in user_ns
266 if shell is not None:
275 if shell is not None:
267 exec s in shell.user_ns_hidden
276 exec s in shell.user_ns_hidden
268
277
269
278
270 def pylab_activate(user_ns, gui=None, import_all=True):
279 def pylab_activate(user_ns, gui=None, import_all=True):
271 """Activate pylab mode in the user's namespace.
280 """Activate pylab mode in the user's namespace.
272
281
273 Loads and initializes numpy, matplotlib and friends for interactive use.
282 Loads and initializes numpy, matplotlib and friends for interactive use.
274
283
275 Parameters
284 Parameters
276 ----------
285 ----------
277 user_ns : dict
286 user_ns : dict
278 Namespace where the imports will occur.
287 Namespace where the imports will occur.
279
288
280 gui : optional, string
289 gui : optional, string
281 A valid gui name following the conventions of the %gui magic.
290 A valid gui name following the conventions of the %gui magic.
282
291
283 import_all : optional, boolean
292 import_all : optional, boolean
284 If true, an 'import *' is done from numpy and pylab.
293 If true, an 'import *' is done from numpy and pylab.
285
294
286 Returns
295 Returns
287 -------
296 -------
288 The actual gui used (if not given as input, it was obtained from matplotlib
297 The actual gui used (if not given as input, it was obtained from matplotlib
289 itself, and will be needed next to configure IPython's gui integration.
298 itself, and will be needed next to configure IPython's gui integration.
290 """
299 """
291 gui, backend = find_gui_and_backend(gui)
300 gui, backend = find_gui_and_backend(gui)
292 activate_matplotlib(backend)
301 activate_matplotlib(backend)
293 import_pylab(user_ns, backend)
302 import_pylab(user_ns, backend)
294
303
295 print """
304 print """
296 Welcome to pylab, a matplotlib-based Python environment [backend: %s].
305 Welcome to pylab, a matplotlib-based Python environment [backend: %s].
297 For more information, type 'help(pylab)'.""" % backend
306 For more information, type 'help(pylab)'.""" % backend
298
307
299 return gui
308 return gui
300
309
General Comments 0
You need to be logged in to leave comments. Login now