Issue with calling ggplot using R_tryEval - c++

I am trying to build a system allowing to execute arbitrary R code from a C++ application.
In orded to achieve that, the core of the method follows what is described here: http://www.hep.by/gnu/r-patched/r-exts/R-exts_121.html
This worked fine for any R code so far. However, I encoutered an issue with using ggplot. I try to send ggplot resulting graph to a png file. It works fine if done directly in a R console, but when I use my C++ interface, the resulting file is empty.
More precisely, the R code is organized as follows:
Load library ggplot2
Define some dummy data to be plotted.
Call png to create a graphics device.
Call ggplot.
Call dev.off() to close the graphics device.
When reduced to a minimal case, here is my code:
#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;
}
Communication with R works fine if it is not a ggplot. For example, if I replace the
RScript += "ggplot(data=df1,aes(x=id,y=notes))+geom_line() \n" ;
With:
RScript += "plot(3) \n";
Then it works fine, a png file is create with the required plot.
With ggplot, this code runs without apparent issue. The qDebug() messages are not triggered. The png file is even created (meaning that the call to png() is executed correctly). But the file is empty.
It is not just an issue with the combination of png() and ggplot() or with my dummy data, since if I just launch the following R script in a R console, I get the expected result (the file is created and contains the plot):
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()
Note: I'm on Windows 10, using R3.4.3.
It is worth noting that the png() method behaves slightly differently on Linux. For windows, the file is created when png() is called, even if it has to remain empty. For Linux, the file wouldn't be created if nothing is written in it.
If the png file already exist, it also gets replaced by an empty one. That's what we should expect when calling png() alone. It's just that the ggplot doesn't get added to it.
It feels like combining R_tryEval() with png() works fine. Combining png() with ggplot works fine, but combining R_tryEval() with png() and ggplot() doesn't. Any idea ?

Related

How do you load MPV Lua scripts with the C Plugin?

After realizing it is nearly impossible to find help on getting keybindings to work with the C plugin in MPV (Possible to allow key bindings with MPV C API when no video (GUI) is being shown?), I decided to learn some Lua to help with the cause. Problem is, the docs aren't very clear on how to add Lua scripts with the C plugin, what I could find out was that check_error(mpv_set_option_string(ctx, "load-scripts", "yes")); should be called before initializing mpv in the C plugin, which points out that there should be a way to add scripts... When loading a script in the terminal you can do mpv video.mp4 --scripts="script_name.lua" and that will call the script from inside $HOME/.config/mpv... How do I achieve the calling of Lua scripts in the C plugin for MPV? I tried a few things including check_error(mpv_set_option_string(ctx, "scripts", "test.lua")); and check_error(mpv_set_property_string(ctx, "scripts", "test.lua")); and const char *cmd2[] = {"scripts", "test.lua", NULL}; check_error(mpv_command(ctx, cmd2));, none of which worked...
How do I call a Lua script for MPV from the C Plugin?
Below is the code I'm using to test things out:
// Build with: g++ main.cpp -o output `pkg-config --libs --cflags mpv`
#include <iostream>
#include <mpv/client.h>
static inline void check_error(int status)
{
if (status < 0)
{
std::cout << "mpv API error: " << mpv_error_string(status) << std::endl;
exit(1);
}
}
int main(int argc, char *argv[])
{
if (argc != 2)
{
std::cout << "pass a single media file as argument" << std::endl;
return 1;
}
mpv_handle *ctx = mpv_create();
if (!ctx)
{
std::cout << "failed creating context" << std::endl;
return 1;
}
// Enable default key bindings, so the user can actually interact with
// the player (and e.g. close the window).
check_error(mpv_set_option_string(ctx, "input-default-bindings", "yes"));
mpv_set_option_string(ctx, "input-vo-keyboard", "yes");
check_error(mpv_set_option_string(ctx, "load-scripts", "yes"));
check_error(mpv_set_option_string(ctx, "scripts", "test.lua")); // DOES NOT WORK :(
int val = 1;
check_error(mpv_set_option(ctx, "osc", MPV_FORMAT_FLAG, &val));
// Done setting up options.
check_error(mpv_initialize(ctx));
// Play the file passed in as a parameter when executing program.
const char *cmd[] = {"loadfile", argv[1], NULL};
check_error(mpv_command(ctx, cmd));
// check_error(mpv_set_option_string(ctx, "scripts", "test.lua"));
check_error(mpv_set_option_string(ctx, "shuffle", "yes")); // shuffle videos
check_error(mpv_set_option_string(ctx, "loop-playlist", "yes")); // loop playlists
// check_error(mpv_set_option_string(ctx, "aspect", "0:0")); // set aspect
// Let it play, and wait until the user quits.
while (1)
{
mpv_event *event = mpv_wait_event(ctx, 10000);
std::cout << "event: " << mpv_event_name(event->event_id) << std::endl;
if (event->event_id == MPV_EVENT_SHUTDOWN)
break;
}
mpv_terminate_destroy(ctx);
return 0;
}
After playing around more with the mpv_set_property_string command, I discovered that you have to specify the FULL path to the Lua file, it by defaults searches for the file in the directory it is being played in, so if I tried to play it in /home/ it will search for /home/test.lua, so to get it to work I had to do check_error(mpv_set_property_string(ctx, "scripts", "/home/netsu/.config/mpv/test.lua")); (give the absolute path)

