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