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