How to properly reset canvas and everything in it for reuse?


Please read tips for efficient and successful posting and posting code

ROOT Version: 6.24.06
Platform: macOS arm64
Compiler: clang


I have written a ROOT function to study the effect of different cuts on a histogram. At the moment, the function looks like this:

void makeXavgHist(std::string fileName, TTree* tree, TCutG* cut1, TCutG* cut2, TCutG* cut3, TCutG* cut4) {
    TCanvas* c2 = new TCanvas("c2", "Xavg Histogram w Cuts", 200, 10, 800, 900);
    gStyle->SetOptStat();
    TString totalCut = Form("%s && %s && %s && %s", cut1->GetName(), cut2->GetName(), cut3->GetName(), cut4->GetName());
    TH1F* xavgHist = new TH1F("h1", "xavg Histogram w Cuts", 600, -300, 300);
    tree->Draw("xavg>>h1(600,-300,300)", totalCut);

    c2->Update();
    gPad->WaitPrimitive();
    
    TFile* outFile = new TFile(Form("./cuts/%s_%s_%s_%s_%s", cut1->GetName(), 
                                                             cut2->GetName(), 
                                                             cut3->GetName(), 
                                                             cut4->GetName(), fileName.c_str()), "RECREATE");
    cut1->Write();
    cut2->Write();
    cut3->Write();
    cut4->Write();
    xavgHist->Write();
    outFile->Close();
    
    gStyle->SetOptStat(0);
    gROOT->Reset();
    c2->Close();
    gSystem->ProcessEvents();
}

Somewhere else in my program, there are nested for loops that are responsible for passing different combinations of cuts to the function. What I found is that, after the first call to the function, no matter what cuts I pass into the function, the histogram always comes out the same.

Try first moving the TFile line to the top (even before the TCanvas line, just to be safe).

