##// END OF EJS Templates
Load rpy2.ipython for rmagic, print deprecation warning
Thomas Kluyver -
Show More
@@ -1,696 +1,706 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 ======
3 ======
4 Rmagic
4 Rmagic
5 ======
5 ======
6
6
7 Magic command interface for interactive work with R via rpy2
7 Magic command interface for interactive work with R via rpy2
8
8
9 .. note::
9 .. note::
10
10
11 The ``rpy2`` package needs to be installed separately. It
11 The ``rpy2`` package needs to be installed separately. It
12 can be obtained using ``easy_install`` or ``pip``.
12 can be obtained using ``easy_install`` or ``pip``.
13
13
14 You will also need a working copy of R.
14 You will also need a working copy of R.
15
15
16 Usage
16 Usage
17 =====
17 =====
18
18
19 To enable the magics below, execute ``%load_ext rmagic``.
19 To enable the magics below, execute ``%load_ext rmagic``.
20
20
21 ``%R``
21 ``%R``
22
22
23 {R_DOC}
23 {R_DOC}
24
24
25 ``%Rpush``
25 ``%Rpush``
26
26
27 {RPUSH_DOC}
27 {RPUSH_DOC}
28
28
29 ``%Rpull``
29 ``%Rpull``
30
30
31 {RPULL_DOC}
31 {RPULL_DOC}
32
32
33 ``%Rget``
33 ``%Rget``
34
34
35 {RGET_DOC}
35 {RGET_DOC}
36
36
37 """
37 """
38 from __future__ import print_function
38 from __future__ import print_function
39
39
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41 # Copyright (C) 2012 The IPython Development Team
41 # Copyright (C) 2012 The IPython Development Team
42 #
42 #
43 # Distributed under the terms of the BSD License. The full license is in
43 # Distributed under the terms of the BSD License. The full license is in
44 # the file COPYING, distributed as part of this software.
44 # the file COPYING, distributed as part of this software.
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46
46
47 import sys
47 import sys
48 import tempfile
48 import tempfile
49 from glob import glob
49 from glob import glob
50 from shutil import rmtree
50 from shutil import rmtree
51 import warnings
51
52
52 # numpy and rpy2 imports
53 # numpy and rpy2 imports
53
54
54 import numpy as np
55 import numpy as np
55
56
56 import rpy2.rinterface as ri
57 import rpy2.rinterface as ri
57 import rpy2.robjects as ro
58 import rpy2.robjects as ro
58 try:
59 try:
59 from rpy2.robjects import pandas2ri
60 from rpy2.robjects import pandas2ri
60 pandas2ri.activate()
61 pandas2ri.activate()
61 except ImportError:
62 except ImportError:
62 pandas2ri = None
63 pandas2ri = None
63 from rpy2.robjects import numpy2ri
64 from rpy2.robjects import numpy2ri
64 numpy2ri.activate()
65 numpy2ri.activate()
65
66
66 # IPython imports
67 # IPython imports
67
68
68 from IPython.core.displaypub import publish_display_data
69 from IPython.core.displaypub import publish_display_data
69 from IPython.core.magic import (Magics, magics_class, line_magic,
70 from IPython.core.magic import (Magics, magics_class, line_magic,
70 line_cell_magic, needs_local_scope)
71 line_cell_magic, needs_local_scope)
71 from IPython.testing.skipdoctest import skip_doctest
72 from IPython.testing.skipdoctest import skip_doctest
72 from IPython.core.magic_arguments import (
73 from IPython.core.magic_arguments import (
73 argument, magic_arguments, parse_argstring
74 argument, magic_arguments, parse_argstring
74 )
75 )
75 from IPython.external.simplegeneric import generic
76 from IPython.external.simplegeneric import generic
76 from IPython.utils.py3compat import (str_to_unicode, unicode_to_str, PY3,
77 from IPython.utils.py3compat import (str_to_unicode, unicode_to_str, PY3,
77 unicode_type)
78 unicode_type)
78 from IPython.utils.text import dedent
79 from IPython.utils.text import dedent
79
80
80 class RInterpreterError(ri.RRuntimeError):
81 class RInterpreterError(ri.RRuntimeError):
81 """An error when running R code in a %%R magic cell."""
82 """An error when running R code in a %%R magic cell."""
82 def __init__(self, line, err, stdout):
83 def __init__(self, line, err, stdout):
83 self.line = line
84 self.line = line
84 self.err = err.rstrip()
85 self.err = err.rstrip()
85 self.stdout = stdout.rstrip()
86 self.stdout = stdout.rstrip()
86
87
87 def __unicode__(self):
88 def __unicode__(self):
88 s = 'Failed to parse and evaluate line %r.\nR error message: %r' % \
89 s = 'Failed to parse and evaluate line %r.\nR error message: %r' % \
89 (self.line, self.err)
90 (self.line, self.err)
90 if self.stdout and (self.stdout != self.err):
91 if self.stdout and (self.stdout != self.err):
91 s += '\nR stdout:\n' + self.stdout
92 s += '\nR stdout:\n' + self.stdout
92 return s
93 return s
93
94
94 if PY3:
95 if PY3:
95 __str__ = __unicode__
96 __str__ = __unicode__
96 else:
97 else:
97 def __str__(self):
98 def __str__(self):
98 return unicode_to_str(unicode(self), 'utf-8')
99 return unicode_to_str(unicode(self), 'utf-8')
99
100
100 def Rconverter(Robj, dataframe=False):
101 def Rconverter(Robj, dataframe=False):
101 """
102 """
102 Convert an object in R's namespace to one suitable
103 Convert an object in R's namespace to one suitable
103 for ipython's namespace.
104 for ipython's namespace.
104
105
105 For a data.frame, it tries to return a structured array.
106 For a data.frame, it tries to return a structured array.
106 It first checks for colnames, then names.
107 It first checks for colnames, then names.
107 If all are NULL, it returns np.asarray(Robj), else
108 If all are NULL, it returns np.asarray(Robj), else
108 it tries to construct a recarray
109 it tries to construct a recarray
109
110
110 Parameters
111 Parameters
111 ----------
112 ----------
112
113
113 Robj: an R object returned from rpy2
114 Robj: an R object returned from rpy2
114 """
115 """
115 is_data_frame = ro.r('is.data.frame')
116 is_data_frame = ro.r('is.data.frame')
116 colnames = ro.r('colnames')
117 colnames = ro.r('colnames')
117 rownames = ro.r('rownames') # with pandas, these could be used for the index
118 rownames = ro.r('rownames') # with pandas, these could be used for the index
118 names = ro.r('names')
119 names = ro.r('names')
119
120
120 if dataframe:
121 if dataframe:
121 as_data_frame = ro.r('as.data.frame')
122 as_data_frame = ro.r('as.data.frame')
122 cols = colnames(Robj)
123 cols = colnames(Robj)
123 _names = names(Robj)
124 _names = names(Robj)
124 if cols != ri.NULL:
125 if cols != ri.NULL:
125 Robj = as_data_frame(Robj)
126 Robj = as_data_frame(Robj)
126 names = tuple(np.array(cols))
127 names = tuple(np.array(cols))
127 elif _names != ri.NULL:
128 elif _names != ri.NULL:
128 names = tuple(np.array(_names))
129 names = tuple(np.array(_names))
129 else: # failed to find names
130 else: # failed to find names
130 return np.asarray(Robj)
131 return np.asarray(Robj)
131 Robj = np.rec.fromarrays(Robj, names = names)
132 Robj = np.rec.fromarrays(Robj, names = names)
132 return np.asarray(Robj)
133 return np.asarray(Robj)
133
134
134 @generic
135 @generic
135 def pyconverter(pyobj):
136 def pyconverter(pyobj):
136 """Convert Python objects to R objects. Add types using the decorator:
137 """Convert Python objects to R objects. Add types using the decorator:
137
138
138 @pyconverter.when_type
139 @pyconverter.when_type
139 """
140 """
140 return pyobj
141 return pyobj
141
142
142 # The default conversion for lists seems to make them a nested list. That has
143 # The default conversion for lists seems to make them a nested list. That has
143 # some advantages, but is rarely convenient, so for interactive use, we convert
144 # some advantages, but is rarely convenient, so for interactive use, we convert
144 # lists to a numpy array, which becomes an R vector.
145 # lists to a numpy array, which becomes an R vector.
145 @pyconverter.when_type(list)
146 @pyconverter.when_type(list)
146 def pyconverter_list(pyobj):
147 def pyconverter_list(pyobj):
147 return np.asarray(pyobj)
148 return np.asarray(pyobj)
148
149
149 if pandas2ri is None:
150 if pandas2ri is None:
150 # pandas2ri was new in rpy2 2.3.3, so for now we'll fallback to pandas'
151 # pandas2ri was new in rpy2 2.3.3, so for now we'll fallback to pandas'
151 # conversion function.
152 # conversion function.
152 try:
153 try:
153 from pandas import DataFrame
154 from pandas import DataFrame
154 from pandas.rpy.common import convert_to_r_dataframe
155 from pandas.rpy.common import convert_to_r_dataframe
155 @pyconverter.when_type(DataFrame)
156 @pyconverter.when_type(DataFrame)
156 def pyconverter_dataframe(pyobj):
157 def pyconverter_dataframe(pyobj):
157 return convert_to_r_dataframe(pyobj, strings_as_factors=True)
158 return convert_to_r_dataframe(pyobj, strings_as_factors=True)
158 except ImportError:
159 except ImportError:
159 pass
160 pass
160
161
161 @magics_class
162 @magics_class
162 class RMagics(Magics):
163 class RMagics(Magics):
163 """A set of magics useful for interactive work with R via rpy2.
164 """A set of magics useful for interactive work with R via rpy2.
164 """
165 """
165
166
166 def __init__(self, shell, Rconverter=Rconverter,
167 def __init__(self, shell, Rconverter=Rconverter,
167 pyconverter=pyconverter,
168 pyconverter=pyconverter,
168 cache_display_data=False):
169 cache_display_data=False):
169 """
170 """
170 Parameters
171 Parameters
171 ----------
172 ----------
172
173
173 shell : IPython shell
174 shell : IPython shell
174
175
175 Rconverter : callable
176 Rconverter : callable
176 To be called on values taken from R before putting them in the
177 To be called on values taken from R before putting them in the
177 IPython namespace.
178 IPython namespace.
178
179
179 pyconverter : callable
180 pyconverter : callable
180 To be called on values in ipython namespace before
181 To be called on values in ipython namespace before
181 assigning to variables in rpy2.
182 assigning to variables in rpy2.
182
183
183 cache_display_data : bool
184 cache_display_data : bool
184 If True, the published results of the final call to R are
185 If True, the published results of the final call to R are
185 cached in the variable 'display_cache'.
186 cached in the variable 'display_cache'.
186
187
187 """
188 """
188 super(RMagics, self).__init__(shell)
189 super(RMagics, self).__init__(shell)
189 self.cache_display_data = cache_display_data
190 self.cache_display_data = cache_display_data
190
191
191 self.r = ro.R()
192 self.r = ro.R()
192
193
193 self.Rstdout_cache = []
194 self.Rstdout_cache = []
194 self.pyconverter = pyconverter
195 self.pyconverter = pyconverter
195 self.Rconverter = Rconverter
196 self.Rconverter = Rconverter
196
197
197 def eval(self, line):
198 def eval(self, line):
198 '''
199 '''
199 Parse and evaluate a line of R code with rpy2.
200 Parse and evaluate a line of R code with rpy2.
200 Returns the output to R's stdout() connection,
201 Returns the output to R's stdout() connection,
201 the value generated by evaluating the code, and a
202 the value generated by evaluating the code, and a
202 boolean indicating whether the return value would be
203 boolean indicating whether the return value would be
203 visible if the line of code were evaluated in an R REPL.
204 visible if the line of code were evaluated in an R REPL.
204
205
205 R Code evaluation and visibility determination are
206 R Code evaluation and visibility determination are
206 done via an R call of the form withVisible({<code>})
207 done via an R call of the form withVisible({<code>})
207
208
208 '''
209 '''
209 old_writeconsole = ri.get_writeconsole()
210 old_writeconsole = ri.get_writeconsole()
210 ri.set_writeconsole(self.write_console)
211 ri.set_writeconsole(self.write_console)
211 try:
212 try:
212 res = ro.r("withVisible({%s\n})" % line)
213 res = ro.r("withVisible({%s\n})" % line)
213 value = res[0] #value (R object)
214 value = res[0] #value (R object)
214 visible = ro.conversion.ri2py(res[1])[0] #visible (boolean)
215 visible = ro.conversion.ri2py(res[1])[0] #visible (boolean)
215 except (ri.RRuntimeError, ValueError) as exception:
216 except (ri.RRuntimeError, ValueError) as exception:
216 warning_or_other_msg = self.flush() # otherwise next return seems to have copy of error
217 warning_or_other_msg = self.flush() # otherwise next return seems to have copy of error
217 raise RInterpreterError(line, str_to_unicode(str(exception)), warning_or_other_msg)
218 raise RInterpreterError(line, str_to_unicode(str(exception)), warning_or_other_msg)
218 text_output = self.flush()
219 text_output = self.flush()
219 ri.set_writeconsole(old_writeconsole)
220 ri.set_writeconsole(old_writeconsole)
220 return text_output, value, visible
221 return text_output, value, visible
221
222
222 def write_console(self, output):
223 def write_console(self, output):
223 '''
224 '''
224 A hook to capture R's stdout in a cache.
225 A hook to capture R's stdout in a cache.
225 '''
226 '''
226 self.Rstdout_cache.append(output)
227 self.Rstdout_cache.append(output)
227
228
228 def flush(self):
229 def flush(self):
229 '''
230 '''
230 Flush R's stdout cache to a string, returning the string.
231 Flush R's stdout cache to a string, returning the string.
231 '''
232 '''
232 value = ''.join([str_to_unicode(s, 'utf-8') for s in self.Rstdout_cache])
233 value = ''.join([str_to_unicode(s, 'utf-8') for s in self.Rstdout_cache])
233 self.Rstdout_cache = []
234 self.Rstdout_cache = []
234 return value
235 return value
235
236
236 @skip_doctest
237 @skip_doctest
237 @needs_local_scope
238 @needs_local_scope
238 @line_magic
239 @line_magic
239 def Rpush(self, line, local_ns=None):
240 def Rpush(self, line, local_ns=None):
240 '''
241 '''
241 A line-level magic for R that pushes
242 A line-level magic for R that pushes
242 variables from python to rpy2. The line should be made up
243 variables from python to rpy2. The line should be made up
243 of whitespace separated variable names in the IPython
244 of whitespace separated variable names in the IPython
244 namespace::
245 namespace::
245
246
246 In [7]: import numpy as np
247 In [7]: import numpy as np
247
248
248 In [8]: X = np.array([4.5,6.3,7.9])
249 In [8]: X = np.array([4.5,6.3,7.9])
249
250
250 In [9]: X.mean()
251 In [9]: X.mean()
251 Out[9]: 6.2333333333333343
252 Out[9]: 6.2333333333333343
252
253
253 In [10]: %Rpush X
254 In [10]: %Rpush X
254
255
255 In [11]: %R mean(X)
256 In [11]: %R mean(X)
256 Out[11]: array([ 6.23333333])
257 Out[11]: array([ 6.23333333])
257
258
258 '''
259 '''
259 if local_ns is None:
260 if local_ns is None:
260 local_ns = {}
261 local_ns = {}
261
262
262 inputs = line.split(' ')
263 inputs = line.split(' ')
263 for input in inputs:
264 for input in inputs:
264 try:
265 try:
265 val = local_ns[input]
266 val = local_ns[input]
266 except KeyError:
267 except KeyError:
267 try:
268 try:
268 val = self.shell.user_ns[input]
269 val = self.shell.user_ns[input]
269 except KeyError:
270 except KeyError:
270 # reraise the KeyError as a NameError so that it looks like
271 # reraise the KeyError as a NameError so that it looks like
271 # the standard python behavior when you use an unnamed
272 # the standard python behavior when you use an unnamed
272 # variable
273 # variable
273 raise NameError("name '%s' is not defined" % input)
274 raise NameError("name '%s' is not defined" % input)
274
275
275 self.r.assign(input, self.pyconverter(val))
276 self.r.assign(input, self.pyconverter(val))
276
277
277 @skip_doctest
278 @skip_doctest
278 @magic_arguments()
279 @magic_arguments()
279 @argument(
280 @argument(
280 '-d', '--as_dataframe', action='store_true',
281 '-d', '--as_dataframe', action='store_true',
281 default=False,
282 default=False,
282 help='Convert objects to data.frames before returning to ipython.'
283 help='Convert objects to data.frames before returning to ipython.'
283 )
284 )
284 @argument(
285 @argument(
285 'outputs',
286 'outputs',
286 nargs='*',
287 nargs='*',
287 )
288 )
288 @line_magic
289 @line_magic
289 def Rpull(self, line):
290 def Rpull(self, line):
290 '''
291 '''
291 A line-level magic for R that pulls
292 A line-level magic for R that pulls
292 variables from python to rpy2::
293 variables from python to rpy2::
293
294
294 In [18]: _ = %R x = c(3,4,6.7); y = c(4,6,7); z = c('a',3,4)
295 In [18]: _ = %R x = c(3,4,6.7); y = c(4,6,7); z = c('a',3,4)
295
296
296 In [19]: %Rpull x y z
297 In [19]: %Rpull x y z
297
298
298 In [20]: x
299 In [20]: x
299 Out[20]: array([ 3. , 4. , 6.7])
300 Out[20]: array([ 3. , 4. , 6.7])
300
301
301 In [21]: y
302 In [21]: y
302 Out[21]: array([ 4., 6., 7.])
303 Out[21]: array([ 4., 6., 7.])
303
304
304 In [22]: z
305 In [22]: z
305 Out[22]:
306 Out[22]:
306 array(['a', '3', '4'],
307 array(['a', '3', '4'],
307 dtype='|S1')
308 dtype='|S1')
308
309
309
310
310 If --as_dataframe, then each object is returned as a structured array
311 If --as_dataframe, then each object is returned as a structured array
311 after first passed through "as.data.frame" in R before
312 after first passed through "as.data.frame" in R before
312 being calling self.Rconverter.
313 being calling self.Rconverter.
313 This is useful when a structured array is desired as output, or
314 This is useful when a structured array is desired as output, or
314 when the object in R has mixed data types.
315 when the object in R has mixed data types.
315 See the %%R docstring for more examples.
316 See the %%R docstring for more examples.
316
317
317 Notes
318 Notes
318 -----
319 -----
319
320
320 Beware that R names can have '.' so this is not fool proof.
321 Beware that R names can have '.' so this is not fool proof.
321 To avoid this, don't name your R objects with '.'s...
322 To avoid this, don't name your R objects with '.'s...
322
323
323 '''
324 '''
324 args = parse_argstring(self.Rpull, line)
325 args = parse_argstring(self.Rpull, line)
325 outputs = args.outputs
326 outputs = args.outputs
326 for output in outputs:
327 for output in outputs:
327 self.shell.push({output:self.Rconverter(self.r(output),dataframe=args.as_dataframe)})
328 self.shell.push({output:self.Rconverter(self.r(output),dataframe=args.as_dataframe)})
328
329
329 @skip_doctest
330 @skip_doctest
330 @magic_arguments()
331 @magic_arguments()
331 @argument(
332 @argument(
332 '-d', '--as_dataframe', action='store_true',
333 '-d', '--as_dataframe', action='store_true',
333 default=False,
334 default=False,
334 help='Convert objects to data.frames before returning to ipython.'
335 help='Convert objects to data.frames before returning to ipython.'
335 )
336 )
336 @argument(
337 @argument(
337 'output',
338 'output',
338 nargs=1,
339 nargs=1,
339 type=str,
340 type=str,
340 )
341 )
341 @line_magic
342 @line_magic
342 def Rget(self, line):
343 def Rget(self, line):
343 '''
344 '''
344 Return an object from rpy2, possibly as a structured array (if possible).
345 Return an object from rpy2, possibly as a structured array (if possible).
345 Similar to Rpull except only one argument is accepted and the value is
346 Similar to Rpull except only one argument is accepted and the value is
346 returned rather than pushed to self.shell.user_ns::
347 returned rather than pushed to self.shell.user_ns::
347
348
348 In [3]: dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')]
349 In [3]: dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')]
349
350
350 In [4]: datapy = np.array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5, 'e')], dtype=dtype)
351 In [4]: datapy = np.array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5, 'e')], dtype=dtype)
351
352
352 In [5]: %R -i datapy
353 In [5]: %R -i datapy
353
354
354 In [6]: %Rget datapy
355 In [6]: %Rget datapy
355 Out[6]:
356 Out[6]:
356 array([['1', '2', '3', '4'],
357 array([['1', '2', '3', '4'],
357 ['2', '3', '2', '5'],
358 ['2', '3', '2', '5'],
358 ['a', 'b', 'c', 'e']],
359 ['a', 'b', 'c', 'e']],
359 dtype='|S1')
360 dtype='|S1')
360
361
361 In [7]: %Rget -d datapy
362 In [7]: %Rget -d datapy
362 Out[7]:
363 Out[7]:
363 array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5.0, 'e')],
364 array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5.0, 'e')],
364 dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')])
365 dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')])
365
366
366 '''
367 '''
367 args = parse_argstring(self.Rget, line)
368 args = parse_argstring(self.Rget, line)
368 output = args.output
369 output = args.output
369 return self.Rconverter(self.r(output[0]),dataframe=args.as_dataframe)
370 return self.Rconverter(self.r(output[0]),dataframe=args.as_dataframe)
370
371
371
372
372 @skip_doctest
373 @skip_doctest
373 @magic_arguments()
374 @magic_arguments()
374 @argument(
375 @argument(
375 '-i', '--input', action='append',
376 '-i', '--input', action='append',
376 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.'
377 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.'
377 )
378 )
378 @argument(
379 @argument(
379 '-o', '--output', action='append',
380 '-o', '--output', action='append',
380 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.'
381 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.'
381 )
382 )
382 @argument(
383 @argument(
383 '-w', '--width', type=int,
384 '-w', '--width', type=int,
384 help='Width of png plotting device sent as an argument to *png* in R.'
385 help='Width of png plotting device sent as an argument to *png* in R.'
385 )
386 )
386 @argument(
387 @argument(
387 '-h', '--height', type=int,
388 '-h', '--height', type=int,
388 help='Height of png plotting device sent as an argument to *png* in R.'
389 help='Height of png plotting device sent as an argument to *png* in R.'
389 )
390 )
390
391
391 @argument(
392 @argument(
392 '-d', '--dataframe', action='append',
393 '-d', '--dataframe', action='append',
393 help='Convert these objects to data.frames and return as structured arrays.'
394 help='Convert these objects to data.frames and return as structured arrays.'
394 )
395 )
395 @argument(
396 @argument(
396 '-u', '--units', type=unicode_type, choices=["px", "in", "cm", "mm"],
397 '-u', '--units', type=unicode_type, choices=["px", "in", "cm", "mm"],
397 help='Units of png plotting device sent as an argument to *png* in R. One of ["px", "in", "cm", "mm"].'
398 help='Units of png plotting device sent as an argument to *png* in R. One of ["px", "in", "cm", "mm"].'
398 )
399 )
399 @argument(
400 @argument(
400 '-r', '--res', type=int,
401 '-r', '--res', type=int,
401 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"].'
402 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"].'
402 )
403 )
403 @argument(
404 @argument(
404 '-p', '--pointsize', type=int,
405 '-p', '--pointsize', type=int,
405 help='Pointsize of png plotting device sent as an argument to *png* in R.'
406 help='Pointsize of png plotting device sent as an argument to *png* in R.'
406 )
407 )
407 @argument(
408 @argument(
408 '-b', '--bg',
409 '-b', '--bg',
409 help='Background of png plotting device sent as an argument to *png* in R.'
410 help='Background of png plotting device sent as an argument to *png* in R.'
410 )
411 )
411 @argument(
412 @argument(
412 '-n', '--noreturn',
413 '-n', '--noreturn',
413 help='Force the magic to not return anything.',
414 help='Force the magic to not return anything.',
414 action='store_true',
415 action='store_true',
415 default=False
416 default=False
416 )
417 )
417 @argument(
418 @argument(
418 'code',
419 'code',
419 nargs='*',
420 nargs='*',
420 )
421 )
421 @needs_local_scope
422 @needs_local_scope
422 @line_cell_magic
423 @line_cell_magic
423 def R(self, line, cell=None, local_ns=None):
424 def R(self, line, cell=None, local_ns=None):
424 '''
425 '''
425 Execute code in R, and pull some of the results back into the Python namespace.
426 Execute code in R, and pull some of the results back into the Python namespace.
426
427
427 In line mode, this will evaluate an expression and convert the returned value to a Python object.
428 In line mode, this will evaluate an expression and convert the returned value to a Python object.
428 The return value is determined by rpy2's behaviour of returning the result of evaluating the
429 The return value is determined by rpy2's behaviour of returning the result of evaluating the
429 final line.
430 final line.
430
431
431 Multiple R lines can be executed by joining them with semicolons::
432 Multiple R lines can be executed by joining them with semicolons::
432
433
433 In [9]: %R X=c(1,4,5,7); sd(X); mean(X)
434 In [9]: %R X=c(1,4,5,7); sd(X); mean(X)
434 Out[9]: array([ 4.25])
435 Out[9]: array([ 4.25])
435
436
436 In cell mode, this will run a block of R code. The resulting value
437 In cell mode, this will run a block of R code. The resulting value
437 is printed if it would printed be when evaluating the same code
438 is printed if it would printed be when evaluating the same code
438 within a standard R REPL.
439 within a standard R REPL.
439
440
440 Nothing is returned to python by default in cell mode::
441 Nothing is returned to python by default in cell mode::
441
442
442 In [10]: %%R
443 In [10]: %%R
443 ....: Y = c(2,4,3,9)
444 ....: Y = c(2,4,3,9)
444 ....: summary(lm(Y~X))
445 ....: summary(lm(Y~X))
445
446
446 Call:
447 Call:
447 lm(formula = Y ~ X)
448 lm(formula = Y ~ X)
448
449
449 Residuals:
450 Residuals:
450 1 2 3 4
451 1 2 3 4
451 0.88 -0.24 -2.28 1.64
452 0.88 -0.24 -2.28 1.64
452
453
453 Coefficients:
454 Coefficients:
454 Estimate Std. Error t value Pr(>|t|)
455 Estimate Std. Error t value Pr(>|t|)
455 (Intercept) 0.0800 2.3000 0.035 0.975
456 (Intercept) 0.0800 2.3000 0.035 0.975
456 X 1.0400 0.4822 2.157 0.164
457 X 1.0400 0.4822 2.157 0.164
457
458
458 Residual standard error: 2.088 on 2 degrees of freedom
459 Residual standard error: 2.088 on 2 degrees of freedom
459 Multiple R-squared: 0.6993,Adjusted R-squared: 0.549
460 Multiple R-squared: 0.6993,Adjusted R-squared: 0.549
460 F-statistic: 4.651 on 1 and 2 DF, p-value: 0.1638
461 F-statistic: 4.651 on 1 and 2 DF, p-value: 0.1638
461
462
462 In the notebook, plots are published as the output of the cell::
463 In the notebook, plots are published as the output of the cell::
463
464
464 %R plot(X, Y)
465 %R plot(X, Y)
465
466
466 will create a scatter plot of X bs Y.
467 will create a scatter plot of X bs Y.
467
468
468 If cell is not None and line has some R code, it is prepended to
469 If cell is not None and line has some R code, it is prepended to
469 the R code in cell.
470 the R code in cell.
470
471
471 Objects can be passed back and forth between rpy2 and python via the -i -o flags in line::
472 Objects can be passed back and forth between rpy2 and python via the -i -o flags in line::
472
473
473 In [14]: Z = np.array([1,4,5,10])
474 In [14]: Z = np.array([1,4,5,10])
474
475
475 In [15]: %R -i Z mean(Z)
476 In [15]: %R -i Z mean(Z)
476 Out[15]: array([ 5.])
477 Out[15]: array([ 5.])
477
478
478
479
479 In [16]: %R -o W W=Z*mean(Z)
480 In [16]: %R -o W W=Z*mean(Z)
480 Out[16]: array([ 5., 20., 25., 50.])
481 Out[16]: array([ 5., 20., 25., 50.])
481
482
482 In [17]: W
483 In [17]: W
483 Out[17]: array([ 5., 20., 25., 50.])
484 Out[17]: array([ 5., 20., 25., 50.])
484
485
485 The return value is determined by these rules:
486 The return value is determined by these rules:
486
487
487 * If the cell is not None, the magic returns None.
488 * If the cell is not None, the magic returns None.
488
489
489 * If the cell evaluates as False, the resulting value is returned
490 * If the cell evaluates as False, the resulting value is returned
490 unless the final line prints something to the console, in
491 unless the final line prints something to the console, in
491 which case None is returned.
492 which case None is returned.
492
493
493 * If the final line results in a NULL value when evaluated
494 * If the final line results in a NULL value when evaluated
494 by rpy2, then None is returned.
495 by rpy2, then None is returned.
495
496
496 * No attempt is made to convert the final value to a structured array.
497 * No attempt is made to convert the final value to a structured array.
497 Use the --dataframe flag or %Rget to push / return a structured array.
498 Use the --dataframe flag or %Rget to push / return a structured array.
498
499
499 * If the -n flag is present, there is no return value.
500 * If the -n flag is present, there is no return value.
500
501
501 * A trailing ';' will also result in no return value as the last
502 * A trailing ';' will also result in no return value as the last
502 value in the line is an empty string.
503 value in the line is an empty string.
503
504
504 The --dataframe argument will attempt to return structured arrays.
505 The --dataframe argument will attempt to return structured arrays.
505 This is useful for dataframes with
506 This is useful for dataframes with
506 mixed data types. Note also that for a data.frame,
507 mixed data types. Note also that for a data.frame,
507 if it is returned as an ndarray, it is transposed::
508 if it is returned as an ndarray, it is transposed::
508
509
509 In [18]: dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')]
510 In [18]: dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')]
510
511
511 In [19]: datapy = np.array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5, 'e')], dtype=dtype)
512 In [19]: datapy = np.array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5, 'e')], dtype=dtype)
512
513
513 In [20]: %%R -o datar
514 In [20]: %%R -o datar
514 datar = datapy
515 datar = datapy
515 ....:
516 ....:
516
517
517 In [21]: datar
518 In [21]: datar
518 Out[21]:
519 Out[21]:
519 array([['1', '2', '3', '4'],
520 array([['1', '2', '3', '4'],
520 ['2', '3', '2', '5'],
521 ['2', '3', '2', '5'],
521 ['a', 'b', 'c', 'e']],
522 ['a', 'b', 'c', 'e']],
522 dtype='|S1')
523 dtype='|S1')
523
524
524 In [22]: %%R -d datar
525 In [22]: %%R -d datar
525 datar = datapy
526 datar = datapy
526 ....:
527 ....:
527
528
528 In [23]: datar
529 In [23]: datar
529 Out[23]:
530 Out[23]:
530 array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5.0, 'e')],
531 array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5.0, 'e')],
531 dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')])
532 dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')])
532
533
533 The --dataframe argument first tries colnames, then names.
534 The --dataframe argument first tries colnames, then names.
534 If both are NULL, it returns an ndarray (i.e. unstructured)::
535 If both are NULL, it returns an ndarray (i.e. unstructured)::
535
536
536 In [1]: %R mydata=c(4,6,8.3); NULL
537 In [1]: %R mydata=c(4,6,8.3); NULL
537
538
538 In [2]: %R -d mydata
539 In [2]: %R -d mydata
539
540
540 In [3]: mydata
541 In [3]: mydata
541 Out[3]: array([ 4. , 6. , 8.3])
542 Out[3]: array([ 4. , 6. , 8.3])
542
543
543 In [4]: %R names(mydata) = c('a','b','c'); NULL
544 In [4]: %R names(mydata) = c('a','b','c'); NULL
544
545
545 In [5]: %R -d mydata
546 In [5]: %R -d mydata
546
547
547 In [6]: mydata
548 In [6]: mydata
548 Out[6]:
549 Out[6]:
549 array((4.0, 6.0, 8.3),
550 array((4.0, 6.0, 8.3),
550 dtype=[('a', '<f8'), ('b', '<f8'), ('c', '<f8')])
551 dtype=[('a', '<f8'), ('b', '<f8'), ('c', '<f8')])
551
552
552 In [7]: %R -o mydata
553 In [7]: %R -o mydata
553
554
554 In [8]: mydata
555 In [8]: mydata
555 Out[8]: array([ 4. , 6. , 8.3])
556 Out[8]: array([ 4. , 6. , 8.3])
556
557
557 '''
558 '''
558
559
559 args = parse_argstring(self.R, line)
560 args = parse_argstring(self.R, line)
560
561
561 # arguments 'code' in line are prepended to
562 # arguments 'code' in line are prepended to
562 # the cell lines
563 # the cell lines
563
564
564 if cell is None:
565 if cell is None:
565 code = ''
566 code = ''
566 return_output = True
567 return_output = True
567 line_mode = True
568 line_mode = True
568 else:
569 else:
569 code = cell
570 code = cell
570 return_output = False
571 return_output = False
571 line_mode = False
572 line_mode = False
572
573
573 code = ' '.join(args.code) + code
574 code = ' '.join(args.code) + code
574
575
575 # if there is no local namespace then default to an empty dict
576 # if there is no local namespace then default to an empty dict
576 if local_ns is None:
577 if local_ns is None:
577 local_ns = {}
578 local_ns = {}
578
579
579 if args.input:
580 if args.input:
580 for input in ','.join(args.input).split(','):
581 for input in ','.join(args.input).split(','):
581 try:
582 try:
582 val = local_ns[input]
583 val = local_ns[input]
583 except KeyError:
584 except KeyError:
584 try:
585 try:
585 val = self.shell.user_ns[input]
586 val = self.shell.user_ns[input]
586 except KeyError:
587 except KeyError:
587 raise NameError("name '%s' is not defined" % input)
588 raise NameError("name '%s' is not defined" % input)
588 self.r.assign(input, self.pyconverter(val))
589 self.r.assign(input, self.pyconverter(val))
589
590
590 if getattr(args, 'units') is not None:
591 if getattr(args, 'units') is not None:
591 if args.units != "px" and getattr(args, 'res') is None:
592 if args.units != "px" and getattr(args, 'res') is None:
592 args.res = 72
593 args.res = 72
593 args.units = '"%s"' % args.units
594 args.units = '"%s"' % args.units
594
595
595 png_argdict = dict([(n, getattr(args, n)) for n in ['units', 'res', 'height', 'width', 'bg', 'pointsize']])
596 png_argdict = dict([(n, getattr(args, n)) for n in ['units', 'res', 'height', 'width', 'bg', 'pointsize']])
596 png_args = ','.join(['%s=%s' % (o,v) for o, v in png_argdict.items() if v is not None])
597 png_args = ','.join(['%s=%s' % (o,v) for o, v in png_argdict.items() if v is not None])
597 # execute the R code in a temporary directory
598 # execute the R code in a temporary directory
598
599
599 tmpd = tempfile.mkdtemp()
600 tmpd = tempfile.mkdtemp()
600 self.r('png("%s/Rplots%%03d.png",%s)' % (tmpd.replace('\\', '/'), png_args))
601 self.r('png("%s/Rplots%%03d.png",%s)' % (tmpd.replace('\\', '/'), png_args))
601
602
602 text_output = ''
603 text_output = ''
603 try:
604 try:
604 if line_mode:
605 if line_mode:
605 for line in code.split(';'):
606 for line in code.split(';'):
606 text_result, result, visible = self.eval(line)
607 text_result, result, visible = self.eval(line)
607 text_output += text_result
608 text_output += text_result
608 if text_result:
609 if text_result:
609 # the last line printed something to the console so we won't return it
610 # the last line printed something to the console so we won't return it
610 return_output = False
611 return_output = False
611 else:
612 else:
612 text_result, result, visible = self.eval(code)
613 text_result, result, visible = self.eval(code)
613 text_output += text_result
614 text_output += text_result
614 if visible:
615 if visible:
615 old_writeconsole = ri.get_writeconsole()
616 old_writeconsole = ri.get_writeconsole()
616 ri.set_writeconsole(self.write_console)
617 ri.set_writeconsole(self.write_console)
617 ro.r.show(result)
618 ro.r.show(result)
618 text_output += self.flush()
619 text_output += self.flush()
619 ri.set_writeconsole(old_writeconsole)
620 ri.set_writeconsole(old_writeconsole)
620
621
621 except RInterpreterError as e:
622 except RInterpreterError as e:
622 print(e.stdout)
623 print(e.stdout)
623 if not e.stdout.endswith(e.err):
624 if not e.stdout.endswith(e.err):
624 print(e.err)
625 print(e.err)
625 rmtree(tmpd)
626 rmtree(tmpd)
626 return
627 return
627 finally:
628 finally:
628 self.r('dev.off()')
629 self.r('dev.off()')
629
630
630 # read out all the saved .png files
631 # read out all the saved .png files
631
632
632 images = [open(imgfile, 'rb').read() for imgfile in glob("%s/Rplots*png" % tmpd)]
633 images = [open(imgfile, 'rb').read() for imgfile in glob("%s/Rplots*png" % tmpd)]
633
634
634 # now publish the images
635 # now publish the images
635 # mimicking IPython/zmq/pylab/backend_inline.py
636 # mimicking IPython/zmq/pylab/backend_inline.py
636 fmt = 'png'
637 fmt = 'png'
637 mimetypes = { 'png' : 'image/png', 'svg' : 'image/svg+xml' }
638 mimetypes = { 'png' : 'image/png', 'svg' : 'image/svg+xml' }
638 mime = mimetypes[fmt]
639 mime = mimetypes[fmt]
639
640
640 # publish the printed R objects, if any
641 # publish the printed R objects, if any
641
642
642 display_data = []
643 display_data = []
643 if text_output:
644 if text_output:
644 display_data.append(('RMagic.R', {'text/plain':text_output}))
645 display_data.append(('RMagic.R', {'text/plain':text_output}))
645
646
646 # flush text streams before sending figures, helps a little with output
647 # flush text streams before sending figures, helps a little with output
647 for image in images:
648 for image in images:
648 # synchronization in the console (though it's a bandaid, not a real sln)
649 # synchronization in the console (though it's a bandaid, not a real sln)
649 sys.stdout.flush(); sys.stderr.flush()
650 sys.stdout.flush(); sys.stderr.flush()
650 display_data.append(('RMagic.R', {mime: image}))
651 display_data.append(('RMagic.R', {mime: image}))
651
652
652 # kill the temporary directory
653 # kill the temporary directory
653 rmtree(tmpd)
654 rmtree(tmpd)
654
655
655 # try to turn every output into a numpy array
656 # try to turn every output into a numpy array
656 # this means that output are assumed to be castable
657 # this means that output are assumed to be castable
657 # as numpy arrays
658 # as numpy arrays
658
659
659 if args.output:
660 if args.output:
660 for output in ','.join(args.output).split(','):
661 for output in ','.join(args.output).split(','):
661 self.shell.push({output:self.Rconverter(self.r(output), dataframe=False)})
662 self.shell.push({output:self.Rconverter(self.r(output), dataframe=False)})
662
663
663 if args.dataframe:
664 if args.dataframe:
664 for output in ','.join(args.dataframe).split(','):
665 for output in ','.join(args.dataframe).split(','):
665 self.shell.push({output:self.Rconverter(self.r(output), dataframe=True)})
666 self.shell.push({output:self.Rconverter(self.r(output), dataframe=True)})
666
667
667 for tag, disp_d in display_data:
668 for tag, disp_d in display_data:
668 publish_display_data(data=disp_d, source=tag)
669 publish_display_data(data=disp_d, source=tag)
669
670
670 # this will keep a reference to the display_data
671 # this will keep a reference to the display_data
671 # which might be useful to other objects who happen to use
672 # which might be useful to other objects who happen to use
672 # this method
673 # this method
673
674
674 if self.cache_display_data:
675 if self.cache_display_data:
675 self.display_cache = display_data
676 self.display_cache = display_data
676
677
677 # if in line mode and return_output, return the result as an ndarray
678 # if in line mode and return_output, return the result as an ndarray
678 if return_output and not args.noreturn:
679 if return_output and not args.noreturn:
679 if result != ri.NULL:
680 if result != ri.NULL:
680 return self.Rconverter(result, dataframe=False)
681 return self.Rconverter(result, dataframe=False)
681
682
682 __doc__ = __doc__.format(
683 __doc__ = __doc__.format(
683 R_DOC = dedent(RMagics.R.__doc__),
684 R_DOC = dedent(RMagics.R.__doc__),
684 RPUSH_DOC = dedent(RMagics.Rpush.__doc__),
685 RPUSH_DOC = dedent(RMagics.Rpush.__doc__),
685 RPULL_DOC = dedent(RMagics.Rpull.__doc__),
686 RPULL_DOC = dedent(RMagics.Rpull.__doc__),
686 RGET_DOC = dedent(RMagics.Rget.__doc__)
687 RGET_DOC = dedent(RMagics.Rget.__doc__)
687 )
688 )
688
689
689
690
690 def load_ipython_extension(ip):
691 def load_ipython_extension(ip):
691 """Load the extension in IPython."""
692 """Load the extension in IPython."""
693 warnings.warn("The rmagic extension in IPython is deprecated in favour of "
694 "rpy2.ipython. If available, that will be loaded instead.")
695 try:
696 import rpy2.ipython
697 except ImportError:
698 pass # Fall back to our own implementation for now
699 else:
700 return rpy2.ipython.load_ipython_extension(ip)
701
692 ip.register_magics(RMagics)
702 ip.register_magics(RMagics)
693 # Initialising rpy2 interferes with readline. Since, at this point, we've
703 # Initialising rpy2 interferes with readline. Since, at this point, we've
694 # probably just loaded rpy2, we reset the delimiters. See issue gh-2759.
704 # probably just loaded rpy2, we reset the delimiters. See issue gh-2759.
695 if ip.has_readline:
705 if ip.has_readline:
696 ip.readline.set_completer_delims(ip.readline_delims)
706 ip.readline.set_completer_delims(ip.readline_delims)
General Comments 0
You need to be logged in to leave comments. Login now