def eval(self, line): ''' Parse and evaluate a line of R code with rpy2. Returns the output to R's stdout() connection, the value generated by evaluating the code, and a boolean indicating whether the return value would be visible if the line of code were evaluated in an R REPL. R Code evaluation and visibility determination are done via an R call of the form withVisible({<code>}) ''' old_writeconsole = ri.get_writeconsole() ri.set_writeconsole(self.write_console) try: res = ro.r("withVisible({%s})" % line) value = res[0] #value (R object) visible = ro.conversion.ri2py(res[1])[0] #visible (boolean) except (ri.RRuntimeError, ValueError) as exception: warning_or_other_msg = self.flush( ) # otherwise next return seems to have copy of error raise RInterpreterError(line, str_to_unicode(str(exception)), warning_or_other_msg) text_output = self.flush() ri.set_writeconsole(old_writeconsole) return text_output, value, visible
def setUp(self): self.console = rinterface.get_writeconsole() def noconsole(x): pass rinterface.set_writeconsole(noconsole)
def eval(self, line): ''' Parse and evaluate a line of R code with rpy2. Returns the output to R's stdout() connection, the value generated by evaluating the code, and a boolean indicating whether the return value would be visible if the line of code were evaluated in an R REPL. R Code evaluation and visibility determination are done via an R call of the form withVisible({<code>}) ''' old_writeconsole = ri.get_writeconsole() ri.set_writeconsole(self.write_console) try: res = ro.r("withVisible({%s\n})" % line) value = res[0] # value (R object) visible = ro.conversion.ri2py(res[1])[0] # visible (boolean) except (ri.RRuntimeError, ValueError) as exception: # otherwise next return seems to have copy of error warning_or_other_msg = self.flush() raise RInterpreterError( line, str_to_unicode(str(exception)), warning_or_other_msg) text_output = self.flush() ri.set_writeconsole(old_writeconsole) return text_output, value, visible
def eval(self, line): """Evaluate a line or block of code in R Parameters ---------- line : str The code to execute Examples -------- >>> r.eval(''' ... x = 1:5 ... df = data.frame(x=x, y=x^2) ... print(df) ... ''') x y 1 1 1 2 2 4 3 3 9 4 4 16 5 5 25 """ old_writeconsole = ri.get_writeconsole() ri.set_writeconsole(self._write_console) try: value = ri.baseenv['eval'](ri.parse(line)) except (ri.RRuntimeError, ValueError) as exception: warning_or_other_msg = self._flush() # otherwise next return seems to have copy of error raise RInterpreterError(line, str_to_unicode(str(exception)), warning_or_other_msg) text_output = self._flush() ri.set_writeconsole(old_writeconsole) if text_output: sys.stdout.write(unicode_to_str(text_output, 'utf-8'))
def testSetWriteConsole(self): buf = [] def f(x): buf.append(x) rinterface.set_writeconsole(f) self.assertEqual(rinterface.get_writeconsole(), f) code = rinterface.SexpVector(["3", ], rinterface.STRSXP) rinterface.baseenv["print"](code) self.assertEqual('[1] "3"\n', str.join('', buf))
def testSetWriteConsole(self): buf = [] def f(x): buf.append(x) rinterface.set_writeconsole(f) self.assertEqual(rinterface.get_writeconsole(), f) code = rinterface.SexpVector([ "3", ], rinterface.STRSXP) rinterface.baseenv["print"](code) self.assertEqual('[1] "3"\n', str.join('', buf))
def eval(self, line): ''' Parse and evaluate a line with rpy2. Returns the output to R's stdout() connection and the value of eval(parse(line)). ''' old_writeconsole = ri.get_writeconsole() ri.set_writeconsole(self.write_console) try: value = ri.baseenv['eval'](ri.parse(line)) except (ri.RRuntimeError, ValueError) as exception: warning_or_other_msg = self.flush() # otherwise next return seems to have copy of error raise RInterpreterError(line, str_to_unicode(str(exception)), warning_or_other_msg) text_output = self.flush() ri.set_writeconsole(old_writeconsole) return text_output, value
def eval(self, line): ''' Parse and evaluate a line with rpy2. Returns the output to R's stdout() connection and the value of eval(parse(line)). ''' old_writeconsole = ri.get_writeconsole() ri.set_writeconsole(self.write_console) try: value = ri.baseenv['eval'](ri.parse(line)) except (ri.RRuntimeError, ValueError) as exception: warning_or_other_msg = self.flush() # otherwise next return seems to have copy of error raise RMagicError(unicode_to_str('parsing and evaluating line "%s".\nR error message: "%s"\n R stdout:"%s"\n' % (line, str_to_unicode(exception.message, 'utf-8'), warning_or_other_msg))) text_output = self.flush() ri.set_writeconsole(old_writeconsole) return text_output, value
def eval(self, line): ''' Parse and evaluate a line with rpy2. Returns the output to R's stdout() connection and the value of eval(parse(line)). ''' old_writeconsole = ri.get_writeconsole() ri.set_writeconsole(self.write_console) try: value = ri.baseenv['eval'](ri.parse(line)) except (ri.RRuntimeError, ValueError) as exception: warning_or_other_msg = self.flush( ) # otherwise next return seems to have copy of error raise RInterpreterError(line, str_to_unicode(str(exception)), warning_or_other_msg) text_output = self.flush() ri.set_writeconsole(old_writeconsole) return text_output, value
def check_syntax(self, text): block = self.currentBlock() block = block.previous() user_data = block.userData() if user_data: if user_data.data == "continue": self.setCurrentBlockUserData(UserData("continue")) try: # if this works, then syntax is correct temp = rinterface.get_writeconsole() def f(x): pass rinterface.set_writeconsole(f) robjects.r.parse(text=unicode(text)) rinterface.set_writeconsole(temp) except robjects.rinterface.RRuntimeError, err: err = QString(unicode(err)) if err.contains("unexpected end of input"): self.setCurrentBlockUserData(UserData("continue")) return err = err.split(":", QString.SkipEmptyParts)[1:].join(" ") if err.startsWith("\n"): err = err[1:] self.setCurrentBlockUserData(UserData("syntax", err))
def caching_eval(self, line, cache_random): ''' A version of eval with caching using the RCacheSuite package Caching depends on both the text of the code and the variables used by the code. This means that running a code cell can safely sometimes return a cached result without new execution of the code. This will not be the default currently. No caching is done by default if code with random elements is detected. If cache_random is True, caching is performed regardless of whether randomness is present in the code. Randomness is detected by comparing the .Random.seed R variable before and after code evaluation. This will detect code leveraging most basic methods of generating random numbers (rnorm, runif, etc), but is not guaranteed to detect more exotic RNGs, such as those implemented in non-core R packages which don't make use of .Random.seed. See ?set.seed in R ''' old_writeconsole = ri.get_writeconsole() ri.set_writeconsole(self.write_console) try: havecache = ro.r.exists("x_rpynotebookcache") if havecache != True: # ri.baseenv['library']("RCacheSuite") ro.r("suppressPackageStartupMessages(library(RCacheSuite))") # ro.r("x_rpynotebookcache <- cacheClass$new( base_dir= './r_caches/')") ro.r("x_rpynotebookcache <- cachingEngine(eval_fun=parseWithVis, return_handler = withVisHandler, write_on_cache = TRUE)") value = ro.r("evalWithCache('%s', cache = x_rpynotebookcache, cacheRand=%s)" %(line, str(cache_random).upper() )) # value = res[0] #value (R object) # visible = ro.conversion.ri2py(res[1])[0] #visible (boolean) # ro.r("x_rpynotebookcache$to_disk()") except (ri.RRuntimeError, ValueError) as exception: warning_or_other_msg = self.flush() # otherwise next return seems to have copy of error raise RInterpreterError(line, str_to_unicode(str(exception)), warning_or_other_msg) text_output = self.flush() ri.set_writeconsole(old_writeconsole) return text_output, value
def eval(self, line): ''' Parse and evaluate a line of R code with rpy2. Returns the output to R's stdout() connection, the value generated by evaluating the code, and a boolean indicating whether the return value would be visible if the line of code were evaluated in an R REPL. R Code evaluation and visibility determination are done via an R call of the form withVisible(eval(parse(code_string))) ''' old_writeconsole = ri.get_writeconsole() ri.set_writeconsole(self.write_console) try: value, visible = ro.r.withVisible(ro.r.eval(ro.r.parse(text=line))) except (ri.RRuntimeError, ValueError) as exception: warning_or_other_msg = self.flush() # otherwise next return seems to have copy of error raise RInterpreterError(line, str_to_unicode(str(exception)), warning_or_other_msg) text_output = self.flush() ri.set_writeconsole(old_writeconsole) return text_output, value, visible[0]
def eval(self, line): ''' Parse and evaluate a line of R code with rpy2. Returns the output to R's stdout() connection, the value generated by evaluating the code, and a boolean indicating whether the return value would be visible if the line of code were evaluated in an R REPL. R Code evaluation and visibility determination are done via an R call of the form withVisible(eval(parse(code_string))) ''' old_writeconsole = ri.get_writeconsole() ri.set_writeconsole(self.write_console) try: value, visible = ro.r.withVisible(ro.r.eval(ro.r.parse(text=line))) except (ri.RRuntimeError, ValueError) as exception: warning_or_other_msg = self.flush( ) # otherwise next return seems to have copy of error raise RInterpreterError(line, str_to_unicode(str(exception)), warning_or_other_msg) text_output = self.flush() ri.set_writeconsole(old_writeconsole) return text_output, value, visible[0]
def R(self, line, cell=None, local_ns=None): ''' Execute code in R, and pull some of the results back into the Python namespace. In line mode, this will evaluate an expression and convert the returned value to a Python object. The return value is determined by rpy2's behaviour of returning the result of evaluating the final line. Multiple R lines can be executed by joining them with semicolons:: In [9]: %R X=c(1,4,5,7); sd(X); mean(X) Out[9]: array([ 4.25]) In cell mode, this will run a block of R code. The resulting value is printed if it would printed be when evaluating the same code within a standard R REPL. Nothing is returned to python by default in cell mode. In [10]: %%R ....: Y = c(2,4,3,9) ....: summary(lm(Y~X)) Call: lm(formula = Y ~ X) Residuals: 1 2 3 4 0.88 -0.24 -2.28 1.64 Coefficients: Estimate Std. Error t value Pr(>|t|) (Intercept) 0.0800 2.3000 0.035 0.975 X 1.0400 0.4822 2.157 0.164 Residual standard error: 2.088 on 2 degrees of freedom Multiple R-squared: 0.6993,Adjusted R-squared: 0.549 F-statistic: 4.651 on 1 and 2 DF, p-value: 0.1638 In the notebook, plots are published as the output of the cell. %R plot(X, Y) will create a scatter plot of X bs Y. If cell is not None and line has some R code, it is prepended to the R code in cell. Objects can be passed back and forth between rpy2 and python via the -i -o flags in line:: In [14]: Z = np.array([1,4,5,10]) In [15]: %R -i Z mean(Z) Out[15]: array([ 5.]) In [16]: %R -o W W=Z*mean(Z) Out[16]: array([ 5., 20., 25., 50.]) In [17]: W Out[17]: array([ 5., 20., 25., 50.]) The return value is determined by these rules: * If the cell is not None, the magic returns None. * If the cell evaluates as False, the resulting value is returned unless the final line prints something to the console, in which case None is returned. * If the final line results in a NULL value when evaluated by rpy2, then None is returned. * No attempt is made to convert the final value to a structured array. Use the --dataframe flag or %Rget to push / return a structured array. * If the -n flag is present, there is no return value. * A trailing ';' will also result in no return value as the last value in the line is an empty string. The --dataframe argument will attempt to return structured arrays. This is useful for dataframes with mixed data types. Note also that for a data.frame, if it is returned as an ndarray, it is transposed:: In [18]: dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')] In [19]: datapy = np.array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5, 'e')], dtype=dtype) In [20]: %%R -o datar datar = datapy ....: In [21]: datar Out[21]: array([['1', '2', '3', '4'], ['2', '3', '2', '5'], ['a', 'b', 'c', 'e']], dtype='|S1') In [22]: %%R -d datar datar = datapy ....: In [23]: datar Out[23]: array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5.0, 'e')], dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')]) The --dataframe argument first tries colnames, then names. If both are NULL, it returns an ndarray (i.e. unstructured):: In [1]: %R mydata=c(4,6,8.3); NULL In [2]: %R -d mydata In [3]: mydata Out[3]: array([ 4. , 6. , 8.3]) In [4]: %R names(mydata) = c('a','b','c'); NULL In [5]: %R -d mydata In [6]: mydata Out[6]: array((4.0, 6.0, 8.3), dtype=[('a', '<f8'), ('b', '<f8'), ('c', '<f8')]) In [7]: %R -o mydata In [8]: mydata Out[8]: array([ 4. , 6. , 8.3]) ''' args = parse_argstring(self.R, line) # arguments 'code' in line are prepended to # the cell lines if cell is None: code = '' return_output = True line_mode = True else: code = cell return_output = False line_mode = False code = ' '.join(args.code) + code # if there is no local namespace then default to an empty dict if local_ns is None: local_ns = {} if args.input: for input in ','.join(args.input).split(','): try: val = local_ns[input] except KeyError: try: val = self.shell.user_ns[input] except KeyError: raise NameError("name '%s' is not defined" % input) self.r.assign(input, self.pyconverter(val)) if getattr(args, 'units') is not None: if args.units != "px" and getattr(args, 'res') is None: args.res = 72 args.units = '"%s"' % args.units png_argdict = dict([(n, getattr(args, n)) for n in ['units', 'res', 'height', 'width', 'bg', 'pointsize']]) png_args = ','.join(['%s=%s' % (o,v) for o, v in png_argdict.items() if v is not None]) # execute the R code in a temporary directory tmpd = tempfile.mkdtemp() self.r('png("%s/Rplots%%03d.png",%s)' % (tmpd.replace('\\', '/'), png_args)) text_output = '' try: if line_mode: for line in code.split(';'): text_result, result, visible = self.eval(line) text_output += text_result if text_result: # the last line printed something to the console so we won't return it return_output = False else: text_result, result, visible = self.eval(code) text_output += text_result if visible: old_writeconsole = ri.get_writeconsole() ri.set_writeconsole(self.write_console) ro.r.show(result) text_output += self.flush() ri.set_writeconsole(old_writeconsole) except RInterpreterError as e: print(e.stdout) if not e.stdout.endswith(e.err): print(e.err) rmtree(tmpd) return self.r('dev.off()') # read out all the saved .png files images = [open(imgfile, 'rb').read() for imgfile in glob("%s/Rplots*png" % tmpd)] # now publish the images # mimicking IPython/zmq/pylab/backend_inline.py fmt = 'png' mimetypes = { 'png' : 'image/png', 'svg' : 'image/svg+xml' } mime = mimetypes[fmt] # publish the printed R objects, if any display_data = [] if text_output: display_data.append(('RMagic.R', {'text/plain':text_output})) # flush text streams before sending figures, helps a little with output for image in images: # synchronization in the console (though it's a bandaid, not a real sln) sys.stdout.flush(); sys.stderr.flush() display_data.append(('RMagic.R', {mime: image})) # kill the temporary directory rmtree(tmpd) # try to turn every output into a numpy array # this means that output are assumed to be castable # as numpy arrays if args.output: for output in ','.join(args.output).split(','): self.shell.push({output:self.Rconverter(self.r(output), dataframe=False)}) if args.dataframe: for output in ','.join(args.dataframe).split(','): self.shell.push({output:self.Rconverter(self.r(output), dataframe=True)}) for tag, disp_d in display_data: publish_display_data(tag, disp_d) # this will keep a reference to the display_data # which might be useful to other objects who happen to use # this method if self.cache_display_data: self.display_cache = display_data # if in line mode and return_output, return the result as an ndarray if return_output and not args.noreturn: if result != ri.NULL: return self.Rconverter(result, dataframe=False)
def R(self, line, cell=None, local_ns=None): ''' Execute code in R, and pull some of the results back into the Python namespace. In line mode, this will evaluate an expression and convert the returned value to a Python object. The return value is determined by rpy2's behaviour of returning the result of evaluating the final line. Multiple R lines can be executed by joining them with semicolons:: In [9]: %R X=c(1,4,5,7); sd(X); mean(X) Out[9]: array([ 4.25]) In cell mode, this will run a block of R code. The resulting value is printed if it would printed be when evaluating the same code within a standard R REPL. Nothing is returned to python by default in cell mode:: In [10]: %%R ....: Y = c(2,4,3,9) ....: summary(lm(Y~X)) Call: lm(formula = Y ~ X) Residuals: 1 2 3 4 0.88 -0.24 -2.28 1.64 Coefficients: Estimate Std. Error t value Pr(>|t|) (Intercept) 0.0800 2.3000 0.035 0.975 X 1.0400 0.4822 2.157 0.164 Residual standard error: 2.088 on 2 degrees of freedom Multiple R-squared: 0.6993,Adjusted R-squared: 0.549 F-statistic: 4.651 on 1 and 2 DF, p-value: 0.1638 In the notebook, plots are published as the output of the cell:: %R plot(X, Y) will create a scatter plot of X bs Y. If cell is not None and line has some R code, it is prepended to the R code in cell. Objects can be passed back and forth between rpy2 and python via the -i -o flags in line:: In [14]: Z = np.array([1,4,5,10]) In [15]: %R -i Z mean(Z) Out[15]: array([ 5.]) In [16]: %R -o W W=Z*mean(Z) Out[16]: array([ 5., 20., 25., 50.]) In [17]: W Out[17]: array([ 5., 20., 25., 50.]) The return value is determined by these rules: * If the cell is not None, the magic returns None. * If the cell evaluates as False, the resulting value is returned unless the final line prints something to the console, in which case None is returned. * If the final line results in a NULL value when evaluated by rpy2, then None is returned. * No attempt is made to convert the final value to a structured array. Use the --dataframe flag or %Rget to push / return a structured array. * If the -n flag is present, there is no return value. * A trailing ';' will also result in no return value as the last value in the line is an empty string. The --dataframe argument will attempt to return structured arrays. This is useful for dataframes with mixed data types. Note also that for a data.frame, if it is returned as an ndarray, it is transposed:: In [18]: dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')] In [19]: datapy = np.array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5, 'e')], dtype=dtype) In [20]: %%R -o datar datar = datapy ....: In [21]: datar Out[21]: array([['1', '2', '3', '4'], ['2', '3', '2', '5'], ['a', 'b', 'c', 'e']], dtype='|S1') In [22]: %%R -d datar datar = datapy ....: In [23]: datar Out[23]: array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5.0, 'e')], dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')]) The --dataframe argument first tries colnames, then names. If both are NULL, it returns an ndarray (i.e. unstructured):: In [1]: %R mydata=c(4,6,8.3); NULL In [2]: %R -d mydata In [3]: mydata Out[3]: array([ 4. , 6. , 8.3]) In [4]: %R names(mydata) = c('a','b','c'); NULL In [5]: %R -d mydata In [6]: mydata Out[6]: array((4.0, 6.0, 8.3), dtype=[('a', '<f8'), ('b', '<f8'), ('c', '<f8')]) In [7]: %R -o mydata In [8]: mydata Out[8]: array([ 4. , 6. , 8.3]) ''' args = parse_argstring(self.R, line) # arguments 'code' in line are prepended to # the cell lines if cell is None: code = '' return_output = True line_mode = True else: code = cell return_output = False line_mode = False code = ' '.join(args.code) + code # if there is no local namespace then default to an empty dict if local_ns is None: local_ns = {} if args.input: for input in ','.join(args.input).split(','): try: val = local_ns[input] except KeyError: try: val = self.shell.user_ns[input] except KeyError: raise NameError("name '%s' is not defined" % input) self.r.assign(input, self.pyconverter(val)) if getattr(args, 'units') is not None: if args.units != "px" and getattr(args, 'res') is None: args.res = 72 args.units = '"%s"' % args.units png_argdict = dict([(n, getattr(args, n)) for n in ['units', 'res', 'height', 'width', 'bg', 'pointsize']]) png_args = ','.join(['%s=%s' % (o,v) for o, v in png_argdict.items() if v is not None]) # execute the R code in a temporary directory tmpd = tempfile.mkdtemp() self.r('png("%s/Rplots%%03d.png",%s)' % (tmpd.replace('\\', '/'), png_args)) text_output = '' try: if line_mode: for line in code.split(';'): text_result, result, visible = self.eval(line) text_output += text_result if text_result: # the last line printed something to the console so we won't return it return_output = False else: text_result, result, visible = self.eval(code) text_output += text_result if visible: old_writeconsole = ri.get_writeconsole() ri.set_writeconsole(self.write_console) ro.r.show(result) text_output += self.flush() ri.set_writeconsole(old_writeconsole) except RInterpreterError as e: print(e.stdout) if not e.stdout.endswith(e.err): print(e.err) rmtree(tmpd) return finally: self.r('dev.off()') # read out all the saved .png files images = [open(imgfile, 'rb').read() for imgfile in glob("%s/Rplots*png" % tmpd)] # now publish the images # mimicking IPython/zmq/pylab/backend_inline.py fmt = 'png' mimetypes = { 'png' : 'image/png', 'svg' : 'image/svg+xml' } mime = mimetypes[fmt] # publish the printed R objects, if any display_data = [] if text_output: display_data.append(('RMagic.R', {'text/plain':text_output})) # flush text streams before sending figures, helps a little with output for image in images: # synchronization in the console (though it's a bandaid, not a real sln) sys.stdout.flush(); sys.stderr.flush() display_data.append(('RMagic.R', {mime: image})) # kill the temporary directory rmtree(tmpd) # try to turn every output into a numpy array # this means that output are assumed to be castable # as numpy arrays if args.output: for output in ','.join(args.output).split(','): self.shell.push({output:self.Rconverter(self.r(output), dataframe=False)}) if args.dataframe: for output in ','.join(args.dataframe).split(','): self.shell.push({output:self.Rconverter(self.r(output), dataframe=True)}) for tag, disp_d in display_data: publish_display_data(data=disp_d, source=tag) # this will keep a reference to the display_data # which might be useful to other objects who happen to use # this method if self.cache_display_data: self.display_cache = display_data # if in line mode and return_output, return the result as an ndarray if return_output and not args.noreturn: if result != ri.NULL: return self.Rconverter(result, dataframe=False)