void makeXavgHist( ...
  TFile *...
  TCanvas *...
...

If it still doesn’t work it would be better to show the rest of the code, or provide a running example that shows the problem. Also I think you don’t need several of the lines you have (Update, WaitPrimitive, SetOptStat to 1 then 0, Reset, ProcessEvents), but maybe you are doing other stuff we don’t see here.

Begin your function with:

gROOT->cd(); // newly created histograms should go here
delete gROOT->FindObject("c2"); // prevent "memory leak"
TCanvas *c2 = new TCanvas("c2", ...);
delete gROOT->FindObject("h1"); // prevent "memory leak"
TH1F *xavgHist = new TH1F("h1", ...);

Replace:
tree->Draw("xavg>>h1(600,-300,300)", totalCut);
with:
tree->Draw("xavg >> h1", totalCut);

Leave “TFile *outFile = new TFile(...);” where it is now.

Replace:
outFile->Close();
with:
delete outFile;

End your function with:

// cleanup
delete xavgHist;
delete c2;

Thank you for the replies! I have tried both suggestions, but I’m still seeing the same symptoms. Here is the rest of my code:

void makeXavgHist(std::string fileName, TTree* tree, TCutG* cut1, TCutG* cut2, TCutG* cut3, TCutG* cut4) {

    gROOT->cd(); // newly created histograms should go here
    delete gROOT->FindObject("c2"); // prevent "memory leak"
    TFile* outFile = new TFile(Form("./cuts/%s_%s_%s_%s_%s", cut1->GetName(), 
                                                             cut2->GetName(), 
                                                             cut3->GetName(), 
                                                             cut4->GetName(), fileName.c_str()), "RECREATE");
    TCanvas* c2 = new TCanvas("c2", "Xavg Histogram w Cuts", 200, 10, 800, 900);
    TString totalCut = Form("%s && %s && %s && %s", cut1->GetName(), cut2->GetName(), cut3->GetName(), cut4->GetName());
    delete gROOT->FindObject("h1"); // prevent "memory leak"
    TH1F* xavgHist = new TH1F("h1", "xavg Histogram w Cuts", 600, -300, 300);
    tree->Draw("xavg>>h1", totalCut);
    c2->Update();
    gPad->WaitPrimitive();    
    cut1->Write();
    cut2->Write();
    cut3->Write();
    cut4->Write();
    xavgHist->Write();
    delete outFile;    
    gStyle->SetOptStat(0);
    c2->Close();
    gSystem->ProcessEvents();
    delete xavgHist;
    delete c2;

}

int main(int argc, char* argv[]) {
    if (argc < 2) {
        printf("Input file is needed!!\n");
        return -1;
    }
    
    int argcROOT = 1;
    char* argvROOT = argv[0];
    TApplication theApp("App", &argcROOT, &argvROOT);

    TString inputFile = argv[1];
    TFile* inFile = new TFile(inputFile, "READ");
    TTree* tree = static_cast<TTree*>(inFile->Get("DataTree"));
    TCanvas* c1 = new TCanvas("c1", "For Cut Making", 200, 10, 1000, 900);
    c1->ToggleToolBar();
    gStyle->SetOptStat(0);

    int color = 16;
    TPad* pad1 = new TPad("pad1", "Pad1", 0.03, 0.55, 0.50, 0.98, color);
    TPad* pad2 = new TPad("pad2", "Pad2", 0.51, 0.55, 0.98, 0.98, color);
    TPad* pad3 = new TPad("pad3", "Pad3", 0.03, 0.02, 0.50, 0.54, color);
    TPad* pad4 = new TPad("pad4", "Pad4", 0.51, 0.02, 0.98, 0.54, color);
    pad1->Draw(); pad1->SetLogz();
    pad2->Draw(); 
    pad3->Draw(); 
    pad4->Draw(); 
    c1->Update();

    std::vector<std::string> cutTypes{"EdE", "xdE", "xE", "xx"};
    int numOfCuts = cutTypes.size();

    std::unordered_map<std::string, std::string> cutTypesToDataType;
    cutTypesToDataType[cutTypes[0]] = "anodeBack:scintLeft>>EdE(100,0,1000,512,0,4096)";
    cutTypesToDataType[cutTypes[1]] = "0.5*(delayBackRightE+delayBackLeftE):xavg>>xdE(600,-300,300,512,0,4096)";
    cutTypesToDataType[cutTypes[2]] = "scintLeft:xavg>>xE(600,-300,300,200,0,2000)";
    cutTypesToDataType[cutTypes[3]] = "x1:x2>>xx(600,-300,300,600,-300,300)";

    pad1->cd();
    tree->Draw(cutTypesToDataType[cutTypes[0]].c_str(), "", "colz");
    pad2->cd();
    tree->Draw(cutTypesToDataType[cutTypes[1]].c_str(), "", "colz");
    pad3->cd();
    tree->Draw(cutTypesToDataType[cutTypes[2]].c_str(), "", "colz");
    pad4->cd();
    tree->Draw(cutTypesToDataType[cutTypes[3]].c_str(), "", "colz");
    c1->Update();

    for (int i = 0; i < numOfCuts; i++) {
        pad1->cd();
        tree->Draw(cutTypesToDataType[cutTypes[i]].c_str(), "", "colz");
        gPad->Modified();
        gPad->Update();
        gPad->WaitPrimitive();
        TCutG* Cut1 = (TCutG*)gROOT->GetListOfSpecials()->FindObject("CUTG");
        TString cutName1 = Form("%sCut", cutTypes[i].c_str());
        Cut1->SetName(cutName1);
        for (int j = 0; j < numOfCuts; j++) {
            if (j == i) continue;
            pad2->cd();
            tree->Draw(cutTypesToDataType[cutTypes[j]].c_str(), cutName1, "colz");
            gPad->Modified();
            gPad->Update();
            gPad->WaitPrimitive();
            TCutG* Cut2 = (TCutG*)gROOT->GetListOfSpecials()->FindObject("CUTG");
            TString cutName2 = Form("%sCut", cutTypes[j].c_str());
            Cut2->SetName(cutName2);
            for (int k = 0; k < numOfCuts; k++) {
                if (k == j || k == i) continue;
                pad3->cd();
                tree->Draw(cutTypesToDataType[cutTypes[k]].c_str(), cutName1 + " && " + cutName2, "colz");
                gPad->Modified();
                gPad->Update();
                gPad->WaitPrimitive();
                TCutG* Cut3 = (TCutG*)gROOT->GetListOfSpecials()->FindObject("CUTG");
                TString cutName3 = Form("%sCut", cutTypes[k].c_str());
                Cut3->SetName(cutName3);
                for (int l = 0; l < numOfCuts; l++) {
                    if (l == k || l == j || l == i) continue;
                    pad4->cd();
                    tree->Draw(cutTypesToDataType[cutTypes[l]].c_str(), cutName1 + " && " + cutName2 + " && " + cutName3, "colz");
                    gPad->Modified();
                    gPad->Update();
                    gPad->WaitPrimitive();
                    TCutG* Cut4 = (TCutG*)gROOT->GetListOfSpecials()->FindObject("CUTG");
                    TString cutName4 = Form("%sCut", cutTypes[l].c_str());
                    Cut4->SetName(cutName4);
                    makeXavgHist(argv[1], tree, Cut1, Cut2, Cut3, Cut4);
                    pad4->cd(); pad4->Clear();
                }
                pad3->cd(); pad3->Clear();
            }
            pad2->cd(); pad2->Clear();
        }
        pad1->cd(); pad1->Clear();
    }

    theApp.Run();

    return 0;
}

Move “TFile *outFile = new TFile(...);” to right before “cut1->Write();”.

Try to dump the cuts inside of your function (maybe they are always the same).

When I try to dump the cuts (with delete or clear) inside of the function, the program crashes right after h1 is closed. So, I delete the cuts within the for loop instead (right before I clear the pads), and it works! Thank you for the suggestions. I checked the cuts originally to make sure, and they clearly show different cuts in the saved files, but this seems to imply that maybe the cuts are always the same.

I guess the problem was that you passed “distinct” pointers to cuts to your function, but then the “totalCut” used only their names. If there were many cuts with the same name, the first created was “found” and used in the “Draw”. So, deleting them after usage ensured that only one cut with a particular name was always present (i.e., the newly created ones).

BTW. By “dump” I meant “print” (“dump the contents”), not “delete” or “clear”.

1 Like

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