##// END OF EJS Templates
Add SVG output.
Stefan van der Walt -
Show More
@@ -36,6 +36,7 b' from shutil import rmtree'
36 36
37 37 import numpy as np
38 38 import oct2py
39 from xml.dom import minidom
39 40
40 41 from IPython.core.displaypub import publish_display_data
41 42 from IPython.core.magic import (Magics, magics_class, line_magic,
@@ -46,10 +47,13 b' from IPython.core.magic_arguments import ('
46 47 )
47 48 from IPython.utils.py3compat import unicode_to_str
48 49
49
50 50 class OctaveMagicError(oct2py.Oct2PyError):
51 51 pass
52 52
53 _mimetypes = {'png' : 'image/png',
54 'svg' : 'image/svg+xml',
55 'jpg' : 'image/jpeg',
56 'jpeg': 'image/jpeg'}
53 57
54 58 @magics_class
55 59 class OctaveMagics(Magics):
@@ -59,12 +63,39 b' class OctaveMagics(Magics):'
59 63 """
60 64 Parameters
61 65 ----------
62
63 66 shell : IPython shell
64 67
65 68 """
66 69 super(OctaveMagics, self).__init__(shell)
67 self.oct = oct2py.Oct2Py()
70 self._oct = oct2py.Oct2Py()
71 self._plot_format = 'png'
72
73
74 def _fix_gnuplot_svg_size(self, image, size=None):
75 """
76 GnuPlot SVGs do not have height/width attributes. Set
77 these to be the same as the viewBox, so that the browser
78 scales the image correctly.
79
80 Parameters
81 ----------
82 image : str
83 SVG data.
84 size : tuple of int
85 Image width, height.
86
87 """
88 (svg,) = minidom.parseString(image).getElementsByTagName('svg')
89 viewbox = svg.getAttribute('viewBox').split(' ')
90
91 if size is not None:
92 width, height = size
93 else:
94 width, height = viewbox[2:]
95
96 svg.setAttribute('width', '%dpx' % width)
97 svg.setAttribute('height', '%dpx' % height)
98 return svg.toxml()
68 99
69 100
70 101 @skip_doctest
@@ -92,7 +123,7 b' class OctaveMagics(Magics):'
92 123 inputs = line.split(' ')
93 124 for input in inputs:
94 125 input = unicode_to_str(input)
95 self.oct.put(input, self.shell.user_ns[input])
126 self._oct.put(input, self.shell.user_ns[input])
96 127
97 128
98 129 @skip_doctest
@@ -117,7 +148,7 b' class OctaveMagics(Magics):'
117 148 outputs = line.split(' ')
118 149 for output in outputs:
119 150 output = unicode_to_str(output)
120 self.shell.push({output: self.oct.get(output)})
151 self.shell.push({output: self._oct.get(output)})
121 152
122 153
123 154 @skip_doctest
@@ -135,8 +166,13 b' class OctaveMagics(Magics):'
135 166 )
136 167 @argument(
137 168 '-s', '--size', action='append',
138 help='Pixel size of plots. Default is "-s 400,250".'
169 help='Pixel size of plots, "width,height". Default is "-s 400,250".'
170 )
171 @argument(
172 '-f', '--format', action='append',
173 help='Plot format (png, svg or jpg).'
139 174 )
175
140 176 @argument(
141 177 'code',
142 178 nargs='*',
@@ -180,11 +216,16 b' class OctaveMagics(Magics):'
180 216 In [17]: W
181 217 Out[17]: array([ 5., 20., 25., 50.])
182 218
219 The size and format of output plots can be specified::
220
221 In [18]: %%octave -s 600,800 -f svg
222 ...: plot([1, 2, 3]);
223
183 224 '''
184 225 args = parse_argstring(self.octave, line)
185 226
186 227 # arguments 'code' in line are prepended to the cell lines
187 if not cell:
228 if cell is None:
188 229 code = ''
189 230 return_output = True
190 231 line_mode = True
@@ -198,7 +239,7 b' class OctaveMagics(Magics):'
198 239 if args.input:
199 240 for input in ','.join(args.input).split(','):
200 241 input = unicode_to_str(input)
201 self.oct.put(input, self.shell.user_ns[input])
242 self._oct.put(input, self.shell.user_ns[input])
202 243
203 244 # generate plots in a temporary directory
204 245 plot_dir = tempfile.mkdtemp()
@@ -207,6 +248,11 b' class OctaveMagics(Magics):'
207 248 else:
208 249 size = '400,240'
209 250
251 if args.format is not None:
252 plot_format = args.format[0]
253 else:
254 plot_format = 'png'
255
210 256 pre_call = '''
211 257 global __ipy_figures = [];
212 258 page_screen_output(0);
@@ -235,15 +281,16 b' class OctaveMagics(Magics):'
235 281 for f = __ipy_figures
236 282 outfile = sprintf('%(plot_dir)s/__ipy_oct_fig_%%03d.png', f);
237 283 try
238 print(f, outfile, '-dpng', '-tight', '-S%(size)s');
284 print(f, outfile, '-d%(plot_format)s', '-tight', '-S%(size)s');
239 285 end
240 286 end
241 287
242 ''' % {'plot_dir': plot_dir, 'size': size}
288 ''' % {'plot_dir': plot_dir, 'size': size,
289 'plot_format': plot_format}
243 290
244 291 code = ' '.join((pre_call, code, post_call))
245 292 try:
246 text_output = self.oct.run(code, verbose=False)
293 text_output = self._oct.run(code, verbose=False)
247 294 except (oct2py.Oct2PyError) as exception:
248 295 raise OctaveMagicError('Octave could not complete execution. '
249 296 'Traceback (currently broken in oct2py): %s'
@@ -257,28 +304,27 b' class OctaveMagics(Magics):'
257 304 display_data.append((key, {'text/plain': text_output}))
258 305
259 306 # Publish images
260 fmt = 'png'
261 mimetypes = {'png' : 'image/png',
262 'svg' : 'image/svg+xml'}
263 mime = mimetypes[fmt]
264
265 307 images = [open(imgfile, 'rb').read() for imgfile in \
266 glob("%s/*.png" % plot_dir)]
308 glob("%s/*" % plot_dir)]
267 309 rmtree(plot_dir)
268 310
311 plot_mime_type = _mimetypes.get(plot_format, 'image/png')
312 width, height = [int(s) for s in size.split(',')]
269 313 for image in images:
270 display_data.append((key, {mime: image}))
314 if plot_format == 'svg':
315 image = self._fix_gnuplot_svg_size(image, size=(width, height))
316 display_data.append((key, {plot_mime_type: image}))
271 317
272 318 if args.output:
273 319 for output in ','.join(args.output).split(','):
274 320 output = unicode_to_str(output)
275 self.shell.push({output: self.oct.get(output)})
321 self.shell.push({output: self._oct.get(output)})
276 322
277 323 for tag, data in display_data:
278 324 publish_display_data(tag, data)
279 325
280 326 if return_output:
281 ans = self.oct.get('_')
327 ans = self._oct.get('_')
282 328
283 329 # Unfortunately, Octave doesn't have a "None" object,
284 330 # so we can't return any NaN outputs
@@ -287,6 +333,7 b' class OctaveMagics(Magics):'
287 333
288 334 return ans
289 335
336
290 337 __doc__ = __doc__.format(
291 338 OCTAVE_DOC = ' '*8 + OctaveMagics.octave.__doc__,
292 339 OCTAVE_PUSH_DOC = ' '*8 + OctaveMagics.octave_push.__doc__,
General Comments 0
You need to be logged in to leave comments. Login now