Execute graphics event loop before the end of the program?

Hi all,

I wish to run following script and plot my data templorarily and play with it in the interactive canvas before its destroyed and then continue forward confirming with enter in the terminal.

Is there any workaround which allows to do that?

//test.cpp
// root test.cpp

void test(){
    TCanvas* canvas = new TCanvas("c", "c", 800, 800);
    TH1F* h = new TH1F();
    h->Draw();
    std::cout<<"I want to plot my juicy data right now."<<std::endl;
    std::cin.get();
    std::cout<<"Oh no! My data is destroyed already :("<<std::endl;
}
void fw(){
    TCanvas* canvas = new TCanvas("c", "c", 800, 800);
    TH1F* h = new TH1F();
    h->Draw();
    std::cout<<"I want to plot my juicy data right now."<<std::endl;
    canvas->Modified();
    canvas->Update();
    gSystem->ProcessEvents(); // needed on MAc
    std::cin.get();
    std::cout<<"Oh no! My data is destroyed already :("<<std::endl;
}

The script worked for me.

But unfortunately, I use these lines in a larger program, where these lines are compiled into the library.

And I realised that this doesn’t work for compiled programs?

g++ -o test `root-config --cflags --glibs` test.cpp

with slightly modified test.cpp

#include <iostream>
#include "TCanvas.h"
#include "TH1F.h"
#include "TSystem.h"
int main(){
    TCanvas* canvas = new TCanvas("c", "c", 800, 800);
    TH1F* h = new TH1F();
    h->Draw();
    std::cout<<"I want to plot my juicy data right now."<<std::endl;
    canvas->Modified();
    canvas->Update();
    gSystem->ProcessEvents(); // needed on MAc
    std::cin.get();
    std::cout<<"Oh no! My data is destroyed already :("<<std::endl;
    return 0;
}
./test

And I don’t see the window pop-up…

To convert a ROOT macro into a standalone application you should follow what is explained here.

1 Like

Thanks for the link @couet !
It works, but when I close the canvas it kills the entire program.

Is there way to let the main progra to continue to run?
Ideally I would like to plot multiple plots like this calling the utility function in the loop of the main program.

So far this:

#include "TF1.h"
#include "TApplication.h"
#include "TCanvas.h"
#include "TRootCanvas.h"

int main(int argc, char **argv){
    TApplication app("app", &argc, argv);
    TCanvas* c = new TCanvas("c", "Something", 0, 0, 800, 600);
    TF1 *f1 = new TF1("f1","sin(x)", -5, 5);
    f1->SetLineColor(kBlue+1);
    f1->SetTitle("My graph;x; sin(x)");
    f1->Draw();
    std::cout<<"I want to plot my juicy data right now."<<std::endl;
    c->Modified(); c->Update();
    TRootCanvas *rc = (TRootCanvas *)c->GetCanvasImp();
    rc->Connect("CloseWindow()", "TApplication", gApplication, "Terminate()");
    app.Run();
    std::cout<<"Oh no! My data is destroyed already :("<<std::endl;
    return 0;
}

g++ test.cpp $(root-config --glibs --cflags --libs) -o test

doesn’'t reach the std::cout<<"Oh no! My data is destroyed already :("<<std::endl;

So basically you want to have something similar to ROOT itself. In that case take inspiration from the ROOT main program: root/main/src/rmain.cxx at master · root-project/root · GitHub

Use app.SetReturnFromRun(true); before calling app.Run();

1 Like

I have tried both app.SetReturnFromRun(true); and using TRint.

I am still unable to make the program alive after the app.Run() :confused:

OK, I’ll try later and let you know (and TRint is unrelated, forget about it)

Thanks.

Maybe for more complete picture if this is more useful, I want to do something like this:

//main.cpp
#include <iostream>

// this is a helper function to draw something using ROOT.
// It is in utility library and will be linked later.
void sinFunctionDrawer(int i);

struct MyMarlinProcessor{
    void init(){
        std::cout<<"Init is called."<<std::endl;
    };
    void processEvent(int i ){
        if (i % 2 == 0) std::cout<<"Even number. Good."<<std::endl;
        else{
            std::cout<<"Odd number detected. Imidiately draw a sin function. And hopefully it will allow me to go to the next event."<<std::endl;

            sinFunctionDrawer(i);
        }
    };
};


