yannrichet/rsession

Get images directly from R

Closed this issue · 4 comments

For me it is often helpful to show an R-plot within a JPanel. Here's what
the core piece of code which is necessary to do so:

        String device = "jpeg"; // device we'll call (this would work with
pretty much any bitmap device)

        String tempFileName = "rmPlotFile." + device;
        REXP xp = connection.parseAndEval("try(" + device + "('" +
tempFileName + "',quality=95, width = " + width + ", height = " + height +
"))");

        if (xp.inherits("try-error")) { // if the result is of the class
try-error then there was a problem
            System.err.println("Can't open " + device + " graphics
device:\n" + xp.asString());
            // this is analogous to 'warnings', but for us it's sufficient
to get just the 1st warning
            REXP w = connection.eval("if (exists('last.warning') &&
length(last.warning)>0) names(last.warning)[1] else 0");
            if (w.isString()) System.err.println(w.asString());
            return null;
        }

        // ok, so the device should be fine - let's plot - replace this by
any plotting code you desire ...
        String preparedScript = RUtils.prepare4RExecution(script);

        String[] splitScript = preparedScript.split(";");
        for (String s : splitScript) {
            try {
                connection.parseAndEval(RUtils.prepare4RExecution(s + ";"));
            } catch (REngineException e) {
                throw new RuntimeException("Error while executing line: " +
s, e);
            }
        }
//        connection.parseAndEval(preparedScript);

        // close the image
        connection.parseAndEval("dev.off();");

        // There is no I/O API in REngine because it's actually more
efficient to use R for this
        // we limit the file size to 1MB which should be sufficient and we
delete the file as well
        xp = connection.parseAndEval("r=readBin('" + tempFileName +
"','raw',2024*2024); unlink('" + tempFileName + "'); r");

        // now this is pretty boring AWT stuff - create an image from the
data and display it ...
        return Toolkit.getDefaultToolkit().createImage(xp.asBytes());

Maybe it would be nice to have this available directly in Rsession. If not 
just close the issue...

Original issue reported on code.google.com by holgerbr...@gmail.com on 9 Apr 2010 at 7:55

A dependency-method was missing in the above posting:


    static String prepare4RExecution(String script) {
        script = script.replace("\r", " ").replace("\n", " ").replace("\t", " ");

        while (script.endsWith(" ")) {
            script = chop(script);
        }

        if (!script.endsWith(";")) {
            script += ";";
        }

        return script;
    }


    static String chop(String str) {
        if (str == null) {
            return null;
        }
        int strLen = str.length();
        if (strLen < 2) {
            return "";
        }
        int lastIdx = strLen - 1;
        String ret = str.substring(0, lastIdx);
        char last = str.charAt(lastIdx);
        if (last == '\n') {
            if (ret.charAt(lastIdx - 1) == '\r') {
                return ret.substring(0, lastIdx - 1);
            }
        }
        return ret;
    }

Original comment by holgerbr...@gmail.com on 9 Apr 2010 at 8:27

I've also implemented a jpanel which gets the image using the method described 
above
and allows for different repainting modes. Tell me if you're interested. :-)

Original comment by holgerbr...@gmail.com on 9 Apr 2010 at 8:29

Now also working with renjin. No more need for that, I think