##// END OF EJS Templates
removed the message about h5py dependence from octavemagic.py
Cavendish McKay -
Show More
@@ -1,364 +1,364 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 ===========
4 4 octavemagic
5 5 ===========
6 6
7 7 Magics for interacting with Octave via oct2py.
8 8
9 9 .. note::
10 10
11 The ``oct2py`` module needs to be installed separately, and in turn depends
12 on ``h5py``. Both can be obtained using ``easy_install`` or ``pip``.
11 The ``oct2py`` module needs to be installed separately and
12 can be obtained using ``easy_install`` or ``pip``.
13 13
14 14 Usage
15 15 =====
16 16
17 17 ``%octave``
18 18
19 19 {OCTAVE_DOC}
20 20
21 21 ``%octave_push``
22 22
23 23 {OCTAVE_PUSH_DOC}
24 24
25 25 ``%octave_pull``
26 26
27 27 {OCTAVE_PULL_DOC}
28 28
29 29 """
30 30
31 31 #-----------------------------------------------------------------------------
32 32 # Copyright (C) 2012 The IPython Development Team
33 33 #
34 34 # Distributed under the terms of the BSD License. The full license is in
35 35 # the file COPYING, distributed as part of this software.
36 36 #-----------------------------------------------------------------------------
37 37
38 38 import tempfile
39 39 from glob import glob
40 40 from shutil import rmtree
41 41
42 42 import numpy as np
43 43 import oct2py
44 44 from xml.dom import minidom
45 45
46 46 from IPython.core.displaypub import publish_display_data
47 47 from IPython.core.magic import (Magics, magics_class, line_magic,
48 48 line_cell_magic)
49 49 from IPython.testing.skipdoctest import skip_doctest
50 50 from IPython.core.magic_arguments import (
51 51 argument, magic_arguments, parse_argstring
52 52 )
53 53 from IPython.utils.py3compat import unicode_to_str
54 54
55 55 class OctaveMagicError(oct2py.Oct2PyError):
56 56 pass
57 57
58 58 _mimetypes = {'png' : 'image/png',
59 59 'svg' : 'image/svg+xml',
60 60 'jpg' : 'image/jpeg',
61 61 'jpeg': 'image/jpeg'}
62 62
63 63 @magics_class
64 64 class OctaveMagics(Magics):
65 65 """A set of magics useful for interactive work with Octave via oct2py.
66 66 """
67 67 def __init__(self, shell):
68 68 """
69 69 Parameters
70 70 ----------
71 71 shell : IPython shell
72 72
73 73 """
74 74 super(OctaveMagics, self).__init__(shell)
75 75 self._oct = oct2py.Oct2Py()
76 76 self._plot_format = 'png'
77 77
78 78 # Allow publish_display_data to be overridden for
79 79 # testing purposes.
80 80 self._publish_display_data = publish_display_data
81 81
82 82
83 83 def _fix_gnuplot_svg_size(self, image, size=None):
84 84 """
85 85 GnuPlot SVGs do not have height/width attributes. Set
86 86 these to be the same as the viewBox, so that the browser
87 87 scales the image correctly.
88 88
89 89 Parameters
90 90 ----------
91 91 image : str
92 92 SVG data.
93 93 size : tuple of int
94 94 Image width, height.
95 95
96 96 """
97 97 (svg,) = minidom.parseString(image).getElementsByTagName('svg')
98 98 viewbox = svg.getAttribute('viewBox').split(' ')
99 99
100 100 if size is not None:
101 101 width, height = size
102 102 else:
103 103 width, height = viewbox[2:]
104 104
105 105 svg.setAttribute('width', '%dpx' % width)
106 106 svg.setAttribute('height', '%dpx' % height)
107 107 return svg.toxml()
108 108
109 109
110 110 @skip_doctest
111 111 @line_magic
112 112 def octave_push(self, line):
113 113 '''
114 114 Line-level magic that pushes a variable to Octave.
115 115
116 116 `line` should be made up of whitespace separated variable names in the
117 117 IPython namespace::
118 118
119 119 In [7]: import numpy as np
120 120
121 121 In [8]: X = np.arange(5)
122 122
123 123 In [9]: X.mean()
124 124 Out[9]: 2.0
125 125
126 126 In [10]: %octave_push X
127 127
128 128 In [11]: %octave mean(X)
129 129 Out[11]: 2.0
130 130
131 131 '''
132 132 inputs = line.split(' ')
133 133 for input in inputs:
134 134 input = unicode_to_str(input)
135 135 self._oct.put(input, self.shell.user_ns[input])
136 136
137 137
138 138 @skip_doctest
139 139 @line_magic
140 140 def octave_pull(self, line):
141 141 '''
142 142 Line-level magic that pulls a variable from Octave.
143 143
144 144 In [18]: _ = %octave x = [1 2; 3 4]; y = 'hello'
145 145
146 146 In [19]: %octave_pull x y
147 147
148 148 In [20]: x
149 149 Out[20]:
150 150 array([[ 1., 2.],
151 151 [ 3., 4.]])
152 152
153 153 In [21]: y
154 154 Out[21]: 'hello'
155 155
156 156 '''
157 157 outputs = line.split(' ')
158 158 for output in outputs:
159 159 output = unicode_to_str(output)
160 160 self.shell.push({output: self._oct.get(output)})
161 161
162 162
163 163 @skip_doctest
164 164 @magic_arguments()
165 165 @argument(
166 166 '-i', '--input', action='append',
167 167 help='Names of input variables to be pushed to Octave. Multiple names '
168 168 'can be passed, separated by commas with no whitespace.'
169 169 )
170 170 @argument(
171 171 '-o', '--output', action='append',
172 172 help='Names of variables to be pulled from Octave after executing cell '
173 173 'body. Multiple names can be passed, separated by commas with no '
174 174 'whitespace.'
175 175 )
176 176 @argument(
177 177 '-s', '--size', action='store',
178 178 help='Pixel size of plots, "width,height". Default is "-s 400,250".'
179 179 )
180 180 @argument(
181 181 '-f', '--format', action='store',
182 182 help='Plot format (png, svg or jpg).'
183 183 )
184 184
185 185 @argument(
186 186 'code',
187 187 nargs='*',
188 188 )
189 189 @line_cell_magic
190 190 def octave(self, line, cell=None):
191 191 '''
192 192 Execute code in Octave, and pull some of the results back into the
193 193 Python namespace.
194 194
195 195 In [9]: %octave X = [1 2; 3 4]; mean(X)
196 196 Out[9]: array([[ 2., 3.]])
197 197
198 198 As a cell, this will run a block of Octave code, without returning any
199 199 value::
200 200
201 201 In [10]: %%octave
202 202 ....: p = [-2, -1, 0, 1, 2]
203 203 ....: polyout(p, 'x')
204 204
205 205 -2*x^4 - 1*x^3 + 0*x^2 + 1*x^1 + 2
206 206
207 207 In the notebook, plots are published as the output of the cell, e.g.
208 208
209 209 %octave plot([1 2 3], [4 5 6])
210 210
211 211 will create a line plot.
212 212
213 213 Objects can be passed back and forth between Octave and IPython via the
214 214 -i and -o flags in line::
215 215
216 216 In [14]: Z = np.array([1, 4, 5, 10])
217 217
218 218 In [15]: %octave -i Z mean(Z)
219 219 Out[15]: array([ 5.])
220 220
221 221
222 222 In [16]: %octave -o W W = Z * mean(Z)
223 223 Out[16]: array([ 5., 20., 25., 50.])
224 224
225 225 In [17]: W
226 226 Out[17]: array([ 5., 20., 25., 50.])
227 227
228 228 The size and format of output plots can be specified::
229 229
230 230 In [18]: %%octave -s 600,800 -f svg
231 231 ...: plot([1, 2, 3]);
232 232
233 233 '''
234 234 args = parse_argstring(self.octave, line)
235 235
236 236 # arguments 'code' in line are prepended to the cell lines
237 237 if cell is None:
238 238 code = ''
239 239 return_output = True
240 240 line_mode = True
241 241 else:
242 242 code = cell
243 243 return_output = False
244 244 line_mode = False
245 245
246 246 code = ' '.join(args.code) + code
247 247
248 248 if args.input:
249 249 for input in ','.join(args.input).split(','):
250 250 input = unicode_to_str(input)
251 251 self._oct.put(input, self.shell.user_ns[input])
252 252
253 253 # generate plots in a temporary directory
254 254 plot_dir = tempfile.mkdtemp()
255 255 if args.size is not None:
256 256 size = args.size
257 257 else:
258 258 size = '400,240'
259 259
260 260 if args.format is not None:
261 261 plot_format = args.format
262 262 else:
263 263 plot_format = 'png'
264 264
265 265 pre_call = '''
266 266 global __ipy_figures = [];
267 267 page_screen_output(0);
268 268
269 269 function fig_create(src, event)
270 270 global __ipy_figures;
271 271 __ipy_figures(size(__ipy_figures) + 1) = src;
272 272 set(src, "visible", "off");
273 273 end
274 274
275 275 set(0, 'DefaultFigureCreateFcn', @fig_create);
276 276
277 277 close all;
278 278 clear ans;
279 279
280 280 # ___<end_pre_call>___ #
281 281 '''
282 282
283 283 post_call = '''
284 284 # ___<start_post_call>___ #
285 285
286 286 # Save output of the last execution
287 287 if exist("ans") == 1
288 288 _ = ans;
289 289 else
290 290 _ = nan;
291 291 end
292 292
293 293 for f = __ipy_figures
294 294 outfile = sprintf('%(plot_dir)s/__ipy_oct_fig_%%03d.png', f);
295 295 try
296 296 print(f, outfile, '-d%(plot_format)s', '-tight', '-S%(size)s');
297 297 end
298 298 end
299 299
300 300 ''' % locals()
301 301
302 302 code = ' '.join((pre_call, code, post_call))
303 303 try:
304 304 text_output = self._oct.run(code, verbose=False)
305 305 except (oct2py.Oct2PyError) as exception:
306 306 msg = exception.message
307 307 msg = msg.split('# ___<end_pre_call>___ #')[1]
308 308 msg = msg.split('# ___<start_post_call>___ #')[0]
309 309 raise OctaveMagicError('Octave could not complete execution. '
310 310 'Traceback (currently broken in oct2py): %s'
311 311 % msg)
312 312
313 313 key = 'OctaveMagic.Octave'
314 314 display_data = []
315 315
316 316 # Publish text output
317 317 if text_output:
318 318 display_data.append((key, {'text/plain': text_output}))
319 319
320 320 # Publish images
321 321 images = [open(imgfile, 'rb').read() for imgfile in \
322 322 glob("%s/*" % plot_dir)]
323 323 rmtree(plot_dir)
324 324
325 325 plot_mime_type = _mimetypes.get(plot_format, 'image/png')
326 326 width, height = [int(s) for s in size.split(',')]
327 327 for image in images:
328 328 if plot_format == 'svg':
329 329 image = self._fix_gnuplot_svg_size(image, size=(width, height))
330 330 display_data.append((key, {plot_mime_type: image}))
331 331
332 332 if args.output:
333 333 for output in ','.join(args.output).split(','):
334 334 output = unicode_to_str(output)
335 335 self.shell.push({output: self._oct.get(output)})
336 336
337 337 for source, data in display_data:
338 338 self._publish_display_data(source, data)
339 339
340 340 if return_output:
341 341 ans = self._oct.get('_')
342 342
343 343 # Unfortunately, Octave doesn't have a "None" object,
344 344 # so we can't return any NaN outputs
345 345 if np.isscalar(ans) and np.isnan(ans):
346 346 ans = None
347 347
348 348 return ans
349 349
350 350
351 351 __doc__ = __doc__.format(
352 352 OCTAVE_DOC = ' '*8 + OctaveMagics.octave.__doc__,
353 353 OCTAVE_PUSH_DOC = ' '*8 + OctaveMagics.octave_push.__doc__,
354 354 OCTAVE_PULL_DOC = ' '*8 + OctaveMagics.octave_pull.__doc__
355 355 )
356 356
357 357
358 358 _loaded = False
359 359 def load_ipython_extension(ip):
360 360 """Load the extension in IPython."""
361 361 global _loaded
362 362 if not _loaded:
363 363 ip.register_magics(OctaveMagics)
364 364 _loaded = True
General Comments 0
You need to be logged in to leave comments. Login now