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