I have integrated Root into a program that reads data from a DAQ device. The program continuously collects data within a while loop. I want to implement a feature where pressing the “P” key toggles the display of a plot window. In other words, pressing “P” should open the plot window, and pressing “P” again should close it. This almost works but the challenge I’m facing is figuring out how to close the plot window without terminating the entire program. The outline of the code looks like this:
TApplication app("app", nullptr, nullptr);
TCanvas* canvas = nullptr;
bool isCanvasOpen = false;
while(true){ // data readout loop
if (p_key_active){
if (!isCanvasOpen){
canvas = new TCanvas("canvas", "My Canvas", 800, 600);
isCanvasOpen = true;
}
///////////////////
// PLOTTING STUFF //
////////////////////
} else {
if (isCanvasOpen) {
canvas->Close();
isCanvasOpen = false;
}
This closes the canvas of the plot properly; however, it leaves a blank Root application window. If I use the Terminate() function to close this window, it shuts down the entire program, which is not the desired behavior. I’m now considering whether I actually need to use the TApplication component. But without it, nothing is displayed at all. I’m looking for guidance on how to properly handle the closing of the plot window without affecting the rest of the program’s functionality.
EDIT: This is the full plotting loop:
TApplication app("app", nullptr, nullptr);
TCanvas* canvas = nullptr;
bool isCanvasOpen = false;
while(true){
if (p is active){
if (!isCanvasOpen){
canvas = new TCanvas("canvas", "My Canvas", 800, 600);
isCanvasOpen = true;
}
TMultiGraph* multiGraph = new TMultiGraph();
for (int i = 0; i < numberofplots; i++){
TGraph* graph = new TGraph(......);
for (int j = 0; j < numberofpoints; j++){
graph->SetPoint(...........);
}
multiGraph->Add(graph);
}
multiGraph->Draw("A PLC");
canvas->Modified();
canvas->Update();
delete multiGraph;
}
} else {
if (isCanvasOpen) {
canvas->Close();
isCanvasOpen = false;
}
...
Now this shows the plots. Removing TApplication, the code still runs but no plots are displayed. Also adding gSystem->ProcessEvents(); does not help. I assume the TApplication sets some important things automatically which I have to set manually.
Hi, thanks for the answer. Unfortunately this does not resolve the issue. This does not close the plotting window and the last plotted multigraph stays on display.
I am trying to get a minimal working example but funny enough this program doesn’t even draw the plots, so again a different behavior. But maybe if this program is fixed I’ll have an answer:
#include <TApplication.h>
#include <TCanvas.h>
#include <TMultiGraph.h>
#include <TGraph.h>
#include <TRootCanvas.h>
#include <chrono>
#include <thread>
#include "TPad.h"
int main() {
TApplication app("app", nullptr, nullptr);
TCanvas* canvas = nullptr;
bool isCanvasOpen = false;
while (true) {
if (!isCanvasOpen) {
isCanvasOpen = true;
canvas = new TCanvas("canvas", "My Canvas", 800, 600);
}
TMultiGraph* multiGraph = new TMultiGraph();
for (int i = 0; i < 5; i++) {
TGraph* graph = new TGraph(500);
for (int j = 0; j < 500; j++) {
double random = 1.0 + (rand() % 9); // Generate a random number between 1 and 9
graph->SetPoint(j, j, random);
}
multiGraph->Add(graph);
}
multiGraph->Draw("A PLC");
canvas->Modified();
canvas->Update();
std::this_thread::sleep_for(std::chrono::seconds(2));
delete multiGraph;
if (isCanvasOpen) {
isCanvasOpen = false;
canvas->Close();
}
std::this_thread::sleep_for(std::chrono::seconds(2));
}
return 0;
}
What I expect:
A plot of my graphs displayed for 2 seconds. The window closing and being closed for 2 seconds, before the next plot opens and is displayed for 2 seconds again and so on.
What i get:
A blank canvas displayed for 4 seconds, closing and immediately an new blank canvas showing and so on.
I tried your “minimal” code on Ubuntu 22.04 on WSL (Windows 10) and I do get a plot on the canvas, it then closes and reopens, draws, etc. in a loop (to stop it I had to crtl+c to kill ROOT, and ROOT complained at the beginning with “Error in TApplication::TApplication: only one instance of TApplication allowed”).
I used ROOT 6.26/10.
Hey thank you. It is very strange. I have tested @Wile_E_Coyote 's solution on two different distros now.
On my Ubuntu machine it still does not work. At least now the blank canvas is shown for 2 seconds, then it closes, reopens after 2 seconds and so on. But no plots to be seen.
Funnily, when I run the macro in a root session it still does not work, but when I kill the macro with Ctrl + C suddenly one plot gets drawn and stays on display.
I also tried it on an older Debian distro and there it works as intended.
When testing my earlier minimal example on the debian machine, it again shows a different behavior: The canvas with the plot opens, the plot disappears after 2 seconds leaving a blank canvas. The plot redraws on the canvas and after 2 seconds and so on.
Ok unfortunately I do not know what this means and/or how to change something.
But I found something else interesting.
I suspect ist has something to do with the fact that the canvas opens and the plot only is drawn on it AFTER 2 seconds. Because when I run this macro:
void plotmacro() {
TCanvas* canvas = new TCanvas("canvas", "My Canvas", 800, 600);
TMultiGraph* multiGraph = new TMultiGraph();
for (int i = 0; i < 5; i++) {
TGraph* graph = new TGraph(500);
for (int j = 0; j < 500; j++) {
double random = 1.0 + (rand() % 9); // Generate a random number between 1 and 9
graph->SetPoint(j, j, random);
}
multiGraph->Add(graph);
}
gROOT->SetSelectedPad(canvas->cd(0)); // for the DrawClone below
multiGraph->DrawClone("A PLC");
canvas->Modified(); canvas->Update();
std::this_thread::sleep_for(std::chrono::seconds(2));
}
It is exactly what happens. So somehow this sleep command messes things up. Also when I remove the first 2 second sleep command from @Wile_E_Coyote 's solution no canvas at all is showing up. Very strange stuff happening.