##// END OF EJS Templates
return vectors instead of structured arrays when 1d and no names
Jonathan Taylor -
Show More
@@ -1,422 +1,431 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 """
24 """
25
25
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 # Copyright (C) 2012 The IPython Development Team
27 # Copyright (C) 2012 The IPython Development Team
28 #
28 #
29 # Distributed under the terms of the BSD License. The full license is in
29 # Distributed under the terms of the BSD License. The full license is in
30 # the file COPYING, distributed as part of this software.
30 # the file COPYING, distributed as part of this software.
31 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
32
32
33 import sys
33 import sys
34 import tempfile
34 import tempfile
35 from glob import glob
35 from glob import glob
36 from shutil import rmtree
36 from shutil import rmtree
37 from getopt import getopt
37 from getopt import getopt
38
38
39 # numpy and rpy2 imports
39 # numpy and rpy2 imports
40
40
41 import numpy as np
41 import numpy as np
42
42
43 import rpy2.rinterface as ri
43 import rpy2.rinterface as ri
44 import rpy2.robjects as ro
44 import rpy2.robjects as ro
45 from rpy2.robjects.numpy2ri import numpy2ri
45 from rpy2.robjects.numpy2ri import numpy2ri
46 ro.conversion.py2ri = numpy2ri
46 ro.conversion.py2ri = numpy2ri
47
47
48 # IPython imports
48 # IPython imports
49
49
50 from IPython.core.displaypub import publish_display_data
50 from IPython.core.displaypub import publish_display_data
51 from IPython.core.magic import (Magics, magics_class, cell_magic, line_magic,
51 from IPython.core.magic import (Magics, magics_class, cell_magic, line_magic,
52 line_cell_magic)
52 line_cell_magic)
53 from IPython.testing.skipdoctest import skip_doctest
53 from IPython.testing.skipdoctest import skip_doctest
54 from IPython.core.magic_arguments import (
54 from IPython.core.magic_arguments import (
55 argument, magic_arguments, parse_argstring
55 argument, magic_arguments, parse_argstring
56 )
56 )
57 from IPython.utils.py3compat import str_to_unicode, unicode_to_str
57 from IPython.utils.py3compat import str_to_unicode, unicode_to_str
58
58
59 class RMagicError(ri.RRuntimeError):
59 class RMagicError(ri.RRuntimeError):
60 pass
60 pass
61
61
62 def Rconverter(Robj):
62 def Rconverter(Robj):
63 """
63 """
64 Convert an object in R's namespace to one suitable
64 Convert an object in R's namespace to one suitable
65 for ipython's namespace.
65 for ipython's namespace.
66
66
67 For a data.frame, it tries to return a structured array.
67 For a data.frame, it tries to return a structured array.
68
68
69 Parameters
69 Parameters
70 ----------
70 ----------
71
71
72 Robj: an R object returned from rpy2
72 Robj: an R object returned from rpy2
73 """
73 """
74 if is_data_frame(Robj):
74 if is_data_frame(Robj):
75 dimRobj = dimR(Robj)
76 if dimRobj != ri.NULL:
77 dimRobj = list(np.array(dimRobj))
78 if len(dimRobj) > 1:
79 try:
75 names = np.array(Robj.do_slot('names'))
80 names = np.array(Robj.do_slot('names'))
76 Robj = np.rec.fromarrays(Robj, names = tuple(names))
81 Robj = np.rec.fromarrays(Robj, names = tuple(names))
82 except LookupError:
83 pass
77 return np.asarray(Robj)
84 return np.asarray(Robj)
78
85
79 is_data_frame = None
86 is_data_frame = None
87 dimR = None
80
88
81 @magics_class
89 @magics_class
82 class RMagics(Magics):
90 class RMagics(Magics):
83 """A set of magics useful for interactive work with R via rpy2.
91 """A set of magics useful for interactive work with R via rpy2.
84 """
92 """
85
93
86 def __init__(self, shell, Rconverter=Rconverter,
94 def __init__(self, shell, Rconverter=Rconverter,
87 pyconverter=np.asarray,
95 pyconverter=np.asarray,
88 cache_display_data=False):
96 cache_display_data=False):
89 """
97 """
90 Parameters
98 Parameters
91 ----------
99 ----------
92
100
93 shell : IPython shell
101 shell : IPython shell
94
102
95 pyconverter : callable
103 pyconverter : callable
96 To be called on values in ipython namespace before
104 To be called on values in ipython namespace before
97 assigning to variables in rpy2.
105 assigning to variables in rpy2.
98
106
99 cache_display_data : bool
107 cache_display_data : bool
100 If True, the published results of the final call to R are
108 If True, the published results of the final call to R are
101 cached in the variable 'display_cache'.
109 cached in the variable 'display_cache'.
102
110
103 """
111 """
104 super(RMagics, self).__init__(shell)
112 super(RMagics, self).__init__(shell)
105 self.cache_display_data = cache_display_data
113 self.cache_display_data = cache_display_data
106
114
107 self.r = ro.R()
115 self.r = ro.R()
108 global is_data_frame
116 global is_data_frame, dimR
109 is_data_frame = self.r('is.data.frame')
117 is_data_frame = self.r('is.data.frame')
118 dimR = self.r('dim')
110
119
111 self.Rstdout_cache = []
120 self.Rstdout_cache = []
112 self.pyconverter = pyconverter
121 self.pyconverter = pyconverter
113 self.Rconverter = Rconverter
122 self.Rconverter = Rconverter
114
123
115 def eval(self, line):
124 def eval(self, line):
116 '''
125 '''
117 Parse and evaluate a line with rpy2.
126 Parse and evaluate a line with rpy2.
118 Returns the output to R's stdout() connection
127 Returns the output to R's stdout() connection
119 and the value of eval(parse(line)).
128 and the value of eval(parse(line)).
120 '''
129 '''
121 old_writeconsole = ri.get_writeconsole()
130 old_writeconsole = ri.get_writeconsole()
122 ri.set_writeconsole(self.write_console)
131 ri.set_writeconsole(self.write_console)
123 try:
132 try:
124 value = ri.baseenv['eval'](ri.parse(line))
133 value = ri.baseenv['eval'](ri.parse(line))
125 except (ri.RRuntimeError, ValueError) as exception:
134 except (ri.RRuntimeError, ValueError) as exception:
126 raise RMagicError(unicode_to_str('parsing and evaluating line "%s". R traceback: "%s"\n' %
135 raise RMagicError(unicode_to_str('parsing and evaluating line "%s". R traceback: "%s"\n' %
127 (line, str_to_unicode(exception.message, 'utf-8'))))
136 (line, str_to_unicode(exception.message, 'utf-8'))))
128 text_output = self.flush()
137 text_output = self.flush()
129 ri.set_writeconsole(old_writeconsole)
138 ri.set_writeconsole(old_writeconsole)
130 return text_output, value
139 return text_output, value
131
140
132 def write_console(self, output):
141 def write_console(self, output):
133 '''
142 '''
134 A hook to capture R's stdout in a cache.
143 A hook to capture R's stdout in a cache.
135 '''
144 '''
136 self.Rstdout_cache.append(output)
145 self.Rstdout_cache.append(output)
137
146
138 def flush(self):
147 def flush(self):
139 '''
148 '''
140 Flush R's stdout cache to a string, returning the string.
149 Flush R's stdout cache to a string, returning the string.
141 '''
150 '''
142 value = ''.join([str_to_unicode(s, 'utf-8') for s in self.Rstdout_cache])
151 value = ''.join([str_to_unicode(s, 'utf-8') for s in self.Rstdout_cache])
143 self.Rstdout_cache = []
152 self.Rstdout_cache = []
144 return value
153 return value
145
154
146 @skip_doctest
155 @skip_doctest
147 @line_magic
156 @line_magic
148 def Rpush(self, line):
157 def Rpush(self, line):
149 '''
158 '''
150 A line-level magic for R that pushes
159 A line-level magic for R that pushes
151 variables from python to rpy2. The line should be made up
160 variables from python to rpy2. The line should be made up
152 of whitespace separated variable names in the IPython
161 of whitespace separated variable names in the IPython
153 namespace::
162 namespace::
154
163
155 In [7]: import numpy as np
164 In [7]: import numpy as np
156
165
157 In [8]: X = np.array([4.5,6.3,7.9])
166 In [8]: X = np.array([4.5,6.3,7.9])
158
167
159 In [9]: X.mean()
168 In [9]: X.mean()
160 Out[9]: 6.2333333333333343
169 Out[9]: 6.2333333333333343
161
170
162 In [10]: %Rpush X
171 In [10]: %Rpush X
163
172
164 In [11]: %R mean(X)
173 In [11]: %R mean(X)
165 Out[11]: array([ 6.23333333])
174 Out[11]: array([ 6.23333333])
166
175
167 '''
176 '''
168
177
169 inputs = line.split(' ')
178 inputs = line.split(' ')
170 for input in inputs:
179 for input in inputs:
171 self.r.assign(input, self.pyconverter(self.shell.user_ns[input]))
180 self.r.assign(input, self.pyconverter(self.shell.user_ns[input]))
172
181
173 @skip_doctest
182 @skip_doctest
174 @line_magic
183 @line_magic
175 def Rpull(self, line):
184 def Rpull(self, line):
176 '''
185 '''
177 A line-level magic for R that pulls
186 A line-level magic for R that pulls
178 variables from python to rpy2::
187 variables from python to rpy2::
179
188
180 In [18]: _ = %R x = c(3,4,6.7); y = c(4,6,7); z = c('a',3,4)
189 In [18]: _ = %R x = c(3,4,6.7); y = c(4,6,7); z = c('a',3,4)
181
190
182 In [19]: %Rpull x y z
191 In [19]: %Rpull x y z
183
192
184 In [20]: x
193 In [20]: x
185 Out[20]: array([ 3. , 4. , 6.7])
194 Out[20]: array([ 3. , 4. , 6.7])
186
195
187 In [21]: y
196 In [21]: y
188 Out[21]: array([ 4., 6., 7.])
197 Out[21]: array([ 4., 6., 7.])
189
198
190 In [22]: z
199 In [22]: z
191 Out[22]:
200 Out[22]:
192 array(['a', '3', '4'],
201 array(['a', '3', '4'],
193 dtype='|S1')
202 dtype='|S1')
194
203
195
204
196 Notes
205 Notes
197 -----
206 -----
198
207
199 Beware that R names can have '.' so this is not fool proof.
208 Beware that R names can have '.' so this is not fool proof.
200 To avoid this, don't name your R objects with '.'s...
209 To avoid this, don't name your R objects with '.'s...
201
210
202 '''
211 '''
203 outputs = line.split(' ')
212 outputs = line.split(' ')
204 for output in outputs:
213 for output in outputs:
205 self.shell.push({output:self.Rconverter(self.r(output))})
214 self.shell.push({output:self.Rconverter(self.r(output))})
206
215
207
216
208 @skip_doctest
217 @skip_doctest
209 @magic_arguments()
218 @magic_arguments()
210 @argument(
219 @argument(
211 '-i', '--input', action='append',
220 '-i', '--input', action='append',
212 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.'
221 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.'
213 )
222 )
214 @argument(
223 @argument(
215 '-o', '--output', action='append',
224 '-o', '--output', action='append',
216 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.'
225 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.'
217 )
226 )
218 @argument(
227 @argument(
219 '-w', '--width', type=int,
228 '-w', '--width', type=int,
220 help='Width of png plotting device sent as an argument to *png* in R.'
229 help='Width of png plotting device sent as an argument to *png* in R.'
221 )
230 )
222 @argument(
231 @argument(
223 '-h', '--height', type=int,
232 '-h', '--height', type=int,
224 help='Height of png plotting device sent as an argument to *png* in R.'
233 help='Height of png plotting device sent as an argument to *png* in R.'
225 )
234 )
226
235
227 @argument(
236 @argument(
228 '-u', '--units', type=int,
237 '-u', '--units', type=int,
229 help='Units of png plotting device sent as an argument to *png* in R. One of ["px", "in", "cm", "mm"].'
238 help='Units of png plotting device sent as an argument to *png* in R. One of ["px", "in", "cm", "mm"].'
230 )
239 )
231 @argument(
240 @argument(
232 '-p', '--pointsize', type=int,
241 '-p', '--pointsize', type=int,
233 help='Pointsize of png plotting device sent as an argument to *png* in R.'
242 help='Pointsize of png plotting device sent as an argument to *png* in R.'
234 )
243 )
235 @argument(
244 @argument(
236 '-b', '--bg',
245 '-b', '--bg',
237 help='Background of png plotting device sent as an argument to *png* in R.'
246 help='Background of png plotting device sent as an argument to *png* in R.'
238 )
247 )
239 @argument(
248 @argument(
240 '-n', '--noreturn',
249 '-n', '--noreturn',
241 help='Force the magic to not return anything.',
250 help='Force the magic to not return anything.',
242 action='store_true',
251 action='store_true',
243 default=False
252 default=False
244 )
253 )
245 @argument(
254 @argument(
246 'code',
255 'code',
247 nargs='*',
256 nargs='*',
248 )
257 )
249 @line_cell_magic
258 @line_cell_magic
250 def R(self, line, cell=None):
259 def R(self, line, cell=None):
251 '''
260 '''
252 Execute code in R, and pull some of the results back into the Python namespace.
261 Execute code in R, and pull some of the results back into the Python namespace.
253
262
254 In line mode, this will evaluate an expression and convert the returned value to a Python object.
263 In line mode, this will evaluate an expression and convert the returned value to a Python object.
255 The return value is determined by rpy2's behaviour of returning the result of evaluating the
264 The return value is determined by rpy2's behaviour of returning the result of evaluating the
256 final line. Multiple R lines can be executed by joining them with semicolons::
265 final line. Multiple R lines can be executed by joining them with semicolons::
257
266
258 In [9]: %R X=c(1,4,5,7); sd(X); mean(X)
267 In [9]: %R X=c(1,4,5,7); sd(X); mean(X)
259 Out[9]: array([ 4.25])
268 Out[9]: array([ 4.25])
260
269
261 As a cell, this will run a block of R code, without bringing anything back by default::
270 As a cell, this will run a block of R code, without bringing anything back by default::
262
271
263 In [10]: %%R
272 In [10]: %%R
264 ....: Y = c(2,4,3,9)
273 ....: Y = c(2,4,3,9)
265 ....: print(summary(lm(Y~X)))
274 ....: print(summary(lm(Y~X)))
266 ....:
275 ....:
267
276
268 Call:
277 Call:
269 lm(formula = Y ~ X)
278 lm(formula = Y ~ X)
270
279
271 Residuals:
280 Residuals:
272 1 2 3 4
281 1 2 3 4
273 0.88 -0.24 -2.28 1.64
282 0.88 -0.24 -2.28 1.64
274
283
275 Coefficients:
284 Coefficients:
276 Estimate Std. Error t value Pr(>|t|)
285 Estimate Std. Error t value Pr(>|t|)
277 (Intercept) 0.0800 2.3000 0.035 0.975
286 (Intercept) 0.0800 2.3000 0.035 0.975
278 X 1.0400 0.4822 2.157 0.164
287 X 1.0400 0.4822 2.157 0.164
279
288
280 Residual standard error: 2.088 on 2 degrees of freedom
289 Residual standard error: 2.088 on 2 degrees of freedom
281 Multiple R-squared: 0.6993,Adjusted R-squared: 0.549
290 Multiple R-squared: 0.6993,Adjusted R-squared: 0.549
282 F-statistic: 4.651 on 1 and 2 DF, p-value: 0.1638
291 F-statistic: 4.651 on 1 and 2 DF, p-value: 0.1638
283
292
284 In the notebook, plots are published as the output of the cell.
293 In the notebook, plots are published as the output of the cell.
285
294
286 %R plot(X, Y)
295 %R plot(X, Y)
287
296
288 will create a scatter plot of X bs Y.
297 will create a scatter plot of X bs Y.
289
298
290 If cell is not None and line has some R code, it is prepended to
299 If cell is not None and line has some R code, it is prepended to
291 the R code in cell.
300 the R code in cell.
292
301
293 Objects can be passed back and forth between rpy2 and python via the -i -o flags in line::
302 Objects can be passed back and forth between rpy2 and python via the -i -o flags in line::
294
303
295 In [14]: Z = np.array([1,4,5,10])
304 In [14]: Z = np.array([1,4,5,10])
296
305
297 In [15]: %R -i Z mean(Z)
306 In [15]: %R -i Z mean(Z)
298 Out[15]: array([ 5.])
307 Out[15]: array([ 5.])
299
308
300
309
301 In [16]: %R -o W W=Z*mean(Z)
310 In [16]: %R -o W W=Z*mean(Z)
302 Out[16]: array([ 5., 20., 25., 50.])
311 Out[16]: array([ 5., 20., 25., 50.])
303
312
304 In [17]: W
313 In [17]: W
305 Out[17]: array([ 5., 20., 25., 50.])
314 Out[17]: array([ 5., 20., 25., 50.])
306
315
307 The return value is determined by these rules:
316 The return value is determined by these rules:
308
317
309 * If the cell is not None, the magic returns None.
318 * If the cell is not None, the magic returns None.
310
319
311 * If the cell evaluates as False, the resulting value is returned
320 * If the cell evaluates as False, the resulting value is returned
312 unless the final line prints something to the console, in
321 unless the final line prints something to the console, in
313 which case None is returned.
322 which case None is returned.
314
323
315 * If the final line results in a NULL value when evaluated
324 * If the final line results in a NULL value when evaluated
316 by rpy2, then None is returned.
325 by rpy2, then None is returned.
317
326
318
327
319 '''
328 '''
320
329
321 args = parse_argstring(self.R, line)
330 args = parse_argstring(self.R, line)
322
331
323 # arguments 'code' in line are prepended to
332 # arguments 'code' in line are prepended to
324 # the cell lines
333 # the cell lines
325 if not cell:
334 if not cell:
326 code = ''
335 code = ''
327 return_output = True
336 return_output = True
328 line_mode = True
337 line_mode = True
329 else:
338 else:
330 code = cell
339 code = cell
331 return_output = False
340 return_output = False
332 line_mode = False
341 line_mode = False
333
342
334 code = ' '.join(args.code) + code
343 code = ' '.join(args.code) + code
335
344
336 if args.input:
345 if args.input:
337 for input in ','.join(args.input).split(','):
346 for input in ','.join(args.input).split(','):
338 self.r.assign(input, self.pyconverter(self.shell.user_ns[input]))
347 self.r.assign(input, self.pyconverter(self.shell.user_ns[input]))
339
348
340 png_argdict = dict([(n, getattr(args, n)) for n in ['units', 'height', 'width', 'bg', 'pointsize']])
349 png_argdict = dict([(n, getattr(args, n)) for n in ['units', 'height', 'width', 'bg', 'pointsize']])
341 png_args = ','.join(['%s=%s' % (o,v) for o, v in png_argdict.items() if v is not None])
350 png_args = ','.join(['%s=%s' % (o,v) for o, v in png_argdict.items() if v is not None])
342 # execute the R code in a temporary directory
351 # execute the R code in a temporary directory
343
352
344 tmpd = tempfile.mkdtemp()
353 tmpd = tempfile.mkdtemp()
345 self.r('png("%s/Rplots%%03d.png",%s)' % (tmpd, png_args))
354 self.r('png("%s/Rplots%%03d.png",%s)' % (tmpd, png_args))
346
355
347 text_output = ''
356 text_output = ''
348 if line_mode:
357 if line_mode:
349 for line in code.split(';'):
358 for line in code.split(';'):
350 text_result, result = self.eval(line)
359 text_result, result = self.eval(line)
351 text_output += text_result
360 text_output += text_result
352 if text_result:
361 if text_result:
353 # the last line printed something to the console so we won't return it
362 # the last line printed something to the console so we won't return it
354 return_output = False
363 return_output = False
355 else:
364 else:
356 text_result, result = self.eval(code)
365 text_result, result = self.eval(code)
357 text_output += text_result
366 text_output += text_result
358
367
359 self.r('dev.off()')
368 self.r('dev.off()')
360
369
361 # read out all the saved .png files
370 # read out all the saved .png files
362
371
363 images = [open(imgfile, 'rb').read() for imgfile in glob("%s/Rplots*png" % tmpd)]
372 images = [open(imgfile, 'rb').read() for imgfile in glob("%s/Rplots*png" % tmpd)]
364
373
365 # now publish the images
374 # now publish the images
366 # mimicking IPython/zmq/pylab/backend_inline.py
375 # mimicking IPython/zmq/pylab/backend_inline.py
367 fmt = 'png'
376 fmt = 'png'
368 mimetypes = { 'png' : 'image/png', 'svg' : 'image/svg+xml' }
377 mimetypes = { 'png' : 'image/png', 'svg' : 'image/svg+xml' }
369 mime = mimetypes[fmt]
378 mime = mimetypes[fmt]
370
379
371 # publish the printed R objects, if any
380 # publish the printed R objects, if any
372
381
373 display_data = []
382 display_data = []
374 if text_output:
383 if text_output:
375 display_data.append(('RMagic.R', {'text/plain':text_output}))
384 display_data.append(('RMagic.R', {'text/plain':text_output}))
376
385
377 # flush text streams before sending figures, helps a little with output
386 # flush text streams before sending figures, helps a little with output
378 for image in images:
387 for image in images:
379 # synchronization in the console (though it's a bandaid, not a real sln)
388 # synchronization in the console (though it's a bandaid, not a real sln)
380 sys.stdout.flush(); sys.stderr.flush()
389 sys.stdout.flush(); sys.stderr.flush()
381 display_data.append(('RMagic.R', {mime: image}))
390 display_data.append(('RMagic.R', {mime: image}))
382
391
383 # kill the temporary directory
392 # kill the temporary directory
384 rmtree(tmpd)
393 rmtree(tmpd)
385
394
386 # try to turn every output into a numpy array
395 # try to turn every output into a numpy array
387 # this means that output are assumed to be castable
396 # this means that output are assumed to be castable
388 # as numpy arrays
397 # as numpy arrays
389
398
390 if args.output:
399 if args.output:
391 for output in ','.join(args.output).split(','):
400 for output in ','.join(args.output).split(','):
392 self.shell.push({output:self.Rconverter(self.r(output))})
401 self.shell.push({output:self.Rconverter(self.r(output))})
393
402
394 for tag, disp_d in display_data:
403 for tag, disp_d in display_data:
395 publish_display_data(tag, disp_d)
404 publish_display_data(tag, disp_d)
396
405
397 # this will keep a reference to the display_data
406 # this will keep a reference to the display_data
398 # which might be useful to other objects who happen to use
407 # which might be useful to other objects who happen to use
399 # this method
408 # this method
400
409
401 if self.cache_display_data:
410 if self.cache_display_data:
402 self.display_cache = display_data
411 self.display_cache = display_data
403
412
404 # if in line mode and return_output, return the result as an ndarray
413 # if in line mode and return_output, return the result as an ndarray
405 if return_output and not args.noreturn:
414 if return_output and not args.noreturn:
406 if result != ri.NULL:
415 if result != ri.NULL:
407 return self.Rconverter(result)
416 return self.Rconverter(result)
408
417
409 __doc__ = __doc__.format(
418 __doc__ = __doc__.format(
410 R_DOC = ' '*8 + RMagics.R.__doc__,
419 R_DOC = ' '*8 + RMagics.R.__doc__,
411 RPUSH_DOC = ' '*8 + RMagics.Rpush.__doc__,
420 RPUSH_DOC = ' '*8 + RMagics.Rpush.__doc__,
412 RPULL_DOC = ' '*8 + RMagics.Rpull.__doc__
421 RPULL_DOC = ' '*8 + RMagics.Rpull.__doc__
413 )
422 )
414
423
415
424
416 _loaded = False
425 _loaded = False
417 def load_ipython_extension(ip):
426 def load_ipython_extension(ip):
418 """Load the extension in IPython."""
427 """Load the extension in IPython."""
419 global _loaded
428 global _loaded
420 if not _loaded:
429 if not _loaded:
421 ip.register_magics(RMagics)
430 ip.register_magics(RMagics)
422 _loaded = True
431 _loaded = True
@@ -1,41 +1,62 b''
1 import numpy as np
1 import numpy as np
2 from IPython.core.interactiveshell import InteractiveShell
2 from IPython.core.interactiveshell import InteractiveShell
3 from IPython.extensions import rmagic
3 from IPython.extensions import rmagic
4 import nose.tools as nt
4
5
5 ip = get_ipython()
6 ip = get_ipython()
6 ip.magic('load_ext rmagic')
7 ip.magic('load_ext rmagic')
7
8
8
9
9 def test_push():
10 def test_push():
10 rm = rmagic.RMagics(ip)
11 rm = rmagic.RMagics(ip)
11 ip.push({'X':np.arange(5), 'Y':np.array([3,5,4,6,7])})
12 ip.push({'X':np.arange(5), 'Y':np.array([3,5,4,6,7])})
12 ip.run_line_magic('Rpush', 'X Y')
13 ip.run_line_magic('Rpush', 'X Y')
13 np.testing.assert_almost_equal(np.asarray(rm.r('X')), ip.user_ns['X'])
14 np.testing.assert_almost_equal(np.asarray(rm.r('X')), ip.user_ns['X'])
14 np.testing.assert_almost_equal(np.asarray(rm.r('Y')), ip.user_ns['Y'])
15 np.testing.assert_almost_equal(np.asarray(rm.r('Y')), ip.user_ns['Y'])
15
16
16 def test_pull():
17 def test_pull():
17 rm = rmagic.RMagics(ip)
18 rm = rmagic.RMagics(ip)
18 rm.r('Z=c(11:20)')
19 rm.r('Z=c(11:20)')
19 ip.run_line_magic('Rpull', 'Z')
20 ip.run_line_magic('Rpull', 'Z')
20 np.testing.assert_almost_equal(np.asarray(rm.r('Z')), ip.user_ns['Z'])
21 np.testing.assert_almost_equal(np.asarray(rm.r('Z')), ip.user_ns['Z'])
21 np.testing.assert_almost_equal(ip.user_ns['Z'], np.arange(11,21))
22 np.testing.assert_almost_equal(ip.user_ns['Z'], np.arange(11,21))
22
23
23 # def test_inline():
24 def test_Rconverter():
24 # rm = rmagic.RMagics(ip)
25 datapy= np.array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c')],
25 # c = ip.run_line_magic('Rinline', 'lm(Y~X)$coef')
26 dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')])
26 # np.testing.assert_almost_equal(c, [3.2, 0.9])
27 ip.user_ns['datapy'] = datapy
28 ip.run_line_magic('Rpush', 'datapy')
29
30 # test to see if a copy is being made
31 v = ip.run_line_magic('R', 'datapy')
32 w = ip.run_line_magic('R', 'datapy')
33 np.testing.assert_almost_equal(w['x'], v['x'])
34 np.testing.assert_almost_equal(w['y'], v['y'])
35 nt.assert_true(np.all(w['z'] == v['z']))
36 np.testing.assert_equal(id(w.data), id(v.data))
37 nt.assert_equal(w.dtype, v.dtype)
38
39 ip.run_cell_magic('R', ' -o datar datar=datapy', '')
40
41 u = ip.run_line_magic('R', 'datar')
42 np.testing.assert_almost_equal(u['x'], v['x'])
43 np.testing.assert_almost_equal(u['y'], v['y'])
44 nt.assert_true(np.all(u['z'] == v['z']))
45 np.testing.assert_equal(id(u.data), id(v.data))
46 nt.assert_equal(u.dtype, v.dtype)
47
27
48
28 def test_cell_magic():
49 def test_cell_magic():
29
50
30 ip.push({'x':np.arange(5), 'y':np.array([3,5,4,6,7])})
51 ip.push({'x':np.arange(5), 'y':np.array([3,5,4,6,7])})
31 snippet = '''
52 snippet = '''
32 print(summary(a))
53 print(summary(a))
33 plot(X, Y, pch=23, bg='orange', cex=2)
54 plot(x, y, pch=23, bg='orange', cex=2)
34 plot(Y, X)
55 plot(x, x)
35 print(summary(X))
56 print(summary(x))
36 r = resid(a)
57 r = resid(a)
37 xc = coef(a)
58 xc = coef(a)
38 '''
59 '''
39 ip.run_cell_magic('R', '-i x,y -o r,xc a=lm(y~x)', snippet)
60 ip.run_cell_magic('R', '-i x,y -o r,xc a=lm(y~x)', snippet)
40 np.testing.assert_almost_equal(ip.user_ns['xc'], [3.2, 0.9])
61 np.testing.assert_almost_equal(ip.user_ns['xc'], [3.2, 0.9])
41 np.testing.assert_almost_equal(ip.user_ns['r'], np.array([-0.2, 0.9, -1. , 0.1, 0.2]))
62 np.testing.assert_almost_equal(ip.user_ns['r'], np.array([-0.2, 0.9, -1. , 0.1, 0.2]))
General Comments 0
You need to be logged in to leave comments. Login now