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