首页 > 解决方案 > 使用 R_tryEval 调用 ggplot 的问题

问题描述

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

到目前为止,这对任何 R 代码都适用。但是,我遇到了使用 ggplot 的问题。我尝试将 ggplot 结果图发送到 png 文件。如果直接在 R 控制台中完成它工作正常,但是当我使用我的 C++ 接口时,生成的文件是空的。

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

当减少到最小的情况下,这是我的代码:

#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;
}

如果不是 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() 结合使用则不行。任何想法 ?

标签: c++rggplot2

解决方案


推荐阅读