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