Program with SPI_SETDESKWALLPAPER Function Only Changes the Desktop Background to the Color Black when Trying to Change it to an Image using C++

I am trying to change the desktop background/wallpaper to a different image with a .png file. Although when I run the program, the background turns to solid black instead.
I am certain that I typed the file name, "ksa.png", correctly in my code to be the image I want to be on my background. I used an if condition to write out the last error on a file when the error occurred and used an else condition to write out "Success" if no errors occurred; but when I run the program, it writes "Success" to the file. I have thought about using a .jpg file instead, thinking that maybe .png files just don't work. I'll give an update when I tried using that.
#include <windows.h>
#include <fstream>
int main () {
const wchar_t *filenm = L"ksa.png";
std::ofstream log;
if (SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, (void*)filenm, SPIF_UPDATEINIFILE) == FALSE) {
log.open("log.txt");
log << "Error: " << GetLastError();
log.close();
}
else {
log.open("log.txt");
log << "Success";
log.close();
}
return 0;
}
When I run this program, the desktop background is suppose to be set as the image "ksa.png". Instead it's solid black. Any help is appreciated for making this work, thank you.
UPDATE
Okay so I updated the code to where it would run a .jpg file and I'm still getting the same result. Also I moved the line log.open("log.txt") command before the SystemParametersInfo() function like Remy Lebeau suggested and it still writes out "Success" to the file. I'm still having the same problem.
Here is my updated code:
#include <windows.h>
#include <fstream>
int main () {
const wchar_t *filenm = L"3.jpg";
std::ofstream log;
log.open("log.txt");
if (SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, (void*)filenm, SPIF_UPDATEINIFILE) == FALSE) {
log << "Error: " << GetLastError();
log.close();
}
else {
log.open("log.txt");
log << "Success";
log.close();
}
return 0;
}
Emmmm,there is a problem with your picture path. I've tried your code. You can't get pictures under relative paths unless you use absolute paths.
Like Cody Gray♦'s judgment .
const wchar_t *filenm = L"C:\\Users\\strives\\Desktop\\timg.bmp";

Issue updating curves in QwtPlot 6.1.3

I am currently working on Ubuntu 14.04, using gcc 4.9.2 and Qwt 6.1.3; I have installed both Qt 4.8.6 and Qt 5.2.1 (and I wonder whether this could be connected to the issues I am experiencing).
I have a simple GUI with a QwtPlot and a QwtPlotCurve attached, which I am trying to update and redraw. In the setupUi() function, I create a few random data points and then plot them:
void ExampleMainWindow::setupUi(QMainWindow* mainWindow)
{
// run the inherited setupUi
Ui_MainWindow::setupUi(mainWindow);
// associate internal pointer to main window
this->mainWindow = mainWindow;
// create some data points
for(unsigned int i = 0; i < 10; i++)
{
this->createDataPoint();
}
for(unsigned int i = 0; i < this->xPlot.size(); i++)
{
cout << "Point #" << i << ": x=" << xPlot[i] << "; y=" << yPlot[i] << endl;
}
this->updateGraph();
// also, connect stuff
connect( this->pushButton, SIGNAL(clicked()), this, SLOT(synchronous()) );
return;
}
Now, this part works as it should. The result is something like this:
Later, I connected the pushButton to a method that should add 10 points to the curve and replot it. The relevant methods are:
void ExampleMainWindow::synchronous()
{
cout << "Creating 10 new data points..." << endl;
for(unsigned int i = 0; i < 10; i++) this->createDataPoint();
cout << "xPlot.size() = " << xPlot.size() << " ; yPlot.size() = " << yPlot.size() << endl;
this->updateGraph();
return;
}
void ExampleMainWindow::updateGraph()
{
// detach everything?
this->qwtPlot->detachItems();
// create a new curve
QwtPlotCurve* curve = new QwtPlotCurve("curve 1");
curve->setSamples( QVector<double>::fromStdVector( xPlot ), QVector<double>::fromStdVector( yPlot ) );
curve->attach( this->qwtPlot );
this->qwtPlot->replot();
//this->qwtPlot->show();
return;
}
Now, the issue is that pressing the pushButton on the GUI does not visually change anything in the QwtPlot. I am sure the program enters synchronous when the pushButton is clicked. So, there is probably something wrong with the function updateGraph, but I am missing something, as I cannot find the issue.
When I compile the project, I use Qt 4.8.6, with
qmake-qt4
make
and I get no compiling errors. My Qt project file is:
TEMPLATE = app
TARGET = example
QT += widgets
CONFIG += qwt
QMAKE_CXXFLAGS += -std=c++11
DEPENDPATH += ../. \
# for Qwt
/usr/local/qwt-6.1.3-svn/lib \
/usr/local/qwt-6.1.3-svn/include
# end for Qwt
INCLUDEPATH += ../. \
# for Qwt
/usr/local/qwt-6.1.3-svn/include
# end for Qwt
LIBS += -lqwt \
-L/usr/local/qwt-6.1.3-svn/lib
# Input
FORMS += example.ui
HEADERS = ExampleMainWindow.h
SOURCES = ExampleMainWindow.cpp \
main.cpp
Even looking at the examples I found online, I am unable to find the problem. Can you help me?
Thanks in advance for your support :-)
EDIT: The phrase pointing out the issue was cut out by mistake.
Ok, after several trials and errors, I found a solution: I installed Qwt (I guess 6.0) through Ubuntu's Software Center, and removed all the other Qwt versions (6.1.2 and 6.1.3) that I had manually installed. Now, the small GUI is working properly.
I guess the error was due to some issue in the paths I provided in the .pro file, but I could not pinpoint the exact mistake. Not really a satisfying answer, but at least it works.

