Show More
@@ -162,6 +162,7 b' class InteractiveShell(Configurable, Magic):' | |||||
162 | object_info_string_level = Enum((0,1,2), default_value=0, |
|
162 | object_info_string_level = Enum((0,1,2), default_value=0, | |
163 | config=True) |
|
163 | config=True) | |
164 | pdb = CBool(False, config=True) |
|
164 | pdb = CBool(False, config=True) | |
|
165 | ||||
165 | pprint = CBool(True, config=True) |
|
166 | pprint = CBool(True, config=True) | |
166 | profile = Str('', config=True) |
|
167 | profile = Str('', config=True) | |
167 | prompt_in1 = Str('In [\\#]: ', config=True) |
|
168 | prompt_in1 = Str('In [\\#]: ', config=True) | |
@@ -212,6 +213,9 b' class InteractiveShell(Configurable, Magic):' | |||||
212 | plugin_manager = Instance('IPython.core.plugin.PluginManager') |
|
213 | plugin_manager = Instance('IPython.core.plugin.PluginManager') | |
213 | payload_manager = Instance('IPython.core.payload.PayloadManager') |
|
214 | payload_manager = Instance('IPython.core.payload.PayloadManager') | |
214 |
|
215 | |||
|
216 | # Private interface | |||
|
217 | _post_execute = set() | |||
|
218 | ||||
215 | def __init__(self, config=None, ipython_dir=None, |
|
219 | def __init__(self, config=None, ipython_dir=None, | |
216 | user_ns=None, user_global_ns=None, |
|
220 | user_ns=None, user_global_ns=None, | |
217 | custom_exceptions=((), None)): |
|
221 | custom_exceptions=((), None)): | |
@@ -570,6 +574,13 b' class InteractiveShell(Configurable, Magic):' | |||||
570 |
|
574 | |||
571 | setattr(self.hooks,name, dp) |
|
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 | # Things related to the "main" module |
|
585 | # Things related to the "main" module | |
575 | #------------------------------------------------------------------------- |
|
586 | #------------------------------------------------------------------------- | |
@@ -2268,6 +2279,21 b' class InteractiveShell(Configurable, Magic):' | |||||
2268 | outflag = 0 |
|
2279 | outflag = 0 | |
2269 | if softspace(sys.stdout, 0): |
|
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 | # Flush out code object which has been run (and source) |
|
2297 | # Flush out code object which has been run (and source) | |
2272 | self.code_to_run = None |
|
2298 | self.code_to_run = None | |
2273 | return outflag |
|
2299 | return outflag |
@@ -114,10 +114,7 b' def main():' | |||||
114 | if args.pure: |
|
114 | if args.pure: | |
115 | kernel_manager.start_kernel(ipython=False) |
|
115 | kernel_manager.start_kernel(ipython=False) | |
116 | elif args.pylab: |
|
116 | elif args.pylab: | |
117 | if args.rich: |
|
117 | kernel_manager.start_kernel(pylab=args.pylab) | |
118 | kernel_manager.start_kernel(pylab='payload-svg') |
|
|||
119 | else: |
|
|||
120 | kernel_manager.start_kernel(pylab=args.pylab) |
|
|||
121 | else: |
|
118 | else: | |
122 | kernel_manager.start_kernel() |
|
119 | kernel_manager.start_kernel() | |
123 | kernel_manager.start_channels() |
|
120 | kernel_manager.start_channels() | |
@@ -127,7 +124,7 b' def main():' | |||||
127 | if args.pure: |
|
124 | if args.pure: | |
128 | kind = 'rich' if args.rich else 'plain' |
|
125 | kind = 'rich' if args.rich else 'plain' | |
129 | widget = FrontendWidget(kind=kind, paging=args.paging) |
|
126 | widget = FrontendWidget(kind=kind, paging=args.paging) | |
130 | elif args.rich: |
|
127 | elif args.rich or args.pylab: | |
131 | widget = RichIPythonWidget(paging=args.paging) |
|
128 | widget = RichIPythonWidget(paging=args.paging) | |
132 | else: |
|
129 | else: | |
133 | widget = IPythonWidget(paging=args.paging) |
|
130 | widget = IPythonWidget(paging=args.paging) |
@@ -21,6 +21,15 b' Authors' | |||||
21 |
|
21 | |||
22 | from IPython.utils.decorators import flag_calls |
|
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 | # Main classes and functions |
|
34 | # Main classes and functions | |
26 | #----------------------------------------------------------------------------- |
|
35 | #----------------------------------------------------------------------------- | |
@@ -42,24 +51,15 b' def find_gui_and_backend(gui=None):' | |||||
42 |
|
51 | |||
43 | import matplotlib |
|
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 | if gui: |
|
54 | if gui: | |
56 | # select backend based on requested gui |
|
55 | # select backend based on requested gui | |
57 |
backend = |
|
56 | backend = backends[gui] | |
58 | else: |
|
57 | else: | |
59 | backend = matplotlib.rcParams['backend'] |
|
58 | backend = matplotlib.rcParams['backend'] | |
60 | # In this case, we need to find what the appropriate gui selection call |
|
59 | # In this case, we need to find what the appropriate gui selection call | |
61 | # should be for IPython, so we can activate inputhook accordingly |
|
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 | gui = b2g.get(backend, None) |
|
63 | gui = b2g.get(backend, None) | |
64 | return gui, backend |
|
64 | return gui, backend | |
65 |
|
65 | |||
@@ -90,7 +90,8 b' def activate_matplotlib(backend):' | |||||
90 | # For this, we wrap it into a decorator which adds a 'called' flag. |
|
90 | # For this, we wrap it into a decorator which adds a 'called' flag. | |
91 | pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive) |
|
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 | """Import the standard pylab symbols into user_ns.""" |
|
95 | """Import the standard pylab symbols into user_ns.""" | |
95 |
|
96 | |||
96 | # Import numpy as np/pyplot as plt are conventions we're trying to |
|
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 | "plt = pyplot\n" |
|
104 | "plt = pyplot\n" | |
104 | ) in user_ns |
|
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 | if import_all: |
|
118 | if import_all: | |
107 | exec("from matplotlib.pylab import *\n" |
|
119 | exec("from matplotlib.pylab import *\n" | |
108 | "from numpy import *\n") in user_ns |
|
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 | gui, backend = find_gui_and_backend(gui) |
|
144 | gui, backend = find_gui_and_backend(gui) | |
133 | activate_matplotlib(backend) |
|
145 | activate_matplotlib(backend) | |
134 | import_pylab(user_ns) |
|
146 | import_pylab(user_ns, backend) | |
135 |
|
147 | |||
136 | print """ |
|
148 | print """ | |
137 | Welcome to pylab, a matplotlib-based Python environment [backend: %s]. |
|
149 | Welcome to pylab, a matplotlib-based Python environment [backend: %s]. |
@@ -192,11 +192,12 b' class Kernel(Configurable):' | |||||
192 | # FIXME: runlines calls the exception handler itself. |
|
192 | # FIXME: runlines calls the exception handler itself. | |
193 | shell._reply_content = None |
|
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 | # Experimental: cell mode! Test more before turning into |
|
198 | # Experimental: cell mode! Test more before turning into | |
196 | # default and removing the hacks around runlines. |
|
199 | # default and removing the hacks around runlines. | |
197 | shell.run_cell(code) |
|
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 | except: |
|
201 | except: | |
201 | status = u'error' |
|
202 | status = u'error' | |
202 | # FIXME: this code right now isn't being used yet by default, |
|
203 | # FIXME: this code right now isn't being used yet by default, | |
@@ -210,10 +211,6 b' class Kernel(Configurable):' | |||||
210 | reply_content.update(shell._showtraceback(etype, evalue, tb_list)) |
|
211 | reply_content.update(shell._showtraceback(etype, evalue, tb_list)) | |
211 | else: |
|
212 | else: | |
212 | status = u'ok' |
|
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 | reply_content[u'status'] = status |
|
215 | reply_content[u'status'] = status | |
219 | # Compute the execution counter so clients can display prompts |
|
216 | # Compute the execution counter so clients can display prompts | |
@@ -236,7 +233,15 b' class Kernel(Configurable):' | |||||
236 | # expressions |
|
233 | # expressions | |
237 | reply_content[u'user_variables'] = {} |
|
234 | reply_content[u'user_variables'] = {} | |
238 | reply_content[u'user_expressions'] = {} |
|
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 | # Send the reply. |
|
245 | # Send the reply. | |
241 | reply_msg = self.session.msg(u'execute_reply', reply_content, parent) |
|
246 | reply_msg = self.session.msg(u'execute_reply', reply_content, parent) | |
242 | io.raw_print(reply_msg) |
|
247 | io.raw_print(reply_msg) | |
@@ -571,7 +576,8 b" given, the GUI backend is matplotlib's, otherwise use one of: \\" | |||||
571 | kernel = make_kernel(namespace, kernel_class, OutStream) |
|
576 | kernel = make_kernel(namespace, kernel_class, OutStream) | |
572 |
|
577 | |||
573 | if namespace.pylab: |
|
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 | start_kernel(namespace, kernel) |
|
582 | start_kernel(namespace, kernel) | |
577 |
|
583 |
@@ -3,11 +3,13 b'' | |||||
3 | #----------------------------------------------------------------------------- |
|
3 | #----------------------------------------------------------------------------- | |
4 | # Imports |
|
4 | # Imports | |
5 | #----------------------------------------------------------------------------- |
|
5 | #----------------------------------------------------------------------------- | |
|
6 | from __future__ import print_function | |||
6 |
|
7 | |||
7 | # Standard library imports |
|
8 | # Standard library imports | |
8 | from cStringIO import StringIO |
|
9 | from cStringIO import StringIO | |
9 |
|
10 | |||
10 | # System library imports. |
|
11 | # System library imports. | |
|
12 | import matplotlib | |||
11 | from matplotlib.backends.backend_svg import new_figure_manager |
|
13 | from matplotlib.backends.backend_svg import new_figure_manager | |
12 | from matplotlib._pylab_helpers import Gcf |
|
14 | from matplotlib._pylab_helpers import Gcf | |
13 |
|
15 | |||
@@ -18,17 +20,68 b' from backend_payload import add_plot_payload' | |||||
18 | # Functions |
|
20 | # Functions | |
19 | #----------------------------------------------------------------------------- |
|
21 | #----------------------------------------------------------------------------- | |
20 |
|
22 | |||
21 | def show(): |
|
23 | def show(close=True): | |
22 | """ Deliver a SVG payload. |
|
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 | for figure_manager in Gcf.get_all_fig_managers(): |
|
32 | for figure_manager in Gcf.get_all_fig_managers(): | |
25 | # Make the background transparent. |
|
33 | send_svg_canvas(figure_manager.canvas) | |
26 | # figure_manager.canvas.figure.patch.set_alpha(0.0) |
|
34 | if close: | |
27 | # Set the background to white instead so it looks good on black. |
|
35 | matplotlib.pyplot.close('all') | |
28 | figure_manager.canvas.figure.set_facecolor('white') |
|
36 | ||
29 | figure_manager.canvas.figure.set_edgecolor('white') |
|
37 | # This flag will be reset by draw_if_interactive when called | |
30 | data = svg_from_canvas(figure_manager.canvas) |
|
38 | show._draw_called = False | |
31 | add_plot_payload('svg', data) |
|
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 | """ | |||
|
71 | # Make the background transparent. | |||
|
72 | # figure_manager.canvas.figure.patch.set_alpha(0.0) | |||
|
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 | def svg_from_canvas(canvas): |
|
87 | def svg_from_canvas(canvas): | |
@@ -37,3 +90,23 b' def svg_from_canvas(canvas):' | |||||
37 | string_io = StringIO() |
|
90 | string_io = StringIO() | |
38 | canvas.print_svg(string_io) |
|
91 | canvas.print_svg(string_io) | |
39 | return string_io.getvalue() |
|
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