c++ - 使用 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 代码组织如下:
- 加载库 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;
}
如果不是 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() 结合使用则不行。任何想法 ?
解决方案
推荐阅读
- python - 如何根据python中用户的语音识别输入调用特定函数?
- r - R中多行的T检验
- entity-framework - 迁移时如何使用 Entity Framework Core 更新数据?
- react-native - 无法处理错误:redux-promise-middleware 中的“中间件不是函数”?
- python - 期权价格的傅里叶变换作为特征函数 Carr Madan 方法的函数的实现
- c# - C# UDPClient 加入多播组。本地地址是什么?
- ios - 通知服务扩展签名证书
- fusionauth - 如何授权用户更新自己的用户数据
- cmake - CMake,与子项目冲突的选项
- flutter - 为localStorage运行“flutter run -d chrome”时如何设置Chrome的端口?