示例#1
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({<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
示例#2
0
    def setUp(self):
        self.console = rinterface.get_writeconsole()

        def noconsole(x):
            pass

        rinterface.set_writeconsole(noconsole)
示例#3
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({<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 setUp(self):
        self.console = rinterface.get_writeconsole()

        def noconsole(x):
            pass

        rinterface.set_writeconsole(noconsole)
示例#5
0
 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'))
示例#6
0
    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))
示例#7
0
    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))
示例#8
0
 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
示例#9
0
文件: rmagic.py 项目: vietlq/ipython
 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
示例#10
0
 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
示例#11
0
 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))
示例#12
0
    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
示例#13
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]
示例#14
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]
示例#15
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)
示例#16
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
        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)