QProcess fails to execute a simple console program

I compiled a c++ source file from the Qt app I am creating. Now I want to run the exe file generated and also to redirect its input and output to txt files. But when I try to run it from QProcess, it fails to execute with exit code -2.
This is how I compiled the file using QProcess -
arguments << fileName << "-o" << exeFileName << "-static";
connect(compileProcess, SIGNAL(finished(int)), this, SLOT(compiled()));
compileProcess->start(QString("g++"), arguments);
And this is how I run the exe from QProcess in the slot compiled() -
runProcess->setStandardInputFile(inputFilename);
runProcess->setStandardOutputFile(QFileInfo(exeFileName).path() + "/output.txt");
int code = runProcess->execute(exeFileName); //code = -2
The program runs fine when I start it manually. So, why can't it be started from QProcess?
I am working with Qt 5.0.2 on Windows 7
This is the source file I am compiling -
#include <iostream>
int main() {
std::string s;s
std::cin >> s;
std::cout << s;
return 0;
}
I finally got it to work. The exe file path had spaces in it and Qt did not implicitly add quotes around it. Adding quotes explicitly did the job.
runProcess->start("\"" + exeFileName + "\"");

Loading .png Image file with Allegro 5

I am writing a game in allegro and would like to load some image files. However, whenever I call al_load_bitmap, I am getting a null pointer. I am using XCode 4.1 as my IDE. I would try compiling using g++ (in case it is a path issue) however I don't know what I need to do in order to compile it in the command line with g++ (simply g++ main.cpp does not work). Anyways, here is my code:
ALLEGRO_PATH *path = al_get_standard_path(ALLEGRO_RESOURCES_PATH);
for (int i = 0; i < NUM_TILES; i++)
{
switch (static_cast<Tile>(i)) {
case GRASS:
al_set_path_filename(path, "grass.png");
tileFiles[i] = al_load_bitmap(al_path_cstr(path, '/'));
if (!tileFiles[i])
{
std::cerr<<"grass.png not initialized"<<std::endl;
}
break;
case DIRT:
al_set_path_filename(path, "dirt.png");
tileFiles[i] = al_load_bitmap(al_path_cstr(path, '/'));
if (!tileFiles[i])
{
std::cerr<<"dirt.png not initialized"<<std::endl;
}
break;
default:
std::cerr
<< "Missing case statement for datatype Tile numbered at "
<< i
<< " in Board::Board (float mw, float mh, int tst)"
<< " declared in Board.cpp."
<< std::endl;
break;
}
}
I have already run:
if(!al_init_image_addon()) {
al_show_native_message_box(display, "Error", "Error", "Failed to initialize al_init_image_addon!",
NULL, ALLEGRO_MESSAGEBOX_ERROR);
return -1;
}
and I have also put:
#include "allegro5/allegro_image.h"
#include "allegro5/allegro_native_dialog.h"
at the top of my file. Neither grass.png, nor dirt.png load and they are in the exact same directory as my main.cpp file. I get no compilation errors, but I consistently get the null pointer when I try to load my images, so when it comes time to draw them to the display, they do not show. Please help!
Neither grass.png, nor dirt.png load and they are in the exact same directory as my main.cpp file
Just a debugging tip... If you were to output the result of al_path_cstr(path, '/') to the console, it should be extremely obvious why the call is failing.
ALLEGRO_RESOURCES_PATH is the location of "bundled resources," which on OS X means the directory of the executable file. (If you were to use an app bundle, then it would be the resource folder of the bundle.) As a quick check, just copy the images into the same directory that your executable file is being built.
Most IDEs have very odd directory structures, IMO. I would ultimately set it up so that you are building into something like:
/src/main.c
/include/main.h
/obj/release
/obj/debug
/bin/game.exe
/bin/game-debug.exe
/bin/image.png
But that's just my preference. Use whatever you like, but you should read the docs again to get a clear picture of the different locations that al_get_standard_path() reveals.
Okay, I had been having the same problem, and I was absolutely positive that I was looking in the correct directory and that the resources for the program were there. I used al_path_cstr(path, '/') and allegro's working directory was as expected. Then I looked at the resource file sizes....
All my resources in my build directory were zero bytes. Copied them over myself and it solved the issue. I hope this helps some one out!