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