##// END OF EJS Templates
Fixed rmagic on Windows....
Benedikt Sauer -
Show More
@@ -1,593 +1,593 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
41 from getopt import getopt
42
42
43 # numpy and rpy2 imports
43 # numpy and rpy2 imports
44
44
45 import numpy as np
45 import numpy as np
46
46
47 import rpy2.rinterface as ri
47 import rpy2.rinterface as ri
48 import rpy2.robjects as ro
48 import rpy2.robjects as ro
49 from rpy2.robjects.numpy2ri import numpy2ri
49 from rpy2.robjects.numpy2ri import numpy2ri
50 ro.conversion.py2ri = numpy2ri
50 ro.conversion.py2ri = numpy2ri
51
51
52 # IPython imports
52 # IPython imports
53
53
54 from IPython.core.displaypub import publish_display_data
54 from IPython.core.displaypub import publish_display_data
55 from IPython.core.magic import (Magics, magics_class, cell_magic, line_magic,
55 from IPython.core.magic import (Magics, magics_class, cell_magic, line_magic,
56 line_cell_magic, needs_local_scope)
56 line_cell_magic, needs_local_scope)
57 from IPython.testing.skipdoctest import skip_doctest
57 from IPython.testing.skipdoctest import skip_doctest
58 from IPython.core.magic_arguments import (
58 from IPython.core.magic_arguments import (
59 argument, magic_arguments, parse_argstring
59 argument, magic_arguments, parse_argstring
60 )
60 )
61 from IPython.utils.py3compat import str_to_unicode, unicode_to_str, PY3
61 from IPython.utils.py3compat import str_to_unicode, unicode_to_str, PY3
62
62
63 class RInterpreterError(ri.RRuntimeError):
63 class RInterpreterError(ri.RRuntimeError):
64 """An error when running R code in a %%R magic cell."""
64 """An error when running R code in a %%R magic cell."""
65 def __init__(self, line, err, stdout):
65 def __init__(self, line, err, stdout):
66 self.line = line
66 self.line = line
67 self.err = err.rstrip()
67 self.err = err.rstrip()
68 self.stdout = stdout.rstrip()
68 self.stdout = stdout.rstrip()
69
69
70 def __unicode__(self):
70 def __unicode__(self):
71 s = 'Failed to parse and evaluate line %r.\nR error message: %r' % \
71 s = 'Failed to parse and evaluate line %r.\nR error message: %r' % \
72 (self.line, self.err)
72 (self.line, self.err)
73 if self.stdout and (self.stdout != self.err):
73 if self.stdout and (self.stdout != self.err):
74 s += '\nR stdout:\n' + self.stdout
74 s += '\nR stdout:\n' + self.stdout
75 return s
75 return s
76
76
77 if PY3:
77 if PY3:
78 __str__ = __unicode__
78 __str__ = __unicode__
79 else:
79 else:
80 def __str__(self):
80 def __str__(self):
81 return unicode_to_str(unicode(self), 'utf-8')
81 return unicode_to_str(unicode(self), 'utf-8')
82
82
83 def Rconverter(Robj, dataframe=False):
83 def Rconverter(Robj, dataframe=False):
84 """
84 """
85 Convert an object in R's namespace to one suitable
85 Convert an object in R's namespace to one suitable
86 for ipython's namespace.
86 for ipython's namespace.
87
87
88 For a data.frame, it tries to return a structured array.
88 For a data.frame, it tries to return a structured array.
89 It first checks for colnames, then names.
89 It first checks for colnames, then names.
90 If all are NULL, it returns np.asarray(Robj), else
90 If all are NULL, it returns np.asarray(Robj), else
91 it tries to construct a recarray
91 it tries to construct a recarray
92
92
93 Parameters
93 Parameters
94 ----------
94 ----------
95
95
96 Robj: an R object returned from rpy2
96 Robj: an R object returned from rpy2
97 """
97 """
98 is_data_frame = ro.r('is.data.frame')
98 is_data_frame = ro.r('is.data.frame')
99 colnames = ro.r('colnames')
99 colnames = ro.r('colnames')
100 rownames = ro.r('rownames') # with pandas, these could be used for the index
100 rownames = ro.r('rownames') # with pandas, these could be used for the index
101 names = ro.r('names')
101 names = ro.r('names')
102
102
103 if dataframe:
103 if dataframe:
104 as_data_frame = ro.r('as.data.frame')
104 as_data_frame = ro.r('as.data.frame')
105 cols = colnames(Robj)
105 cols = colnames(Robj)
106 _names = names(Robj)
106 _names = names(Robj)
107 if cols != ri.NULL:
107 if cols != ri.NULL:
108 Robj = as_data_frame(Robj)
108 Robj = as_data_frame(Robj)
109 names = tuple(np.array(cols))
109 names = tuple(np.array(cols))
110 elif _names != ri.NULL:
110 elif _names != ri.NULL:
111 names = tuple(np.array(_names))
111 names = tuple(np.array(_names))
112 else: # failed to find names
112 else: # failed to find names
113 return np.asarray(Robj)
113 return np.asarray(Robj)
114 Robj = np.rec.fromarrays(Robj, names = names)
114 Robj = np.rec.fromarrays(Robj, names = names)
115 return np.asarray(Robj)
115 return np.asarray(Robj)
116
116
117 @magics_class
117 @magics_class
118 class RMagics(Magics):
118 class RMagics(Magics):
119 """A set of magics useful for interactive work with R via rpy2.
119 """A set of magics useful for interactive work with R via rpy2.
120 """
120 """
121
121
122 def __init__(self, shell, Rconverter=Rconverter,
122 def __init__(self, shell, Rconverter=Rconverter,
123 pyconverter=np.asarray,
123 pyconverter=np.asarray,
124 cache_display_data=False):
124 cache_display_data=False):
125 """
125 """
126 Parameters
126 Parameters
127 ----------
127 ----------
128
128
129 shell : IPython shell
129 shell : IPython shell
130
130
131 pyconverter : callable
131 pyconverter : callable
132 To be called on values in ipython namespace before
132 To be called on values in ipython namespace before
133 assigning to variables in rpy2.
133 assigning to variables in rpy2.
134
134
135 cache_display_data : bool
135 cache_display_data : bool
136 If True, the published results of the final call to R are
136 If True, the published results of the final call to R are
137 cached in the variable 'display_cache'.
137 cached in the variable 'display_cache'.
138
138
139 """
139 """
140 super(RMagics, self).__init__(shell)
140 super(RMagics, self).__init__(shell)
141 self.cache_display_data = cache_display_data
141 self.cache_display_data = cache_display_data
142
142
143 self.r = ro.R()
143 self.r = ro.R()
144
144
145 self.Rstdout_cache = []
145 self.Rstdout_cache = []
146 self.pyconverter = pyconverter
146 self.pyconverter = pyconverter
147 self.Rconverter = Rconverter
147 self.Rconverter = Rconverter
148
148
149 def eval(self, line):
149 def eval(self, line):
150 '''
150 '''
151 Parse and evaluate a line with rpy2.
151 Parse and evaluate a line with rpy2.
152 Returns the output to R's stdout() connection
152 Returns the output to R's stdout() connection
153 and the value of eval(parse(line)).
153 and the value of eval(parse(line)).
154 '''
154 '''
155 old_writeconsole = ri.get_writeconsole()
155 old_writeconsole = ri.get_writeconsole()
156 ri.set_writeconsole(self.write_console)
156 ri.set_writeconsole(self.write_console)
157 try:
157 try:
158 value = ri.baseenv['eval'](ri.parse(line))
158 value = ri.baseenv['eval'](ri.parse(line))
159 except (ri.RRuntimeError, ValueError) as exception:
159 except (ri.RRuntimeError, ValueError) as exception:
160 warning_or_other_msg = self.flush() # otherwise next return seems to have copy of error
160 warning_or_other_msg = self.flush() # otherwise next return seems to have copy of error
161 raise RInterpreterError(line, str_to_unicode(str(exception)), warning_or_other_msg)
161 raise RInterpreterError(line, str_to_unicode(str(exception)), warning_or_other_msg)
162 text_output = self.flush()
162 text_output = self.flush()
163 ri.set_writeconsole(old_writeconsole)
163 ri.set_writeconsole(old_writeconsole)
164 return text_output, value
164 return text_output, value
165
165
166 def write_console(self, output):
166 def write_console(self, output):
167 '''
167 '''
168 A hook to capture R's stdout in a cache.
168 A hook to capture R's stdout in a cache.
169 '''
169 '''
170 self.Rstdout_cache.append(output)
170 self.Rstdout_cache.append(output)
171
171
172 def flush(self):
172 def flush(self):
173 '''
173 '''
174 Flush R's stdout cache to a string, returning the string.
174 Flush R's stdout cache to a string, returning the string.
175 '''
175 '''
176 value = ''.join([str_to_unicode(s, 'utf-8') for s in self.Rstdout_cache])
176 value = ''.join([str_to_unicode(s, 'utf-8') for s in self.Rstdout_cache])
177 self.Rstdout_cache = []
177 self.Rstdout_cache = []
178 return value
178 return value
179
179
180 @skip_doctest
180 @skip_doctest
181 @line_magic
181 @line_magic
182 def Rpush(self, line):
182 def Rpush(self, line):
183 '''
183 '''
184 A line-level magic for R that pushes
184 A line-level magic for R that pushes
185 variables from python to rpy2. The line should be made up
185 variables from python to rpy2. The line should be made up
186 of whitespace separated variable names in the IPython
186 of whitespace separated variable names in the IPython
187 namespace::
187 namespace::
188
188
189 In [7]: import numpy as np
189 In [7]: import numpy as np
190
190
191 In [8]: X = np.array([4.5,6.3,7.9])
191 In [8]: X = np.array([4.5,6.3,7.9])
192
192
193 In [9]: X.mean()
193 In [9]: X.mean()
194 Out[9]: 6.2333333333333343
194 Out[9]: 6.2333333333333343
195
195
196 In [10]: %Rpush X
196 In [10]: %Rpush X
197
197
198 In [11]: %R mean(X)
198 In [11]: %R mean(X)
199 Out[11]: array([ 6.23333333])
199 Out[11]: array([ 6.23333333])
200
200
201 '''
201 '''
202
202
203 inputs = line.split(' ')
203 inputs = line.split(' ')
204 for input in inputs:
204 for input in inputs:
205 self.r.assign(input, self.pyconverter(self.shell.user_ns[input]))
205 self.r.assign(input, self.pyconverter(self.shell.user_ns[input]))
206
206
207 @skip_doctest
207 @skip_doctest
208 @magic_arguments()
208 @magic_arguments()
209 @argument(
209 @argument(
210 '-d', '--as_dataframe', action='store_true',
210 '-d', '--as_dataframe', action='store_true',
211 default=False,
211 default=False,
212 help='Convert objects to data.frames before returning to ipython.'
212 help='Convert objects to data.frames before returning to ipython.'
213 )
213 )
214 @argument(
214 @argument(
215 'outputs',
215 'outputs',
216 nargs='*',
216 nargs='*',
217 )
217 )
218 @line_magic
218 @line_magic
219 def Rpull(self, line):
219 def Rpull(self, line):
220 '''
220 '''
221 A line-level magic for R that pulls
221 A line-level magic for R that pulls
222 variables from python to rpy2::
222 variables from python to rpy2::
223
223
224 In [18]: _ = %R x = c(3,4,6.7); y = c(4,6,7); z = c('a',3,4)
224 In [18]: _ = %R x = c(3,4,6.7); y = c(4,6,7); z = c('a',3,4)
225
225
226 In [19]: %Rpull x y z
226 In [19]: %Rpull x y z
227
227
228 In [20]: x
228 In [20]: x
229 Out[20]: array([ 3. , 4. , 6.7])
229 Out[20]: array([ 3. , 4. , 6.7])
230
230
231 In [21]: y
231 In [21]: y
232 Out[21]: array([ 4., 6., 7.])
232 Out[21]: array([ 4., 6., 7.])
233
233
234 In [22]: z
234 In [22]: z
235 Out[22]:
235 Out[22]:
236 array(['a', '3', '4'],
236 array(['a', '3', '4'],
237 dtype='|S1')
237 dtype='|S1')
238
238
239
239
240 If --as_dataframe, then each object is returned as a structured array
240 If --as_dataframe, then each object is returned as a structured array
241 after first passed through "as.data.frame" in R before
241 after first passed through "as.data.frame" in R before
242 being calling self.Rconverter.
242 being calling self.Rconverter.
243 This is useful when a structured array is desired as output, or
243 This is useful when a structured array is desired as output, or
244 when the object in R has mixed data types.
244 when the object in R has mixed data types.
245 See the %%R docstring for more examples.
245 See the %%R docstring for more examples.
246
246
247 Notes
247 Notes
248 -----
248 -----
249
249
250 Beware that R names can have '.' so this is not fool proof.
250 Beware that R names can have '.' so this is not fool proof.
251 To avoid this, don't name your R objects with '.'s...
251 To avoid this, don't name your R objects with '.'s...
252
252
253 '''
253 '''
254 args = parse_argstring(self.Rpull, line)
254 args = parse_argstring(self.Rpull, line)
255 outputs = args.outputs
255 outputs = args.outputs
256 for output in outputs:
256 for output in outputs:
257 self.shell.push({output:self.Rconverter(self.r(output),dataframe=args.as_dataframe)})
257 self.shell.push({output:self.Rconverter(self.r(output),dataframe=args.as_dataframe)})
258
258
259 @skip_doctest
259 @skip_doctest
260 @magic_arguments()
260 @magic_arguments()
261 @argument(
261 @argument(
262 '-d', '--as_dataframe', action='store_true',
262 '-d', '--as_dataframe', action='store_true',
263 default=False,
263 default=False,
264 help='Convert objects to data.frames before returning to ipython.'
264 help='Convert objects to data.frames before returning to ipython.'
265 )
265 )
266 @argument(
266 @argument(
267 'output',
267 'output',
268 nargs=1,
268 nargs=1,
269 type=str,
269 type=str,
270 )
270 )
271 @line_magic
271 @line_magic
272 def Rget(self, line):
272 def Rget(self, line):
273 '''
273 '''
274 Return an object from rpy2, possibly as a structured array (if possible).
274 Return an object from rpy2, possibly as a structured array (if possible).
275 Similar to Rpull except only one argument is accepted and the value is
275 Similar to Rpull except only one argument is accepted and the value is
276 returned rather than pushed to self.shell.user_ns::
276 returned rather than pushed to self.shell.user_ns::
277
277
278 In [3]: dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')]
278 In [3]: dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')]
279
279
280 In [4]: datapy = np.array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5, 'e')], dtype=dtype)
280 In [4]: datapy = np.array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5, 'e')], dtype=dtype)
281
281
282 In [5]: %R -i datapy
282 In [5]: %R -i datapy
283
283
284 In [6]: %Rget datapy
284 In [6]: %Rget datapy
285 Out[6]:
285 Out[6]:
286 array([['1', '2', '3', '4'],
286 array([['1', '2', '3', '4'],
287 ['2', '3', '2', '5'],
287 ['2', '3', '2', '5'],
288 ['a', 'b', 'c', 'e']],
288 ['a', 'b', 'c', 'e']],
289 dtype='|S1')
289 dtype='|S1')
290
290
291 In [7]: %Rget -d datapy
291 In [7]: %Rget -d datapy
292 Out[7]:
292 Out[7]:
293 array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5.0, 'e')],
293 array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5.0, 'e')],
294 dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')])
294 dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')])
295
295
296 '''
296 '''
297 args = parse_argstring(self.Rget, line)
297 args = parse_argstring(self.Rget, line)
298 output = args.output
298 output = args.output
299 return self.Rconverter(self.r(output[0]),dataframe=args.as_dataframe)
299 return self.Rconverter(self.r(output[0]),dataframe=args.as_dataframe)
300
300
301
301
302 @skip_doctest
302 @skip_doctest
303 @magic_arguments()
303 @magic_arguments()
304 @argument(
304 @argument(
305 '-i', '--input', action='append',
305 '-i', '--input', action='append',
306 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.'
306 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.'
307 )
307 )
308 @argument(
308 @argument(
309 '-o', '--output', action='append',
309 '-o', '--output', action='append',
310 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.'
310 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.'
311 )
311 )
312 @argument(
312 @argument(
313 '-w', '--width', type=int,
313 '-w', '--width', type=int,
314 help='Width of png plotting device sent as an argument to *png* in R.'
314 help='Width of png plotting device sent as an argument to *png* in R.'
315 )
315 )
316 @argument(
316 @argument(
317 '-h', '--height', type=int,
317 '-h', '--height', type=int,
318 help='Height of png plotting device sent as an argument to *png* in R.'
318 help='Height of png plotting device sent as an argument to *png* in R.'
319 )
319 )
320
320
321 @argument(
321 @argument(
322 '-d', '--dataframe', action='append',
322 '-d', '--dataframe', action='append',
323 help='Convert these objects to data.frames and return as structured arrays.'
323 help='Convert these objects to data.frames and return as structured arrays.'
324 )
324 )
325 @argument(
325 @argument(
326 '-u', '--units', type=int,
326 '-u', '--units', type=int,
327 help='Units of png plotting device sent as an argument to *png* in R. One of ["px", "in", "cm", "mm"].'
327 help='Units of png plotting device sent as an argument to *png* in R. One of ["px", "in", "cm", "mm"].'
328 )
328 )
329 @argument(
329 @argument(
330 '-p', '--pointsize', type=int,
330 '-p', '--pointsize', type=int,
331 help='Pointsize of png plotting device sent as an argument to *png* in R.'
331 help='Pointsize of png plotting device sent as an argument to *png* in R.'
332 )
332 )
333 @argument(
333 @argument(
334 '-b', '--bg',
334 '-b', '--bg',
335 help='Background of png plotting device sent as an argument to *png* in R.'
335 help='Background of png plotting device sent as an argument to *png* in R.'
336 )
336 )
337 @argument(
337 @argument(
338 '-n', '--noreturn',
338 '-n', '--noreturn',
339 help='Force the magic to not return anything.',
339 help='Force the magic to not return anything.',
340 action='store_true',
340 action='store_true',
341 default=False
341 default=False
342 )
342 )
343 @argument(
343 @argument(
344 'code',
344 'code',
345 nargs='*',
345 nargs='*',
346 )
346 )
347 @needs_local_scope
347 @needs_local_scope
348 @line_cell_magic
348 @line_cell_magic
349 def R(self, line, cell=None, local_ns=None):
349 def R(self, line, cell=None, local_ns=None):
350 '''
350 '''
351 Execute code in R, and pull some of the results back into the Python namespace.
351 Execute code in R, and pull some of the results back into the Python namespace.
352
352
353 In line mode, this will evaluate an expression and convert the returned value to a Python object.
353 In line mode, this will evaluate an expression and convert the returned value to a Python object.
354 The return value is determined by rpy2's behaviour of returning the result of evaluating the
354 The return value is determined by rpy2's behaviour of returning the result of evaluating the
355 final line.
355 final line.
356
356
357 Multiple R lines can be executed by joining them with semicolons::
357 Multiple R lines can be executed by joining them with semicolons::
358
358
359 In [9]: %R X=c(1,4,5,7); sd(X); mean(X)
359 In [9]: %R X=c(1,4,5,7); sd(X); mean(X)
360 Out[9]: array([ 4.25])
360 Out[9]: array([ 4.25])
361
361
362 As a cell, this will run a block of R code, without bringing anything back by default::
362 As a cell, this will run a block of R code, without bringing anything back by default::
363
363
364 In [10]: %%R
364 In [10]: %%R
365 ....: Y = c(2,4,3,9)
365 ....: Y = c(2,4,3,9)
366 ....: print(summary(lm(Y~X)))
366 ....: print(summary(lm(Y~X)))
367 ....:
367 ....:
368
368
369 Call:
369 Call:
370 lm(formula = Y ~ X)
370 lm(formula = Y ~ X)
371
371
372 Residuals:
372 Residuals:
373 1 2 3 4
373 1 2 3 4
374 0.88 -0.24 -2.28 1.64
374 0.88 -0.24 -2.28 1.64
375
375
376 Coefficients:
376 Coefficients:
377 Estimate Std. Error t value Pr(>|t|)
377 Estimate Std. Error t value Pr(>|t|)
378 (Intercept) 0.0800 2.3000 0.035 0.975
378 (Intercept) 0.0800 2.3000 0.035 0.975
379 X 1.0400 0.4822 2.157 0.164
379 X 1.0400 0.4822 2.157 0.164
380
380
381 Residual standard error: 2.088 on 2 degrees of freedom
381 Residual standard error: 2.088 on 2 degrees of freedom
382 Multiple R-squared: 0.6993,Adjusted R-squared: 0.549
382 Multiple R-squared: 0.6993,Adjusted R-squared: 0.549
383 F-statistic: 4.651 on 1 and 2 DF, p-value: 0.1638
383 F-statistic: 4.651 on 1 and 2 DF, p-value: 0.1638
384
384
385 In the notebook, plots are published as the output of the cell.
385 In the notebook, plots are published as the output of the cell.
386
386
387 %R plot(X, Y)
387 %R plot(X, Y)
388
388
389 will create a scatter plot of X bs Y.
389 will create a scatter plot of X bs Y.
390
390
391 If cell is not None and line has some R code, it is prepended to
391 If cell is not None and line has some R code, it is prepended to
392 the R code in cell.
392 the R code in cell.
393
393
394 Objects can be passed back and forth between rpy2 and python via the -i -o flags in line::
394 Objects can be passed back and forth between rpy2 and python via the -i -o flags in line::
395
395
396 In [14]: Z = np.array([1,4,5,10])
396 In [14]: Z = np.array([1,4,5,10])
397
397
398 In [15]: %R -i Z mean(Z)
398 In [15]: %R -i Z mean(Z)
399 Out[15]: array([ 5.])
399 Out[15]: array([ 5.])
400
400
401
401
402 In [16]: %R -o W W=Z*mean(Z)
402 In [16]: %R -o W W=Z*mean(Z)
403 Out[16]: array([ 5., 20., 25., 50.])
403 Out[16]: array([ 5., 20., 25., 50.])
404
404
405 In [17]: W
405 In [17]: W
406 Out[17]: array([ 5., 20., 25., 50.])
406 Out[17]: array([ 5., 20., 25., 50.])
407
407
408 The return value is determined by these rules:
408 The return value is determined by these rules:
409
409
410 * If the cell is not None, the magic returns None.
410 * If the cell is not None, the magic returns None.
411
411
412 * If the cell evaluates as False, the resulting value is returned
412 * If the cell evaluates as False, the resulting value is returned
413 unless the final line prints something to the console, in
413 unless the final line prints something to the console, in
414 which case None is returned.
414 which case None is returned.
415
415
416 * If the final line results in a NULL value when evaluated
416 * If the final line results in a NULL value when evaluated
417 by rpy2, then None is returned.
417 by rpy2, then None is returned.
418
418
419 * No attempt is made to convert the final value to a structured array.
419 * No attempt is made to convert the final value to a structured array.
420 Use the --dataframe flag or %Rget to push / return a structured array.
420 Use the --dataframe flag or %Rget to push / return a structured array.
421
421
422 * If the -n flag is present, there is no return value.
422 * If the -n flag is present, there is no return value.
423
423
424 * A trailing ';' will also result in no return value as the last
424 * A trailing ';' will also result in no return value as the last
425 value in the line is an empty string.
425 value in the line is an empty string.
426
426
427 The --dataframe argument will attempt to return structured arrays.
427 The --dataframe argument will attempt to return structured arrays.
428 This is useful for dataframes with
428 This is useful for dataframes with
429 mixed data types. Note also that for a data.frame,
429 mixed data types. Note also that for a data.frame,
430 if it is returned as an ndarray, it is transposed::
430 if it is returned as an ndarray, it is transposed::
431
431
432 In [18]: dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')]
432 In [18]: dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')]
433
433
434 In [19]: datapy = np.array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5, 'e')], dtype=dtype)
434 In [19]: datapy = np.array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5, 'e')], dtype=dtype)
435
435
436 In [20]: %%R -o datar
436 In [20]: %%R -o datar
437 datar = datapy
437 datar = datapy
438 ....:
438 ....:
439
439
440 In [21]: datar
440 In [21]: datar
441 Out[21]:
441 Out[21]:
442 array([['1', '2', '3', '4'],
442 array([['1', '2', '3', '4'],
443 ['2', '3', '2', '5'],
443 ['2', '3', '2', '5'],
444 ['a', 'b', 'c', 'e']],
444 ['a', 'b', 'c', 'e']],
445 dtype='|S1')
445 dtype='|S1')
446
446
447 In [22]: %%R -d datar
447 In [22]: %%R -d datar
448 datar = datapy
448 datar = datapy
449 ....:
449 ....:
450
450
451 In [23]: datar
451 In [23]: datar
452 Out[23]:
452 Out[23]:
453 array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5.0, 'e')],
453 array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5.0, 'e')],
454 dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')])
454 dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')])
455
455
456 The --dataframe argument first tries colnames, then names.
456 The --dataframe argument first tries colnames, then names.
457 If both are NULL, it returns an ndarray (i.e. unstructured)::
457 If both are NULL, it returns an ndarray (i.e. unstructured)::
458
458
459 In [1]: %R mydata=c(4,6,8.3); NULL
459 In [1]: %R mydata=c(4,6,8.3); NULL
460
460
461 In [2]: %R -d mydata
461 In [2]: %R -d mydata
462
462
463 In [3]: mydata
463 In [3]: mydata
464 Out[3]: array([ 4. , 6. , 8.3])
464 Out[3]: array([ 4. , 6. , 8.3])
465
465
466 In [4]: %R names(mydata) = c('a','b','c'); NULL
466 In [4]: %R names(mydata) = c('a','b','c'); NULL
467
467
468 In [5]: %R -d mydata
468 In [5]: %R -d mydata
469
469
470 In [6]: mydata
470 In [6]: mydata
471 Out[6]:
471 Out[6]:
472 array((4.0, 6.0, 8.3),
472 array((4.0, 6.0, 8.3),
473 dtype=[('a', '<f8'), ('b', '<f8'), ('c', '<f8')])
473 dtype=[('a', '<f8'), ('b', '<f8'), ('c', '<f8')])
474
474
475 In [7]: %R -o mydata
475 In [7]: %R -o mydata
476
476
477 In [8]: mydata
477 In [8]: mydata
478 Out[8]: array([ 4. , 6. , 8.3])
478 Out[8]: array([ 4. , 6. , 8.3])
479
479
480 '''
480 '''
481
481
482 args = parse_argstring(self.R, line)
482 args = parse_argstring(self.R, line)
483
483
484 # arguments 'code' in line are prepended to
484 # arguments 'code' in line are prepended to
485 # the cell lines
485 # the cell lines
486
486
487 if cell is None:
487 if cell is None:
488 code = ''
488 code = ''
489 return_output = True
489 return_output = True
490 line_mode = True
490 line_mode = True
491 else:
491 else:
492 code = cell
492 code = cell
493 return_output = False
493 return_output = False
494 line_mode = False
494 line_mode = False
495
495
496 code = ' '.join(args.code) + code
496 code = ' '.join(args.code) + code
497
497
498 # if there is no local namespace then default to an empty dict
498 # if there is no local namespace then default to an empty dict
499 if local_ns is None:
499 if local_ns is None:
500 local_ns = {}
500 local_ns = {}
501
501
502 if args.input:
502 if args.input:
503 for input in ','.join(args.input).split(','):
503 for input in ','.join(args.input).split(','):
504 try:
504 try:
505 val = local_ns[input]
505 val = local_ns[input]
506 except KeyError:
506 except KeyError:
507 val = self.shell.user_ns[input]
507 val = self.shell.user_ns[input]
508 self.r.assign(input, self.pyconverter(val))
508 self.r.assign(input, self.pyconverter(val))
509
509
510 png_argdict = dict([(n, getattr(args, n)) for n in ['units', 'height', 'width', 'bg', 'pointsize']])
510 png_argdict = dict([(n, getattr(args, n)) for n in ['units', 'height', 'width', 'bg', 'pointsize']])
511 png_args = ','.join(['%s=%s' % (o,v) for o, v in png_argdict.items() if v is not None])
511 png_args = ','.join(['%s=%s' % (o,v) for o, v in png_argdict.items() if v is not None])
512 # execute the R code in a temporary directory
512 # execute the R code in a temporary directory
513
513
514 tmpd = tempfile.mkdtemp()
514 tmpd = tempfile.mkdtemp()
515 self.r('png("%s/Rplots%%03d.png",%s)' % (tmpd, png_args))
515 self.r('png("%s/Rplots%%03d.png",%s)' % (tmpd.replace('\\', '/'), png_args))
516
516
517 text_output = ''
517 text_output = ''
518 if line_mode:
518 if line_mode:
519 for line in code.split(';'):
519 for line in code.split(';'):
520 text_result, result = self.eval(line)
520 text_result, result = self.eval(line)
521 text_output += text_result
521 text_output += text_result
522 if text_result:
522 if text_result:
523 # the last line printed something to the console so we won't return it
523 # the last line printed something to the console so we won't return it
524 return_output = False
524 return_output = False
525 else:
525 else:
526 text_result, result = self.eval(code)
526 text_result, result = self.eval(code)
527 text_output += text_result
527 text_output += text_result
528
528
529 self.r('dev.off()')
529 self.r('dev.off()')
530
530
531 # read out all the saved .png files
531 # read out all the saved .png files
532
532
533 images = [open(imgfile, 'rb').read() for imgfile in glob("%s/Rplots*png" % tmpd)]
533 images = [open(imgfile, 'rb').read() for imgfile in glob("%s/Rplots*png" % tmpd)]
534
534
535 # now publish the images
535 # now publish the images
536 # mimicking IPython/zmq/pylab/backend_inline.py
536 # mimicking IPython/zmq/pylab/backend_inline.py
537 fmt = 'png'
537 fmt = 'png'
538 mimetypes = { 'png' : 'image/png', 'svg' : 'image/svg+xml' }
538 mimetypes = { 'png' : 'image/png', 'svg' : 'image/svg+xml' }
539 mime = mimetypes[fmt]
539 mime = mimetypes[fmt]
540
540
541 # publish the printed R objects, if any
541 # publish the printed R objects, if any
542
542
543 display_data = []
543 display_data = []
544 if text_output:
544 if text_output:
545 display_data.append(('RMagic.R', {'text/plain':text_output}))
545 display_data.append(('RMagic.R', {'text/plain':text_output}))
546
546
547 # flush text streams before sending figures, helps a little with output
547 # flush text streams before sending figures, helps a little with output
548 for image in images:
548 for image in images:
549 # synchronization in the console (though it's a bandaid, not a real sln)
549 # synchronization in the console (though it's a bandaid, not a real sln)
550 sys.stdout.flush(); sys.stderr.flush()
550 sys.stdout.flush(); sys.stderr.flush()
551 display_data.append(('RMagic.R', {mime: image}))
551 display_data.append(('RMagic.R', {mime: image}))
552
552
553 # kill the temporary directory
553 # kill the temporary directory
554 rmtree(tmpd)
554 rmtree(tmpd)
555
555
556 # try to turn every output into a numpy array
556 # try to turn every output into a numpy array
557 # this means that output are assumed to be castable
557 # this means that output are assumed to be castable
558 # as numpy arrays
558 # as numpy arrays
559
559
560 if args.output:
560 if args.output:
561 for output in ','.join(args.output).split(','):
561 for output in ','.join(args.output).split(','):
562 self.shell.push({output:self.Rconverter(self.r(output), dataframe=False)})
562 self.shell.push({output:self.Rconverter(self.r(output), dataframe=False)})
563
563
564 if args.dataframe:
564 if args.dataframe:
565 for output in ','.join(args.dataframe).split(','):
565 for output in ','.join(args.dataframe).split(','):
566 self.shell.push({output:self.Rconverter(self.r(output), dataframe=True)})
566 self.shell.push({output:self.Rconverter(self.r(output), dataframe=True)})
567
567
568 for tag, disp_d in display_data:
568 for tag, disp_d in display_data:
569 publish_display_data(tag, disp_d)
569 publish_display_data(tag, disp_d)
570
570
571 # this will keep a reference to the display_data
571 # this will keep a reference to the display_data
572 # which might be useful to other objects who happen to use
572 # which might be useful to other objects who happen to use
573 # this method
573 # this method
574
574
575 if self.cache_display_data:
575 if self.cache_display_data:
576 self.display_cache = display_data
576 self.display_cache = display_data
577
577
578 # if in line mode and return_output, return the result as an ndarray
578 # if in line mode and return_output, return the result as an ndarray
579 if return_output and not args.noreturn:
579 if return_output and not args.noreturn:
580 if result != ri.NULL:
580 if result != ri.NULL:
581 return self.Rconverter(result, dataframe=False)
581 return self.Rconverter(result, dataframe=False)
582
582
583 __doc__ = __doc__.format(
583 __doc__ = __doc__.format(
584 R_DOC = ' '*8 + RMagics.R.__doc__,
584 R_DOC = ' '*8 + RMagics.R.__doc__,
585 RPUSH_DOC = ' '*8 + RMagics.Rpush.__doc__,
585 RPUSH_DOC = ' '*8 + RMagics.Rpush.__doc__,
586 RPULL_DOC = ' '*8 + RMagics.Rpull.__doc__,
586 RPULL_DOC = ' '*8 + RMagics.Rpull.__doc__,
587 RGET_DOC = ' '*8 + RMagics.Rget.__doc__
587 RGET_DOC = ' '*8 + RMagics.Rget.__doc__
588 )
588 )
589
589
590
590
591 def load_ipython_extension(ip):
591 def load_ipython_extension(ip):
592 """Load the extension in IPython."""
592 """Load the extension in IPython."""
593 ip.register_magics(RMagics)
593 ip.register_magics(RMagics)
General Comments 0
You need to be logged in to leave comments. Login now