Show More
@@ -162,6 +162,7 b' class InteractiveShell(Configurable, Magic):' | |||
|
162 | 162 | object_info_string_level = Enum((0,1,2), default_value=0, |
|
163 | 163 | config=True) |
|
164 | 164 | pdb = CBool(False, config=True) |
|
165 | ||
|
165 | 166 | pprint = CBool(True, config=True) |
|
166 | 167 | profile = Str('', config=True) |
|
167 | 168 | prompt_in1 = Str('In [\\#]: ', config=True) |
@@ -212,6 +213,9 b' class InteractiveShell(Configurable, Magic):' | |||
|
212 | 213 | plugin_manager = Instance('IPython.core.plugin.PluginManager') |
|
213 | 214 | payload_manager = Instance('IPython.core.payload.PayloadManager') |
|
214 | 215 | |
|
216 | # Private interface | |
|
217 | _post_execute = set() | |
|
218 | ||
|
215 | 219 | def __init__(self, config=None, ipython_dir=None, |
|
216 | 220 | user_ns=None, user_global_ns=None, |
|
217 | 221 | custom_exceptions=((), None)): |
@@ -570,6 +574,13 b' class InteractiveShell(Configurable, Magic):' | |||
|
570 | 574 | |
|
571 | 575 | setattr(self.hooks,name, dp) |
|
572 | 576 | |
|
577 | def register_post_execute(self, func): | |
|
578 | """Register a function for calling after code execution. | |
|
579 | """ | |
|
580 | if not callable(func): | |
|
581 | raise ValueError('argument %s must be callable' % func) | |
|
582 | self._post_execute.add(func) | |
|
583 | ||
|
573 | 584 | #------------------------------------------------------------------------- |
|
574 | 585 | # Things related to the "main" module |
|
575 | 586 | #------------------------------------------------------------------------- |
@@ -2268,6 +2279,21 b' class InteractiveShell(Configurable, Magic):' | |||
|
2268 | 2279 | outflag = 0 |
|
2269 | 2280 | if softspace(sys.stdout, 0): |
|
2270 | 2281 | |
|
2282 | ||
|
2283 | # Execute any registered post-execution functions. Here, any errors | |
|
2284 | # are reported only minimally and just on the terminal, because the | |
|
2285 | # main exception channel may be occupied with a user traceback. | |
|
2286 | # FIXME: we need to think this mechanism a little more carefully. | |
|
2287 | for func in self._post_execute: | |
|
2288 | try: | |
|
2289 | func() | |
|
2290 | except: | |
|
2291 | head = '[ ERROR ] Evaluating post_execute function: %s' % func | |
|
2292 | print >> io.Term.cout, head | |
|
2293 | print >> io.Term.cout, self._simple_error() | |
|
2294 | print >> io.Term.cout, 'Removing from post_execute' | |
|
2295 | self._post_execute.remove(func) | |
|
2296 | ||
|
2271 | 2297 | # Flush out code object which has been run (and source) |
|
2272 | 2298 | self.code_to_run = None |
|
2273 | 2299 | return outflag |
@@ -114,9 +114,6 b' def main():' | |||
|
114 | 114 | if args.pure: |
|
115 | 115 | kernel_manager.start_kernel(ipython=False) |
|
116 | 116 | elif args.pylab: |
|
117 | if args.rich: | |
|
118 | kernel_manager.start_kernel(pylab='payload-svg') | |
|
119 | else: | |
|
120 | 117 |
|
|
121 | 118 | else: |
|
122 | 119 | kernel_manager.start_kernel() |
@@ -127,7 +124,7 b' def main():' | |||
|
127 | 124 | if args.pure: |
|
128 | 125 | kind = 'rich' if args.rich else 'plain' |
|
129 | 126 | widget = FrontendWidget(kind=kind, paging=args.paging) |
|
130 | elif args.rich: | |
|
127 | elif args.rich or args.pylab: | |
|
131 | 128 | widget = RichIPythonWidget(paging=args.paging) |
|
132 | 129 | else: |
|
133 | 130 | widget = IPythonWidget(paging=args.paging) |
@@ -21,6 +21,15 b' Authors' | |||
|
21 | 21 | |
|
22 | 22 | from IPython.utils.decorators import flag_calls |
|
23 | 23 | |
|
24 | # If user specifies a GUI, that dictates the backend, otherwise we read the | |
|
25 | # user's mpl default from the mpl rc structure | |
|
26 | backends = {'tk': 'TkAgg', | |
|
27 | 'gtk': 'GTKAgg', | |
|
28 | 'wx': 'WXAgg', | |
|
29 | 'qt': 'Qt4Agg', # qt3 not supported | |
|
30 | 'qt4': 'Qt4Agg', | |
|
31 | 'payload-svg' : 'module://IPython.zmq.pylab.backend_payload_svg'} | |
|
32 | ||
|
24 | 33 | #----------------------------------------------------------------------------- |
|
25 | 34 | # Main classes and functions |
|
26 | 35 | #----------------------------------------------------------------------------- |
@@ -42,24 +51,15 b' def find_gui_and_backend(gui=None):' | |||
|
42 | 51 | |
|
43 | 52 | import matplotlib |
|
44 | 53 | |
|
45 | # If user specifies a GUI, that dictates the backend, otherwise we read the | |
|
46 | # user's mpl default from the mpl rc structure | |
|
47 | g2b = {'tk': 'TkAgg', | |
|
48 | 'gtk': 'GTKAgg', | |
|
49 | 'wx': 'WXAgg', | |
|
50 | 'qt': 'Qt4Agg', # qt3 not supported | |
|
51 | 'qt4': 'Qt4Agg', | |
|
52 | 'payload-svg' : \ | |
|
53 | 'module://IPython.zmq.pylab.backend_payload_svg'} | |
|
54 | ||
|
55 | 54 | if gui: |
|
56 | 55 | # select backend based on requested gui |
|
57 |
backend = |
|
|
56 | backend = backends[gui] | |
|
58 | 57 | else: |
|
59 | 58 | backend = matplotlib.rcParams['backend'] |
|
60 | 59 | # In this case, we need to find what the appropriate gui selection call |
|
61 | 60 | # should be for IPython, so we can activate inputhook accordingly |
|
62 | b2g = dict(zip(g2b.values(),g2b.keys())) | |
|
61 | g2b = backends # maps gui names to mpl backend names | |
|
62 | b2g = dict(zip(g2b.values(), g2b.keys())) # reverse dict | |
|
63 | 63 | gui = b2g.get(backend, None) |
|
64 | 64 | return gui, backend |
|
65 | 65 | |
@@ -90,7 +90,8 b' def activate_matplotlib(backend):' | |||
|
90 | 90 | # For this, we wrap it into a decorator which adds a 'called' flag. |
|
91 | 91 | pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive) |
|
92 | 92 | |
|
93 | def import_pylab(user_ns, import_all=True): | |
|
93 | ||
|
94 | def import_pylab(user_ns, backend, import_all=True, shell=None): | |
|
94 | 95 | """Import the standard pylab symbols into user_ns.""" |
|
95 | 96 | |
|
96 | 97 | # Import numpy as np/pyplot as plt are conventions we're trying to |
@@ -103,6 +104,17 b' def import_pylab(user_ns, import_all=True):' | |||
|
103 | 104 | "plt = pyplot\n" |
|
104 | 105 | ) in user_ns |
|
105 | 106 | |
|
107 | if shell is not None: | |
|
108 | # If using our svg payload backend, register the post-execution | |
|
109 | # function that will pick up the results for display. This can only be | |
|
110 | # done with access to the real shell object. | |
|
111 | if backend == backends['payload-svg']: | |
|
112 | from IPython.zmq.pylab.backend_payload_svg import flush_svg | |
|
113 | shell.register_post_execute(flush_svg) | |
|
114 | else: | |
|
115 | from IPython.zmq.pylab.backend_payload_svg import paste | |
|
116 | user_ns['paste'] = paste | |
|
117 | ||
|
106 | 118 | if import_all: |
|
107 | 119 | exec("from matplotlib.pylab import *\n" |
|
108 | 120 | "from numpy import *\n") in user_ns |
@@ -131,7 +143,7 b' def pylab_activate(user_ns, gui=None, import_all=True):' | |||
|
131 | 143 | """ |
|
132 | 144 | gui, backend = find_gui_and_backend(gui) |
|
133 | 145 | activate_matplotlib(backend) |
|
134 | import_pylab(user_ns) | |
|
146 | import_pylab(user_ns, backend) | |
|
135 | 147 | |
|
136 | 148 | print """ |
|
137 | 149 | Welcome to pylab, a matplotlib-based Python environment [backend: %s]. |
@@ -192,11 +192,12 b' class Kernel(Configurable):' | |||
|
192 | 192 | # FIXME: runlines calls the exception handler itself. |
|
193 | 193 | shell._reply_content = None |
|
194 | 194 | |
|
195 | # For now leave this here until we're sure we can stop using it | |
|
196 | #shell.runlines(code) | |
|
197 | ||
|
195 | 198 | # Experimental: cell mode! Test more before turning into |
|
196 | 199 | # default and removing the hacks around runlines. |
|
197 | 200 | shell.run_cell(code) |
|
198 | # For now leave this here until we're sure we can stop using it | |
|
199 | #shell.runlines(code) | |
|
200 | 201 | except: |
|
201 | 202 | status = u'error' |
|
202 | 203 | # FIXME: this code right now isn't being used yet by default, |
@@ -210,10 +211,6 b' class Kernel(Configurable):' | |||
|
210 | 211 | reply_content.update(shell._showtraceback(etype, evalue, tb_list)) |
|
211 | 212 | else: |
|
212 | 213 | status = u'ok' |
|
213 | reply_content[u'payload'] = shell.payload_manager.read_payload() | |
|
214 | # Be agressive about clearing the payload because we don't want | |
|
215 | # it to sit in memory until the next execute_request comes in. | |
|
216 | shell.payload_manager.clear_payload() | |
|
217 | 214 | |
|
218 | 215 | reply_content[u'status'] = status |
|
219 | 216 | # Compute the execution counter so clients can display prompts |
@@ -237,6 +234,14 b' class Kernel(Configurable):' | |||
|
237 | 234 | reply_content[u'user_variables'] = {} |
|
238 | 235 | reply_content[u'user_expressions'] = {} |
|
239 | 236 | |
|
237 | # Payloads should be retrieved regardless of outcome, so we can both | |
|
238 | # recover partial output (that could have been generated early in a | |
|
239 | # block, before an error) and clear the payload system always. | |
|
240 | reply_content[u'payload'] = shell.payload_manager.read_payload() | |
|
241 | # Be agressive about clearing the payload because we don't want | |
|
242 | # it to sit in memory until the next execute_request comes in. | |
|
243 | shell.payload_manager.clear_payload() | |
|
244 | ||
|
240 | 245 | # Send the reply. |
|
241 | 246 | reply_msg = self.session.msg(u'execute_reply', reply_content, parent) |
|
242 | 247 | io.raw_print(reply_msg) |
@@ -571,7 +576,8 b" given, the GUI backend is matplotlib's, otherwise use one of: \\" | |||
|
571 | 576 | kernel = make_kernel(namespace, kernel_class, OutStream) |
|
572 | 577 | |
|
573 | 578 | if namespace.pylab: |
|
574 |
pylabtools.import_pylab(kernel.shell.user_ns |
|
|
579 | pylabtools.import_pylab(kernel.shell.user_ns, backend, | |
|
580 | shell=kernel.shell) | |
|
575 | 581 | |
|
576 | 582 | start_kernel(namespace, kernel) |
|
577 | 583 |
@@ -3,11 +3,13 b'' | |||
|
3 | 3 | #----------------------------------------------------------------------------- |
|
4 | 4 | # Imports |
|
5 | 5 | #----------------------------------------------------------------------------- |
|
6 | from __future__ import print_function | |
|
6 | 7 | |
|
7 | 8 | # Standard library imports |
|
8 | 9 | from cStringIO import StringIO |
|
9 | 10 | |
|
10 | 11 | # System library imports. |
|
12 | import matplotlib | |
|
11 | 13 | from matplotlib.backends.backend_svg import new_figure_manager |
|
12 | 14 | from matplotlib._pylab_helpers import Gcf |
|
13 | 15 | |
@@ -18,17 +20,68 b' from backend_payload import add_plot_payload' | |||
|
18 | 20 | # Functions |
|
19 | 21 | #----------------------------------------------------------------------------- |
|
20 | 22 | |
|
21 | def show(): | |
|
22 | """ Deliver a SVG payload. | |
|
23 | def show(close=True): | |
|
24 | """Show all figures as SVG payloads sent to the IPython clients. | |
|
25 | ||
|
26 | Parameters | |
|
27 | ---------- | |
|
28 | close : bool, optional | |
|
29 | If true, a ``plt.close('all')`` call is automatically issued after | |
|
30 | sending all the SVG figures. | |
|
23 | 31 | """ |
|
24 | 32 | for figure_manager in Gcf.get_all_fig_managers(): |
|
33 | send_svg_canvas(figure_manager.canvas) | |
|
34 | if close: | |
|
35 | matplotlib.pyplot.close('all') | |
|
36 | ||
|
37 | # This flag will be reset by draw_if_interactive when called | |
|
38 | show._draw_called = False | |
|
39 | ||
|
40 | ||
|
41 | def paste(*figs): | |
|
42 | """Paste figures into the console workspace. | |
|
43 | ||
|
44 | If no arguments are given, all available figures are pasted. If the | |
|
45 | argument list contains references to invalid figures, a warning is printed | |
|
46 | but the function continues pasting further figures. | |
|
47 | ||
|
48 | Parameters | |
|
49 | ---------- | |
|
50 | figs : tuple | |
|
51 | A tuple that can contain any mixture of integers and figure objects. | |
|
52 | """ | |
|
53 | if not figs: | |
|
54 | show(close=False) | |
|
55 | else: | |
|
56 | fig_managers = Gcf.get_all_fig_managers() | |
|
57 | fig_index = dict( [(fm.canvas.figure, fm.canvas) for fm in fig_managers] | |
|
58 | + [ (fm.canvas.figure.number, fm.canvas) for fm in fig_managers] ) | |
|
59 | ||
|
60 | for fig in figs: | |
|
61 | canvas = fig_index.get(fig) | |
|
62 | if canvas is None: | |
|
63 | print('Warning: figure %s not available.' % fig) | |
|
64 | else: | |
|
65 | send_svg_canvas(canvas) | |
|
66 | ||
|
67 | ||
|
68 | def send_svg_canvas(canvas): | |
|
69 | """Draw the current canvas and send it as an SVG payload. | |
|
70 | """ | |
|
25 | 71 |
|
|
26 | 72 |
|
|
27 | # Set the background to white instead so it looks good on black. | |
|
28 | figure_manager.canvas.figure.set_facecolor('white') | |
|
29 | figure_manager.canvas.figure.set_edgecolor('white') | |
|
30 | data = svg_from_canvas(figure_manager.canvas) | |
|
31 | add_plot_payload('svg', data) | |
|
73 | ||
|
74 | # Set the background to white instead so it looks good on black. We store | |
|
75 | # the current values to restore them at the end. | |
|
76 | fc = canvas.figure.get_facecolor() | |
|
77 | ec = canvas.figure.get_edgecolor() | |
|
78 | canvas.figure.set_facecolor('white') | |
|
79 | canvas.figure.set_edgecolor('white') | |
|
80 | try: | |
|
81 | add_plot_payload('svg', svg_from_canvas(canvas)) | |
|
82 | finally: | |
|
83 | canvas.figure.set_facecolor(fc) | |
|
84 | canvas.figure.set_edgecolor(ec) | |
|
32 | 85 | |
|
33 | 86 | |
|
34 | 87 | def svg_from_canvas(canvas): |
@@ -37,3 +90,23 b' def svg_from_canvas(canvas):' | |||
|
37 | 90 | string_io = StringIO() |
|
38 | 91 | canvas.print_svg(string_io) |
|
39 | 92 | return string_io.getvalue() |
|
93 | ||
|
94 | ||
|
95 | def draw_if_interactive(): | |
|
96 | """ | |
|
97 | Is called after every pylab drawing command | |
|
98 | """ | |
|
99 | # We simply flag we were called and otherwise do nothing. At the end of | |
|
100 | # the code execution, a separate call to show_close() will act upon this. | |
|
101 | show._draw_called = True | |
|
102 | ||
|
103 | ||
|
104 | def flush_svg(): | |
|
105 | """Call show, close all open figures, sending all SVG images. | |
|
106 | ||
|
107 | This is meant to be called automatically and will call show() if, during | |
|
108 | prior code execution, there had been any calls to draw_if_interactive. | |
|
109 | """ | |
|
110 | if show._draw_called: | |
|
111 | show(close=True) | |
|
112 | show._draw_called = False |
General Comments 0
You need to be logged in to leave comments.
Login now