##// END OF EJS Templates
Merge pull request #4209 from davclark/magic-doc-fixes...
Thomas Kluyver -
r12548:23b8d0b2 merge
parent child Browse files
Show More
@@ -1,325 +1,334 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 =====================
3 =====================
4 Cython related magics
4 Cython related magics
5 =====================
5 =====================
6
6
7 Magic command interface for interactive work with Cython
8
9 .. note::
10
11 The ``Cython`` package needs to be installed separately. It
12 can be obtained using ``easy_install`` or ``pip``.
13
7 Usage
14 Usage
8 =====
15 =====
9
16
17 To enable the magics below, execute ``%load_ext cythonmagic``.
18
10 ``%%cython``
19 ``%%cython``
11
20
12 {CYTHON_DOC}
21 {CYTHON_DOC}
13
22
14 ``%%cython_inline``
23 ``%%cython_inline``
15
24
16 {CYTHON_INLINE_DOC}
25 {CYTHON_INLINE_DOC}
17
26
18 ``%%cython_pyximport``
27 ``%%cython_pyximport``
19
28
20 {CYTHON_PYXIMPORT_DOC}
29 {CYTHON_PYXIMPORT_DOC}
21
30
22 Author:
31 Author:
23 * Brian Granger
32 * Brian Granger
24
33
25 Parts of this code were taken from Cython.inline.
34 Parts of this code were taken from Cython.inline.
26 """
35 """
27 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
28 # Copyright (C) 2010-2011, IPython Development Team.
37 # Copyright (C) 2010-2011, IPython Development Team.
29 #
38 #
30 # Distributed under the terms of the Modified BSD License.
39 # Distributed under the terms of the Modified BSD License.
31 #
40 #
32 # The full license is in the file COPYING.txt, distributed with this software.
41 # The full license is in the file COPYING.txt, distributed with this software.
33 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
34
43
35 from __future__ import print_function
44 from __future__ import print_function
36
45
37 import imp
46 import imp
38 import io
47 import io
39 import os
48 import os
40 import re
49 import re
41 import sys
50 import sys
42 import time
51 import time
43
52
44 try:
53 try:
45 reload
54 reload
46 except NameError: # Python 3
55 except NameError: # Python 3
47 from imp import reload
56 from imp import reload
48
57
49 try:
58 try:
50 import hashlib
59 import hashlib
51 except ImportError:
60 except ImportError:
52 import md5 as hashlib
61 import md5 as hashlib
53
62
54 from distutils.core import Distribution, Extension
63 from distutils.core import Distribution, Extension
55 from distutils.command.build_ext import build_ext
64 from distutils.command.build_ext import build_ext
56
65
57 from IPython.core import display
66 from IPython.core import display
58 from IPython.core import magic_arguments
67 from IPython.core import magic_arguments
59 from IPython.core.magic import Magics, magics_class, cell_magic
68 from IPython.core.magic import Magics, magics_class, cell_magic
60 from IPython.utils import py3compat
69 from IPython.utils import py3compat
61 from IPython.utils.path import get_ipython_cache_dir
70 from IPython.utils.path import get_ipython_cache_dir
62
71
63 import Cython
72 import Cython
64 from Cython.Compiler.Errors import CompileError
73 from Cython.Compiler.Errors import CompileError
65 from Cython.Build.Dependencies import cythonize
74 from Cython.Build.Dependencies import cythonize
66
75
67
76
68 @magics_class
77 @magics_class
69 class CythonMagics(Magics):
78 class CythonMagics(Magics):
70
79
71 def __init__(self, shell):
80 def __init__(self, shell):
72 super(CythonMagics,self).__init__(shell)
81 super(CythonMagics,self).__init__(shell)
73 self._reloads = {}
82 self._reloads = {}
74 self._code_cache = {}
83 self._code_cache = {}
75
84
76 def _import_all(self, module):
85 def _import_all(self, module):
77 for k,v in module.__dict__.items():
86 for k,v in module.__dict__.items():
78 if not k.startswith('__'):
87 if not k.startswith('__'):
79 self.shell.push({k:v})
88 self.shell.push({k:v})
80
89
81 @cell_magic
90 @cell_magic
82 def cython_inline(self, line, cell):
91 def cython_inline(self, line, cell):
83 """Compile and run a Cython code cell using Cython.inline.
92 """Compile and run a Cython code cell using Cython.inline.
84
93
85 This magic simply passes the body of the cell to Cython.inline
94 This magic simply passes the body of the cell to Cython.inline
86 and returns the result. If the variables `a` and `b` are defined
95 and returns the result. If the variables `a` and `b` are defined
87 in the user's namespace, here is a simple example that returns
96 in the user's namespace, here is a simple example that returns
88 their sum::
97 their sum::
89
98
90 %%cython_inline
99 %%cython_inline
91 return a+b
100 return a+b
92
101
93 For most purposes, we recommend the usage of the `%%cython` magic.
102 For most purposes, we recommend the usage of the `%%cython` magic.
94 """
103 """
95 locs = self.shell.user_global_ns
104 locs = self.shell.user_global_ns
96 globs = self.shell.user_ns
105 globs = self.shell.user_ns
97 return Cython.inline(cell, locals=locs, globals=globs)
106 return Cython.inline(cell, locals=locs, globals=globs)
98
107
99 @cell_magic
108 @cell_magic
100 def cython_pyximport(self, line, cell):
109 def cython_pyximport(self, line, cell):
101 """Compile and import a Cython code cell using pyximport.
110 """Compile and import a Cython code cell using pyximport.
102
111
103 The contents of the cell are written to a `.pyx` file in the current
112 The contents of the cell are written to a `.pyx` file in the current
104 working directory, which is then imported using `pyximport`. This
113 working directory, which is then imported using `pyximport`. This
105 magic requires a module name to be passed::
114 magic requires a module name to be passed::
106
115
107 %%cython_pyximport modulename
116 %%cython_pyximport modulename
108 def f(x):
117 def f(x):
109 return 2.0*x
118 return 2.0*x
110
119
111 The compiled module is then imported and all of its symbols are
120 The compiled module is then imported and all of its symbols are
112 injected into the user's namespace. For most purposes, we recommend
121 injected into the user's namespace. For most purposes, we recommend
113 the usage of the `%%cython` magic.
122 the usage of the `%%cython` magic.
114 """
123 """
115 module_name = line.strip()
124 module_name = line.strip()
116 if not module_name:
125 if not module_name:
117 raise ValueError('module name must be given')
126 raise ValueError('module name must be given')
118 fname = module_name + '.pyx'
127 fname = module_name + '.pyx'
119 with io.open(fname, 'w', encoding='utf-8') as f:
128 with io.open(fname, 'w', encoding='utf-8') as f:
120 f.write(cell)
129 f.write(cell)
121 if 'pyximport' not in sys.modules:
130 if 'pyximport' not in sys.modules:
122 import pyximport
131 import pyximport
123 pyximport.install(reload_support=True)
132 pyximport.install(reload_support=True)
124 if module_name in self._reloads:
133 if module_name in self._reloads:
125 module = self._reloads[module_name]
134 module = self._reloads[module_name]
126 reload(module)
135 reload(module)
127 else:
136 else:
128 __import__(module_name)
137 __import__(module_name)
129 module = sys.modules[module_name]
138 module = sys.modules[module_name]
130 self._reloads[module_name] = module
139 self._reloads[module_name] = module
131 self._import_all(module)
140 self._import_all(module)
132
141
133 @magic_arguments.magic_arguments()
142 @magic_arguments.magic_arguments()
134 @magic_arguments.argument(
143 @magic_arguments.argument(
135 '-c', '--compile-args', action='append', default=[],
144 '-c', '--compile-args', action='append', default=[],
136 help="Extra flags to pass to compiler via the `extra_compile_args` "
145 help="Extra flags to pass to compiler via the `extra_compile_args` "
137 "Extension flag (can be specified multiple times)."
146 "Extension flag (can be specified multiple times)."
138 )
147 )
139 @magic_arguments.argument(
148 @magic_arguments.argument(
140 '--link-args', action='append', default=[],
149 '--link-args', action='append', default=[],
141 help="Extra flags to pass to linker via the `extra_link_args` "
150 help="Extra flags to pass to linker via the `extra_link_args` "
142 "Extension flag (can be specified multiple times)."
151 "Extension flag (can be specified multiple times)."
143 )
152 )
144 @magic_arguments.argument(
153 @magic_arguments.argument(
145 '-l', '--lib', action='append', default=[],
154 '-l', '--lib', action='append', default=[],
146 help="Add a library to link the extension against (can be specified "
155 help="Add a library to link the extension against (can be specified "
147 "multiple times)."
156 "multiple times)."
148 )
157 )
149 @magic_arguments.argument(
158 @magic_arguments.argument(
150 '-L', dest='library_dirs', metavar='dir', action='append', default=[],
159 '-L', dest='library_dirs', metavar='dir', action='append', default=[],
151 help="Add a path to the list of libary directories (can be specified "
160 help="Add a path to the list of libary directories (can be specified "
152 "multiple times)."
161 "multiple times)."
153 )
162 )
154 @magic_arguments.argument(
163 @magic_arguments.argument(
155 '-I', '--include', action='append', default=[],
164 '-I', '--include', action='append', default=[],
156 help="Add a path to the list of include directories (can be specified "
165 help="Add a path to the list of include directories (can be specified "
157 "multiple times)."
166 "multiple times)."
158 )
167 )
159 @magic_arguments.argument(
168 @magic_arguments.argument(
160 '-+', '--cplus', action='store_true', default=False,
169 '-+', '--cplus', action='store_true', default=False,
161 help="Output a C++ rather than C file."
170 help="Output a C++ rather than C file."
162 )
171 )
163 @magic_arguments.argument(
172 @magic_arguments.argument(
164 '-f', '--force', action='store_true', default=False,
173 '-f', '--force', action='store_true', default=False,
165 help="Force the compilation of a new module, even if the source has been "
174 help="Force the compilation of a new module, even if the source has been "
166 "previously compiled."
175 "previously compiled."
167 )
176 )
168 @magic_arguments.argument(
177 @magic_arguments.argument(
169 '-a', '--annotate', action='store_true', default=False,
178 '-a', '--annotate', action='store_true', default=False,
170 help="Produce a colorized HTML version of the source."
179 help="Produce a colorized HTML version of the source."
171 )
180 )
172 @cell_magic
181 @cell_magic
173 def cython(self, line, cell):
182 def cython(self, line, cell):
174 """Compile and import everything from a Cython code cell.
183 """Compile and import everything from a Cython code cell.
175
184
176 The contents of the cell are written to a `.pyx` file in the
185 The contents of the cell are written to a `.pyx` file in the
177 directory `IPYTHONDIR/cython` using a filename with the hash of the
186 directory `IPYTHONDIR/cython` using a filename with the hash of the
178 code. This file is then cythonized and compiled. The resulting module
187 code. This file is then cythonized and compiled. The resulting module
179 is imported and all of its symbols are injected into the user's
188 is imported and all of its symbols are injected into the user's
180 namespace. The usage is similar to that of `%%cython_pyximport` but
189 namespace. The usage is similar to that of `%%cython_pyximport` but
181 you don't have to pass a module name::
190 you don't have to pass a module name::
182
191
183 %%cython
192 %%cython
184 def f(x):
193 def f(x):
185 return 2.0*x
194 return 2.0*x
186
195
187 To compile OpenMP codes, pass the required `--compile-args`
196 To compile OpenMP codes, pass the required `--compile-args`
188 and `--link-args`. For example with gcc::
197 and `--link-args`. For example with gcc::
189
198
190 %%cython --compile-args=-fopenmp --link-args=-fopenmp
199 %%cython --compile-args=-fopenmp --link-args=-fopenmp
191 ...
200 ...
192 """
201 """
193 args = magic_arguments.parse_argstring(self.cython, line)
202 args = magic_arguments.parse_argstring(self.cython, line)
194 code = cell if cell.endswith('\n') else cell+'\n'
203 code = cell if cell.endswith('\n') else cell+'\n'
195 lib_dir = os.path.join(get_ipython_cache_dir(), 'cython')
204 lib_dir = os.path.join(get_ipython_cache_dir(), 'cython')
196 quiet = True
205 quiet = True
197 key = code, sys.version_info, sys.executable, Cython.__version__
206 key = code, sys.version_info, sys.executable, Cython.__version__
198
207
199 if not os.path.exists(lib_dir):
208 if not os.path.exists(lib_dir):
200 os.makedirs(lib_dir)
209 os.makedirs(lib_dir)
201
210
202 if args.force:
211 if args.force:
203 # Force a new module name by adding the current time to the
212 # Force a new module name by adding the current time to the
204 # key which is hashed to determine the module name.
213 # key which is hashed to determine the module name.
205 key += time.time(),
214 key += time.time(),
206
215
207 module_name = "_cython_magic_" + hashlib.md5(str(key).encode('utf-8')).hexdigest()
216 module_name = "_cython_magic_" + hashlib.md5(str(key).encode('utf-8')).hexdigest()
208 module_path = os.path.join(lib_dir, module_name + self.so_ext)
217 module_path = os.path.join(lib_dir, module_name + self.so_ext)
209
218
210 have_module = os.path.isfile(module_path)
219 have_module = os.path.isfile(module_path)
211 need_cythonize = not have_module
220 need_cythonize = not have_module
212
221
213 if args.annotate:
222 if args.annotate:
214 html_file = os.path.join(lib_dir, module_name + '.html')
223 html_file = os.path.join(lib_dir, module_name + '.html')
215 if not os.path.isfile(html_file):
224 if not os.path.isfile(html_file):
216 need_cythonize = True
225 need_cythonize = True
217
226
218 if need_cythonize:
227 if need_cythonize:
219 c_include_dirs = args.include
228 c_include_dirs = args.include
220 if 'numpy' in code:
229 if 'numpy' in code:
221 import numpy
230 import numpy
222 c_include_dirs.append(numpy.get_include())
231 c_include_dirs.append(numpy.get_include())
223 pyx_file = os.path.join(lib_dir, module_name + '.pyx')
232 pyx_file = os.path.join(lib_dir, module_name + '.pyx')
224 pyx_file = py3compat.cast_bytes_py2(pyx_file, encoding=sys.getfilesystemencoding())
233 pyx_file = py3compat.cast_bytes_py2(pyx_file, encoding=sys.getfilesystemencoding())
225 with io.open(pyx_file, 'w', encoding='utf-8') as f:
234 with io.open(pyx_file, 'w', encoding='utf-8') as f:
226 f.write(code)
235 f.write(code)
227 extension = Extension(
236 extension = Extension(
228 name = module_name,
237 name = module_name,
229 sources = [pyx_file],
238 sources = [pyx_file],
230 include_dirs = c_include_dirs,
239 include_dirs = c_include_dirs,
231 library_dirs = args.library_dirs,
240 library_dirs = args.library_dirs,
232 extra_compile_args = args.compile_args,
241 extra_compile_args = args.compile_args,
233 extra_link_args = args.link_args,
242 extra_link_args = args.link_args,
234 libraries = args.lib,
243 libraries = args.lib,
235 language = 'c++' if args.cplus else 'c',
244 language = 'c++' if args.cplus else 'c',
236 )
245 )
237 build_extension = self._get_build_extension()
246 build_extension = self._get_build_extension()
238 try:
247 try:
239 opts = dict(
248 opts = dict(
240 quiet=quiet,
249 quiet=quiet,
241 annotate = args.annotate,
250 annotate = args.annotate,
242 force = True,
251 force = True,
243 )
252 )
244 build_extension.extensions = cythonize([extension], **opts)
253 build_extension.extensions = cythonize([extension], **opts)
245 except CompileError:
254 except CompileError:
246 return
255 return
247
256
248 if not have_module:
257 if not have_module:
249 build_extension.build_temp = os.path.dirname(pyx_file)
258 build_extension.build_temp = os.path.dirname(pyx_file)
250 build_extension.build_lib = lib_dir
259 build_extension.build_lib = lib_dir
251 build_extension.run()
260 build_extension.run()
252 self._code_cache[key] = module_name
261 self._code_cache[key] = module_name
253
262
254 module = imp.load_dynamic(module_name, module_path)
263 module = imp.load_dynamic(module_name, module_path)
255 self._import_all(module)
264 self._import_all(module)
256
265
257 if args.annotate:
266 if args.annotate:
258 try:
267 try:
259 with io.open(html_file, encoding='utf-8') as f:
268 with io.open(html_file, encoding='utf-8') as f:
260 annotated_html = f.read()
269 annotated_html = f.read()
261 except IOError as e:
270 except IOError as e:
262 # File could not be opened. Most likely the user has a version
271 # File could not be opened. Most likely the user has a version
263 # of Cython before 0.15.1 (when `cythonize` learned the
272 # of Cython before 0.15.1 (when `cythonize` learned the
264 # `force` keyword argument) and has already compiled this
273 # `force` keyword argument) and has already compiled this
265 # exact source without annotation.
274 # exact source without annotation.
266 print('Cython completed successfully but the annotated '
275 print('Cython completed successfully but the annotated '
267 'source could not be read.', file=sys.stderr)
276 'source could not be read.', file=sys.stderr)
268 print(e, file=sys.stderr)
277 print(e, file=sys.stderr)
269 else:
278 else:
270 return display.HTML(self.clean_annotated_html(annotated_html))
279 return display.HTML(self.clean_annotated_html(annotated_html))
271
280
272 @property
281 @property
273 def so_ext(self):
282 def so_ext(self):
274 """The extension suffix for compiled modules."""
283 """The extension suffix for compiled modules."""
275 try:
284 try:
276 return self._so_ext
285 return self._so_ext
277 except AttributeError:
286 except AttributeError:
278 self._so_ext = self._get_build_extension().get_ext_filename('')
287 self._so_ext = self._get_build_extension().get_ext_filename('')
279 return self._so_ext
288 return self._so_ext
280
289
281 def _clear_distutils_mkpath_cache(self):
290 def _clear_distutils_mkpath_cache(self):
282 """clear distutils mkpath cache
291 """clear distutils mkpath cache
283
292
284 prevents distutils from skipping re-creation of dirs that have been removed
293 prevents distutils from skipping re-creation of dirs that have been removed
285 """
294 """
286 try:
295 try:
287 from distutils.dir_util import _path_created
296 from distutils.dir_util import _path_created
288 except ImportError:
297 except ImportError:
289 pass
298 pass
290 else:
299 else:
291 _path_created.clear()
300 _path_created.clear()
292
301
293 def _get_build_extension(self):
302 def _get_build_extension(self):
294 self._clear_distutils_mkpath_cache()
303 self._clear_distutils_mkpath_cache()
295 dist = Distribution()
304 dist = Distribution()
296 config_files = dist.find_config_files()
305 config_files = dist.find_config_files()
297 try:
306 try:
298 config_files.remove('setup.cfg')
307 config_files.remove('setup.cfg')
299 except ValueError:
308 except ValueError:
300 pass
309 pass
301 dist.parse_config_files(config_files)
310 dist.parse_config_files(config_files)
302 build_extension = build_ext(dist)
311 build_extension = build_ext(dist)
303 build_extension.finalize_options()
312 build_extension.finalize_options()
304 return build_extension
313 return build_extension
305
314
306 @staticmethod
315 @staticmethod
307 def clean_annotated_html(html):
316 def clean_annotated_html(html):
308 """Clean up the annotated HTML source.
317 """Clean up the annotated HTML source.
309
318
310 Strips the link to the generated C or C++ file, which we do not
319 Strips the link to the generated C or C++ file, which we do not
311 present to the user.
320 present to the user.
312 """
321 """
313 r = re.compile('<p>Raw output: <a href="(.*)">(.*)</a>')
322 r = re.compile('<p>Raw output: <a href="(.*)">(.*)</a>')
314 html = '\n'.join(l for l in html.splitlines() if not r.match(l))
323 html = '\n'.join(l for l in html.splitlines() if not r.match(l))
315 return html
324 return html
316
325
317 __doc__ = __doc__.format(
326 __doc__ = __doc__.format(
318 CYTHON_DOC = ' '*8 + CythonMagics.cython.__doc__,
327 CYTHON_DOC = ' '*8 + CythonMagics.cython.__doc__,
319 CYTHON_INLINE_DOC = ' '*8 + CythonMagics.cython_inline.__doc__,
328 CYTHON_INLINE_DOC = ' '*8 + CythonMagics.cython_inline.__doc__,
320 CYTHON_PYXIMPORT_DOC = ' '*8 + CythonMagics.cython_pyximport.__doc__,
329 CYTHON_PYXIMPORT_DOC = ' '*8 + CythonMagics.cython_pyximport.__doc__,
321 )
330 )
322
331
323 def load_ipython_extension(ip):
332 def load_ipython_extension(ip):
324 """Load the extension in IPython."""
333 """Load the extension in IPython."""
325 ip.register_magics(CythonMagics)
334 ip.register_magics(CythonMagics)
@@ -1,367 +1,371 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 ===========
3 ===========
4 octavemagic
4 octavemagic
5 ===========
5 ===========
6
6
7 Magics for interacting with Octave via oct2py.
7 Magics for interacting with Octave via oct2py.
8
8
9 .. note::
9 .. note::
10
10
11 The ``oct2py`` module needs to be installed separately and
11 The ``oct2py`` module needs to be installed separately and
12 can be obtained using ``easy_install`` or ``pip``.
12 can be obtained using ``easy_install`` or ``pip``.
13
13
14 You will also need a working copy of GNU Octave.
15
14 Usage
16 Usage
15 =====
17 =====
16
18
19 To enable the magics below, execute ``%load_ext octavemagic``.
20
17 ``%octave``
21 ``%octave``
18
22
19 {OCTAVE_DOC}
23 {OCTAVE_DOC}
20
24
21 ``%octave_push``
25 ``%octave_push``
22
26
23 {OCTAVE_PUSH_DOC}
27 {OCTAVE_PUSH_DOC}
24
28
25 ``%octave_pull``
29 ``%octave_pull``
26
30
27 {OCTAVE_PULL_DOC}
31 {OCTAVE_PULL_DOC}
28
32
29 """
33 """
30
34
31 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
32 # Copyright (C) 2012 The IPython Development Team
36 # Copyright (C) 2012 The IPython Development Team
33 #
37 #
34 # Distributed under the terms of the BSD License. The full license is in
38 # Distributed under the terms of the BSD License. The full license is in
35 # the file COPYING, distributed as part of this software.
39 # the file COPYING, distributed as part of this software.
36 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
37
41
38 import tempfile
42 import tempfile
39 from glob import glob
43 from glob import glob
40 from shutil import rmtree
44 from shutil import rmtree
41
45
42 import numpy as np
46 import numpy as np
43 import oct2py
47 import oct2py
44 from xml.dom import minidom
48 from xml.dom import minidom
45
49
46 from IPython.core.displaypub import publish_display_data
50 from IPython.core.displaypub import publish_display_data
47 from IPython.core.magic import (Magics, magics_class, line_magic,
51 from IPython.core.magic import (Magics, magics_class, line_magic,
48 line_cell_magic, needs_local_scope)
52 line_cell_magic, needs_local_scope)
49 from IPython.testing.skipdoctest import skip_doctest
53 from IPython.testing.skipdoctest import skip_doctest
50 from IPython.core.magic_arguments import (
54 from IPython.core.magic_arguments import (
51 argument, magic_arguments, parse_argstring
55 argument, magic_arguments, parse_argstring
52 )
56 )
53 from IPython.utils.py3compat import unicode_to_str
57 from IPython.utils.py3compat import unicode_to_str
54
58
55 class OctaveMagicError(oct2py.Oct2PyError):
59 class OctaveMagicError(oct2py.Oct2PyError):
56 pass
60 pass
57
61
58 _mimetypes = {'png' : 'image/png',
62 _mimetypes = {'png' : 'image/png',
59 'svg' : 'image/svg+xml',
63 'svg' : 'image/svg+xml',
60 'jpg' : 'image/jpeg',
64 'jpg' : 'image/jpeg',
61 'jpeg': 'image/jpeg'}
65 'jpeg': 'image/jpeg'}
62
66
63 @magics_class
67 @magics_class
64 class OctaveMagics(Magics):
68 class OctaveMagics(Magics):
65 """A set of magics useful for interactive work with Octave via oct2py.
69 """A set of magics useful for interactive work with Octave via oct2py.
66 """
70 """
67 def __init__(self, shell):
71 def __init__(self, shell):
68 """
72 """
69 Parameters
73 Parameters
70 ----------
74 ----------
71 shell : IPython shell
75 shell : IPython shell
72
76
73 """
77 """
74 super(OctaveMagics, self).__init__(shell)
78 super(OctaveMagics, self).__init__(shell)
75 self._oct = oct2py.Oct2Py()
79 self._oct = oct2py.Oct2Py()
76 self._plot_format = 'png'
80 self._plot_format = 'png'
77
81
78 # Allow publish_display_data to be overridden for
82 # Allow publish_display_data to be overridden for
79 # testing purposes.
83 # testing purposes.
80 self._publish_display_data = publish_display_data
84 self._publish_display_data = publish_display_data
81
85
82
86
83 def _fix_gnuplot_svg_size(self, image, size=None):
87 def _fix_gnuplot_svg_size(self, image, size=None):
84 """
88 """
85 GnuPlot SVGs do not have height/width attributes. Set
89 GnuPlot SVGs do not have height/width attributes. Set
86 these to be the same as the viewBox, so that the browser
90 these to be the same as the viewBox, so that the browser
87 scales the image correctly.
91 scales the image correctly.
88
92
89 Parameters
93 Parameters
90 ----------
94 ----------
91 image : str
95 image : str
92 SVG data.
96 SVG data.
93 size : tuple of int
97 size : tuple of int
94 Image width, height.
98 Image width, height.
95
99
96 """
100 """
97 (svg,) = minidom.parseString(image).getElementsByTagName('svg')
101 (svg,) = minidom.parseString(image).getElementsByTagName('svg')
98 viewbox = svg.getAttribute('viewBox').split(' ')
102 viewbox = svg.getAttribute('viewBox').split(' ')
99
103
100 if size is not None:
104 if size is not None:
101 width, height = size
105 width, height = size
102 else:
106 else:
103 width, height = viewbox[2:]
107 width, height = viewbox[2:]
104
108
105 svg.setAttribute('width', '%dpx' % width)
109 svg.setAttribute('width', '%dpx' % width)
106 svg.setAttribute('height', '%dpx' % height)
110 svg.setAttribute('height', '%dpx' % height)
107 return svg.toxml()
111 return svg.toxml()
108
112
109
113
110 @skip_doctest
114 @skip_doctest
111 @line_magic
115 @line_magic
112 def octave_push(self, line):
116 def octave_push(self, line):
113 '''
117 '''
114 Line-level magic that pushes a variable to Octave.
118 Line-level magic that pushes a variable to Octave.
115
119
116 `line` should be made up of whitespace separated variable names in the
120 `line` should be made up of whitespace separated variable names in the
117 IPython namespace::
121 IPython namespace::
118
122
119 In [7]: import numpy as np
123 In [7]: import numpy as np
120
124
121 In [8]: X = np.arange(5)
125 In [8]: X = np.arange(5)
122
126
123 In [9]: X.mean()
127 In [9]: X.mean()
124 Out[9]: 2.0
128 Out[9]: 2.0
125
129
126 In [10]: %octave_push X
130 In [10]: %octave_push X
127
131
128 In [11]: %octave mean(X)
132 In [11]: %octave mean(X)
129 Out[11]: 2.0
133 Out[11]: 2.0
130
134
131 '''
135 '''
132 inputs = line.split(' ')
136 inputs = line.split(' ')
133 for input in inputs:
137 for input in inputs:
134 input = unicode_to_str(input)
138 input = unicode_to_str(input)
135 self._oct.put(input, self.shell.user_ns[input])
139 self._oct.put(input, self.shell.user_ns[input])
136
140
137
141
138 @skip_doctest
142 @skip_doctest
139 @line_magic
143 @line_magic
140 def octave_pull(self, line):
144 def octave_pull(self, line):
141 '''
145 '''
142 Line-level magic that pulls a variable from Octave.
146 Line-level magic that pulls a variable from Octave.
143
147
144 In [18]: _ = %octave x = [1 2; 3 4]; y = 'hello'
148 In [18]: _ = %octave x = [1 2; 3 4]; y = 'hello'
145
149
146 In [19]: %octave_pull x y
150 In [19]: %octave_pull x y
147
151
148 In [20]: x
152 In [20]: x
149 Out[20]:
153 Out[20]:
150 array([[ 1., 2.],
154 array([[ 1., 2.],
151 [ 3., 4.]])
155 [ 3., 4.]])
152
156
153 In [21]: y
157 In [21]: y
154 Out[21]: 'hello'
158 Out[21]: 'hello'
155
159
156 '''
160 '''
157 outputs = line.split(' ')
161 outputs = line.split(' ')
158 for output in outputs:
162 for output in outputs:
159 output = unicode_to_str(output)
163 output = unicode_to_str(output)
160 self.shell.push({output: self._oct.get(output)})
164 self.shell.push({output: self._oct.get(output)})
161
165
162
166
163 @skip_doctest
167 @skip_doctest
164 @magic_arguments()
168 @magic_arguments()
165 @argument(
169 @argument(
166 '-i', '--input', action='append',
170 '-i', '--input', action='append',
167 help='Names of input variables to be pushed to Octave. Multiple names '
171 help='Names of input variables to be pushed to Octave. Multiple names '
168 'can be passed, separated by commas with no whitespace.'
172 'can be passed, separated by commas with no whitespace.'
169 )
173 )
170 @argument(
174 @argument(
171 '-o', '--output', action='append',
175 '-o', '--output', action='append',
172 help='Names of variables to be pulled from Octave after executing cell '
176 help='Names of variables to be pulled from Octave after executing cell '
173 'body. Multiple names can be passed, separated by commas with no '
177 'body. Multiple names can be passed, separated by commas with no '
174 'whitespace.'
178 'whitespace.'
175 )
179 )
176 @argument(
180 @argument(
177 '-s', '--size', action='store',
181 '-s', '--size', action='store',
178 help='Pixel size of plots, "width,height". Default is "-s 400,250".'
182 help='Pixel size of plots, "width,height". Default is "-s 400,250".'
179 )
183 )
180 @argument(
184 @argument(
181 '-f', '--format', action='store',
185 '-f', '--format', action='store',
182 help='Plot format (png, svg or jpg).'
186 help='Plot format (png, svg or jpg).'
183 )
187 )
184
188
185 @needs_local_scope
189 @needs_local_scope
186 @argument(
190 @argument(
187 'code',
191 'code',
188 nargs='*',
192 nargs='*',
189 )
193 )
190 @line_cell_magic
194 @line_cell_magic
191 def octave(self, line, cell=None, local_ns=None):
195 def octave(self, line, cell=None, local_ns=None):
192 '''
196 '''
193 Execute code in Octave, and pull some of the results back into the
197 Execute code in Octave, and pull some of the results back into the
194 Python namespace.
198 Python namespace.
195
199
196 In [9]: %octave X = [1 2; 3 4]; mean(X)
200 In [9]: %octave X = [1 2; 3 4]; mean(X)
197 Out[9]: array([[ 2., 3.]])
201 Out[9]: array([[ 2., 3.]])
198
202
199 As a cell, this will run a block of Octave code, without returning any
203 As a cell, this will run a block of Octave code, without returning any
200 value::
204 value::
201
205
202 In [10]: %%octave
206 In [10]: %%octave
203 ....: p = [-2, -1, 0, 1, 2]
207 ....: p = [-2, -1, 0, 1, 2]
204 ....: polyout(p, 'x')
208 ....: polyout(p, 'x')
205
209
206 -2*x^4 - 1*x^3 + 0*x^2 + 1*x^1 + 2
210 -2*x^4 - 1*x^3 + 0*x^2 + 1*x^1 + 2
207
211
208 In the notebook, plots are published as the output of the cell, e.g.
212 In the notebook, plots are published as the output of the cell, e.g.
209
213
210 %octave plot([1 2 3], [4 5 6])
214 %octave plot([1 2 3], [4 5 6])
211
215
212 will create a line plot.
216 will create a line plot.
213
217
214 Objects can be passed back and forth between Octave and IPython via the
218 Objects can be passed back and forth between Octave and IPython via the
215 -i and -o flags in line::
219 -i and -o flags in line::
216
220
217 In [14]: Z = np.array([1, 4, 5, 10])
221 In [14]: Z = np.array([1, 4, 5, 10])
218
222
219 In [15]: %octave -i Z mean(Z)
223 In [15]: %octave -i Z mean(Z)
220 Out[15]: array([ 5.])
224 Out[15]: array([ 5.])
221
225
222
226
223 In [16]: %octave -o W W = Z * mean(Z)
227 In [16]: %octave -o W W = Z * mean(Z)
224 Out[16]: array([ 5., 20., 25., 50.])
228 Out[16]: array([ 5., 20., 25., 50.])
225
229
226 In [17]: W
230 In [17]: W
227 Out[17]: array([ 5., 20., 25., 50.])
231 Out[17]: array([ 5., 20., 25., 50.])
228
232
229 The size and format of output plots can be specified::
233 The size and format of output plots can be specified::
230
234
231 In [18]: %%octave -s 600,800 -f svg
235 In [18]: %%octave -s 600,800 -f svg
232 ...: plot([1, 2, 3]);
236 ...: plot([1, 2, 3]);
233
237
234 '''
238 '''
235 args = parse_argstring(self.octave, line)
239 args = parse_argstring(self.octave, line)
236
240
237 # arguments 'code' in line are prepended to the cell lines
241 # arguments 'code' in line are prepended to the cell lines
238 if cell is None:
242 if cell is None:
239 code = ''
243 code = ''
240 return_output = True
244 return_output = True
241 else:
245 else:
242 code = cell
246 code = cell
243 return_output = False
247 return_output = False
244
248
245 code = ' '.join(args.code) + code
249 code = ' '.join(args.code) + code
246
250
247 # if there is no local namespace then default to an empty dict
251 # if there is no local namespace then default to an empty dict
248 if local_ns is None:
252 if local_ns is None:
249 local_ns = {}
253 local_ns = {}
250
254
251 if args.input:
255 if args.input:
252 for input in ','.join(args.input).split(','):
256 for input in ','.join(args.input).split(','):
253 input = unicode_to_str(input)
257 input = unicode_to_str(input)
254 try:
258 try:
255 val = local_ns[input]
259 val = local_ns[input]
256 except KeyError:
260 except KeyError:
257 val = self.shell.user_ns[input]
261 val = self.shell.user_ns[input]
258 self._oct.put(input, val)
262 self._oct.put(input, val)
259
263
260 # generate plots in a temporary directory
264 # generate plots in a temporary directory
261 plot_dir = tempfile.mkdtemp().replace('\\', '/')
265 plot_dir = tempfile.mkdtemp().replace('\\', '/')
262 if args.size is not None:
266 if args.size is not None:
263 size = args.size
267 size = args.size
264 else:
268 else:
265 size = '400,240'
269 size = '400,240'
266
270
267 if args.format is not None:
271 if args.format is not None:
268 plot_format = args.format
272 plot_format = args.format
269 else:
273 else:
270 plot_format = 'png'
274 plot_format = 'png'
271
275
272 pre_call = '''
276 pre_call = '''
273 global __ipy_figures = [];
277 global __ipy_figures = [];
274 page_screen_output(0);
278 page_screen_output(0);
275
279
276 function fig_create(src, event)
280 function fig_create(src, event)
277 global __ipy_figures;
281 global __ipy_figures;
278 __ipy_figures(size(__ipy_figures) + 1) = src;
282 __ipy_figures(size(__ipy_figures) + 1) = src;
279 set(src, "visible", "off");
283 set(src, "visible", "off");
280 end
284 end
281
285
282 set(0, 'DefaultFigureCreateFcn', @fig_create);
286 set(0, 'DefaultFigureCreateFcn', @fig_create);
283
287
284 close all;
288 close all;
285 clear ans;
289 clear ans;
286
290
287 # ___<end_pre_call>___ #
291 # ___<end_pre_call>___ #
288 '''
292 '''
289
293
290 post_call = '''
294 post_call = '''
291 # ___<start_post_call>___ #
295 # ___<start_post_call>___ #
292
296
293 # Save output of the last execution
297 # Save output of the last execution
294 if exist("ans") == 1
298 if exist("ans") == 1
295 _ = ans;
299 _ = ans;
296 else
300 else
297 _ = nan;
301 _ = nan;
298 end
302 end
299
303
300 for f = __ipy_figures
304 for f = __ipy_figures
301 outfile = sprintf('%(plot_dir)s/__ipy_oct_fig_%%03d.png', f);
305 outfile = sprintf('%(plot_dir)s/__ipy_oct_fig_%%03d.png', f);
302 try
306 try
303 print(f, outfile, '-d%(plot_format)s', '-tight', '-S%(size)s');
307 print(f, outfile, '-d%(plot_format)s', '-tight', '-S%(size)s');
304 end
308 end
305 end
309 end
306
310
307 ''' % locals()
311 ''' % locals()
308
312
309 code = ' '.join((pre_call, code, post_call))
313 code = ' '.join((pre_call, code, post_call))
310 try:
314 try:
311 text_output = self._oct.run(code, verbose=False)
315 text_output = self._oct.run(code, verbose=False)
312 except (oct2py.Oct2PyError) as exception:
316 except (oct2py.Oct2PyError) as exception:
313 msg = exception.message
317 msg = exception.message
314 msg = msg.split('# ___<end_pre_call>___ #')[1]
318 msg = msg.split('# ___<end_pre_call>___ #')[1]
315 msg = msg.split('# ___<start_post_call>___ #')[0]
319 msg = msg.split('# ___<start_post_call>___ #')[0]
316 raise OctaveMagicError('Octave could not complete execution. '
320 raise OctaveMagicError('Octave could not complete execution. '
317 'Traceback (currently broken in oct2py): %s'
321 'Traceback (currently broken in oct2py): %s'
318 % msg)
322 % msg)
319
323
320 key = 'OctaveMagic.Octave'
324 key = 'OctaveMagic.Octave'
321 display_data = []
325 display_data = []
322
326
323 # Publish text output
327 # Publish text output
324 if text_output:
328 if text_output:
325 display_data.append((key, {'text/plain': text_output}))
329 display_data.append((key, {'text/plain': text_output}))
326
330
327 # Publish images
331 # Publish images
328 images = [open(imgfile, 'rb').read() for imgfile in \
332 images = [open(imgfile, 'rb').read() for imgfile in \
329 glob("%s/*" % plot_dir)]
333 glob("%s/*" % plot_dir)]
330 rmtree(plot_dir)
334 rmtree(plot_dir)
331
335
332 plot_mime_type = _mimetypes.get(plot_format, 'image/png')
336 plot_mime_type = _mimetypes.get(plot_format, 'image/png')
333 width, height = [int(s) for s in size.split(',')]
337 width, height = [int(s) for s in size.split(',')]
334 for image in images:
338 for image in images:
335 if plot_format == 'svg':
339 if plot_format == 'svg':
336 image = self._fix_gnuplot_svg_size(image, size=(width, height))
340 image = self._fix_gnuplot_svg_size(image, size=(width, height))
337 display_data.append((key, {plot_mime_type: image}))
341 display_data.append((key, {plot_mime_type: image}))
338
342
339 if args.output:
343 if args.output:
340 for output in ','.join(args.output).split(','):
344 for output in ','.join(args.output).split(','):
341 output = unicode_to_str(output)
345 output = unicode_to_str(output)
342 self.shell.push({output: self._oct.get(output)})
346 self.shell.push({output: self._oct.get(output)})
343
347
344 for source, data in display_data:
348 for source, data in display_data:
345 self._publish_display_data(source, data)
349 self._publish_display_data(source, data)
346
350
347 if return_output:
351 if return_output:
348 ans = self._oct.get('_')
352 ans = self._oct.get('_')
349
353
350 # Unfortunately, Octave doesn't have a "None" object,
354 # Unfortunately, Octave doesn't have a "None" object,
351 # so we can't return any NaN outputs
355 # so we can't return any NaN outputs
352 if np.isscalar(ans) and np.isnan(ans):
356 if np.isscalar(ans) and np.isnan(ans):
353 ans = None
357 ans = None
354
358
355 return ans
359 return ans
356
360
357
361
358 __doc__ = __doc__.format(
362 __doc__ = __doc__.format(
359 OCTAVE_DOC = ' '*8 + OctaveMagics.octave.__doc__,
363 OCTAVE_DOC = ' '*8 + OctaveMagics.octave.__doc__,
360 OCTAVE_PUSH_DOC = ' '*8 + OctaveMagics.octave_push.__doc__,
364 OCTAVE_PUSH_DOC = ' '*8 + OctaveMagics.octave_push.__doc__,
361 OCTAVE_PULL_DOC = ' '*8 + OctaveMagics.octave_pull.__doc__
365 OCTAVE_PULL_DOC = ' '*8 + OctaveMagics.octave_pull.__doc__
362 )
366 )
363
367
364
368
365 def load_ipython_extension(ip):
369 def load_ipython_extension(ip):
366 """Load the extension in IPython."""
370 """Load the extension in IPython."""
367 ip.register_magics(OctaveMagics)
371 ip.register_magics(OctaveMagics)
@@ -1,684 +1,693 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 ======
3 ======
4 Rmagic
4 Rmagic
5 ======
5 ======
6
6
7 Magic command interface for interactive work with R via rpy2
7 Magic command interface for interactive work with R via rpy2
8
8
9 .. note::
10
11 The ``rpy2`` package needs to be installed separately. It
12 can be obtained using ``easy_install`` or ``pip``.
13
14 You will also need a working copy of R.
15
9 Usage
16 Usage
10 =====
17 =====
11
18
19 To enable the magics below, execute ``%load_ext rmagic``.
20
12 ``%R``
21 ``%R``
13
22
14 {R_DOC}
23 {R_DOC}
15
24
16 ``%Rpush``
25 ``%Rpush``
17
26
18 {RPUSH_DOC}
27 {RPUSH_DOC}
19
28
20 ``%Rpull``
29 ``%Rpull``
21
30
22 {RPULL_DOC}
31 {RPULL_DOC}
23
32
24 ``%Rget``
33 ``%Rget``
25
34
26 {RGET_DOC}
35 {RGET_DOC}
27
36
28 """
37 """
29
38
30 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
31 # Copyright (C) 2012 The IPython Development Team
40 # Copyright (C) 2012 The IPython Development Team
32 #
41 #
33 # Distributed under the terms of the BSD License. The full license is in
42 # Distributed under the terms of the BSD License. The full license is in
34 # the file COPYING, distributed as part of this software.
43 # the file COPYING, distributed as part of this software.
35 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
36
45
37 import sys
46 import sys
38 import tempfile
47 import tempfile
39 from glob import glob
48 from glob import glob
40 from shutil import rmtree
49 from shutil import rmtree
41
50
42 # numpy and rpy2 imports
51 # numpy and rpy2 imports
43
52
44 import numpy as np
53 import numpy as np
45
54
46 import rpy2.rinterface as ri
55 import rpy2.rinterface as ri
47 import rpy2.robjects as ro
56 import rpy2.robjects as ro
48 try:
57 try:
49 from rpy2.robjects import pandas2ri
58 from rpy2.robjects import pandas2ri
50 pandas2ri.activate()
59 pandas2ri.activate()
51 except ImportError:
60 except ImportError:
52 pandas2ri = None
61 pandas2ri = None
53 from rpy2.robjects import numpy2ri
62 from rpy2.robjects import numpy2ri
54 numpy2ri.activate()
63 numpy2ri.activate()
55
64
56 # IPython imports
65 # IPython imports
57
66
58 from IPython.core.displaypub import publish_display_data
67 from IPython.core.displaypub import publish_display_data
59 from IPython.core.magic import (Magics, magics_class, line_magic,
68 from IPython.core.magic import (Magics, magics_class, line_magic,
60 line_cell_magic, needs_local_scope)
69 line_cell_magic, needs_local_scope)
61 from IPython.testing.skipdoctest import skip_doctest
70 from IPython.testing.skipdoctest import skip_doctest
62 from IPython.core.magic_arguments import (
71 from IPython.core.magic_arguments import (
63 argument, magic_arguments, parse_argstring
72 argument, magic_arguments, parse_argstring
64 )
73 )
65 from IPython.external.simplegeneric import generic
74 from IPython.external.simplegeneric import generic
66 from IPython.utils.py3compat import str_to_unicode, unicode_to_str, PY3
75 from IPython.utils.py3compat import str_to_unicode, unicode_to_str, PY3
67
76
68 class RInterpreterError(ri.RRuntimeError):
77 class RInterpreterError(ri.RRuntimeError):
69 """An error when running R code in a %%R magic cell."""
78 """An error when running R code in a %%R magic cell."""
70 def __init__(self, line, err, stdout):
79 def __init__(self, line, err, stdout):
71 self.line = line
80 self.line = line
72 self.err = err.rstrip()
81 self.err = err.rstrip()
73 self.stdout = stdout.rstrip()
82 self.stdout = stdout.rstrip()
74
83
75 def __unicode__(self):
84 def __unicode__(self):
76 s = 'Failed to parse and evaluate line %r.\nR error message: %r' % \
85 s = 'Failed to parse and evaluate line %r.\nR error message: %r' % \
77 (self.line, self.err)
86 (self.line, self.err)
78 if self.stdout and (self.stdout != self.err):
87 if self.stdout and (self.stdout != self.err):
79 s += '\nR stdout:\n' + self.stdout
88 s += '\nR stdout:\n' + self.stdout
80 return s
89 return s
81
90
82 if PY3:
91 if PY3:
83 __str__ = __unicode__
92 __str__ = __unicode__
84 else:
93 else:
85 def __str__(self):
94 def __str__(self):
86 return unicode_to_str(unicode(self), 'utf-8')
95 return unicode_to_str(unicode(self), 'utf-8')
87
96
88 def Rconverter(Robj, dataframe=False):
97 def Rconverter(Robj, dataframe=False):
89 """
98 """
90 Convert an object in R's namespace to one suitable
99 Convert an object in R's namespace to one suitable
91 for ipython's namespace.
100 for ipython's namespace.
92
101
93 For a data.frame, it tries to return a structured array.
102 For a data.frame, it tries to return a structured array.
94 It first checks for colnames, then names.
103 It first checks for colnames, then names.
95 If all are NULL, it returns np.asarray(Robj), else
104 If all are NULL, it returns np.asarray(Robj), else
96 it tries to construct a recarray
105 it tries to construct a recarray
97
106
98 Parameters
107 Parameters
99 ----------
108 ----------
100
109
101 Robj: an R object returned from rpy2
110 Robj: an R object returned from rpy2
102 """
111 """
103 is_data_frame = ro.r('is.data.frame')
112 is_data_frame = ro.r('is.data.frame')
104 colnames = ro.r('colnames')
113 colnames = ro.r('colnames')
105 rownames = ro.r('rownames') # with pandas, these could be used for the index
114 rownames = ro.r('rownames') # with pandas, these could be used for the index
106 names = ro.r('names')
115 names = ro.r('names')
107
116
108 if dataframe:
117 if dataframe:
109 as_data_frame = ro.r('as.data.frame')
118 as_data_frame = ro.r('as.data.frame')
110 cols = colnames(Robj)
119 cols = colnames(Robj)
111 _names = names(Robj)
120 _names = names(Robj)
112 if cols != ri.NULL:
121 if cols != ri.NULL:
113 Robj = as_data_frame(Robj)
122 Robj = as_data_frame(Robj)
114 names = tuple(np.array(cols))
123 names = tuple(np.array(cols))
115 elif _names != ri.NULL:
124 elif _names != ri.NULL:
116 names = tuple(np.array(_names))
125 names = tuple(np.array(_names))
117 else: # failed to find names
126 else: # failed to find names
118 return np.asarray(Robj)
127 return np.asarray(Robj)
119 Robj = np.rec.fromarrays(Robj, names = names)
128 Robj = np.rec.fromarrays(Robj, names = names)
120 return np.asarray(Robj)
129 return np.asarray(Robj)
121
130
122 @generic
131 @generic
123 def pyconverter(pyobj):
132 def pyconverter(pyobj):
124 """Convert Python objects to R objects. Add types using the decorator:
133 """Convert Python objects to R objects. Add types using the decorator:
125
134
126 @pyconverter.when_type
135 @pyconverter.when_type
127 """
136 """
128 return pyobj
137 return pyobj
129
138
130 # The default conversion for lists seems to make them a nested list. That has
139 # The default conversion for lists seems to make them a nested list. That has
131 # some advantages, but is rarely convenient, so for interactive use, we convert
140 # some advantages, but is rarely convenient, so for interactive use, we convert
132 # lists to a numpy array, which becomes an R vector.
141 # lists to a numpy array, which becomes an R vector.
133 @pyconverter.when_type(list)
142 @pyconverter.when_type(list)
134 def pyconverter_list(pyobj):
143 def pyconverter_list(pyobj):
135 return np.asarray(pyobj)
144 return np.asarray(pyobj)
136
145
137 if pandas2ri is None:
146 if pandas2ri is None:
138 # pandas2ri was new in rpy2 2.3.3, so for now we'll fallback to pandas'
147 # pandas2ri was new in rpy2 2.3.3, so for now we'll fallback to pandas'
139 # conversion function.
148 # conversion function.
140 try:
149 try:
141 from pandas import DataFrame
150 from pandas import DataFrame
142 from pandas.rpy.common import convert_to_r_dataframe
151 from pandas.rpy.common import convert_to_r_dataframe
143 @pyconverter.when_type(DataFrame)
152 @pyconverter.when_type(DataFrame)
144 def pyconverter_dataframe(pyobj):
153 def pyconverter_dataframe(pyobj):
145 return convert_to_r_dataframe(pyobj, strings_as_factors=True)
154 return convert_to_r_dataframe(pyobj, strings_as_factors=True)
146 except ImportError:
155 except ImportError:
147 pass
156 pass
148
157
149 @magics_class
158 @magics_class
150 class RMagics(Magics):
159 class RMagics(Magics):
151 """A set of magics useful for interactive work with R via rpy2.
160 """A set of magics useful for interactive work with R via rpy2.
152 """
161 """
153
162
154 def __init__(self, shell, Rconverter=Rconverter,
163 def __init__(self, shell, Rconverter=Rconverter,
155 pyconverter=pyconverter,
164 pyconverter=pyconverter,
156 cache_display_data=False):
165 cache_display_data=False):
157 """
166 """
158 Parameters
167 Parameters
159 ----------
168 ----------
160
169
161 shell : IPython shell
170 shell : IPython shell
162
171
163 Rconverter : callable
172 Rconverter : callable
164 To be called on values taken from R before putting them in the
173 To be called on values taken from R before putting them in the
165 IPython namespace.
174 IPython namespace.
166
175
167 pyconverter : callable
176 pyconverter : callable
168 To be called on values in ipython namespace before
177 To be called on values in ipython namespace before
169 assigning to variables in rpy2.
178 assigning to variables in rpy2.
170
179
171 cache_display_data : bool
180 cache_display_data : bool
172 If True, the published results of the final call to R are
181 If True, the published results of the final call to R are
173 cached in the variable 'display_cache'.
182 cached in the variable 'display_cache'.
174
183
175 """
184 """
176 super(RMagics, self).__init__(shell)
185 super(RMagics, self).__init__(shell)
177 self.cache_display_data = cache_display_data
186 self.cache_display_data = cache_display_data
178
187
179 self.r = ro.R()
188 self.r = ro.R()
180
189
181 self.Rstdout_cache = []
190 self.Rstdout_cache = []
182 self.pyconverter = pyconverter
191 self.pyconverter = pyconverter
183 self.Rconverter = Rconverter
192 self.Rconverter = Rconverter
184
193
185 def eval(self, line):
194 def eval(self, line):
186 '''
195 '''
187 Parse and evaluate a line of R code with rpy2.
196 Parse and evaluate a line of R code with rpy2.
188 Returns the output to R's stdout() connection,
197 Returns the output to R's stdout() connection,
189 the value generated by evaluating the code, and a
198 the value generated by evaluating the code, and a
190 boolean indicating whether the return value would be
199 boolean indicating whether the return value would be
191 visible if the line of code were evaluated in an R REPL.
200 visible if the line of code were evaluated in an R REPL.
192
201
193 R Code evaluation and visibility determination are
202 R Code evaluation and visibility determination are
194 done via an R call of the form withVisible({<code>})
203 done via an R call of the form withVisible({<code>})
195
204
196 '''
205 '''
197 old_writeconsole = ri.get_writeconsole()
206 old_writeconsole = ri.get_writeconsole()
198 ri.set_writeconsole(self.write_console)
207 ri.set_writeconsole(self.write_console)
199 try:
208 try:
200 res = ro.r("withVisible({%s})" % line)
209 res = ro.r("withVisible({%s})" % line)
201 value = res[0] #value (R object)
210 value = res[0] #value (R object)
202 visible = ro.conversion.ri2py(res[1])[0] #visible (boolean)
211 visible = ro.conversion.ri2py(res[1])[0] #visible (boolean)
203 except (ri.RRuntimeError, ValueError) as exception:
212 except (ri.RRuntimeError, ValueError) as exception:
204 warning_or_other_msg = self.flush() # otherwise next return seems to have copy of error
213 warning_or_other_msg = self.flush() # otherwise next return seems to have copy of error
205 raise RInterpreterError(line, str_to_unicode(str(exception)), warning_or_other_msg)
214 raise RInterpreterError(line, str_to_unicode(str(exception)), warning_or_other_msg)
206 text_output = self.flush()
215 text_output = self.flush()
207 ri.set_writeconsole(old_writeconsole)
216 ri.set_writeconsole(old_writeconsole)
208 return text_output, value, visible
217 return text_output, value, visible
209
218
210 def write_console(self, output):
219 def write_console(self, output):
211 '''
220 '''
212 A hook to capture R's stdout in a cache.
221 A hook to capture R's stdout in a cache.
213 '''
222 '''
214 self.Rstdout_cache.append(output)
223 self.Rstdout_cache.append(output)
215
224
216 def flush(self):
225 def flush(self):
217 '''
226 '''
218 Flush R's stdout cache to a string, returning the string.
227 Flush R's stdout cache to a string, returning the string.
219 '''
228 '''
220 value = ''.join([str_to_unicode(s, 'utf-8') for s in self.Rstdout_cache])
229 value = ''.join([str_to_unicode(s, 'utf-8') for s in self.Rstdout_cache])
221 self.Rstdout_cache = []
230 self.Rstdout_cache = []
222 return value
231 return value
223
232
224 @skip_doctest
233 @skip_doctest
225 @needs_local_scope
234 @needs_local_scope
226 @line_magic
235 @line_magic
227 def Rpush(self, line, local_ns=None):
236 def Rpush(self, line, local_ns=None):
228 '''
237 '''
229 A line-level magic for R that pushes
238 A line-level magic for R that pushes
230 variables from python to rpy2. The line should be made up
239 variables from python to rpy2. The line should be made up
231 of whitespace separated variable names in the IPython
240 of whitespace separated variable names in the IPython
232 namespace::
241 namespace::
233
242
234 In [7]: import numpy as np
243 In [7]: import numpy as np
235
244
236 In [8]: X = np.array([4.5,6.3,7.9])
245 In [8]: X = np.array([4.5,6.3,7.9])
237
246
238 In [9]: X.mean()
247 In [9]: X.mean()
239 Out[9]: 6.2333333333333343
248 Out[9]: 6.2333333333333343
240
249
241 In [10]: %Rpush X
250 In [10]: %Rpush X
242
251
243 In [11]: %R mean(X)
252 In [11]: %R mean(X)
244 Out[11]: array([ 6.23333333])
253 Out[11]: array([ 6.23333333])
245
254
246 '''
255 '''
247 if local_ns is None:
256 if local_ns is None:
248 local_ns = {}
257 local_ns = {}
249
258
250 inputs = line.split(' ')
259 inputs = line.split(' ')
251 for input in inputs:
260 for input in inputs:
252 try:
261 try:
253 val = local_ns[input]
262 val = local_ns[input]
254 except KeyError:
263 except KeyError:
255 try:
264 try:
256 val = self.shell.user_ns[input]
265 val = self.shell.user_ns[input]
257 except KeyError:
266 except KeyError:
258 # reraise the KeyError as a NameError so that it looks like
267 # reraise the KeyError as a NameError so that it looks like
259 # the standard python behavior when you use an unnamed
268 # the standard python behavior when you use an unnamed
260 # variable
269 # variable
261 raise NameError("name '%s' is not defined" % input)
270 raise NameError("name '%s' is not defined" % input)
262
271
263 self.r.assign(input, self.pyconverter(val))
272 self.r.assign(input, self.pyconverter(val))
264
273
265 @skip_doctest
274 @skip_doctest
266 @magic_arguments()
275 @magic_arguments()
267 @argument(
276 @argument(
268 '-d', '--as_dataframe', action='store_true',
277 '-d', '--as_dataframe', action='store_true',
269 default=False,
278 default=False,
270 help='Convert objects to data.frames before returning to ipython.'
279 help='Convert objects to data.frames before returning to ipython.'
271 )
280 )
272 @argument(
281 @argument(
273 'outputs',
282 'outputs',
274 nargs='*',
283 nargs='*',
275 )
284 )
276 @line_magic
285 @line_magic
277 def Rpull(self, line):
286 def Rpull(self, line):
278 '''
287 '''
279 A line-level magic for R that pulls
288 A line-level magic for R that pulls
280 variables from python to rpy2::
289 variables from python to rpy2::
281
290
282 In [18]: _ = %R x = c(3,4,6.7); y = c(4,6,7); z = c('a',3,4)
291 In [18]: _ = %R x = c(3,4,6.7); y = c(4,6,7); z = c('a',3,4)
283
292
284 In [19]: %Rpull x y z
293 In [19]: %Rpull x y z
285
294
286 In [20]: x
295 In [20]: x
287 Out[20]: array([ 3. , 4. , 6.7])
296 Out[20]: array([ 3. , 4. , 6.7])
288
297
289 In [21]: y
298 In [21]: y
290 Out[21]: array([ 4., 6., 7.])
299 Out[21]: array([ 4., 6., 7.])
291
300
292 In [22]: z
301 In [22]: z
293 Out[22]:
302 Out[22]:
294 array(['a', '3', '4'],
303 array(['a', '3', '4'],
295 dtype='|S1')
304 dtype='|S1')
296
305
297
306
298 If --as_dataframe, then each object is returned as a structured array
307 If --as_dataframe, then each object is returned as a structured array
299 after first passed through "as.data.frame" in R before
308 after first passed through "as.data.frame" in R before
300 being calling self.Rconverter.
309 being calling self.Rconverter.
301 This is useful when a structured array is desired as output, or
310 This is useful when a structured array is desired as output, or
302 when the object in R has mixed data types.
311 when the object in R has mixed data types.
303 See the %%R docstring for more examples.
312 See the %%R docstring for more examples.
304
313
305 Notes
314 Notes
306 -----
315 -----
307
316
308 Beware that R names can have '.' so this is not fool proof.
317 Beware that R names can have '.' so this is not fool proof.
309 To avoid this, don't name your R objects with '.'s...
318 To avoid this, don't name your R objects with '.'s...
310
319
311 '''
320 '''
312 args = parse_argstring(self.Rpull, line)
321 args = parse_argstring(self.Rpull, line)
313 outputs = args.outputs
322 outputs = args.outputs
314 for output in outputs:
323 for output in outputs:
315 self.shell.push({output:self.Rconverter(self.r(output),dataframe=args.as_dataframe)})
324 self.shell.push({output:self.Rconverter(self.r(output),dataframe=args.as_dataframe)})
316
325
317 @skip_doctest
326 @skip_doctest
318 @magic_arguments()
327 @magic_arguments()
319 @argument(
328 @argument(
320 '-d', '--as_dataframe', action='store_true',
329 '-d', '--as_dataframe', action='store_true',
321 default=False,
330 default=False,
322 help='Convert objects to data.frames before returning to ipython.'
331 help='Convert objects to data.frames before returning to ipython.'
323 )
332 )
324 @argument(
333 @argument(
325 'output',
334 'output',
326 nargs=1,
335 nargs=1,
327 type=str,
336 type=str,
328 )
337 )
329 @line_magic
338 @line_magic
330 def Rget(self, line):
339 def Rget(self, line):
331 '''
340 '''
332 Return an object from rpy2, possibly as a structured array (if possible).
341 Return an object from rpy2, possibly as a structured array (if possible).
333 Similar to Rpull except only one argument is accepted and the value is
342 Similar to Rpull except only one argument is accepted and the value is
334 returned rather than pushed to self.shell.user_ns::
343 returned rather than pushed to self.shell.user_ns::
335
344
336 In [3]: dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')]
345 In [3]: dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')]
337
346
338 In [4]: datapy = np.array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5, 'e')], dtype=dtype)
347 In [4]: datapy = np.array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5, 'e')], dtype=dtype)
339
348
340 In [5]: %R -i datapy
349 In [5]: %R -i datapy
341
350
342 In [6]: %Rget datapy
351 In [6]: %Rget datapy
343 Out[6]:
352 Out[6]:
344 array([['1', '2', '3', '4'],
353 array([['1', '2', '3', '4'],
345 ['2', '3', '2', '5'],
354 ['2', '3', '2', '5'],
346 ['a', 'b', 'c', 'e']],
355 ['a', 'b', 'c', 'e']],
347 dtype='|S1')
356 dtype='|S1')
348
357
349 In [7]: %Rget -d datapy
358 In [7]: %Rget -d datapy
350 Out[7]:
359 Out[7]:
351 array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5.0, 'e')],
360 array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5.0, 'e')],
352 dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')])
361 dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')])
353
362
354 '''
363 '''
355 args = parse_argstring(self.Rget, line)
364 args = parse_argstring(self.Rget, line)
356 output = args.output
365 output = args.output
357 return self.Rconverter(self.r(output[0]),dataframe=args.as_dataframe)
366 return self.Rconverter(self.r(output[0]),dataframe=args.as_dataframe)
358
367
359
368
360 @skip_doctest
369 @skip_doctest
361 @magic_arguments()
370 @magic_arguments()
362 @argument(
371 @argument(
363 '-i', '--input', action='append',
372 '-i', '--input', action='append',
364 help='Names of input variable from shell.user_ns to be assigned to R variables of the same names after calling self.pyconverter. Multiple names can be passed separated only by commas with no whitespace.'
373 help='Names of input variable from shell.user_ns to be assigned to R variables of the same names after calling self.pyconverter. Multiple names can be passed separated only by commas with no whitespace.'
365 )
374 )
366 @argument(
375 @argument(
367 '-o', '--output', action='append',
376 '-o', '--output', action='append',
368 help='Names of variables to be pushed from rpy2 to shell.user_ns after executing cell body and applying self.Rconverter. Multiple names can be passed separated only by commas with no whitespace.'
377 help='Names of variables to be pushed from rpy2 to shell.user_ns after executing cell body and applying self.Rconverter. Multiple names can be passed separated only by commas with no whitespace.'
369 )
378 )
370 @argument(
379 @argument(
371 '-w', '--width', type=int,
380 '-w', '--width', type=int,
372 help='Width of png plotting device sent as an argument to *png* in R.'
381 help='Width of png plotting device sent as an argument to *png* in R.'
373 )
382 )
374 @argument(
383 @argument(
375 '-h', '--height', type=int,
384 '-h', '--height', type=int,
376 help='Height of png plotting device sent as an argument to *png* in R.'
385 help='Height of png plotting device sent as an argument to *png* in R.'
377 )
386 )
378
387
379 @argument(
388 @argument(
380 '-d', '--dataframe', action='append',
389 '-d', '--dataframe', action='append',
381 help='Convert these objects to data.frames and return as structured arrays.'
390 help='Convert these objects to data.frames and return as structured arrays.'
382 )
391 )
383 @argument(
392 @argument(
384 '-u', '--units', type=unicode, choices=["px", "in", "cm", "mm"],
393 '-u', '--units', type=unicode, choices=["px", "in", "cm", "mm"],
385 help='Units of png plotting device sent as an argument to *png* in R. One of ["px", "in", "cm", "mm"].'
394 help='Units of png plotting device sent as an argument to *png* in R. One of ["px", "in", "cm", "mm"].'
386 )
395 )
387 @argument(
396 @argument(
388 '-r', '--res', type=int,
397 '-r', '--res', type=int,
389 help='Resolution of png plotting device sent as an argument to *png* in R. Defaults to 72 if *units* is one of ["in", "cm", "mm"].'
398 help='Resolution of png plotting device sent as an argument to *png* in R. Defaults to 72 if *units* is one of ["in", "cm", "mm"].'
390 )
399 )
391 @argument(
400 @argument(
392 '-p', '--pointsize', type=int,
401 '-p', '--pointsize', type=int,
393 help='Pointsize of png plotting device sent as an argument to *png* in R.'
402 help='Pointsize of png plotting device sent as an argument to *png* in R.'
394 )
403 )
395 @argument(
404 @argument(
396 '-b', '--bg',
405 '-b', '--bg',
397 help='Background of png plotting device sent as an argument to *png* in R.'
406 help='Background of png plotting device sent as an argument to *png* in R.'
398 )
407 )
399 @argument(
408 @argument(
400 '-n', '--noreturn',
409 '-n', '--noreturn',
401 help='Force the magic to not return anything.',
410 help='Force the magic to not return anything.',
402 action='store_true',
411 action='store_true',
403 default=False
412 default=False
404 )
413 )
405 @argument(
414 @argument(
406 'code',
415 'code',
407 nargs='*',
416 nargs='*',
408 )
417 )
409 @needs_local_scope
418 @needs_local_scope
410 @line_cell_magic
419 @line_cell_magic
411 def R(self, line, cell=None, local_ns=None):
420 def R(self, line, cell=None, local_ns=None):
412 '''
421 '''
413 Execute code in R, and pull some of the results back into the Python namespace.
422 Execute code in R, and pull some of the results back into the Python namespace.
414
423
415 In line mode, this will evaluate an expression and convert the returned value to a Python object.
424 In line mode, this will evaluate an expression and convert the returned value to a Python object.
416 The return value is determined by rpy2's behaviour of returning the result of evaluating the
425 The return value is determined by rpy2's behaviour of returning the result of evaluating the
417 final line.
426 final line.
418
427
419 Multiple R lines can be executed by joining them with semicolons::
428 Multiple R lines can be executed by joining them with semicolons::
420
429
421 In [9]: %R X=c(1,4,5,7); sd(X); mean(X)
430 In [9]: %R X=c(1,4,5,7); sd(X); mean(X)
422 Out[9]: array([ 4.25])
431 Out[9]: array([ 4.25])
423
432
424 In cell mode, this will run a block of R code. The resulting value
433 In cell mode, this will run a block of R code. The resulting value
425 is printed if it would printed be when evaluating the same code
434 is printed if it would printed be when evaluating the same code
426 within a standard R REPL.
435 within a standard R REPL.
427
436
428 Nothing is returned to python by default in cell mode.
437 Nothing is returned to python by default in cell mode::
429
438
430 In [10]: %%R
439 In [10]: %%R
431 ....: Y = c(2,4,3,9)
440 ....: Y = c(2,4,3,9)
432 ....: summary(lm(Y~X))
441 ....: summary(lm(Y~X))
433
442
434 Call:
443 Call:
435 lm(formula = Y ~ X)
444 lm(formula = Y ~ X)
436
445
437 Residuals:
446 Residuals:
438 1 2 3 4
447 1 2 3 4
439 0.88 -0.24 -2.28 1.64
448 0.88 -0.24 -2.28 1.64
440
449
441 Coefficients:
450 Coefficients:
442 Estimate Std. Error t value Pr(>|t|)
451 Estimate Std. Error t value Pr(>|t|)
443 (Intercept) 0.0800 2.3000 0.035 0.975
452 (Intercept) 0.0800 2.3000 0.035 0.975
444 X 1.0400 0.4822 2.157 0.164
453 X 1.0400 0.4822 2.157 0.164
445
454
446 Residual standard error: 2.088 on 2 degrees of freedom
455 Residual standard error: 2.088 on 2 degrees of freedom
447 Multiple R-squared: 0.6993,Adjusted R-squared: 0.549
456 Multiple R-squared: 0.6993,Adjusted R-squared: 0.549
448 F-statistic: 4.651 on 1 and 2 DF, p-value: 0.1638
457 F-statistic: 4.651 on 1 and 2 DF, p-value: 0.1638
449
458
450 In the notebook, plots are published as the output of the cell.
459 In the notebook, plots are published as the output of the cell::
451
460
452 %R plot(X, Y)
461 %R plot(X, Y)
453
462
454 will create a scatter plot of X bs Y.
463 will create a scatter plot of X bs Y.
455
464
456 If cell is not None and line has some R code, it is prepended to
465 If cell is not None and line has some R code, it is prepended to
457 the R code in cell.
466 the R code in cell.
458
467
459 Objects can be passed back and forth between rpy2 and python via the -i -o flags in line::
468 Objects can be passed back and forth between rpy2 and python via the -i -o flags in line::
460
469
461 In [14]: Z = np.array([1,4,5,10])
470 In [14]: Z = np.array([1,4,5,10])
462
471
463 In [15]: %R -i Z mean(Z)
472 In [15]: %R -i Z mean(Z)
464 Out[15]: array([ 5.])
473 Out[15]: array([ 5.])
465
474
466
475
467 In [16]: %R -o W W=Z*mean(Z)
476 In [16]: %R -o W W=Z*mean(Z)
468 Out[16]: array([ 5., 20., 25., 50.])
477 Out[16]: array([ 5., 20., 25., 50.])
469
478
470 In [17]: W
479 In [17]: W
471 Out[17]: array([ 5., 20., 25., 50.])
480 Out[17]: array([ 5., 20., 25., 50.])
472
481
473 The return value is determined by these rules:
482 The return value is determined by these rules:
474
483
475 * If the cell is not None, the magic returns None.
484 * If the cell is not None, the magic returns None.
476
485
477 * If the cell evaluates as False, the resulting value is returned
486 * If the cell evaluates as False, the resulting value is returned
478 unless the final line prints something to the console, in
487 unless the final line prints something to the console, in
479 which case None is returned.
488 which case None is returned.
480
489
481 * If the final line results in a NULL value when evaluated
490 * If the final line results in a NULL value when evaluated
482 by rpy2, then None is returned.
491 by rpy2, then None is returned.
483
492
484 * No attempt is made to convert the final value to a structured array.
493 * No attempt is made to convert the final value to a structured array.
485 Use the --dataframe flag or %Rget to push / return a structured array.
494 Use the --dataframe flag or %Rget to push / return a structured array.
486
495
487 * If the -n flag is present, there is no return value.
496 * If the -n flag is present, there is no return value.
488
497
489 * A trailing ';' will also result in no return value as the last
498 * A trailing ';' will also result in no return value as the last
490 value in the line is an empty string.
499 value in the line is an empty string.
491
500
492 The --dataframe argument will attempt to return structured arrays.
501 The --dataframe argument will attempt to return structured arrays.
493 This is useful for dataframes with
502 This is useful for dataframes with
494 mixed data types. Note also that for a data.frame,
503 mixed data types. Note also that for a data.frame,
495 if it is returned as an ndarray, it is transposed::
504 if it is returned as an ndarray, it is transposed::
496
505
497 In [18]: dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')]
506 In [18]: dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')]
498
507
499 In [19]: datapy = np.array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5, 'e')], dtype=dtype)
508 In [19]: datapy = np.array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5, 'e')], dtype=dtype)
500
509
501 In [20]: %%R -o datar
510 In [20]: %%R -o datar
502 datar = datapy
511 datar = datapy
503 ....:
512 ....:
504
513
505 In [21]: datar
514 In [21]: datar
506 Out[21]:
515 Out[21]:
507 array([['1', '2', '3', '4'],
516 array([['1', '2', '3', '4'],
508 ['2', '3', '2', '5'],
517 ['2', '3', '2', '5'],
509 ['a', 'b', 'c', 'e']],
518 ['a', 'b', 'c', 'e']],
510 dtype='|S1')
519 dtype='|S1')
511
520
512 In [22]: %%R -d datar
521 In [22]: %%R -d datar
513 datar = datapy
522 datar = datapy
514 ....:
523 ....:
515
524
516 In [23]: datar
525 In [23]: datar
517 Out[23]:
526 Out[23]:
518 array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5.0, 'e')],
527 array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5.0, 'e')],
519 dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')])
528 dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')])
520
529
521 The --dataframe argument first tries colnames, then names.
530 The --dataframe argument first tries colnames, then names.
522 If both are NULL, it returns an ndarray (i.e. unstructured)::
531 If both are NULL, it returns an ndarray (i.e. unstructured)::
523
532
524 In [1]: %R mydata=c(4,6,8.3); NULL
533 In [1]: %R mydata=c(4,6,8.3); NULL
525
534
526 In [2]: %R -d mydata
535 In [2]: %R -d mydata
527
536
528 In [3]: mydata
537 In [3]: mydata
529 Out[3]: array([ 4. , 6. , 8.3])
538 Out[3]: array([ 4. , 6. , 8.3])
530
539
531 In [4]: %R names(mydata) = c('a','b','c'); NULL
540 In [4]: %R names(mydata) = c('a','b','c'); NULL
532
541
533 In [5]: %R -d mydata
542 In [5]: %R -d mydata
534
543
535 In [6]: mydata
544 In [6]: mydata
536 Out[6]:
545 Out[6]:
537 array((4.0, 6.0, 8.3),
546 array((4.0, 6.0, 8.3),
538 dtype=[('a', '<f8'), ('b', '<f8'), ('c', '<f8')])
547 dtype=[('a', '<f8'), ('b', '<f8'), ('c', '<f8')])
539
548
540 In [7]: %R -o mydata
549 In [7]: %R -o mydata
541
550
542 In [8]: mydata
551 In [8]: mydata
543 Out[8]: array([ 4. , 6. , 8.3])
552 Out[8]: array([ 4. , 6. , 8.3])
544
553
545 '''
554 '''
546
555
547 args = parse_argstring(self.R, line)
556 args = parse_argstring(self.R, line)
548
557
549 # arguments 'code' in line are prepended to
558 # arguments 'code' in line are prepended to
550 # the cell lines
559 # the cell lines
551
560
552 if cell is None:
561 if cell is None:
553 code = ''
562 code = ''
554 return_output = True
563 return_output = True
555 line_mode = True
564 line_mode = True
556 else:
565 else:
557 code = cell
566 code = cell
558 return_output = False
567 return_output = False
559 line_mode = False
568 line_mode = False
560
569
561 code = ' '.join(args.code) + code
570 code = ' '.join(args.code) + code
562
571
563 # if there is no local namespace then default to an empty dict
572 # if there is no local namespace then default to an empty dict
564 if local_ns is None:
573 if local_ns is None:
565 local_ns = {}
574 local_ns = {}
566
575
567 if args.input:
576 if args.input:
568 for input in ','.join(args.input).split(','):
577 for input in ','.join(args.input).split(','):
569 try:
578 try:
570 val = local_ns[input]
579 val = local_ns[input]
571 except KeyError:
580 except KeyError:
572 try:
581 try:
573 val = self.shell.user_ns[input]
582 val = self.shell.user_ns[input]
574 except KeyError:
583 except KeyError:
575 raise NameError("name '%s' is not defined" % input)
584 raise NameError("name '%s' is not defined" % input)
576 self.r.assign(input, self.pyconverter(val))
585 self.r.assign(input, self.pyconverter(val))
577
586
578 if getattr(args, 'units') is not None:
587 if getattr(args, 'units') is not None:
579 if args.units != "px" and getattr(args, 'res') is None:
588 if args.units != "px" and getattr(args, 'res') is None:
580 args.res = 72
589 args.res = 72
581 args.units = '"%s"' % args.units
590 args.units = '"%s"' % args.units
582
591
583 png_argdict = dict([(n, getattr(args, n)) for n in ['units', 'res', 'height', 'width', 'bg', 'pointsize']])
592 png_argdict = dict([(n, getattr(args, n)) for n in ['units', 'res', 'height', 'width', 'bg', 'pointsize']])
584 png_args = ','.join(['%s=%s' % (o,v) for o, v in png_argdict.items() if v is not None])
593 png_args = ','.join(['%s=%s' % (o,v) for o, v in png_argdict.items() if v is not None])
585 # execute the R code in a temporary directory
594 # execute the R code in a temporary directory
586
595
587 tmpd = tempfile.mkdtemp()
596 tmpd = tempfile.mkdtemp()
588 self.r('png("%s/Rplots%%03d.png",%s)' % (tmpd.replace('\\', '/'), png_args))
597 self.r('png("%s/Rplots%%03d.png",%s)' % (tmpd.replace('\\', '/'), png_args))
589
598
590 text_output = ''
599 text_output = ''
591 try:
600 try:
592 if line_mode:
601 if line_mode:
593 for line in code.split(';'):
602 for line in code.split(';'):
594 text_result, result, visible = self.eval(line)
603 text_result, result, visible = self.eval(line)
595 text_output += text_result
604 text_output += text_result
596 if text_result:
605 if text_result:
597 # the last line printed something to the console so we won't return it
606 # the last line printed something to the console so we won't return it
598 return_output = False
607 return_output = False
599 else:
608 else:
600 text_result, result, visible = self.eval(code)
609 text_result, result, visible = self.eval(code)
601 text_output += text_result
610 text_output += text_result
602 if visible:
611 if visible:
603 old_writeconsole = ri.get_writeconsole()
612 old_writeconsole = ri.get_writeconsole()
604 ri.set_writeconsole(self.write_console)
613 ri.set_writeconsole(self.write_console)
605 ro.r.show(result)
614 ro.r.show(result)
606 text_output += self.flush()
615 text_output += self.flush()
607 ri.set_writeconsole(old_writeconsole)
616 ri.set_writeconsole(old_writeconsole)
608
617
609 except RInterpreterError as e:
618 except RInterpreterError as e:
610 print(e.stdout)
619 print(e.stdout)
611 if not e.stdout.endswith(e.err):
620 if not e.stdout.endswith(e.err):
612 print(e.err)
621 print(e.err)
613 rmtree(tmpd)
622 rmtree(tmpd)
614 return
623 return
615
624
616 self.r('dev.off()')
625 self.r('dev.off()')
617
626
618 # read out all the saved .png files
627 # read out all the saved .png files
619
628
620 images = [open(imgfile, 'rb').read() for imgfile in glob("%s/Rplots*png" % tmpd)]
629 images = [open(imgfile, 'rb').read() for imgfile in glob("%s/Rplots*png" % tmpd)]
621
630
622 # now publish the images
631 # now publish the images
623 # mimicking IPython/zmq/pylab/backend_inline.py
632 # mimicking IPython/zmq/pylab/backend_inline.py
624 fmt = 'png'
633 fmt = 'png'
625 mimetypes = { 'png' : 'image/png', 'svg' : 'image/svg+xml' }
634 mimetypes = { 'png' : 'image/png', 'svg' : 'image/svg+xml' }
626 mime = mimetypes[fmt]
635 mime = mimetypes[fmt]
627
636
628 # publish the printed R objects, if any
637 # publish the printed R objects, if any
629
638
630 display_data = []
639 display_data = []
631 if text_output:
640 if text_output:
632 display_data.append(('RMagic.R', {'text/plain':text_output}))
641 display_data.append(('RMagic.R', {'text/plain':text_output}))
633
642
634 # flush text streams before sending figures, helps a little with output
643 # flush text streams before sending figures, helps a little with output
635 for image in images:
644 for image in images:
636 # synchronization in the console (though it's a bandaid, not a real sln)
645 # synchronization in the console (though it's a bandaid, not a real sln)
637 sys.stdout.flush(); sys.stderr.flush()
646 sys.stdout.flush(); sys.stderr.flush()
638 display_data.append(('RMagic.R', {mime: image}))
647 display_data.append(('RMagic.R', {mime: image}))
639
648
640 # kill the temporary directory
649 # kill the temporary directory
641 rmtree(tmpd)
650 rmtree(tmpd)
642
651
643 # try to turn every output into a numpy array
652 # try to turn every output into a numpy array
644 # this means that output are assumed to be castable
653 # this means that output are assumed to be castable
645 # as numpy arrays
654 # as numpy arrays
646
655
647 if args.output:
656 if args.output:
648 for output in ','.join(args.output).split(','):
657 for output in ','.join(args.output).split(','):
649 self.shell.push({output:self.Rconverter(self.r(output), dataframe=False)})
658 self.shell.push({output:self.Rconverter(self.r(output), dataframe=False)})
650
659
651 if args.dataframe:
660 if args.dataframe:
652 for output in ','.join(args.dataframe).split(','):
661 for output in ','.join(args.dataframe).split(','):
653 self.shell.push({output:self.Rconverter(self.r(output), dataframe=True)})
662 self.shell.push({output:self.Rconverter(self.r(output), dataframe=True)})
654
663
655 for tag, disp_d in display_data:
664 for tag, disp_d in display_data:
656 publish_display_data(tag, disp_d)
665 publish_display_data(tag, disp_d)
657
666
658 # this will keep a reference to the display_data
667 # this will keep a reference to the display_data
659 # which might be useful to other objects who happen to use
668 # which might be useful to other objects who happen to use
660 # this method
669 # this method
661
670
662 if self.cache_display_data:
671 if self.cache_display_data:
663 self.display_cache = display_data
672 self.display_cache = display_data
664
673
665 # if in line mode and return_output, return the result as an ndarray
674 # if in line mode and return_output, return the result as an ndarray
666 if return_output and not args.noreturn:
675 if return_output and not args.noreturn:
667 if result != ri.NULL:
676 if result != ri.NULL:
668 return self.Rconverter(result, dataframe=False)
677 return self.Rconverter(result, dataframe=False)
669
678
670 __doc__ = __doc__.format(
679 __doc__ = __doc__.format(
671 R_DOC = ' '*8 + RMagics.R.__doc__,
680 R_DOC = ' '*8 + RMagics.R.__doc__,
672 RPUSH_DOC = ' '*8 + RMagics.Rpush.__doc__,
681 RPUSH_DOC = ' '*8 + RMagics.Rpush.__doc__,
673 RPULL_DOC = ' '*8 + RMagics.Rpull.__doc__,
682 RPULL_DOC = ' '*8 + RMagics.Rpull.__doc__,
674 RGET_DOC = ' '*8 + RMagics.Rget.__doc__
683 RGET_DOC = ' '*8 + RMagics.Rget.__doc__
675 )
684 )
676
685
677
686
678 def load_ipython_extension(ip):
687 def load_ipython_extension(ip):
679 """Load the extension in IPython."""
688 """Load the extension in IPython."""
680 ip.register_magics(RMagics)
689 ip.register_magics(RMagics)
681 # Initialising rpy2 interferes with readline. Since, at this point, we've
690 # Initialising rpy2 interferes with readline. Since, at this point, we've
682 # probably just loaded rpy2, we reset the delimiters. See issue gh-2759.
691 # probably just loaded rpy2, we reset the delimiters. See issue gh-2759.
683 if ip.has_readline:
692 if ip.has_readline:
684 ip.readline.set_completer_delims(ip.readline_delims)
693 ip.readline.set_completer_delims(ip.readline_delims)
General Comments 0
You need to be logged in to leave comments. Login now