// this is the main program with its own complicated framework (Marlin), which executes physical (with data) event loop.
int main(int argc, char **argv){

    MyMarlinProcessor proc;
    proc.init();

    for (int i = 0; i < 42; i++) proc.processEvent(i);

    return 0;
}
//sinFunctionDrawer.cpp
#include "TF1.h"
#include "TApplication.h"
#include "TRint.h"
#include "TCanvas.h"
#include "TRootCanvas.h"

void sinFunctionDrawer(int i){

    int argc{};
    char** argv{};
    TApplication app = TApplication("app", &argc, argv);
    TCanvas* c = new TCanvas("c", "Something", 0, 0, 800, 600);
    TF1 *f1 = new TF1("f1","sin(x)", -5, 5);
    f1->SetLineColor(kBlue+1);
    f1->SetTitle("My graph;x; sin(x)");
    f1->Draw();
    c->Modified(); c->Update();
    TRootCanvas *rc = (TRootCanvas *)c->GetCanvasImp();
    rc->Connect("CloseWindow()", "TApplication", gApplication, "Terminate()");
    app.Run(true);

    std::cout<<"I made a nice sin function and ready to go to the next event:"<< i+1 <<std::endl;

    return;
}

Compile and run:

g++ main.cpp sinFunctionDrawer.cpp $(root-config --glibs --cflags --libs) -o main
./main

Output:

Init is called.
Even number. Good.
Odd number detected. Imidiately draw a sin function. And hopefully it will allow me to go to the next event.
I made a nice sin function and ready to go to the next event:1
Even number. Good.
Odd number detected. Imidiately draw a sin function. And hopefully it will allow me to go to the next event.
Error in <TApplication::TApplication>: only one instance of TApplication allowed

 *** Break *** segmentation violation

Use app.Run(true);:

C:\Users\bellenot\rootdev\forum\FoxWise>main
I want to plot my juicy data right now.
Oh no! My data is destroyed already :(

C:\Users\bellenot\rootdev\forum\FoxWise>
1 Like

Thanks!

Although for the event loop example above it complains:
Error in <TApplication::TApplication>: only one instance of TApplication allowed

So I assume return doesn’t kill the instance which is stored somewhere internaly?

Creating and deleting applications is definitively not a good approach. Try something like this:

//main.cpp
#include "TApplication.h"
#include <iostream>

// this is a helper function to draw something using ROOT.
// It is in utility library and will be linked later.
void sinFunctionDrawer(int i);

struct MyMarlinProcessor {
    void init() {
        std::cout<<"Init is called."<<std::endl;
    };
    void processEvent(int i) {
        if (i % 2 == 0) std::cout<<"Even number. Good."<<std::endl;
        else{
            std::cout<<"Odd number detected. Imidiately draw a sin function. And hopefully it will allow me to go to the next event."<<std::endl;
            sinFunctionDrawer(i);
        }
    };
};

// this is the main program with its own complicated framework (Marlin), which executes physical (with data) event loop.
int main(int argc, char **argv)
{
    TApplication app = TApplication("app", &argc, argv);
    MyMarlinProcessor proc;
    proc.init();
    for (int i = 0; i < 42; i++) proc.processEvent(i);
    app.Run(true);
    return 0;
}

and

//sinFunctionDrawer.cpp
#include "TF1.h"
#include "TCanvas.h"
#include "TSystem.h"

void sinFunctionDrawer(int i) {
    TCanvas* c = new TCanvas("c", "Something", 0, 0, 800, 600);
    TF1 *f1 = new TF1("f1","sin(x)", -5, 5);
    f1->SetLineColor(kBlue+1);
    f1->SetTitle("My graph;x; sin(x)");
    f1->Draw();
    c->Modified(); c->Update();
    while (!gSystem->ProcessEvents()) {
        gSystem->Sleep(20);
    }
    std::cout<<"I made a nice sin function and ready to go to the next event:"<< i+1 <<std::endl;
    return;
}

And you can simply plot the next event by selecting the Canvas Option → Interrupt menu entry. There are more solutions (more or less complex), but at least that give you an idea…

1 Like

Thanks a lot!
Not so elegant, but it does the job.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.