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