使用R_tryEval

时间:2018-07-04 08:12:34

标签: c++ r ggplot2

我正在尝试构建一个系统,该系统允许从C ++应用程序执行任意R代码。 为了实现这一目标,该方法的核心遵循此处描述的内容:http://www.hep.by/gnu/r-patched/r-exts/R-exts_121.html

到目前为止,这对于任何R代码都可以正常工作。但是,我遇到了使用ggplot的问题。我尝试将ggplot结果图发送到png文件。如果直接在R控制台中进行操作,效果很好,但是当我使用C ++接口时,结果文件为空。

更准确地说,R代码的组织方式如下:

  • 加载库ggplot2
  • 定义一些要绘制的虚拟数据。
  • 调用png创建图形设备。
  • 致电ggplot。
  • 调用dev.off()关闭图形设备。

当简化为最小情况时,这是我的代码:

#include <QDebug>

#include <Rembedded.h>
#include <Rinternals.h>
#include <R_ext/Parse.h>

int main(int argc, char *argv[])
{
    const char *argvrf[] = {"RConsole"};
    int argcrf = sizeof(argvrf) / sizeof(argvrf[0]);

    Rf_initEmbeddedR(argcrf, (char**)argvrf);

    // Create some dummy data for a ggplot.
    // For the purpose of this minimal example, R code is just directly defined as a QString here.

    QString RScript = "library(\"ggplot2\") \n" ;
    RScript += "id<-c(1,2,3,4,5) \n" ;
    RScript += "names<-c(\"A\",\"B\",\"C\",\"D\",\"E\") \n" ;
    RScript += "notes<-c(12,20,13,15,10) \n" ;
    RScript += "df1<-data.frame(id,names,notes) \n" ;

    // Define a file as graphicsDevice (adapt adress to your own filesystem)
    RScript += "png(\"C:/Users/Evain/Desktop/tests/testggplot.png\", width=480, height=480, res=72) \n" ;
    // Drawing the ggplot.
    RScript += "ggplot(data=df1,aes(x=id,y=notes))+geom_line() \n" ;
    // Closing the graphic device.
    RScript += "dev.off() \n" ;


    ParseStatus status;
    SEXP cmdSexp, cmdexpr = R_NilValue;
    int i, errorOccurred, retVal=0;

    // Convert the command line to SEXP
    PROTECT(cmdSexp = Rf_allocVector(STRSXP, 1));
    SET_STRING_ELT(cmdSexp, 0, Rf_mkChar(RScript.toLocal8Bit().data()));
    cmdexpr = PROTECT(R_ParseVector(cmdSexp, -1, &status, R_NilValue));

    switch (status){
    case PARSE_OK: {
        // Loop is needed here as EXPSEXP might be of length > 1
        for(i = 0; ((i < Rf_length(cmdexpr)) && (retVal==0)); i++){
            R_tryEval(VECTOR_ELT(cmdexpr, i), R_GlobalEnv, &errorOccurred);
            if (errorOccurred) {
                // Interrupt process.
                qDebug() << "Error occured" ;
                retVal = -1;
            }
        }
        break ;
    }
    default: {
        qDebug() << "Incorrect R command" ;
        break;
    }
    }
    return 0;
}

如果R不是ggplot,则与R的通信可以正常工作。例如,如果我替换

RScript += "ggplot(data=df1,aes(x=id,y=notes))+geom_line() \n" ;

使用:

RScript += "plot(3) \n";

然后工作正常,使用所需的图创建一个png文件。 使用ggplot,此代码可以正常运行。不触发qDebug()消息。甚至会创建png文件(这意味着对png()的调用已正确执行)。但是文件为空。

这不仅是png()和ggplot()的组合,还是我的虚拟数据的问题,因为如果我只是在R控制台中启动以下R脚本,则会得到预期的结果(文件已创建并包含该图):

library("ggplot2")
id<-c(1,2,3,4,5)
names<-c("A","B","C","D","E")
notes<-c(12,20,13,15,10)    
df1<-data.frame(id,names,notes)

png("C:/Users/Evain/Desktop/tests/testggplot.png", width=480, height=480, res=72)
ggplot(data=df1,aes(x=id,y=notes))+geom_line()
dev.off()

注意:我在Windows 10上,使用R3.4.3。 值得注意的是,png()方法在Linux上的行为略有不同。对于Windows,即使必须保留为空,也会在调用png()时创建文件。对于Linux,如果未写任何文件,则不会创建该文件。

如果png文件已经存在,它也会被替换为一个空文件。那就是我们在单独调用png()时应该期望的。只是没有将ggplot添加到其中。

感觉就像将R_tryEval()与png()结合使用一样不错。将png()与ggplot结合使用可以很好地工作,但是将R_tryEval()与png()和ggplot()结合使用则不能。有什么想法吗?

0 个答案:

没有答案