##// END OF EJS Templates
Simplify input transformers...
Simplify input transformers More can now be implemented as stateless transformers

File last commit:

r8967:e52191c6
r10107:bccc0e22
Show More
octavemagic.py
367 lines | 9.9 KiB | text/x-python | PythonLexer
Stefan van der Walt
Octave magic based on oct2py.
r7378 # -*- coding: utf-8 -*-
"""
===========
octavemagic
===========
Stefan van der Walt
Fix plotting.
r7379 Magics for interacting with Octave via oct2py.
Stefan van der Walt
Octave magic based on oct2py.
r7378
Stefan van der Walt
Incorporate PR feedback.
r7439 .. note::
Cavendish McKay
removed the message about h5py dependence from octavemagic.py
r8009 The ``oct2py`` module needs to be installed separately and
can be obtained using ``easy_install`` or ``pip``.
Stefan van der Walt
Incorporate PR feedback.
r7439
Stefan van der Walt
Octave magic based on oct2py.
r7378 Usage
=====
``%octave``
{OCTAVE_DOC}
``%octave_push``
{OCTAVE_PUSH_DOC}
``%octave_pull``
{OCTAVE_PULL_DOC}
"""
#-----------------------------------------------------------------------------
# Copyright (C) 2012 The IPython Development Team
#
# Distributed under the terms of the BSD License. The full license is in
# the file COPYING, distributed as part of this software.
#-----------------------------------------------------------------------------
import tempfile
from glob import glob
from shutil import rmtree
import numpy as np
import oct2py
Stefan van der Walt
Add SVG output.
r7381 from xml.dom import minidom
Stefan van der Walt
Octave magic based on oct2py.
r7378
from IPython.core.displaypub import publish_display_data
Stefan van der Walt
Fix plotting.
r7379 from IPython.core.magic import (Magics, magics_class, line_magic,
Guy Haskin Fernald
Added functionality to %R and %octave magics so that -i first looks in local...
r8262 line_cell_magic, needs_local_scope)
Stefan van der Walt
Octave magic based on oct2py.
r7378 from IPython.testing.skipdoctest import skip_doctest
from IPython.core.magic_arguments import (
argument, magic_arguments, parse_argstring
)
from IPython.utils.py3compat import unicode_to_str
class OctaveMagicError(oct2py.Oct2PyError):
pass
Stefan van der Walt
Add SVG output.
r7381 _mimetypes = {'png' : 'image/png',
'svg' : 'image/svg+xml',
'jpg' : 'image/jpeg',
'jpeg': 'image/jpeg'}
Stefan van der Walt
Octave magic based on oct2py.
r7378
@magics_class
class OctaveMagics(Magics):
"""A set of magics useful for interactive work with Octave via oct2py.
"""
def __init__(self, shell):
"""
Parameters
----------
shell : IPython shell
"""
super(OctaveMagics, self).__init__(shell)
Stefan van der Walt
Add SVG output.
r7381 self._oct = oct2py.Oct2Py()
self._plot_format = 'png'
Stefan van der Walt
Add tests.
r7383 # Allow publish_display_data to be overridden for
# testing purposes.
self._publish_display_data = publish_display_data
Stefan van der Walt
Add SVG output.
r7381
def _fix_gnuplot_svg_size(self, image, size=None):
"""
GnuPlot SVGs do not have height/width attributes. Set
these to be the same as the viewBox, so that the browser
scales the image correctly.
Parameters
----------
image : str
SVG data.
size : tuple of int
Image width, height.
"""
(svg,) = minidom.parseString(image).getElementsByTagName('svg')
viewbox = svg.getAttribute('viewBox').split(' ')
if size is not None:
width, height = size
else:
width, height = viewbox[2:]
svg.setAttribute('width', '%dpx' % width)
svg.setAttribute('height', '%dpx' % height)
return svg.toxml()
Stefan van der Walt
Octave magic based on oct2py.
r7378
@skip_doctest
@line_magic
def octave_push(self, line):
'''
Line-level magic that pushes a variable to Octave.
`line` should be made up of whitespace separated variable names in the
IPython namespace::
In [7]: import numpy as np
In [8]: X = np.arange(5)
In [9]: X.mean()
Out[9]: 2.0
In [10]: %octave_push X
In [11]: %octave mean(X)
Out[11]: 2.0
'''
inputs = line.split(' ')
for input in inputs:
Stefan van der Walt
Fix figure handling. Fix pull.
r7380 input = unicode_to_str(input)
Stefan van der Walt
Add SVG output.
r7381 self._oct.put(input, self.shell.user_ns[input])
Stefan van der Walt
Octave magic based on oct2py.
r7378
@skip_doctest
@line_magic
def octave_pull(self, line):
'''
Line-level magic that pulls a variable from Octave.
In [18]: _ = %octave x = [1 2; 3 4]; y = 'hello'
In [19]: %octave_pull x y
In [20]: x
Out[20]:
array([[ 1., 2.],
[ 3., 4.]])
In [21]: y
Out[21]: 'hello'
'''
outputs = line.split(' ')
for output in outputs:
Stefan van der Walt
Fix plotting.
r7379 output = unicode_to_str(output)
Stefan van der Walt
Add SVG output.
r7381 self.shell.push({output: self._oct.get(output)})
Stefan van der Walt
Octave magic based on oct2py.
r7378
@skip_doctest
@magic_arguments()
@argument(
'-i', '--input', action='append',
Stefan van der Walt
Fix figure handling. Fix pull.
r7380 help='Names of input variables to be pushed to Octave. Multiple names '
'can be passed, separated by commas with no whitespace.'
Stefan van der Walt
Octave magic based on oct2py.
r7378 )
@argument(
'-o', '--output', action='append',
Stefan van der Walt
Fix figure handling. Fix pull.
r7380 help='Names of variables to be pulled from Octave after executing cell '
'body. Multiple names can be passed, separated by commas with no '
'whitespace.'
Stefan van der Walt
Octave magic based on oct2py.
r7378 )
@argument(
Stefan van der Walt
Incorporate PR feedback.
r7439 '-s', '--size', action='store',
Stefan van der Walt
Add SVG output.
r7381 help='Pixel size of plots, "width,height". Default is "-s 400,250".'
)
@argument(
Stefan van der Walt
Incorporate PR feedback.
r7439 '-f', '--format', action='store',
Stefan van der Walt
Add SVG output.
r7381 help='Plot format (png, svg or jpg).'
Stefan van der Walt
Fix plotting.
r7379 )
Stefan van der Walt
Add SVG output.
r7381
Guy Haskin Fernald
Added functionality to %R and %octave magics so that -i first looks in local...
r8262 @needs_local_scope
Stefan van der Walt
Fix plotting.
r7379 @argument(
Stefan van der Walt
Octave magic based on oct2py.
r7378 'code',
nargs='*',
)
@line_cell_magic
Guy Haskin Fernald
Added functionality to %R and %octave magics so that -i first looks in local...
r8262 def octave(self, line, cell=None, local_ns=None):
Stefan van der Walt
Octave magic based on oct2py.
r7378 '''
Execute code in Octave, and pull some of the results back into the
Python namespace.
In [9]: %octave X = [1 2; 3 4]; mean(X)
Out[9]: array([[ 2., 3.]])
As a cell, this will run a block of Octave code, without returning any
value::
In [10]: %%octave
....: p = [-2, -1, 0, 1, 2]
....: polyout(p, 'x')
-2*x^4 - 1*x^3 + 0*x^2 + 1*x^1 + 2
In the notebook, plots are published as the output of the cell, e.g.
%octave plot([1 2 3], [4 5 6])
will create a line plot.
Objects can be passed back and forth between Octave and IPython via the
-i and -o flags in line::
In [14]: Z = np.array([1, 4, 5, 10])
In [15]: %octave -i Z mean(Z)
Out[15]: array([ 5.])
In [16]: %octave -o W W = Z * mean(Z)
Out[16]: array([ 5., 20., 25., 50.])
In [17]: W
Out[17]: array([ 5., 20., 25., 50.])
Stefan van der Walt
Add SVG output.
r7381 The size and format of output plots can be specified::
In [18]: %%octave -s 600,800 -f svg
...: plot([1, 2, 3]);
Stefan van der Walt
Octave magic based on oct2py.
r7378 '''
args = parse_argstring(self.octave, line)
# arguments 'code' in line are prepended to the cell lines
Stefan van der Walt
Add SVG output.
r7381 if cell is None:
Stefan van der Walt
Octave magic based on oct2py.
r7378 code = ''
return_output = True
else:
code = cell
return_output = False
code = ' '.join(args.code) + code
Guy Haskin Fernald
Added functionality to %R and %octave magics so that -i first looks in local...
r8262 # if there is no local namespace then default to an empty dict
if local_ns is None:
local_ns = {}
Stefan van der Walt
Octave magic based on oct2py.
r7378 if args.input:
for input in ','.join(args.input).split(','):
Stefan van der Walt
Fix plotting.
r7379 input = unicode_to_str(input)
Guy Haskin Fernald
Added functionality to %R and %octave magics so that -i first looks in local...
r8262 try:
val = local_ns[input]
except KeyError:
val = self.shell.user_ns[input]
self._oct.put(input, val)
Stefan van der Walt
Octave magic based on oct2py.
r7378
# generate plots in a temporary directory
Steven Silvester
BUG: Octavemagic inline plots not working on Windows: Fixed
r8967 plot_dir = tempfile.mkdtemp().replace('\\', '/')
Stefan van der Walt
Fix plotting.
r7379 if args.size is not None:
Stefan van der Walt
Incorporate PR feedback.
r7439 size = args.size
Stefan van der Walt
Fix plotting.
r7379 else:
size = '400,240'
Stefan van der Walt
Octave magic based on oct2py.
r7378
Stefan van der Walt
Add SVG output.
r7381 if args.format is not None:
Stefan van der Walt
Incorporate PR feedback.
r7439 plot_format = args.format
Stefan van der Walt
Add SVG output.
r7381 else:
plot_format = 'png'
Stefan van der Walt
Octave magic based on oct2py.
r7378 pre_call = '''
global __ipy_figures = [];
page_screen_output(0);
function fig_create(src, event)
global __ipy_figures;
Stefan van der Walt
Correctly handle multiple figures.
r7382 __ipy_figures(size(__ipy_figures) + 1) = src;
Stefan van der Walt
Fix plotting.
r7379 set(src, "visible", "off");
Stefan van der Walt
Octave magic based on oct2py.
r7378 end
set(0, 'DefaultFigureCreateFcn', @fig_create);
Stefan van der Walt
Fix figure handling. Fix pull.
r7380 close all;
Stefan van der Walt
Octave magic based on oct2py.
r7378 clear ans;
Stefan van der Walt
Hide pre- and post-call from user.
r7384
# ___<end_pre_call>___ #
Stefan van der Walt
Octave magic based on oct2py.
r7378 '''
post_call = '''
Stefan van der Walt
Hide pre- and post-call from user.
r7384 # ___<start_post_call>___ #
Stefan van der Walt
Octave magic based on oct2py.
r7378
# Save output of the last execution
if exist("ans") == 1
_ = ans;
else
_ = nan;
end
for f = __ipy_figures
Stefan van der Walt
Fix figure handling. Fix pull.
r7380 outfile = sprintf('%(plot_dir)s/__ipy_oct_fig_%%03d.png', f);
try
Stefan van der Walt
Add SVG output.
r7381 print(f, outfile, '-d%(plot_format)s', '-tight', '-S%(size)s');
Stefan van der Walt
Fix figure handling. Fix pull.
r7380 end
Stefan van der Walt
Octave magic based on oct2py.
r7378 end
Stefan van der Walt
Incorporate PR feedback.
r7439 ''' % locals()
Stefan van der Walt
Octave magic based on oct2py.
r7378
code = ' '.join((pre_call, code, post_call))
try:
Stefan van der Walt
Add SVG output.
r7381 text_output = self._oct.run(code, verbose=False)
Stefan van der Walt
Octave magic based on oct2py.
r7378 except (oct2py.Oct2PyError) as exception:
Stefan van der Walt
Hide pre- and post-call from user.
r7384 msg = exception.message
msg = msg.split('# ___<end_pre_call>___ #')[1]
msg = msg.split('# ___<start_post_call>___ #')[0]
Stefan van der Walt
Octave magic based on oct2py.
r7378 raise OctaveMagicError('Octave could not complete execution. '
'Traceback (currently broken in oct2py): %s'
Stefan van der Walt
Hide pre- and post-call from user.
r7384 % msg)
Stefan van der Walt
Octave magic based on oct2py.
r7378
key = 'OctaveMagic.Octave'
display_data = []
# Publish text output
if text_output:
display_data.append((key, {'text/plain': text_output}))
# Publish images
images = [open(imgfile, 'rb').read() for imgfile in \
Stefan van der Walt
Add SVG output.
r7381 glob("%s/*" % plot_dir)]
Stefan van der Walt
Octave magic based on oct2py.
r7378 rmtree(plot_dir)
Stefan van der Walt
Add SVG output.
r7381 plot_mime_type = _mimetypes.get(plot_format, 'image/png')
width, height = [int(s) for s in size.split(',')]
Stefan van der Walt
Octave magic based on oct2py.
r7378 for image in images:
Stefan van der Walt
Add SVG output.
r7381 if plot_format == 'svg':
image = self._fix_gnuplot_svg_size(image, size=(width, height))
display_data.append((key, {plot_mime_type: image}))
Stefan van der Walt
Octave magic based on oct2py.
r7378
if args.output:
for output in ','.join(args.output).split(','):
output = unicode_to_str(output)
Stefan van der Walt
Add SVG output.
r7381 self.shell.push({output: self._oct.get(output)})
Stefan van der Walt
Octave magic based on oct2py.
r7378
Stefan van der Walt
Add tests.
r7383 for source, data in display_data:
self._publish_display_data(source, data)
Stefan van der Walt
Octave magic based on oct2py.
r7378
if return_output:
Stefan van der Walt
Add SVG output.
r7381 ans = self._oct.get('_')
Stefan van der Walt
Octave magic based on oct2py.
r7378
# Unfortunately, Octave doesn't have a "None" object,
# so we can't return any NaN outputs
Stefan van der Walt
Fix plotting.
r7379 if np.isscalar(ans) and np.isnan(ans):
Stefan van der Walt
Octave magic based on oct2py.
r7378 ans = None
return ans
Stefan van der Walt
Add SVG output.
r7381
Stefan van der Walt
Octave magic based on oct2py.
r7378 __doc__ = __doc__.format(
OCTAVE_DOC = ' '*8 + OctaveMagics.octave.__doc__,
OCTAVE_PUSH_DOC = ' '*8 + OctaveMagics.octave_push.__doc__,
OCTAVE_PULL_DOC = ' '*8 + OctaveMagics.octave_pull.__doc__
)
def load_ipython_extension(ip):
"""Load the extension in IPython."""
Thomas Kluyver
Extensions no longer responsible for checking if they are already loaded
r8552 ip.register_magics(OctaveMagics)