Show More
@@ -87,8 +87,8 b' def figsize(sizex, sizey):' | |||||
87 | matplotlib.rcParams['figure.figsize'] = [sizex, sizey] |
|
87 | matplotlib.rcParams['figure.figsize'] = [sizex, sizey] | |
88 |
|
88 | |||
89 |
|
89 | |||
90 | def figure_to_svg(fig): |
|
90 | def print_figure(fig, fmt='png'): | |
91 | """Convert a figure to svg for inline display.""" |
|
91 | """Convert a figure to svg or png for inline display.""" | |
92 | # 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 | |
93 | # get big blank areas in the qt console. |
|
93 | # get big blank areas in the qt console. | |
94 | if not fig.axes: |
|
94 | if not fig.axes: | |
@@ -100,12 +100,15 b' def figure_to_svg(fig):' | |||||
100 | fig.set_edgecolor('white') |
|
100 | fig.set_edgecolor('white') | |
101 | try: |
|
101 | try: | |
102 | string_io = StringIO() |
|
102 | string_io = StringIO() | |
103 | fig.canvas.print_figure(string_io, format='svg') |
|
103 | # use 72 dpi to match QTConsole's dpi | |
104 | svg = string_io.getvalue() |
|
104 | fig.canvas.print_figure(string_io, format=fmt, dpi=72) | |
|
105 | data = string_io.getvalue() | |||
105 | finally: |
|
106 | finally: | |
106 | fig.set_facecolor(fc) |
|
107 | fig.set_facecolor(fc) | |
107 | fig.set_edgecolor(ec) |
|
108 | fig.set_edgecolor(ec) | |
108 | return svg |
|
109 | if fmt == 'png': | |
|
110 | data = data.encode('base64') | |||
|
111 | return data | |||
109 |
|
112 | |||
110 |
|
113 | |||
111 | # We need a little factory function here to create the closure where |
|
114 | # We need a little factory function here to create the closure where | |
@@ -150,6 +153,29 b' def mpl_runner(safe_execfile):' | |||||
150 | return mpl_execfile |
|
153 | return mpl_execfile | |
151 |
|
154 | |||
152 |
|
155 | |||
|
156 | def select_figure_format(shell, fmt): | |||
|
157 | """Select figure format for inline backend, either 'png' or 'svg'. | |||
|
158 | ||||
|
159 | Using this method ensures only one figure format is active at a time. | |||
|
160 | """ | |||
|
161 | from matplotlib.figure import Figure | |||
|
162 | from IPython.zmq.pylab import backend_inline | |||
|
163 | ||||
|
164 | svg_formatter = shell.display_formatter.formatters['image/svg+xml'] | |||
|
165 | png_formatter = shell.display_formatter.formatters['image/png'] | |||
|
166 | ||||
|
167 | if fmt=='png': | |||
|
168 | svg_formatter.type_printers.pop(Figure, None) | |||
|
169 | png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png')) | |||
|
170 | elif fmt=='svg': | |||
|
171 | png_formatter.type_printers.pop(Figure, None) | |||
|
172 | svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg')) | |||
|
173 | else: | |||
|
174 | raise ValueError("supported formats are: 'png', 'svg', not %r"%fmt) | |||
|
175 | ||||
|
176 | # set the format to be used in the backend() | |||
|
177 | backend_inline._figure_format = fmt | |||
|
178 | ||||
153 | #----------------------------------------------------------------------------- |
|
179 | #----------------------------------------------------------------------------- | |
154 | # Code for initializing matplotlib and importing pylab |
|
180 | # Code for initializing matplotlib and importing pylab | |
155 | #----------------------------------------------------------------------------- |
|
181 | #----------------------------------------------------------------------------- | |
@@ -208,7 +234,6 b' def activate_matplotlib(backend):' | |||||
208 | # For this, we wrap it into a decorator which adds a 'called' flag. |
|
234 | # For this, we wrap it into a decorator which adds a 'called' flag. | |
209 | pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive) |
|
235 | pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive) | |
210 |
|
236 | |||
211 |
|
||||
212 | def import_pylab(user_ns, backend, import_all=True, shell=None): |
|
237 | def import_pylab(user_ns, backend, import_all=True, shell=None): | |
213 | """Import the standard pylab symbols into user_ns.""" |
|
238 | """Import the standard pylab symbols into user_ns.""" | |
214 |
|
239 | |||
@@ -228,43 +253,32 b' def import_pylab(user_ns, backend, import_all=True, shell=None):' | |||||
228 | # If using our svg payload backend, register the post-execution |
|
253 | # If using our svg payload backend, register the post-execution | |
229 | # function that will pick up the results for display. This can only be |
|
254 | # function that will pick up the results for display. This can only be | |
230 | # done with access to the real shell object. |
|
255 | # done with access to the real shell object. | |
|
256 | # | |||
|
257 | from IPython.zmq.pylab.backend_inline import InlineBackendConfig | |||
|
258 | ||||
|
259 | cfg = InlineBackendConfig.instance(config=shell.config) | |||
|
260 | cfg.shell = shell | |||
|
261 | ||||
231 | if backend == backends['inline']: |
|
262 | if backend == backends['inline']: | |
232 |
from IPython.zmq.pylab.backend_inline import flush_ |
|
263 | from IPython.zmq.pylab.backend_inline import flush_figures | |
233 | from matplotlib import pyplot |
|
264 | from matplotlib import pyplot | |
234 |
shell.register_post_execute(flush_ |
|
265 | shell.register_post_execute(flush_figures) | |
235 | # The typical default figure size is too large for inline use, |
|
266 | # load inline_rc | |
236 | # so we shrink the figure size to 6x4, and tweak fonts to |
|
267 | pyplot.rcParams.update(cfg.rc) | |
237 | # make that fit. This is configurable via Global.pylab_inline_rc, |
|
|||
238 | # or rather it will be once the zmq kernel is hooked up to |
|
|||
239 | # the config system. |
|
|||
240 |
|
||||
241 | default_rc = { |
|
|||
242 | 'figure.figsize': (6.0,4.0), |
|
|||
243 | # 12pt labels get cutoff on 6x4 logplots, so use 10pt. |
|
|||
244 | 'font.size': 10, |
|
|||
245 | # 10pt still needs a little more room on the xlabel: |
|
|||
246 | 'figure.subplot.bottom' : .125 |
|
|||
247 | } |
|
|||
248 | rc = getattr(shell.config.Global, 'pylab_inline_rc', default_rc) |
|
|||
249 | pyplot.rcParams.update(rc) |
|
|||
250 | shell.config.Global.pylab_inline_rc = rc |
|
|||
251 |
|
268 | |||
252 | # Add 'figsize' to pyplot and to the user's namespace |
|
269 | # Add 'figsize' to pyplot and to the user's namespace | |
253 | user_ns['figsize'] = pyplot.figsize = figsize |
|
270 | user_ns['figsize'] = pyplot.figsize = figsize | |
254 | shell.user_ns_hidden['figsize'] = figsize |
|
271 | shell.user_ns_hidden['figsize'] = figsize | |
255 |
|
272 | |||
|
273 | # Setup the default figure format | |||
|
274 | fmt = cfg.figure_format | |||
|
275 | select_figure_format(shell, fmt) | |||
|
276 | ||||
256 | # The old pastefig function has been replaced by display |
|
277 | # The old pastefig function has been replaced by display | |
257 | # Always add this svg formatter so display works. |
|
278 | from IPython.core.display import display | |
258 | from IPython.core.display import display, display_svg |
|
|||
259 | svg_formatter = shell.display_formatter.formatters['image/svg+xml'] |
|
|||
260 | svg_formatter.for_type_by_name( |
|
|||
261 | 'matplotlib.figure','Figure',figure_to_svg |
|
|||
262 | ) |
|
|||
263 | # Add display and display_png to the user's namespace |
|
279 | # Add display and display_png to the user's namespace | |
264 | user_ns['display'] = display |
|
280 | user_ns['display'] = display | |
265 | shell.user_ns_hidden['display'] = display |
|
281 | shell.user_ns_hidden['display'] = display | |
266 | user_ns['display_svg'] = display_svg |
|
|||
267 | shell.user_ns_hidden['display_svg'] = display_svg |
|
|||
268 | user_ns['getfigs'] = getfigs |
|
282 | user_ns['getfigs'] = getfigs | |
269 | shell.user_ns_hidden['getfigs'] = getfigs |
|
283 | shell.user_ns_hidden['getfigs'] = getfigs | |
270 |
|
284 |
@@ -10,12 +10,46 b' import sys' | |||||
10 |
|
10 | |||
11 | # Third-party imports |
|
11 | # Third-party imports | |
12 | import matplotlib |
|
12 | import matplotlib | |
13 |
from matplotlib.backends.backend_ |
|
13 | from matplotlib.backends.backend_agg import new_figure_manager | |
14 | from matplotlib._pylab_helpers import Gcf |
|
14 | from matplotlib._pylab_helpers import Gcf | |
15 |
|
15 | |||
16 | # Local imports. |
|
16 | # Local imports. | |
|
17 | from IPython.config.configurable import SingletonConfigurable | |||
17 | from IPython.core.displaypub import publish_display_data |
|
18 | from IPython.core.displaypub import publish_display_data | |
18 |
from IPython.lib.pylabtools import figure |
|
19 | from IPython.lib.pylabtools import print_figure, select_figure_format | |
|
20 | from IPython.utils.traitlets import Dict, Instance, CaselessStrEnum | |||
|
21 | #----------------------------------------------------------------------------- | |||
|
22 | # Configurable for inline backend options | |||
|
23 | #----------------------------------------------------------------------------- | |||
|
24 | ||||
|
25 | class InlineBackendConfig(SingletonConfigurable): | |||
|
26 | """An object to store configuration of the inline backend.""" | |||
|
27 | ||||
|
28 | # The typical default figure size is too large for inline use, | |||
|
29 | # so we shrink the figure size to 6x4, and tweak fonts to | |||
|
30 | # make that fit. This is configurable via Global.pylab_inline_rc, | |||
|
31 | # or rather it will be once the zmq kernel is hooked up to | |||
|
32 | # the config system. | |||
|
33 | rc = Dict({'figure.figsize': (6.0,4.0), | |||
|
34 | # 12pt labels get cutoff on 6x4 logplots, so use 10pt. | |||
|
35 | 'font.size': 10, | |||
|
36 | # 10pt still needs a little more room on the xlabel: | |||
|
37 | 'figure.subplot.bottom' : .125 | |||
|
38 | }, config=True, | |||
|
39 | help="""Subset of matplotlib rcParams that should be different for the | |||
|
40 | inline backend.""" | |||
|
41 | ) | |||
|
42 | figure_format = CaselessStrEnum(['svg', 'png'], default_value='png', config=True, | |||
|
43 | help="The image format for figures with the inline backend.") | |||
|
44 | ||||
|
45 | def _format_changed(self, name, old, new): | |||
|
46 | if self.shell is None: | |||
|
47 | return | |||
|
48 | else: | |||
|
49 | select_figure_format(self.shell, new) | |||
|
50 | ||||
|
51 | shell = Instance('IPython.core.interactiveshell.InteractiveShellABC') | |||
|
52 | ||||
19 |
|
53 | |||
20 | #----------------------------------------------------------------------------- |
|
54 | #----------------------------------------------------------------------------- | |
21 | # Functions |
|
55 | # Functions | |
@@ -32,7 +66,7 b' def show(close=True):' | |||||
32 | removed from the internal list of figures. |
|
66 | removed from the internal list of figures. | |
33 | """ |
|
67 | """ | |
34 | for figure_manager in Gcf.get_all_fig_managers(): |
|
68 | for figure_manager in Gcf.get_all_fig_managers(): | |
35 |
send_ |
|
69 | send_figure(figure_manager.canvas.figure) | |
36 | if close: |
|
70 | if close: | |
37 | matplotlib.pyplot.close('all') |
|
71 | matplotlib.pyplot.close('all') | |
38 |
|
72 | |||
@@ -50,8 +84,8 b' def draw_if_interactive():' | |||||
50 | show._draw_called = True |
|
84 | show._draw_called = True | |
51 |
|
85 | |||
52 |
|
86 | |||
53 |
def flush_ |
|
87 | def flush_figures(): | |
54 |
"""Call show, close all open figures, sending all |
|
88 | """Call show, close all open figures, sending all figure images. | |
55 |
|
89 | |||
56 | This is meant to be called automatically and will call show() if, during |
|
90 | This is meant to be called automatically and will call show() if, during | |
57 | prior code execution, there had been any calls to draw_if_interactive. |
|
91 | prior code execution, there had been any calls to draw_if_interactive. | |
@@ -61,21 +95,23 b' def flush_svg():' | |||||
61 | show._draw_called = False |
|
95 | show._draw_called = False | |
62 |
|
96 | |||
63 |
|
97 | |||
64 |
def send_ |
|
98 | def send_figure(fig): | |
65 |
"""Draw the current figure and send it as a |
|
99 | """Draw the current figure and send it as a PNG payload. | |
66 | """ |
|
100 | """ | |
67 | # For an empty figure, don't even bother calling figure_to_svg, to avoid |
|
101 | # For an empty figure, don't even bother calling figure_to_svg, to avoid | |
68 | # big blank spaces in the qt console |
|
102 | # big blank spaces in the qt console | |
69 | if not fig.axes: |
|
103 | if not fig.axes: | |
70 | return |
|
104 | return | |
71 |
|
105 | fmt = InlineBackendConfig.instance().figure_format | ||
72 | svg = figure_to_svg(fig) |
|
106 | data = print_figure(fig, fmt) | |
|
107 | mimetypes = { 'png' : 'image/png', 'svg' : 'image/svg+xml' } | |||
|
108 | mime = mimetypes[fmt] | |||
73 | # flush text streams before sending figures, helps a little with output |
|
109 | # flush text streams before sending figures, helps a little with output | |
74 | # synchronization in the console (though it's a bandaid, not a real sln) |
|
110 | # synchronization in the console (though it's a bandaid, not a real sln) | |
75 | sys.stdout.flush(); sys.stderr.flush() |
|
111 | sys.stdout.flush(); sys.stderr.flush() | |
76 | publish_display_data( |
|
112 | publish_display_data( | |
77 |
'IPython.zmq.pylab.backend_inline.send_ |
|
113 | 'IPython.zmq.pylab.backend_inline.send_figure', | |
78 | 'Matplotlib Plot', |
|
114 | 'Matplotlib Plot', | |
79 |
{ |
|
115 | {mime : data} | |
80 | ) |
|
116 | ) | |
81 |
|
117 |
General Comments 0
You need to be logged in to leave comments.
Login now