Show More
This diff has been collapsed as it changes many lines, (571 lines changed) Show them Hide them | |||||
@@ -0,0 +1,571 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | """ | |||
|
3 | ====== | |||
|
4 | Rmagic | |||
|
5 | ====== | |||
|
6 | ||||
|
7 | Magic command interface for interactive work with R via rpy2 | |||
|
8 | ||||
|
9 | Usage | |||
|
10 | ===== | |||
|
11 | ||||
|
12 | ``%R`` | |||
|
13 | ||||
|
14 | {R_DOC} | |||
|
15 | ||||
|
16 | ``%Rpush`` | |||
|
17 | ||||
|
18 | {RPUSH_DOC} | |||
|
19 | ||||
|
20 | ``%Rpull`` | |||
|
21 | ||||
|
22 | {RPULL_DOC} | |||
|
23 | ||||
|
24 | ``%Rget`` | |||
|
25 | ||||
|
26 | {RGET_DOC} | |||
|
27 | ||||
|
28 | """ | |||
|
29 | ||||
|
30 | #----------------------------------------------------------------------------- | |||
|
31 | # Copyright (C) 2012 The IPython Development Team | |||
|
32 | # | |||
|
33 | # Distributed under the terms of the BSD License. The full license is in | |||
|
34 | # the file COPYING, distributed as part of this software. | |||
|
35 | #----------------------------------------------------------------------------- | |||
|
36 | ||||
|
37 | import sys | |||
|
38 | import tempfile | |||
|
39 | from glob import glob | |||
|
40 | from shutil import rmtree | |||
|
41 | from getopt import getopt | |||
|
42 | ||||
|
43 | # numpy and rpy2 imports | |||
|
44 | ||||
|
45 | import numpy as np | |||
|
46 | ||||
|
47 | import rpy2.rinterface as ri | |||
|
48 | import rpy2.robjects as ro | |||
|
49 | from rpy2.robjects.numpy2ri import numpy2ri | |||
|
50 | ro.conversion.py2ri = numpy2ri | |||
|
51 | ||||
|
52 | # IPython imports | |||
|
53 | ||||
|
54 | from IPython.core.displaypub import publish_display_data | |||
|
55 | from IPython.core.magic import (Magics, magics_class, cell_magic, line_magic, | |||
|
56 | line_cell_magic) | |||
|
57 | from IPython.testing.skipdoctest import skip_doctest | |||
|
58 | from IPython.core.magic_arguments import ( | |||
|
59 | argument, magic_arguments, parse_argstring | |||
|
60 | ) | |||
|
61 | from IPython.utils.py3compat import str_to_unicode, unicode_to_str | |||
|
62 | ||||
|
63 | class RMagicError(ri.RRuntimeError): | |||
|
64 | pass | |||
|
65 | ||||
|
66 | def Rconverter(Robj, dataframe=False): | |||
|
67 | """ | |||
|
68 | Convert an object in R's namespace to one suitable | |||
|
69 | for ipython's namespace. | |||
|
70 | ||||
|
71 | For a data.frame, it tries to return a structured array. | |||
|
72 | It first checks for colnames, then names. | |||
|
73 | If all are NULL, it returns np.asarray(Robj), else | |||
|
74 | it tries to construct a recarray | |||
|
75 | ||||
|
76 | Parameters | |||
|
77 | ---------- | |||
|
78 | ||||
|
79 | Robj: an R object returned from rpy2 | |||
|
80 | """ | |||
|
81 | is_data_frame = ro.r('is.data.frame') | |||
|
82 | colnames = ro.r('colnames') | |||
|
83 | rownames = ro.r('rownames') # with pandas, these could be used for the index | |||
|
84 | names = ro.r('names') | |||
|
85 | ||||
|
86 | if dataframe: | |||
|
87 | as_data_frame = ro.r('as.data.frame') | |||
|
88 | cols = colnames(Robj) | |||
|
89 | _names = names(Robj) | |||
|
90 | if cols != ri.NULL: | |||
|
91 | Robj = as_data_frame(Robj) | |||
|
92 | names = tuple(np.array(cols)) | |||
|
93 | elif _names != ri.NULL: | |||
|
94 | names = tuple(np.array(_names)) | |||
|
95 | else: # failed to find names | |||
|
96 | return np.asarray(Robj) | |||
|
97 | Robj = np.rec.fromarrays(Robj, names = names) | |||
|
98 | return np.asarray(Robj) | |||
|
99 | ||||
|
100 | @magics_class | |||
|
101 | class RMagics(Magics): | |||
|
102 | """A set of magics useful for interactive work with R via rpy2. | |||
|
103 | """ | |||
|
104 | ||||
|
105 | def __init__(self, shell, Rconverter=Rconverter, | |||
|
106 | pyconverter=np.asarray, | |||
|
107 | cache_display_data=False): | |||
|
108 | """ | |||
|
109 | Parameters | |||
|
110 | ---------- | |||
|
111 | ||||
|
112 | shell : IPython shell | |||
|
113 | ||||
|
114 | pyconverter : callable | |||
|
115 | To be called on values in ipython namespace before | |||
|
116 | assigning to variables in rpy2. | |||
|
117 | ||||
|
118 | cache_display_data : bool | |||
|
119 | If True, the published results of the final call to R are | |||
|
120 | cached in the variable 'display_cache'. | |||
|
121 | ||||
|
122 | """ | |||
|
123 | super(RMagics, self).__init__(shell) | |||
|
124 | self.cache_display_data = cache_display_data | |||
|
125 | ||||
|
126 | self.r = ro.R() | |||
|
127 | ||||
|
128 | self.Rstdout_cache = [] | |||
|
129 | self.pyconverter = pyconverter | |||
|
130 | self.Rconverter = Rconverter | |||
|
131 | ||||
|
132 | def eval(self, line): | |||
|
133 | ''' | |||
|
134 | Parse and evaluate a line with rpy2. | |||
|
135 | Returns the output to R's stdout() connection | |||
|
136 | and the value of eval(parse(line)). | |||
|
137 | ''' | |||
|
138 | old_writeconsole = ri.get_writeconsole() | |||
|
139 | ri.set_writeconsole(self.write_console) | |||
|
140 | try: | |||
|
141 | value = ri.baseenv['eval'](ri.parse(line)) | |||
|
142 | except (ri.RRuntimeError, ValueError) as exception: | |||
|
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' % | |||
|
145 | (line, str_to_unicode(exception.message, 'utf-8'), warning_or_other_msg))) | |||
|
146 | text_output = self.flush() | |||
|
147 | ri.set_writeconsole(old_writeconsole) | |||
|
148 | return text_output, value | |||
|
149 | ||||
|
150 | def write_console(self, output): | |||
|
151 | ''' | |||
|
152 | A hook to capture R's stdout in a cache. | |||
|
153 | ''' | |||
|
154 | self.Rstdout_cache.append(output) | |||
|
155 | ||||
|
156 | def flush(self): | |||
|
157 | ''' | |||
|
158 | Flush R's stdout cache to a string, returning the string. | |||
|
159 | ''' | |||
|
160 | value = ''.join([str_to_unicode(s, 'utf-8') for s in self.Rstdout_cache]) | |||
|
161 | self.Rstdout_cache = [] | |||
|
162 | return value | |||
|
163 | ||||
|
164 | @skip_doctest | |||
|
165 | @line_magic | |||
|
166 | def Rpush(self, line): | |||
|
167 | ''' | |||
|
168 | A line-level magic for R that pushes | |||
|
169 | variables from python to rpy2. The line should be made up | |||
|
170 | of whitespace separated variable names in the IPython | |||
|
171 | namespace:: | |||
|
172 | ||||
|
173 | In [7]: import numpy as np | |||
|
174 | ||||
|
175 | In [8]: X = np.array([4.5,6.3,7.9]) | |||
|
176 | ||||
|
177 | In [9]: X.mean() | |||
|
178 | Out[9]: 6.2333333333333343 | |||
|
179 | ||||
|
180 | In [10]: %Rpush X | |||
|
181 | ||||
|
182 | In [11]: %R mean(X) | |||
|
183 | Out[11]: array([ 6.23333333]) | |||
|
184 | ||||
|
185 | ''' | |||
|
186 | ||||
|
187 | inputs = line.split(' ') | |||
|
188 | for input in inputs: | |||
|
189 | self.r.assign(input, self.pyconverter(self.shell.user_ns[input])) | |||
|
190 | ||||
|
191 | @skip_doctest | |||
|
192 | @magic_arguments() | |||
|
193 | @argument( | |||
|
194 | '-d', '--as_dataframe', action='store_true', | |||
|
195 | default=False, | |||
|
196 | help='Convert objects to data.frames before returning to ipython.' | |||
|
197 | ) | |||
|
198 | @argument( | |||
|
199 | 'outputs', | |||
|
200 | nargs='*', | |||
|
201 | ) | |||
|
202 | @line_magic | |||
|
203 | def Rpull(self, line): | |||
|
204 | ''' | |||
|
205 | A line-level magic for R that pulls | |||
|
206 | variables from python to rpy2:: | |||
|
207 | ||||
|
208 | In [18]: _ = %R x = c(3,4,6.7); y = c(4,6,7); z = c('a',3,4) | |||
|
209 | ||||
|
210 | In [19]: %Rpull x y z | |||
|
211 | ||||
|
212 | In [20]: x | |||
|
213 | Out[20]: array([ 3. , 4. , 6.7]) | |||
|
214 | ||||
|
215 | In [21]: y | |||
|
216 | Out[21]: array([ 4., 6., 7.]) | |||
|
217 | ||||
|
218 | In [22]: z | |||
|
219 | Out[22]: | |||
|
220 | array(['a', '3', '4'], | |||
|
221 | dtype='|S1') | |||
|
222 | ||||
|
223 | ||||
|
224 | If --as_dataframe, then each object is returned as a structured array | |||
|
225 | after first passed through "as.data.frame" in R before | |||
|
226 | being calling self.Rconverter. | |||
|
227 | This is useful when a structured array is desired as output, or | |||
|
228 | when the object in R has mixed data types. | |||
|
229 | See the %%R docstring for more examples. | |||
|
230 | ||||
|
231 | Notes | |||
|
232 | ----- | |||
|
233 | ||||
|
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... | |||
|
236 | ||||
|
237 | ''' | |||
|
238 | args = parse_argstring(self.Rpull, line) | |||
|
239 | outputs = args.outputs | |||
|
240 | for output in outputs: | |||
|
241 | self.shell.push({output:self.Rconverter(self.r(output),dataframe=args.as_dataframe)}) | |||
|
242 | ||||
|
243 | @skip_doctest | |||
|
244 | @magic_arguments() | |||
|
245 | @argument( | |||
|
246 | '-d', '--as_dataframe', action='store_true', | |||
|
247 | default=False, | |||
|
248 | help='Convert objects to data.frames before returning to ipython.' | |||
|
249 | ) | |||
|
250 | @argument( | |||
|
251 | 'output', | |||
|
252 | nargs=1, | |||
|
253 | type=str, | |||
|
254 | ) | |||
|
255 | @line_magic | |||
|
256 | def Rget(self, line): | |||
|
257 | ''' | |||
|
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 | |||
|
260 | returned rather than pushed to self.shell.user_ns:: | |||
|
261 | ||||
|
262 | In [3]: dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')] | |||
|
263 | ||||
|
264 | In [4]: datapy = np.array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5, 'e')], dtype=dtype) | |||
|
265 | ||||
|
266 | In [5]: %R -i datapy | |||
|
267 | ||||
|
268 | In [6]: %Rget datapy | |||
|
269 | Out[6]: | |||
|
270 | array([['1', '2', '3', '4'], | |||
|
271 | ['2', '3', '2', '5'], | |||
|
272 | ['a', 'b', 'c', 'e']], | |||
|
273 | dtype='|S1') | |||
|
274 | ||||
|
275 | In [7]: %Rget -d datapy | |||
|
276 | Out[7]: | |||
|
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')]) | |||
|
279 | ||||
|
280 | ''' | |||
|
281 | args = parse_argstring(self.Rget, line) | |||
|
282 | output = args.output | |||
|
283 | return self.Rconverter(self.r(output[0]),dataframe=args.as_dataframe) | |||
|
284 | ||||
|
285 | ||||
|
286 | @skip_doctest | |||
|
287 | @magic_arguments() | |||
|
288 | @argument( | |||
|
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.' | |||
|
291 | ) | |||
|
292 | @argument( | |||
|
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.' | |||
|
295 | ) | |||
|
296 | @argument( | |||
|
297 | '-w', '--width', type=int, | |||
|
298 | help='Width of png plotting device sent as an argument to *png* in R.' | |||
|
299 | ) | |||
|
300 | @argument( | |||
|
301 | '-h', '--height', type=int, | |||
|
302 | help='Height of png plotting device sent as an argument to *png* in R.' | |||
|
303 | ) | |||
|
304 | ||||
|
305 | @argument( | |||
|
306 | '-d', '--dataframe', action='append', | |||
|
307 | help='Convert these objects to data.frames and return as structured arrays.' | |||
|
308 | ) | |||
|
309 | @argument( | |||
|
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"].' | |||
|
312 | ) | |||
|
313 | @argument( | |||
|
314 | '-p', '--pointsize', type=int, | |||
|
315 | help='Pointsize of png plotting device sent as an argument to *png* in R.' | |||
|
316 | ) | |||
|
317 | @argument( | |||
|
318 | '-b', '--bg', | |||
|
319 | help='Background of png plotting device sent as an argument to *png* in R.' | |||
|
320 | ) | |||
|
321 | @argument( | |||
|
322 | '-n', '--noreturn', | |||
|
323 | help='Force the magic to not return anything.', | |||
|
324 | action='store_true', | |||
|
325 | default=False | |||
|
326 | ) | |||
|
327 | @argument( | |||
|
328 | 'code', | |||
|
329 | nargs='*', | |||
|
330 | ) | |||
|
331 | @line_cell_magic | |||
|
332 | def R(self, line, cell=None): | |||
|
333 | ''' | |||
|
334 | Execute code in R, and pull some of the results back into the Python namespace. | |||
|
335 | ||||
|
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 | |||
|
338 | final line. | |||
|
339 | ||||
|
340 | Multiple R lines can be executed by joining them with semicolons:: | |||
|
341 | ||||
|
342 | In [9]: %R X=c(1,4,5,7); sd(X); mean(X) | |||
|
343 | Out[9]: array([ 4.25]) | |||
|
344 | ||||
|
345 | As a cell, this will run a block of R code, without bringing anything back by default:: | |||
|
346 | ||||
|
347 | In [10]: %%R | |||
|
348 | ....: Y = c(2,4,3,9) | |||
|
349 | ....: print(summary(lm(Y~X))) | |||
|
350 | ....: | |||
|
351 | ||||
|
352 | Call: | |||
|
353 | lm(formula = Y ~ X) | |||
|
354 | ||||
|
355 | Residuals: | |||
|
356 | 1 2 3 4 | |||
|
357 | 0.88 -0.24 -2.28 1.64 | |||
|
358 | ||||
|
359 | Coefficients: | |||
|
360 | Estimate Std. Error t value Pr(>|t|) | |||
|
361 | (Intercept) 0.0800 2.3000 0.035 0.975 | |||
|
362 | X 1.0400 0.4822 2.157 0.164 | |||
|
363 | ||||
|
364 | Residual standard error: 2.088 on 2 degrees of freedom | |||
|
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 | |||
|
367 | ||||
|
368 | In the notebook, plots are published as the output of the cell. | |||
|
369 | ||||
|
370 | %R plot(X, Y) | |||
|
371 | ||||
|
372 | will create a scatter plot of X bs Y. | |||
|
373 | ||||
|
374 | If cell is not None and line has some R code, it is prepended to | |||
|
375 | the R code in cell. | |||
|
376 | ||||
|
377 | Objects can be passed back and forth between rpy2 and python via the -i -o flags in line:: | |||
|
378 | ||||
|
379 | In [14]: Z = np.array([1,4,5,10]) | |||
|
380 | ||||
|
381 | In [15]: %R -i Z mean(Z) | |||
|
382 | Out[15]: array([ 5.]) | |||
|
383 | ||||
|
384 | ||||
|
385 | In [16]: %R -o W W=Z*mean(Z) | |||
|
386 | Out[16]: array([ 5., 20., 25., 50.]) | |||
|
387 | ||||
|
388 | In [17]: W | |||
|
389 | Out[17]: array([ 5., 20., 25., 50.]) | |||
|
390 | ||||
|
391 | The return value is determined by these rules: | |||
|
392 | ||||
|
393 | * If the cell is not None, the magic returns None. | |||
|
394 | ||||
|
395 | * If the cell evaluates as False, the resulting value is returned | |||
|
396 | unless the final line prints something to the console, in | |||
|
397 | which case None is returned. | |||
|
398 | ||||
|
399 | * If the final line results in a NULL value when evaluated | |||
|
400 | by rpy2, then None is returned. | |||
|
401 | ||||
|
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. | |||
|
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 | ||||
|
410 | The --dataframe argument will attempt to return structured arrays. | |||
|
411 | This is useful for dataframes with | |||
|
412 | mixed data types. Note also that for a data.frame, | |||
|
413 | if it is returned as an ndarray, it is transposed:: | |||
|
414 | ||||
|
415 | In [18]: dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')] | |||
|
416 | ||||
|
417 | In [19]: datapy = np.array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5, 'e')], dtype=dtype) | |||
|
418 | ||||
|
419 | In [20]: %%R -o datar | |||
|
420 | datar = datapy | |||
|
421 | ....: | |||
|
422 | ||||
|
423 | In [21]: datar | |||
|
424 | Out[21]: | |||
|
425 | array([['1', '2', '3', '4'], | |||
|
426 | ['2', '3', '2', '5'], | |||
|
427 | ['a', 'b', 'c', 'e']], | |||
|
428 | dtype='|S1') | |||
|
429 | ||||
|
430 | In [22]: %%R -d datar | |||
|
431 | datar = datapy | |||
|
432 | ....: | |||
|
433 | ||||
|
434 | In [23]: datar | |||
|
435 | Out[23]: | |||
|
436 | array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5.0, 'e')], | |||
|
437 | dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')]) | |||
|
438 | ||||
|
439 | The --dataframe argument first tries colnames, then names. | |||
|
440 | If both are NULL, it returns an ndarray (i.e. unstructured):: | |||
|
441 | ||||
|
442 | In [1]: %R mydata=c(4,6,8.3); NULL | |||
|
443 | ||||
|
444 | In [2]: %R -d mydata | |||
|
445 | ||||
|
446 | In [3]: mydata | |||
|
447 | Out[3]: array([ 4. , 6. , 8.3]) | |||
|
448 | ||||
|
449 | In [4]: %R names(mydata) = c('a','b','c'); NULL | |||
|
450 | ||||
|
451 | In [5]: %R -d mydata | |||
|
452 | ||||
|
453 | In [6]: mydata | |||
|
454 | Out[6]: | |||
|
455 | array((4.0, 6.0, 8.3), | |||
|
456 | dtype=[('a', '<f8'), ('b', '<f8'), ('c', '<f8')]) | |||
|
457 | ||||
|
458 | In [7]: %R -o mydata | |||
|
459 | ||||
|
460 | In [8]: mydata | |||
|
461 | Out[8]: array([ 4. , 6. , 8.3]) | |||
|
462 | ||||
|
463 | ''' | |||
|
464 | ||||
|
465 | args = parse_argstring(self.R, line) | |||
|
466 | ||||
|
467 | # arguments 'code' in line are prepended to | |||
|
468 | # the cell lines | |||
|
469 | if not cell: | |||
|
470 | code = '' | |||
|
471 | return_output = True | |||
|
472 | line_mode = True | |||
|
473 | else: | |||
|
474 | code = cell | |||
|
475 | return_output = False | |||
|
476 | line_mode = False | |||
|
477 | ||||
|
478 | code = ' '.join(args.code) + code | |||
|
479 | ||||
|
480 | if args.input: | |||
|
481 | for input in ','.join(args.input).split(','): | |||
|
482 | self.r.assign(input, self.pyconverter(self.shell.user_ns[input])) | |||
|
483 | ||||
|
484 | png_argdict = dict([(n, getattr(args, n)) for n in ['units', 'height', 'width', 'bg', 'pointsize']]) | |||
|
485 | png_args = ','.join(['%s=%s' % (o,v) for o, v in png_argdict.items() if v is not None]) | |||
|
486 | # execute the R code in a temporary directory | |||
|
487 | ||||
|
488 | tmpd = tempfile.mkdtemp() | |||
|
489 | self.r('png("%s/Rplots%%03d.png",%s)' % (tmpd, png_args)) | |||
|
490 | ||||
|
491 | text_output = '' | |||
|
492 | if line_mode: | |||
|
493 | for line in code.split(';'): | |||
|
494 | text_result, result = self.eval(line) | |||
|
495 | text_output += text_result | |||
|
496 | if text_result: | |||
|
497 | # the last line printed something to the console so we won't return it | |||
|
498 | return_output = False | |||
|
499 | else: | |||
|
500 | text_result, result = self.eval(code) | |||
|
501 | text_output += text_result | |||
|
502 | ||||
|
503 | self.r('dev.off()') | |||
|
504 | ||||
|
505 | # read out all the saved .png files | |||
|
506 | ||||
|
507 | images = [open(imgfile, 'rb').read() for imgfile in glob("%s/Rplots*png" % tmpd)] | |||
|
508 | ||||
|
509 | # now publish the images | |||
|
510 | # mimicking IPython/zmq/pylab/backend_inline.py | |||
|
511 | fmt = 'png' | |||
|
512 | mimetypes = { 'png' : 'image/png', 'svg' : 'image/svg+xml' } | |||
|
513 | mime = mimetypes[fmt] | |||
|
514 | ||||
|
515 | # publish the printed R objects, if any | |||
|
516 | ||||
|
517 | display_data = [] | |||
|
518 | if text_output: | |||
|
519 | display_data.append(('RMagic.R', {'text/plain':text_output})) | |||
|
520 | ||||
|
521 | # flush text streams before sending figures, helps a little with output | |||
|
522 | for image in images: | |||
|
523 | # synchronization in the console (though it's a bandaid, not a real sln) | |||
|
524 | sys.stdout.flush(); sys.stderr.flush() | |||
|
525 | display_data.append(('RMagic.R', {mime: image})) | |||
|
526 | ||||
|
527 | # kill the temporary directory | |||
|
528 | rmtree(tmpd) | |||
|
529 | ||||
|
530 | # try to turn every output into a numpy array | |||
|
531 | # this means that output are assumed to be castable | |||
|
532 | # as numpy arrays | |||
|
533 | ||||
|
534 | if args.output: | |||
|
535 | for output in ','.join(args.output).split(','): | |||
|
536 | self.shell.push({output:self.Rconverter(self.r(output), dataframe=False)}) | |||
|
537 | ||||
|
538 | if args.dataframe: | |||
|
539 | for output in ','.join(args.dataframe).split(','): | |||
|
540 | self.shell.push({output:self.Rconverter(self.r(output), dataframe=True)}) | |||
|
541 | ||||
|
542 | for tag, disp_d in display_data: | |||
|
543 | publish_display_data(tag, disp_d) | |||
|
544 | ||||
|
545 | # this will keep a reference to the display_data | |||
|
546 | # which might be useful to other objects who happen to use | |||
|
547 | # this method | |||
|
548 | ||||
|
549 | if self.cache_display_data: | |||
|
550 | self.display_cache = display_data | |||
|
551 | ||||
|
552 | # if in line mode and return_output, return the result as an ndarray | |||
|
553 | if return_output and not args.noreturn: | |||
|
554 | if result != ri.NULL: | |||
|
555 | return self.Rconverter(result, dataframe=False) | |||
|
556 | ||||
|
557 | __doc__ = __doc__.format( | |||
|
558 | R_DOC = ' '*8 + RMagics.R.__doc__, | |||
|
559 | RPUSH_DOC = ' '*8 + RMagics.Rpush.__doc__, | |||
|
560 | RPULL_DOC = ' '*8 + RMagics.Rpull.__doc__, | |||
|
561 | RGET_DOC = ' '*8 + RMagics.Rget.__doc__ | |||
|
562 | ) | |||
|
563 | ||||
|
564 | ||||
|
565 | _loaded = False | |||
|
566 | def load_ipython_extension(ip): | |||
|
567 | """Load the extension in IPython.""" | |||
|
568 | global _loaded | |||
|
569 | if not _loaded: | |||
|
570 | ip.register_magics(RMagics) | |||
|
571 | _loaded = True |
@@ -0,0 +1,62 b'' | |||||
|
1 | import numpy as np | |||
|
2 | from IPython.core.interactiveshell import InteractiveShell | |||
|
3 | from IPython.extensions import rmagic | |||
|
4 | import nose.tools as nt | |||
|
5 | ||||
|
6 | ip = get_ipython() | |||
|
7 | ip.magic('load_ext rmagic') | |||
|
8 | ||||
|
9 | ||||
|
10 | def test_push(): | |||
|
11 | rm = rmagic.RMagics(ip) | |||
|
12 | ip.push({'X':np.arange(5), 'Y':np.array([3,5,4,6,7])}) | |||
|
13 | ip.run_line_magic('Rpush', 'X Y') | |||
|
14 | np.testing.assert_almost_equal(np.asarray(rm.r('X')), ip.user_ns['X']) | |||
|
15 | np.testing.assert_almost_equal(np.asarray(rm.r('Y')), ip.user_ns['Y']) | |||
|
16 | ||||
|
17 | def test_pull(): | |||
|
18 | rm = rmagic.RMagics(ip) | |||
|
19 | rm.r('Z=c(11:20)') | |||
|
20 | ip.run_line_magic('Rpull', 'Z') | |||
|
21 | np.testing.assert_almost_equal(np.asarray(rm.r('Z')), ip.user_ns['Z']) | |||
|
22 | np.testing.assert_almost_equal(ip.user_ns['Z'], np.arange(11,21)) | |||
|
23 | ||||
|
24 | def test_Rconverter(): | |||
|
25 | datapy= np.array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c')], | |||
|
26 | dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')]) | |||
|
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('Rget', '-d datapy') | |||
|
32 | w = ip.run_line_magic('Rget', '-d 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', ' -d datar datar=datapy', '') | |||
|
40 | ||||
|
41 | u = ip.run_line_magic('Rget', ' -d 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 | ||||
|
48 | ||||
|
49 | def test_cell_magic(): | |||
|
50 | ||||
|
51 | ip.push({'x':np.arange(5), 'y':np.array([3,5,4,6,7])}) | |||
|
52 | snippet = ''' | |||
|
53 | print(summary(a)) | |||
|
54 | plot(x, y, pch=23, bg='orange', cex=2) | |||
|
55 | plot(x, x) | |||
|
56 | print(summary(x)) | |||
|
57 | r = resid(a) | |||
|
58 | xc = coef(a) | |||
|
59 | ''' | |||
|
60 | ip.run_cell_magic('R', '-i x,y -o r,xc a=lm(y~x)', snippet) | |||
|
61 | np.testing.assert_almost_equal(ip.user_ns['xc'], [3.2, 0.9]) | |||
|
62 | np.testing.assert_almost_equal(ip.user_ns['r'], np.array([-0.2, 0.9, -1. , 0.1, 0.2])) |
This diff has been collapsed as it changes many lines, (874 lines changed) Show them Hide them | |||||
@@ -0,0 +1,874 b'' | |||||
|
1 | { | |||
|
2 | "metadata": { | |||
|
3 | "name": "rmagic_extension" | |||
|
4 | }, | |||
|
5 | "nbformat": 3, | |||
|
6 | "worksheets": [ | |||
|
7 | { | |||
|
8 | "cells": [ | |||
|
9 | { | |||
|
10 | "cell_type": "heading", | |||
|
11 | "level": 1, | |||
|
12 | "source": [ | |||
|
13 | "Rmagic Functions Extension" | |||
|
14 | ] | |||
|
15 | }, | |||
|
16 | { | |||
|
17 | "cell_type": "heading", | |||
|
18 | "level": 2, | |||
|
19 | "source": [ | |||
|
20 | "Line magics" | |||
|
21 | ] | |||
|
22 | }, | |||
|
23 | { | |||
|
24 | "cell_type": "markdown", | |||
|
25 | "source": [ | |||
|
26 | "IPython has an `rmagic` extension that contains a some magic functions for working with R via rpy2. This extension can be loaded using the `%load_ext` magic as follows:" | |||
|
27 | ] | |||
|
28 | }, | |||
|
29 | { | |||
|
30 | "cell_type": "code", | |||
|
31 | "collapsed": true, | |||
|
32 | "input": [ | |||
|
33 | "%load_ext rmagic", | |||
|
34 | " " | |||
|
35 | ], | |||
|
36 | "language": "python", | |||
|
37 | "outputs": [], | |||
|
38 | "prompt_number": 1 | |||
|
39 | }, | |||
|
40 | { | |||
|
41 | "cell_type": "markdown", | |||
|
42 | "source": [ | |||
|
43 | "A typical use case one imagines is having some numpy arrays, wanting to compute some statistics of interest on these", | |||
|
44 | " arrays and return the result back to python. Let's suppose we just want to fit a simple linear model to a scatterplot." | |||
|
45 | ] | |||
|
46 | }, | |||
|
47 | { | |||
|
48 | "cell_type": "code", | |||
|
49 | "collapsed": false, | |||
|
50 | "input": [ | |||
|
51 | "import numpy as np", | |||
|
52 | "import pylab", | |||
|
53 | "X = np.array([0,1,2,3,4])", | |||
|
54 | "Y = np.array([3,5,4,6,7])", | |||
|
55 | "pylab.scatter(X, Y)", | |||
|
56 | "" | |||
|
57 | ], | |||
|
58 | "language": "python", | |||
|
59 | "outputs": [ | |||
|
60 | { | |||
|
61 | "output_type": "pyout", | |||
|
62 | "prompt_number": 2, | |||
|
63 | "text": [ | |||
|
64 | "<matplotlib.collections.PathCollection at 0x10f32f610>" | |||
|
65 | ] | |||
|
66 | } | |||
|
67 | ], | |||
|
68 | "prompt_number": 2 | |||
|
69 | }, | |||
|
70 | { | |||
|
71 | "cell_type": "markdown", | |||
|
72 | "source": [ | |||
|
73 | "We can accomplish this by first pushing variables to R, fitting a model and returning the results. The line magic %Rpush copies its arguments to variables of the same name in rpy2. The %R line magic evaluates the string in rpy2 and returns the results. In this case, the coefficients of a linear model." | |||
|
74 | ] | |||
|
75 | }, | |||
|
76 | { | |||
|
77 | "cell_type": "code", | |||
|
78 | "collapsed": false, | |||
|
79 | "input": [ | |||
|
80 | "%Rpush X Y", | |||
|
81 | "%R lm(Y~X)$coef" | |||
|
82 | ], | |||
|
83 | "language": "python", | |||
|
84 | "outputs": [ | |||
|
85 | { | |||
|
86 | "output_type": "pyout", | |||
|
87 | "prompt_number": 3, | |||
|
88 | "text": [ | |||
|
89 | "array([ 3.2, 0.9])" | |||
|
90 | ] | |||
|
91 | } | |||
|
92 | ], | |||
|
93 | "prompt_number": 3 | |||
|
94 | }, | |||
|
95 | { | |||
|
96 | "cell_type": "markdown", | |||
|
97 | "source": [ | |||
|
98 | "We can check that this is correct fairly easily:" | |||
|
99 | ] | |||
|
100 | }, | |||
|
101 | { | |||
|
102 | "cell_type": "code", | |||
|
103 | "collapsed": false, | |||
|
104 | "input": [ | |||
|
105 | "Xr = X - X.mean(); Yr = Y - Y.mean()", | |||
|
106 | "slope = (Xr*Yr).sum() / (Xr**2).sum()", | |||
|
107 | "intercept = Y.mean() - X.mean() * slope", | |||
|
108 | "(intercept, slope)" | |||
|
109 | ], | |||
|
110 | "language": "python", | |||
|
111 | "outputs": [ | |||
|
112 | { | |||
|
113 | "output_type": "pyout", | |||
|
114 | "prompt_number": 4, | |||
|
115 | "text": [ | |||
|
116 | "(3.2000000000000002, 0.90000000000000002)" | |||
|
117 | ] | |||
|
118 | } | |||
|
119 | ], | |||
|
120 | "prompt_number": 4 | |||
|
121 | }, | |||
|
122 | { | |||
|
123 | "cell_type": "markdown", | |||
|
124 | "source": [ | |||
|
125 | "It is also possible to return more than one value with %R." | |||
|
126 | ] | |||
|
127 | }, | |||
|
128 | { | |||
|
129 | "cell_type": "code", | |||
|
130 | "collapsed": false, | |||
|
131 | "input": [ | |||
|
132 | "%R resid(lm(Y~X)); coef(lm(X~Y))", | |||
|
133 | "" | |||
|
134 | ], | |||
|
135 | "language": "python", | |||
|
136 | "outputs": [ | |||
|
137 | { | |||
|
138 | "output_type": "pyout", | |||
|
139 | "prompt_number": 5, | |||
|
140 | "text": [ | |||
|
141 | "array([-2.5, 0.9])" | |||
|
142 | ] | |||
|
143 | } | |||
|
144 | ], | |||
|
145 | "prompt_number": 5 | |||
|
146 | }, | |||
|
147 | { | |||
|
148 | "cell_type": "markdown", | |||
|
149 | "source": [ | |||
|
150 | "One can also easily capture the results of %R into python objects. Like R, the return value of this multiline expression (multiline in the sense that it is separated by ';') is the final value, which is ", | |||
|
151 | "the *coef(lm(X~Y))*. To pull other variables from R, there is one more magic." | |||
|
152 | ] | |||
|
153 | }, | |||
|
154 | { | |||
|
155 | "cell_type": "markdown", | |||
|
156 | "source": [ | |||
|
157 | "There are two more line magics, %Rpull and %Rget. Both are useful after some R code has been executed and there are variables", | |||
|
158 | "in the rpy2 namespace that one would like to retrieve. The main difference is that one", | |||
|
159 | " returns the value (%Rget), while the other pulls it to self.shell.user_ns (%Rpull). Imagine we've stored the results", | |||
|
160 | "of some calculation in the variable \"a\" in rpy2's namespace. By using the %R magic, we can obtain these results and", | |||
|
161 | "store them in b. We can also pull them directly to user_ns with %Rpull. They are both views on the same data." | |||
|
162 | ] | |||
|
163 | }, | |||
|
164 | { | |||
|
165 | "cell_type": "code", | |||
|
166 | "collapsed": false, | |||
|
167 | "input": [ | |||
|
168 | "b = %R a=resid(lm(Y~X))", | |||
|
169 | "%Rpull a", | |||
|
170 | "print a", | |||
|
171 | "assert id(b.data) == id(a.data)", | |||
|
172 | "%R -o a" | |||
|
173 | ], | |||
|
174 | "language": "python", | |||
|
175 | "outputs": [ | |||
|
176 | { | |||
|
177 | "output_type": "stream", | |||
|
178 | "stream": "stdout", | |||
|
179 | "text": [ | |||
|
180 | "[-0.2 0.9 -1. 0.1 0.2]", | |||
|
181 | "" | |||
|
182 | ] | |||
|
183 | } | |||
|
184 | ], | |||
|
185 | "prompt_number": 6 | |||
|
186 | }, | |||
|
187 | { | |||
|
188 | "cell_type": "markdown", | |||
|
189 | "source": [ | |||
|
190 | "%Rpull is equivalent to calling %R with just -o", | |||
|
191 | "" | |||
|
192 | ] | |||
|
193 | }, | |||
|
194 | { | |||
|
195 | "cell_type": "code", | |||
|
196 | "collapsed": false, | |||
|
197 | "input": [ | |||
|
198 | "%R d=resid(lm(Y~X)); e=coef(lm(Y~X))", | |||
|
199 | "%R -o d -o e", | |||
|
200 | "%Rpull e", | |||
|
201 | "print d", | |||
|
202 | "print e", | |||
|
203 | "import numpy as np", | |||
|
204 | "np.testing.assert_almost_equal(d, a)" | |||
|
205 | ], | |||
|
206 | "language": "python", | |||
|
207 | "outputs": [ | |||
|
208 | { | |||
|
209 | "output_type": "stream", | |||
|
210 | "stream": "stdout", | |||
|
211 | "text": [ | |||
|
212 | "[-0.2 0.9 -1. 0.1 0.2]", | |||
|
213 | "[ 3.2 0.9]", | |||
|
214 | "" | |||
|
215 | ] | |||
|
216 | } | |||
|
217 | ], | |||
|
218 | "prompt_number": 7 | |||
|
219 | }, | |||
|
220 | { | |||
|
221 | "cell_type": "markdown", | |||
|
222 | "source": [ | |||
|
223 | "On the other hand %Rpush is equivalent to calling %R with just -i and no trailing code." | |||
|
224 | ] | |||
|
225 | }, | |||
|
226 | { | |||
|
227 | "cell_type": "code", | |||
|
228 | "collapsed": false, | |||
|
229 | "input": [ | |||
|
230 | "A = np.arange(20)", | |||
|
231 | "%R -i A", | |||
|
232 | "%R mean(A)", | |||
|
233 | "" | |||
|
234 | ], | |||
|
235 | "language": "python", | |||
|
236 | "outputs": [ | |||
|
237 | { | |||
|
238 | "output_type": "pyout", | |||
|
239 | "prompt_number": 8, | |||
|
240 | "text": [ | |||
|
241 | "array([ 9.5])" | |||
|
242 | ] | |||
|
243 | } | |||
|
244 | ], | |||
|
245 | "prompt_number": 8 | |||
|
246 | }, | |||
|
247 | { | |||
|
248 | "cell_type": "markdown", | |||
|
249 | "source": [ | |||
|
250 | "The magic %Rget retrieves one variable from R." | |||
|
251 | ] | |||
|
252 | }, | |||
|
253 | { | |||
|
254 | "cell_type": "code", | |||
|
255 | "collapsed": false, | |||
|
256 | "input": [ | |||
|
257 | "%Rget A" | |||
|
258 | ], | |||
|
259 | "language": "python", | |||
|
260 | "outputs": [ | |||
|
261 | { | |||
|
262 | "output_type": "pyout", | |||
|
263 | "prompt_number": 9, | |||
|
264 | "text": [ | |||
|
265 | "array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,", | |||
|
266 | " 17, 18, 19], dtype=int32)" | |||
|
267 | ] | |||
|
268 | } | |||
|
269 | ], | |||
|
270 | "prompt_number": 9 | |||
|
271 | }, | |||
|
272 | { | |||
|
273 | "cell_type": "heading", | |||
|
274 | "level": 2, | |||
|
275 | "source": [ | |||
|
276 | "Plotting and capturing output" | |||
|
277 | ] | |||
|
278 | }, | |||
|
279 | { | |||
|
280 | "cell_type": "markdown", | |||
|
281 | "source": [ | |||
|
282 | "R's console (i.e. its stdout() connection) is captured by ipython, as are any plots which are published as PNG files like the notebook with arguments --pylab inline. As a call to %R may produce a return value (see above) we must ask what happens to a magic like the one below. The R code specifies that something is published to the notebook. If anything is published to the notebook, that call to %R returns None." | |||
|
283 | ] | |||
|
284 | }, | |||
|
285 | { | |||
|
286 | "cell_type": "code", | |||
|
287 | "collapsed": false, | |||
|
288 | "input": [ | |||
|
289 | "v1 = %R plot(X,Y); print(summary(lm(Y~X))); vv=mean(X)*mean(Y)", | |||
|
290 | "print 'v1 is:', v1", | |||
|
291 | "v2 = %R mean(X)*mean(Y)", | |||
|
292 | "print 'v2 is:', v2" | |||
|
293 | ], | |||
|
294 | "language": "python", | |||
|
295 | "outputs": [ | |||
|
296 | { | |||
|
297 | "output_type": "display_data", | |||
|
298 | "text": [ | |||
|
299 | "", | |||
|
300 | "Call:", | |||
|
301 | "lm(formula = Y ~ X)", | |||
|
302 | "", | |||
|
303 | "Residuals:", | |||
|
304 | " 1 2 3 4 5 ", | |||
|
305 | "-0.2 0.9 -1.0 0.1 0.2 ", | |||
|
306 | "", | |||
|
307 | "Coefficients:", | |||
|
308 | " Estimate Std. Error t value Pr(>|t|) ", | |||
|
309 | "(Intercept) 3.2000 0.6164 5.191 0.0139 *", | |||
|
310 | "X 0.9000 0.2517 3.576 0.0374 *", | |||
|
311 | "---", | |||
|
312 | "Signif. codes: 0 \u2018***\u2019 0.001 \u2018**\u2019 0.01 \u2018*\u2019 0.05 \u2018.\u2019 0.1 \u2018 \u2019 1 ", | |||
|
313 | "", | |||
|
314 | "Residual standard error: 0.7958 on 3 degrees of freedom", | |||
|
315 | "Multiple R-squared: 0.81,\tAdjusted R-squared: 0.7467 ", | |||
|
316 | "F-statistic: 12.79 on 1 and 3 DF, p-value: 0.03739 ", | |||
|
317 | "", | |||
|
318 | "" | |||
|
319 | ] | |||
|
320 | }, | |||
|
321 | { | |||
|
322 | "output_type": "display_data", | |||
|
323 | "png": "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\nUpK06OAUzDPgiIjOnTvHggULYtWqVTFjxoz41re+FevWrYshQ4bEQw899B9/vmvXrtG1a9f9nnv5\n5Zdj/fr1h3oyAEkGDBgQEyZMiEceeSSaNGkS8+bNi5tvvvmgnrhlKqgA/9spp5wSU6dOjalTp8aO\nHTti06ZN2ZMAKDBlZWWxYcOGOOOMM6Jr167RvHnzeO+996JFixbZ02qlIAI8YcKE6Nix437PNWvW\nLJo1a1bHiwD4NBg5cmSMHDkye8Z/pSACPHDgwOwJAFCnCuZNWABQnwgwACQQYABIIMAAkECAASCB\nAANAAgEGgAQCDAAJBBgAEggwACQQYABIIMAAkECAASCBAANAAgEGgAQCDAAJBBgAEggwACQQYABI\nIMAAkECAASCBAANAAgEGgAQCDAAJBBgAEggwACQQYABIIMAAkECAASCBAANAAgEGgAQCDAAJBBgA\nEggwACQQYABIIMAAkECAASCBAANAAgEGgAQCDAAJBBgAEggwACQQYABIIMAAkECAASCBAANAAgEG\ngAQCDAAJBBgAEggwACQQYABIIMAAkECAASCBAANAAgEGgAQCDAAJBBgAEggwACQQYABIIMAAkECA\nASCBAANAAgEGgAQCDAAJBBgAEggwACQQYABIIMAAkECAASCBAANAAgEGgAQCDAAJGmUPOJCdO3dG\nw4YNo6SkJHsKwEGprq6OGTNmxC9/+cs44ogj4rrrroszzzwzexYFpiCeAa9bty4GDx4cy5Ytiw0b\nNsTQoUOjXbt2cdRRR8WQIUNi9+7d2RMBam3w4MGxYMGCmDx5cowZMya+//3vx4svvpg9iwJTEAG+\n9dZb4/jjj4/Pf/7zcd9990VVVVWsXLky3nzzzdi+fXtMmjSpVteprq6Oqqqq/X5VV1dHTU3NYf6X\nAPXd66+/Hu+++248+eST0alTp+jevXvMmDEj7rvvvuxpFJiCuAX92muvxapVq+KII46IZ555JubN\nmxelpaURETFp0qQYMWJEra4zc+bMmDNnzn7PrV69Ok488cRDNRlgvyorK6N3794fO9ahQ4eorq5O\nWkShKogAd+3aNWbNmhXXXHNN9OzZM+bPnx+jR4+OiIgXXnghunTpUqvrDB06NIYOHbrfc2PHjo31\n69cfss0A+9O1a9e49957Y9OmTXHsscdGRMSiRYviww8/TF5GoSmIAE+bNi2+/vWvx8MPPxydO3eO\nG2+8MR555JH4zGc+E9u2bYvXXnsteyJArZxwwgkxdOjQaN26dcyePTu2bt0azz77bDz55JPZ0ygw\nBRHgk08+Od56661YsGBBrF69Oo4//vg4+uijo0uXLtG3b99o1KggZgLUSv/+/WP58uWxaNGiaNKk\nSZSXl+97Ngz/VjBla9CgQVx00UVx0UUXZU8B+J917949unfvnj2DAlYQ74IGgPpGgAEggQADQAIB\nBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBA\ngAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAk\nEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwA\nCQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQAD\nQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASPCJ\nAN90002xffv2jC3UY5WVlfHyyy/HwoUL46OPPsqeA3DYfSLA69ati9NOOy0WLVqUsWefDRs2RFVV\nVeoG6sbatWvj0ksvjddffz0qKiqiZcuWsX79+uxZAIfVJwL8+OOPxx133BFlZWUxYcKE2L1792Ef\nMXjw4Fi1alVERKxevTr69u0bHTt2jHbt2sWoUaNiz549h30DOT766KM47bTT4rvf/W5873vfiylT\npsTMmTNjwoQJsXfv3ux5AIdNo/0dHDhwYHz1q1+NG2+8Mc4666y4/PLL95079dRT49JLLz2kI1au\nXBk7duyIiIgpU6bEKaecErNnz46NGzfGuHHjYsqUKXHrrbf+x+s899xzsWDBgv2eW7RoURx77LGH\ndDf/uz//+c9x1VVXRe/evfcdGzRoUDz33HPx/vvvR8eOHRPXARw++w1wRESDBg2ipKQk1q9fHytX\nrtx3vHnz5od10EsvvRRr1qyJFi1axDHHHBOTJ0+OcePG1SrAPXr0iJNOOmm/5yorK/dFnsLRuHHj\nqKys/Nix6urqWLt2bTRp0iRpFcDht98Al5eXx/XXXx9f/vKXY8WKFdGmTZvDPmTJkiXRvn37OOec\nc2LTpk3RokWLiIhYsWJFnH766bW6Rtu2baNt27b7Pde6dWuvKRegLl26xMknnxy33357TJgwIaqq\nquIrX/lK9OzZM1q3bp09D+Cw+USAr7jiiqioqIj7778/vvnNb9bJiKuuuiqef/75mDRpUmzdujUa\nN24c5eXlcdttt8W0adOioqKiTnaQY9KkSXH99dfHxRdfHE2bNo0hQ4bE8OHDs2cBHFafCHCrVq3i\nj3/84wGfSR4O48ePj/Hjx0dExN///vfYtm1bRET06dMnbrzxxsN+25tcDRs2jGnTpmXPAKhTnwjw\ngw8+mLFjnw4dOkSHDh0iIuKcc85J3QIAh4vfhAUACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIB\nBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBA\ngAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAk\nEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwA\nCQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQAD\nQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEBRvgnTt3xrZt27JnQFFZtmxZ\nDBw4MPr06RNlZWWxadOm7ElQbxVsgOfOnRvjxo3LngFF469//WvccMMNMX78+Hj22Wdj6NChcfnl\nl8fmzZuzp0G91Ch7QEREly5dYuPGjR87tnv37qiqqoq5c+dG//79Y+bMmf/xOlu2bInKysr9ntu6\ndWvs2bPnkOyFT6O77ror7rjjjjjzzDMjIuJrX/tavPPOO/HYY4/F6NGjk9dB/VMQAZ45c2YMGTIk\nBg0aFFdffXVERMybNy+WLl0aP/jBD6JZs2a1uk5FRUXMnz9/v+d+85vfRNu2bQ/ZZvi0+fDDD6Nd\nu3YfO1ZaWhqrV69OWgT1W0EE+Pzzz49ly5bFqFGjYty4cfHAAw9E69ato3nz5nHCCSfU+jplZWVR\nVla233Njx46N9evXH6rJ8KnTo0eP+OEPfxgzZsyIiH/dZfrOd74Tc+fOTV4G9VNBBDgiomXLljFr\n1qx44okn4oILLogePXpEw4YNs2dB0Rg2bFjMnz8/evfuHf37948FCxbExIkTo1evXtnToF4qmAD/\n2+WXXx7nnXdejBw5Mrp37549B4pGw4YN47nnnouKiorYvHlzTJw4Mc4444zsWVBvFVyAI/71utTz\nzz+fPQOK0oUXXpg9AYgC/hgSABQzAQaABAIMAAkEGAASCDAAJBBgAEggwACQQIABIIEAA0ACAQaA\nBAIMAAkEGAASCDAAJBBgAEggwACQQIABIIEAA0ACAQaABAIMAAkEGAASCDAAJBBgAEggwACQQIAB\nIIEAA0ACAQaABAIMAAkEGAASCDAAJBBgAEggwACQQIABIIEAA0ACAQaABAIMAAkEGAASCDAAJBBg\nAEggwACQQIABIIEAA0ACAQaABAIMAAkEGAASCDAAJBBgAEggwACQQIABIIEAA0ACAQaABAIMAAkE\nGAASCDAAJBBgAEggwACQQIABIIEAA0ACAQaABAIMAAkEGAASCDAAJBBgAEggwACQQIABIIEAA0AC\nAQaABAIMAAkEGAASCDAAJBBgAEggwACQQIABIEGj7AGF7qWXXor3338/jjvuuOjTp0/2HACKRME+\nA967d29s27YtdcPVV18dTz31VJSUlMRdd90Vl112WVRXV6duAqA4FESA9+zZE1OmTIkhQ4bEG2+8\nEXPmzIm2bdvGUUcdFZdeemns2rWrzjeVl5fHW2+9FQ899FAMGjQofvGLX0TLli3jpz/9aZ1vAaD4\nFMQt6JtuuinefvvtOOOMM+KKK66IRo0axdy5c6O0tDTGjh0b8+bNiyuuuOI/Xmf27Nnx9NNP7/fc\nm2++GaWlpbXetHz58rjnnns+dmz48OHx+OOP1/oaAHAgBRHg+fPnx7Jly6Jly5bRpEmT+OCDD+LL\nX/5yRERMnjw5Jk6cWKsAX3bZZXHJJZfs99yTTz4ZO3bsqPWmli1bxurVq+P888/fd+z3v/99tGzZ\nstbXAIADKYgAn3TSSbFq1ao4++yz45prrom//e1v+86tWLEiOnfuXKvrNG7cOBo3brzfcy1btoy9\ne/fWetOwYcOirKws2rVrF2effXYsWrQoRowYEZWVlbW+BgAcSEEEeNy4cdGvX7/48Y9/HP369Yv2\n7dtHRMQtt9wSjzzySCxcuLDON7Vp0ybmzZsXN910U8yaNSvatGkT69ati1atWtX5FgCKT0EE+KKL\n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\nrkJggg==\n" | |||
|
324 | }, | |||
|
325 | { | |||
|
326 | "output_type": "stream", | |||
|
327 | "stream": "stdout", | |||
|
328 | "text": [ | |||
|
329 | "v1 is: [ 10.]", | |||
|
330 | "v2 is: [ 10.]", | |||
|
331 | "" | |||
|
332 | ] | |||
|
333 | } | |||
|
334 | ], | |||
|
335 | "prompt_number": 10 | |||
|
336 | }, | |||
|
337 | { | |||
|
338 | "cell_type": "heading", | |||
|
339 | "level": 2, | |||
|
340 | "source": [ | |||
|
341 | "What value is returned from %R?" | |||
|
342 | ] | |||
|
343 | }, | |||
|
344 | { | |||
|
345 | "cell_type": "markdown", | |||
|
346 | "source": [ | |||
|
347 | "Some calls have no particularly interesting return value, the magic %R will not return anything in this case. The return value in rpy2 is actually NULL so %R returns None." | |||
|
348 | ] | |||
|
349 | }, | |||
|
350 | { | |||
|
351 | "cell_type": "code", | |||
|
352 | "collapsed": false, | |||
|
353 | "input": [ | |||
|
354 | "v = %R plot(X,Y)", | |||
|
355 | "assert v == None" | |||
|
356 | ], | |||
|
357 | "language": "python", | |||
|
358 | "outputs": [ | |||
|
359 | { | |||
|
360 | "output_type": "display_data", | |||
|
361 | "png": "iVBORw0KGgoAAAANSUhEUgAAAeAAAAHgCAYAAAB91L6VAAAD8GlDQ1BJQ0MgUHJvZmlsZQAAKJGN\nVd1v21QUP4lvXKQWP6Cxjg4Vi69VU1u5GxqtxgZJk6XpQhq5zdgqpMl1bhpT1za2021Vn/YCbwz4\nA4CyBx6QeEIaDMT2su0BtElTQRXVJKQ9dNpAaJP2gqpwrq9Tu13GuJGvfznndz7v0TVAx1ea45hJ\nGWDe8l01n5GPn5iWO1YhCc9BJ/RAp6Z7TrpcLgIuxoVH1sNfIcHeNwfa6/9zdVappwMknkJsVz19\nHvFpgJSpO64PIN5G+fAp30Hc8TziHS4miFhheJbjLMMzHB8POFPqKGKWi6TXtSriJcT9MzH5bAzz\nHIK1I08t6hq6zHpRdu2aYdJYuk9Q/881bzZa8Xrx6fLmJo/iu4/VXnfH1BB/rmu5ScQvI77m+Bkm\nfxXxvcZcJY14L0DymZp7pML5yTcW61PvIN6JuGr4halQvmjNlCa4bXJ5zj6qhpxrujeKPYMXEd+q\n00KR5yNAlWZzrF+Ie+uNsdC/MO4tTOZafhbroyXuR3Df08bLiHsQf+ja6gTPWVimZl7l/oUrjl8O\ncxDWLbNU5D6JRL2gxkDu16fGuC054OMhclsyXTOOFEL+kmMGs4i5kfNuQ62EnBuam8tzP+Q+tSqh\nz9SuqpZlvR1EfBiOJTSgYMMM7jpYsAEyqJCHDL4dcFFTAwNMlFDUUpQYiadhDmXteeWAw3HEmA2s\n15k1RmnP4RHuhBybdBOF7MfnICmSQ2SYjIBM3iRvkcMki9IRcnDTthyLz2Ld2fTzPjTQK+Mdg8y5\nnkZfFO+se9LQr3/09xZr+5GcaSufeAfAww60mAPx+q8u/bAr8rFCLrx7s+vqEkw8qb+p26n11Aru\nq6m1iJH6PbWGv1VIY25mkNE8PkaQhxfLIF7DZXx80HD/A3l2jLclYs061xNpWCfoB6WHJTjbH0mV\n35Q/lRXlC+W8cndbl9t2SfhU+Fb4UfhO+F74GWThknBZ+Em4InwjXIyd1ePnY/Psg3pb1TJNu15T\nMKWMtFt6ScpKL0ivSMXIn9QtDUlj0h7U7N48t3i8eC0GnMC91dX2sTivgloDTgUVeEGHLTizbf5D\na9JLhkhh29QOs1luMcScmBXTIIt7xRFxSBxnuJWfuAd1I7jntkyd/pgKaIwVr3MgmDo2q8x6IdB5\nQH162mcX7ajtnHGN2bov71OU1+U0fqqoXLD0wX5ZM005UHmySz3qLtDqILDvIL+iH6jB9y2x83ok\n898GOPQX3lk3Itl0A+BrD6D7tUjWh3fis58BXDigN9yF8M5PJH4B8Gr79/F/XRm8m241mw/wvur4\nBGDj42bzn+Vmc+NL9L8GcMn8F1kAcXjEKMJAAAAYFklEQVR4nO3de5DVBf3/8TfBKne8MICwqCiQ\nVkg6KuqYETZCkgPYqqGEBSIwgnJRGo0cRxgxw3FGhVJRErLFC4o3GoVNE4JKMhJSoCSlMkZuC0hy\nWXZ/fzQx40/4thTs+3j28ZjZP/bzmf2cFzPMPOd8zjm7DWpqamoCAKhTn8keAAD1kQADQAIBBoAE\nAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEg\ngQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAA\nSCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQY\nABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEgQaPsAXXp\nqaeeiqqqquwZABSINm3aRK9evVIeu0FNTU1NyiPXsblz58bdd98dV199dfYUAArEvffeG4899lh8\n8YtfrPPHrjfPgKuqqmLw4MExfPjw7CkAFIg1a9ZEdXV1ymN7DRgAEggwACQQYABIIMAAkECAASCB\nAANAAgEGgAT15nPAABSnt956K7Zu3Rqf/exn45hjjsmeU2sF8Qz4/fffj71792bPAOBTpKamJm69\n9daYNGlSzJ07N0pLS2Pp0qXZs2qtIALct2/fuOCCC2Lt2rXZUwD4lJg8eXLs2LEjysvLY+rUqfHG\nG2/EDTfcEO+99172tFopmFvQ3bp1i/POOy8mTJgQQ4cOjVatWh30NV577bX49a9/vd9zixYtijZt\n2sSIESP+16kAFIBly5bFjBkz9n1/yimnxJAhQ+JXv/pVnHDCCYnLaqcgngFHRAwbNiwWL14cP//5\nz6O0tDRGjBgRixcvjm3bttX6Gu3atYtu3brt96thw4axYcOGw/gvAKAuNW/ePHbu3PmxY5WVlVFS\nUpK06OAUzDPgiIjOnTvHggULYtWqVTFjxoz41re+FevWrYshQ4bEQw899B9/vmvXrtG1a9f9nnv5\n5Zdj/fr1h3oyAEkGDBgQEyZMiEceeSSaNGkS8+bNi5tvvvmgnrhlKqgA/9spp5wSU6dOjalTp8aO\nHTti06ZN2ZMAKDBlZWWxYcOGOOOMM6Jr167RvHnzeO+996JFixbZ02qlIAI8YcKE6Nix437PNWvW\nLJo1a1bHiwD4NBg5cmSMHDkye8Z/pSACPHDgwOwJAFCnCuZNWABQnwgwACQQYABIIMAAkECAASCB\nAANAAgEGgAQCDAAJBBgAEggwACQQYABIIMAAkECAASCBAANAAgEGgAQCDAAJBBgAEggwACQQYABI\nIMAAkECAASCBAANAAgEGgAQCDAAJBBgAEggwACQQYABIIMAAkECAASCBAANAAgEGgAQCDAAJBBgA\nEggwACQQYABIIMAAkECAASCBAANAAgEGgAQCDAAJBBgAEggwACQQYABIIMAAkECAASCBAANAAgEG\ngAQCDAAJBBgAEggwACQQYABIIMAAkECAASCBAANAAgEGgAQCDAAJBBgAEggwACQQYABIIMAAkECA\nASCBAANAAgEGgAQCDAAJBBgAEggwACQQYABIIMAAkECAASCBAANAAgEGgAQCDAAJGmUPOJCdO3dG\nw4YNo6SkJHsKwEGprq6OGTNmxC9/+cs44ogj4rrrroszzzwzexYFpiCeAa9bty4GDx4cy5Ytiw0b\nNsTQoUOjXbt2cdRRR8WQIUNi9+7d2RMBam3w4MGxYMGCmDx5cowZMya+//3vx4svvpg9iwJTEAG+\n9dZb4/jjj4/Pf/7zcd9990VVVVWsXLky3nzzzdi+fXtMmjSpVteprq6Oqqqq/X5VV1dHTU3NYf6X\nAPXd66+/Hu+++248+eST0alTp+jevXvMmDEj7rvvvuxpFJiCuAX92muvxapVq+KII46IZ555JubN\nmxelpaURETFp0qQYMWJEra4zc+bMmDNnzn7PrV69Ok488cRDNRlgvyorK6N3794fO9ahQ4eorq5O\nWkShKogAd+3aNWbNmhXXXHNN9OzZM+bPnx+jR4+OiIgXXnghunTpUqvrDB06NIYOHbrfc2PHjo31\n69cfss0A+9O1a9e49957Y9OmTXHsscdGRMSiRYviww8/TF5GoSmIAE+bNi2+/vWvx8MPPxydO3eO\nG2+8MR555JH4zGc+E9u2bYvXXnsteyJArZxwwgkxdOjQaN26dcyePTu2bt0azz77bDz55JPZ0ygw\nBRHgk08+Od56661YsGBBrF69Oo4//vg4+uijo0uXLtG3b99o1KggZgLUSv/+/WP58uWxaNGiaNKk\nSZSXl+97Ngz/VjBla9CgQVx00UVx0UUXZU8B+J917949unfvnj2DAlYQ74IGgPpGgAEggQADQAIB\nBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBA\ngAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAk\nEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwA\nCQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQAD\nQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASPCJ\nAN90002xffv2jC3UY5WVlfHyyy/HwoUL46OPPsqeA3DYfSLA69ati9NOOy0WLVqUsWefDRs2RFVV\nVeoG6sbatWvj0ksvjddffz0qKiqiZcuWsX79+uxZAIfVJwL8+OOPxx133BFlZWUxYcKE2L1792Ef\nMXjw4Fi1alVERKxevTr69u0bHTt2jHbt2sWoUaNiz549h30DOT766KM47bTT4rvf/W5873vfiylT\npsTMmTNjwoQJsXfv3ux5AIdNo/0dHDhwYHz1q1+NG2+8Mc4666y4/PLL95079dRT49JLLz2kI1au\nXBk7duyIiIgpU6bEKaecErNnz46NGzfGuHHjYsqUKXHrrbf+x+s899xzsWDBgv2eW7RoURx77LGH\ndDf/uz//+c9x1VVXRe/evfcdGzRoUDz33HPx/vvvR8eOHRPXARw++w1wRESDBg2ipKQk1q9fHytX\nrtx3vHnz5od10EsvvRRr1qyJFi1axDHHHBOTJ0+OcePG1SrAPXr0iJNOOmm/5yorK/dFnsLRuHHj\nqKys/Nix6urqWLt2bTRp0iRpFcDht98Al5eXx/XXXx9f/vKXY8WKFdGmTZvDPmTJkiXRvn37OOec\nc2LTpk3RokWLiIhYsWJFnH766bW6Rtu2baNt27b7Pde6dWuvKRegLl26xMknnxy33357TJgwIaqq\nquIrX/lK9OzZM1q3bp09D+Cw+USAr7jiiqioqIj7778/vvnNb9bJiKuuuiqef/75mDRpUmzdujUa\nN24c5eXlcdttt8W0adOioqKiTnaQY9KkSXH99dfHxRdfHE2bNo0hQ4bE8OHDs2cBHFafCHCrVq3i\nj3/84wGfSR4O48ePj/Hjx0dExN///vfYtm1bRET06dMnbrzxxsN+25tcDRs2jGnTpmXPAKhTnwjw\ngw8+mLFjnw4dOkSHDh0iIuKcc85J3QIAh4vfhAUACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIB\nBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBA\ngAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAk\nEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwA\nCQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQAD\nQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEBRvgnTt3xrZt27JnQFFZtmxZ\nDBw4MPr06RNlZWWxadOm7ElQbxVsgOfOnRvjxo3LngFF469//WvccMMNMX78+Hj22Wdj6NChcfnl\nl8fmzZuzp0G91Ch7QEREly5dYuPGjR87tnv37qiqqoq5c+dG//79Y+bMmf/xOlu2bInKysr9ntu6\ndWvs2bPnkOyFT6O77ror7rjjjjjzzDMjIuJrX/tavPPOO/HYY4/F6NGjk9dB/VMQAZ45c2YMGTIk\nBg0aFFdffXVERMybNy+WLl0aP/jBD6JZs2a1uk5FRUXMnz9/v+d+85vfRNu2bQ/ZZvi0+fDDD6Nd\nu3YfO1ZaWhqrV69OWgT1W0EE+Pzzz49ly5bFqFGjYty4cfHAAw9E69ato3nz5nHCCSfU+jplZWVR\nVla233Njx46N9evXH6rJ8KnTo0eP+OEPfxgzZsyIiH/dZfrOd74Tc+fOTV4G9VNBBDgiomXLljFr\n1qx44okn4oILLogePXpEw4YNs2dB0Rg2bFjMnz8/evfuHf37948FCxbExIkTo1evXtnToF4qmAD/\n2+WXXx7nnXdejBw5Mrp37549B4pGw4YN47nnnouKiorYvHlzTJw4Mc4444zsWVBvFVyAI/71utTz\nzz+fPQOK0oUXXpg9AYgC/hgSABQzAQaABAIMAAkEGAASCDAAJBBgAEggwACQQIABIIEAA0ACAQaA\nBAIMAAkEGAASCDAAJBBgAEggwACQQIABIIEAA0ACAQaABAIMAAkEGAASCDAAJBBgAEggwACQQIAB\nIIEAA0ACAQaABAIMAAkEGAASCDAAJBBgAEggwACQQIABIIEAA0ACAQaABAIMAAkEGAASCDAAJBBg\nAEggwACQQIABIIEAA0ACAQaABAIMAAkEGAASCDAAJBBgAEggwACQQIABIIEAA0ACAQaABAIMAAkE\nGAASCDAAJBBgAEggwACQQIABIIEAA0ACAQaABAIMAAkEGAASCDAAJBBgAEggwACQQIABIIEAA0AC\nAQaABAIMAAkEGAASCDAAJBBgAEggwACQQIABIEGj7AGF7qWXXor3338/jjvuuOjTp0/2HACKRME+\nA967d29s27YtdcPVV18dTz31VJSUlMRdd90Vl112WVRXV6duAqA4FESA9+zZE1OmTIkhQ4bEG2+8\nEXPmzIm2bdvGUUcdFZdeemns2rWrzjeVl5fHW2+9FQ899FAMGjQofvGLX0TLli3jpz/9aZ1vAaD4\nFMQt6JtuuinefvvtOOOMM+KKK66IRo0axdy5c6O0tDTGjh0b8+bNiyuuuOI/Xmf27Nnx9NNP7/fc\nm2++GaWlpbXetHz58rjnnns+dmz48OHx+OOP1/oaAHAgBRHg+fPnx7Jly6Jly5bRpEmT+OCDD+LL\nX/5yRERMnjw5Jk6cWKsAX3bZZXHJJZfs99yTTz4ZO3bsqPWmli1bxurVq+P888/fd+z3v/99tGzZ\nstbXAIADKYgAn3TSSbFq1ao4++yz45prrom//e1v+86tWLEiOnfuXKvrNG7cOBo3brzfcy1btoy9\ne/fWetOwYcOirKws2rVrF2effXYsWrQoRowYEZWVlbW+BgAcSEEEeNy4cdGvX7/48Y9/HP369Yv2\n7dtHRMQtt9wSjzzySCxcuLDON7Vp0ybmzZsXN910U8yaNSvatGkT69ati1atWtX5FgCKT0EE+KKL\n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\nrkJggg==\n" | |||
|
362 | } | |||
|
363 | ], | |||
|
364 | "prompt_number": 11 | |||
|
365 | }, | |||
|
366 | { | |||
|
367 | "cell_type": "markdown", | |||
|
368 | "source": [ | |||
|
369 | "Also, if the return value of a call to %R (in line mode) has just been printed to the console, then its value is also not returned." | |||
|
370 | ] | |||
|
371 | }, | |||
|
372 | { | |||
|
373 | "cell_type": "code", | |||
|
374 | "collapsed": false, | |||
|
375 | "input": [ | |||
|
376 | "v = %R print(X)", | |||
|
377 | "assert v == None" | |||
|
378 | ], | |||
|
379 | "language": "python", | |||
|
380 | "outputs": [ | |||
|
381 | { | |||
|
382 | "output_type": "display_data", | |||
|
383 | "text": [ | |||
|
384 | "[1] 0 1 2 3 4", | |||
|
385 | "" | |||
|
386 | ] | |||
|
387 | } | |||
|
388 | ], | |||
|
389 | "prompt_number": 12 | |||
|
390 | }, | |||
|
391 | { | |||
|
392 | "cell_type": "markdown", | |||
|
393 | "source": [ | |||
|
394 | "But, if the last value did not print anything to console, the value is returned:", | |||
|
395 | "" | |||
|
396 | ] | |||
|
397 | }, | |||
|
398 | { | |||
|
399 | "cell_type": "code", | |||
|
400 | "collapsed": false, | |||
|
401 | "input": [ | |||
|
402 | "v = %R print(summary(X)); X", | |||
|
403 | "print 'v:', v" | |||
|
404 | ], | |||
|
405 | "language": "python", | |||
|
406 | "outputs": [ | |||
|
407 | { | |||
|
408 | "output_type": "display_data", | |||
|
409 | "text": [ | |||
|
410 | " Min. 1st Qu. Median Mean 3rd Qu. Max. ", | |||
|
411 | " 0 1 2 2 3 4 ", | |||
|
412 | "" | |||
|
413 | ] | |||
|
414 | }, | |||
|
415 | { | |||
|
416 | "output_type": "stream", | |||
|
417 | "stream": "stdout", | |||
|
418 | "text": [ | |||
|
419 | "v: [0 1 2 3 4]", | |||
|
420 | "" | |||
|
421 | ] | |||
|
422 | } | |||
|
423 | ], | |||
|
424 | "prompt_number": 13 | |||
|
425 | }, | |||
|
426 | { | |||
|
427 | "cell_type": "markdown", | |||
|
428 | "source": [ | |||
|
429 | "The return value can be suppressed by a trailing ';' or an -n argument.", | |||
|
430 | "" | |||
|
431 | ] | |||
|
432 | }, | |||
|
433 | { | |||
|
434 | "cell_type": "code", | |||
|
435 | "collapsed": true, | |||
|
436 | "input": [ | |||
|
437 | "%R -n X" | |||
|
438 | ], | |||
|
439 | "language": "python", | |||
|
440 | "outputs": [], | |||
|
441 | "prompt_number": 14 | |||
|
442 | }, | |||
|
443 | { | |||
|
444 | "cell_type": "code", | |||
|
445 | "collapsed": true, | |||
|
446 | "input": [ | |||
|
447 | "%R X; " | |||
|
448 | ], | |||
|
449 | "language": "python", | |||
|
450 | "outputs": [], | |||
|
451 | "prompt_number": 15 | |||
|
452 | }, | |||
|
453 | { | |||
|
454 | "cell_type": "heading", | |||
|
455 | "level": 2, | |||
|
456 | "source": [ | |||
|
457 | "Cell level magic" | |||
|
458 | ] | |||
|
459 | }, | |||
|
460 | { | |||
|
461 | "cell_type": "markdown", | |||
|
462 | "source": [ | |||
|
463 | "Often, we will want to do more than a simple linear regression model. There may be several lines of R code that we want to ", | |||
|
464 | "use before returning to python. This is the cell-level magic.", | |||
|
465 | "", | |||
|
466 | "", | |||
|
467 | "For the cell level magic, inputs can be passed via the -i or --inputs argument in the line. These variables are copied ", | |||
|
468 | "from the shell namespace to R's namespace using rpy2.robjects.r.assign. It would be nice not to have to copy these into R: rnumpy ( http://bitbucket.org/njs/rnumpy/wiki/API ) has done some work to limit or at least make transparent the number of copies of an array. This seems like a natural thing to try to build on. Arrays can be output from R via the -o or --outputs argument in the line. All other arguments are sent to R's png function, which is the graphics device used to create the plots.", | |||
|
469 | "", | |||
|
470 | "We can redo the above calculations in one ipython cell. We might also want to add some output such as a summary", | |||
|
471 | " from R or perhaps the standard plotting diagnostics of the lm." | |||
|
472 | ] | |||
|
473 | }, | |||
|
474 | { | |||
|
475 | "cell_type": "code", | |||
|
476 | "collapsed": false, | |||
|
477 | "input": [ | |||
|
478 | "%%R -i X,Y -o XYcoef", | |||
|
479 | "XYlm = lm(Y~X)", | |||
|
480 | "XYcoef = coef(XYlm)", | |||
|
481 | "print(summary(XYlm))", | |||
|
482 | "par(mfrow=c(2,2))", | |||
|
483 | "plot(XYlm)" | |||
|
484 | ], | |||
|
485 | "language": "python", | |||
|
486 | "outputs": [ | |||
|
487 | { | |||
|
488 | "output_type": "display_data", | |||
|
489 | "text": [ | |||
|
490 | "", | |||
|
491 | "Call:", | |||
|
492 | "lm(formula = Y ~ X)", | |||
|
493 | "", | |||
|
494 | "Residuals:", | |||
|
495 | " 1 2 3 4 5 ", | |||
|
496 | "-0.2 0.9 -1.0 0.1 0.2 ", | |||
|
497 | "", | |||
|
498 | "Coefficients:", | |||
|
499 | " Estimate Std. Error t value Pr(>|t|) ", | |||
|
500 | "(Intercept) 3.2000 0.6164 5.191 0.0139 *", | |||
|
501 | "X 0.9000 0.2517 3.576 0.0374 *", | |||
|
502 | "---", | |||
|
503 | "Signif. codes: 0 \u2018***\u2019 0.001 \u2018**\u2019 0.01 \u2018*\u2019 0.05 \u2018.\u2019 0.1 \u2018 \u2019 1 ", | |||
|
504 | "", | |||
|
505 | "Residual standard error: 0.7958 on 3 degrees of freedom", | |||
|
506 | "Multiple R-squared: 0.81,\tAdjusted R-squared: 0.7467 ", | |||
|
507 | "F-statistic: 12.79 on 1 and 3 DF, p-value: 0.03739 ", | |||
|
508 | "", | |||
|
509 | "" | |||
|
510 | ] | |||
|
511 | }, | |||
|
512 | { | |||
|
513 | "output_type": "display_data", | |||
|
514 | "png": "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\n" | |||
|
515 | } | |||
|
516 | ], | |||
|
517 | "prompt_number": 16 | |||
|
518 | }, | |||
|
519 | { | |||
|
520 | "cell_type": "heading", | |||
|
521 | "level": 2, | |||
|
522 | "source": [ | |||
|
523 | "Passing data back and forth" | |||
|
524 | ] | |||
|
525 | }, | |||
|
526 | { | |||
|
527 | "cell_type": "markdown", | |||
|
528 | "source": [ | |||
|
529 | "Currently, data is passed through RMagics.pyconverter when going from python to R and RMagics.Rconverter when ", | |||
|
530 | "going from R to python. These currently default to numpy.ndarray. Future work will involve writing better converters, most likely involving integration with http://pandas.sourceforge.net.", | |||
|
531 | "", | |||
|
532 | "Passing ndarrays into R seems to require a copy, though once an object is returned to python, this object is NOT copied, and it is possible to change its values.", | |||
|
533 | "" | |||
|
534 | ] | |||
|
535 | }, | |||
|
536 | { | |||
|
537 | "cell_type": "code", | |||
|
538 | "collapsed": true, | |||
|
539 | "input": [ | |||
|
540 | "seq1 = np.arange(10)" | |||
|
541 | ], | |||
|
542 | "language": "python", | |||
|
543 | "outputs": [], | |||
|
544 | "prompt_number": 17 | |||
|
545 | }, | |||
|
546 | { | |||
|
547 | "cell_type": "code", | |||
|
548 | "collapsed": false, | |||
|
549 | "input": [ | |||
|
550 | "%%R -i seq1 -o seq2", | |||
|
551 | "seq2 = rep(seq1, 2)", | |||
|
552 | "print(seq2)" | |||
|
553 | ], | |||
|
554 | "language": "python", | |||
|
555 | "outputs": [ | |||
|
556 | { | |||
|
557 | "output_type": "display_data", | |||
|
558 | "text": [ | |||
|
559 | " [1] 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9", | |||
|
560 | "" | |||
|
561 | ] | |||
|
562 | } | |||
|
563 | ], | |||
|
564 | "prompt_number": 18 | |||
|
565 | }, | |||
|
566 | { | |||
|
567 | "cell_type": "code", | |||
|
568 | "collapsed": false, | |||
|
569 | "input": [ | |||
|
570 | "seq2[::2] = 0", | |||
|
571 | "seq2" | |||
|
572 | ], | |||
|
573 | "language": "python", | |||
|
574 | "outputs": [ | |||
|
575 | { | |||
|
576 | "output_type": "pyout", | |||
|
577 | "prompt_number": 19, | |||
|
578 | "text": [ | |||
|
579 | "array([0, 1, 0, 3, 0, 5, 0, 7, 0, 9, 0, 1, 0, 3, 0, 5, 0, 7, 0, 9], dtype=int32)" | |||
|
580 | ] | |||
|
581 | } | |||
|
582 | ], | |||
|
583 | "prompt_number": 19 | |||
|
584 | }, | |||
|
585 | { | |||
|
586 | "cell_type": "code", | |||
|
587 | "collapsed": false, | |||
|
588 | "input": [ | |||
|
589 | "%%R", | |||
|
590 | "print(seq2)" | |||
|
591 | ], | |||
|
592 | "language": "python", | |||
|
593 | "outputs": [ | |||
|
594 | { | |||
|
595 | "output_type": "display_data", | |||
|
596 | "text": [ | |||
|
597 | " [1] 0 1 0 3 0 5 0 7 0 9 0 1 0 3 0 5 0 7 0 9", | |||
|
598 | "" | |||
|
599 | ] | |||
|
600 | } | |||
|
601 | ], | |||
|
602 | "prompt_number": 20 | |||
|
603 | }, | |||
|
604 | { | |||
|
605 | "cell_type": "markdown", | |||
|
606 | "source": [ | |||
|
607 | "Once the array data has been passed to R, modifring its contents does not modify R's copy of the data." | |||
|
608 | ] | |||
|
609 | }, | |||
|
610 | { | |||
|
611 | "cell_type": "code", | |||
|
612 | "collapsed": false, | |||
|
613 | "input": [ | |||
|
614 | "seq1[0] = 200", | |||
|
615 | "%R print(seq1)" | |||
|
616 | ], | |||
|
617 | "language": "python", | |||
|
618 | "outputs": [ | |||
|
619 | { | |||
|
620 | "output_type": "display_data", | |||
|
621 | "text": [ | |||
|
622 | " [1] 0 1 2 3 4 5 6 7 8 9", | |||
|
623 | "" | |||
|
624 | ] | |||
|
625 | } | |||
|
626 | ], | |||
|
627 | "prompt_number": 21 | |||
|
628 | }, | |||
|
629 | { | |||
|
630 | "cell_type": "markdown", | |||
|
631 | "source": [ | |||
|
632 | "But, if we pass data as both input and output, then the value of \"data\" in user_ns will be overwritten and the", | |||
|
633 | "new array will be a view of the data in R's copy." | |||
|
634 | ] | |||
|
635 | }, | |||
|
636 | { | |||
|
637 | "cell_type": "code", | |||
|
638 | "collapsed": false, | |||
|
639 | "input": [ | |||
|
640 | "print seq1", | |||
|
641 | "%R -i seq1 -o seq1", | |||
|
642 | "print seq1", | |||
|
643 | "seq1[0] = 200", | |||
|
644 | "%R print(seq1)", | |||
|
645 | "seq1_view = %R seq1", | |||
|
646 | "assert(id(seq1_view.data) == id(seq1.data))" | |||
|
647 | ], | |||
|
648 | "language": "python", | |||
|
649 | "outputs": [ | |||
|
650 | { | |||
|
651 | "output_type": "stream", | |||
|
652 | "stream": "stdout", | |||
|
653 | "text": [ | |||
|
654 | "[200 1 2 3 4 5 6 7 8 9]", | |||
|
655 | "[200 1 2 3 4 5 6 7 8 9]", | |||
|
656 | "" | |||
|
657 | ] | |||
|
658 | }, | |||
|
659 | { | |||
|
660 | "output_type": "display_data", | |||
|
661 | "text": [ | |||
|
662 | " [1] 200 1 2 3 4 5 6 7 8 9", | |||
|
663 | "" | |||
|
664 | ] | |||
|
665 | } | |||
|
666 | ], | |||
|
667 | "prompt_number": 22 | |||
|
668 | }, | |||
|
669 | { | |||
|
670 | "cell_type": "heading", | |||
|
671 | "level": 2, | |||
|
672 | "source": [ | |||
|
673 | "Exception handling", | |||
|
674 | "" | |||
|
675 | ] | |||
|
676 | }, | |||
|
677 | { | |||
|
678 | "cell_type": "markdown", | |||
|
679 | "source": [ | |||
|
680 | "Exceptions are handled by passing back rpy2's exception and the line that triggered it." | |||
|
681 | ] | |||
|
682 | }, | |||
|
683 | { | |||
|
684 | "cell_type": "code", | |||
|
685 | "collapsed": false, | |||
|
686 | "input": [ | |||
|
687 | "try:", | |||
|
688 | " %R -n nosuchvar", | |||
|
689 | "except Exception as e:", | |||
|
690 | " print e.message", | |||
|
691 | " pass" | |||
|
692 | ], | |||
|
693 | "language": "python", | |||
|
694 | "outputs": [ | |||
|
695 | { | |||
|
696 | "output_type": "stream", | |||
|
697 | "stream": "stdout", | |||
|
698 | "text": [ | |||
|
699 | "parsing and evaluating line \"nosuchvar\".", | |||
|
700 | "R error message: \"Error in eval(expr, envir, enclos) : object 'nosuchvar' not found", | |||
|
701 | "\"", | |||
|
702 | " R stdout:\"Error in eval(expr, envir, enclos) : object 'nosuchvar' not found", | |||
|
703 | "\"", | |||
|
704 | "", | |||
|
705 | "" | |||
|
706 | ] | |||
|
707 | } | |||
|
708 | ], | |||
|
709 | "prompt_number": 23 | |||
|
710 | }, | |||
|
711 | { | |||
|
712 | "cell_type": "heading", | |||
|
713 | "level": 2, | |||
|
714 | "source": [ | |||
|
715 | "Structured arrays and data frames", | |||
|
716 | "" | |||
|
717 | ] | |||
|
718 | }, | |||
|
719 | { | |||
|
720 | "cell_type": "markdown", | |||
|
721 | "source": [ | |||
|
722 | "In R, data frames play an important role as they allow array-like objects of mixed type with column names (and row names). In bumpy, the closest analogy is a structured array with named fields. In future work, it would be nice to use pandas to return full-fledged DataFrames from rpy2. In the mean time, structured arrays can be passed back and forth with the -d flag to %R, %Rpull, and %Rget" | |||
|
723 | ] | |||
|
724 | }, | |||
|
725 | { | |||
|
726 | "cell_type": "code", | |||
|
727 | "collapsed": true, | |||
|
728 | "input": [ | |||
|
729 | "datapy= np.array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c')],", | |||
|
730 | " dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')])", | |||
|
731 | "" | |||
|
732 | ], | |||
|
733 | "language": "python", | |||
|
734 | "outputs": [], | |||
|
735 | "prompt_number": 24 | |||
|
736 | }, | |||
|
737 | { | |||
|
738 | "cell_type": "code", | |||
|
739 | "collapsed": true, | |||
|
740 | "input": [ | |||
|
741 | "%%R -i datapy -d datar", | |||
|
742 | "datar = datapy" | |||
|
743 | ], | |||
|
744 | "language": "python", | |||
|
745 | "outputs": [], | |||
|
746 | "prompt_number": 25 | |||
|
747 | }, | |||
|
748 | { | |||
|
749 | "cell_type": "code", | |||
|
750 | "collapsed": false, | |||
|
751 | "input": [ | |||
|
752 | "datar" | |||
|
753 | ], | |||
|
754 | "language": "python", | |||
|
755 | "outputs": [ | |||
|
756 | { | |||
|
757 | "output_type": "pyout", | |||
|
758 | "prompt_number": 26, | |||
|
759 | "text": [ | |||
|
760 | "array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c')], ", | |||
|
761 | " dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')])" | |||
|
762 | ] | |||
|
763 | } | |||
|
764 | ], | |||
|
765 | "prompt_number": 26 | |||
|
766 | }, | |||
|
767 | { | |||
|
768 | "cell_type": "code", | |||
|
769 | "collapsed": false, | |||
|
770 | "input": [ | |||
|
771 | "%R datar2 = datapy", | |||
|
772 | "%Rpull -d datar2", | |||
|
773 | "datar2" | |||
|
774 | ], | |||
|
775 | "language": "python", | |||
|
776 | "outputs": [ | |||
|
777 | { | |||
|
778 | "output_type": "pyout", | |||
|
779 | "prompt_number": 27, | |||
|
780 | "text": [ | |||
|
781 | "array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c')], ", | |||
|
782 | " dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')])" | |||
|
783 | ] | |||
|
784 | } | |||
|
785 | ], | |||
|
786 | "prompt_number": 27 | |||
|
787 | }, | |||
|
788 | { | |||
|
789 | "cell_type": "code", | |||
|
790 | "collapsed": false, | |||
|
791 | "input": [ | |||
|
792 | "%Rget -d datar2" | |||
|
793 | ], | |||
|
794 | "language": "python", | |||
|
795 | "outputs": [ | |||
|
796 | { | |||
|
797 | "output_type": "pyout", | |||
|
798 | "prompt_number": 28, | |||
|
799 | "text": [ | |||
|
800 | "array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c')], ", | |||
|
801 | " dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')])" | |||
|
802 | ] | |||
|
803 | } | |||
|
804 | ], | |||
|
805 | "prompt_number": 28 | |||
|
806 | }, | |||
|
807 | { | |||
|
808 | "cell_type": "markdown", | |||
|
809 | "source": [ | |||
|
810 | "For arrays without names, the -d argument has no effect because the R object has no colnames or names." | |||
|
811 | ] | |||
|
812 | }, | |||
|
813 | { | |||
|
814 | "cell_type": "code", | |||
|
815 | "collapsed": false, | |||
|
816 | "input": [ | |||
|
817 | "Z = np.arange(6)", | |||
|
818 | "%R -i Z", | |||
|
819 | "%Rget -d Z" | |||
|
820 | ], | |||
|
821 | "language": "python", | |||
|
822 | "outputs": [ | |||
|
823 | { | |||
|
824 | "output_type": "pyout", | |||
|
825 | "prompt_number": 29, | |||
|
826 | "text": [ | |||
|
827 | "array([0, 1, 2, 3, 4, 5], dtype=int32)" | |||
|
828 | ] | |||
|
829 | } | |||
|
830 | ], | |||
|
831 | "prompt_number": 29 | |||
|
832 | }, | |||
|
833 | { | |||
|
834 | "cell_type": "markdown", | |||
|
835 | "source": [ | |||
|
836 | "For mixed-type data frames in R, if the -d flag is not used, then an array of a single type is returned and", | |||
|
837 | "its value is transposed. This would be nice to fix, but it seems something that should be fixed at the rpy2 level (See: https://bitbucket.org/lgautier/rpy2/issue/44/numpyrecarray-as-dataframe)" | |||
|
838 | ] | |||
|
839 | }, | |||
|
840 | { | |||
|
841 | "cell_type": "code", | |||
|
842 | "collapsed": false, | |||
|
843 | "input": [ | |||
|
844 | "%Rget datar2" | |||
|
845 | ], | |||
|
846 | "language": "python", | |||
|
847 | "outputs": [ | |||
|
848 | { | |||
|
849 | "output_type": "pyout", | |||
|
850 | "prompt_number": 30, | |||
|
851 | "text": [ | |||
|
852 | "array([['1', '2', '3'],", | |||
|
853 | " ['2', '3', '2'],", | |||
|
854 | " ['a', 'b', 'c']], ", | |||
|
855 | " dtype='|S1')" | |||
|
856 | ] | |||
|
857 | } | |||
|
858 | ], | |||
|
859 | "prompt_number": 30 | |||
|
860 | }, | |||
|
861 | { | |||
|
862 | "cell_type": "code", | |||
|
863 | "collapsed": true, | |||
|
864 | "input": [ | |||
|
865 | "" | |||
|
866 | ], | |||
|
867 | "language": "python", | |||
|
868 | "outputs": [], | |||
|
869 | "prompt_number": 30 | |||
|
870 | } | |||
|
871 | ] | |||
|
872 | } | |||
|
873 | ] | |||
|
874 | } No newline at end of file |
@@ -0,0 +1,7 b'' | |||||
|
1 | .. _extensions_rmagic: | |||
|
2 | ||||
|
3 | =========== | |||
|
4 | Rmagic | |||
|
5 | =========== | |||
|
6 | ||||
|
7 | .. automodule:: IPython.extensions.rmagic |
@@ -148,16 +148,17 b' have = {}' | |||||
148 |
|
148 | |||
149 | have['curses'] = test_for('_curses') |
|
149 | have['curses'] = test_for('_curses') | |
150 | have['matplotlib'] = test_for('matplotlib') |
|
150 | have['matplotlib'] = test_for('matplotlib') | |
|
151 | have['numpy'] = test_for('numpy') | |||
151 | have['pexpect'] = test_for('IPython.external.pexpect') |
|
152 | have['pexpect'] = test_for('IPython.external.pexpect') | |
152 | have['pymongo'] = test_for('pymongo') |
|
153 | have['pymongo'] = test_for('pymongo') | |
153 | have['pygments'] = test_for('pygments') |
|
154 | have['pygments'] = test_for('pygments') | |
154 | have['wx'] = test_for('wx') |
|
|||
155 | have['wx.aui'] = test_for('wx.aui') |
|
|||
156 | have['qt'] = test_for('IPython.external.qt') |
|
155 | have['qt'] = test_for('IPython.external.qt') | |
|
156 | have['rpy2'] = test_for('rpy2') | |||
157 | have['sqlite3'] = test_for('sqlite3') |
|
157 | have['sqlite3'] = test_for('sqlite3') | |
158 | have['cython'] = test_for('Cython') |
|
158 | have['cython'] = test_for('Cython') | |
159 |
|
||||
160 | have['tornado'] = test_for('tornado.version_info', (2,1,0), callback=None) |
|
159 | have['tornado'] = test_for('tornado.version_info', (2,1,0), callback=None) | |
|
160 | have['wx'] = test_for('wx') | |||
|
161 | have['wx.aui'] = test_for('wx.aui') | |||
161 |
|
162 | |||
162 | if os.name == 'nt': |
|
163 | if os.name == 'nt': | |
163 | min_zmq = (2,1,7) |
|
164 | min_zmq = (2,1,7) | |
@@ -280,6 +281,10 b' def make_exclude():' | |||||
280 | if not have['tornado']: |
|
281 | if not have['tornado']: | |
281 | exclusions.append(ipjoin('frontend', 'html')) |
|
282 | exclusions.append(ipjoin('frontend', 'html')) | |
282 |
|
283 | |||
|
284 | if not have['rpy2'] or not have['numpy']: | |||
|
285 | exclusions.append(ipjoin('extensions', 'rmagic')) | |||
|
286 | exclusions.append(ipjoin('extensions', 'tests', 'test_rmagic')) | |||
|
287 | ||||
283 | # This is needed for the reg-exp to match on win32 in the ipdoctest plugin. |
|
288 | # This is needed for the reg-exp to match on win32 in the ipdoctest plugin. | |
284 | if sys.platform == 'win32': |
|
289 | if sys.platform == 'win32': | |
285 | exclusions = [s.replace('\\','\\\\') for s in exclusions] |
|
290 | exclusions = [s.replace('\\','\\\\') for s in exclusions] |
General Comments 0
You need to be logged in to leave comments.
Login now