Issue with creating TCanvas and drawing histograms

ROOT Version: 6.34.02
Platform: win64 (Windows 11)
Compiler: MSVC 19.39.33521.0


I am attempting to make some mass distribution histograms of the phi meson for 4 different beam polarizations and 10 t-ranges. I have defined these 40 histograms both using a nested loop and a stringstream so that each histogram has an easy-to-understand name and title.

Ultimately, I want to have a single canvas with a total of 10 pads so that all 4 polarization angles are displayed on the same graph with the corresponding t-range kind of like this crude drawing:

When drawing the histograms, the code runs as normal with now issues, but instead of a CMake window popping up, the ROOT icon appears on my taskbar, then after a couple seconds ROOT closes.

I ran another macro with a similar structure as this one and all the histograms were drawn as normal. I can’t seem to find where the problem is in my code.

void phiMass_t_pol_cut() {
    TFile *filein = new TFile("flat_pi0pippim__B4_cut.root");
    TTree *tree = (TTree *)filein->Get("pi0pippim__B4_cut");

    UInt_t run;
    Int_t pol;
    float tagWeight, Mandelstam_t;

    TLorentzVector *pim_p4_kin = 0;
    TLorentzVector *pip_p4_kin = 0;
    TLorentzVector *decaypi0_p4_kin = 0;

    tree->SetBranchAddress("decaypi0_p4_kin", &decaypi0_p4_kin);
    tree->SetBranchAddress("pim_p4_kin", &pim_p4_kin);
    tree->SetBranchAddress("pip_p4_kin", &pip_p4_kin);

    tree->SetBranchAddress("run", &run);
    tree->SetBranchAddress("tagWeight", &tagWeight);
    tree->SetBranchAddress("pol", &pol);
    tree->SetBranchAddress("Mandlestam_t", &Mandelstam_t);

    //define the histograms loop

    int polValues[4] = {0, 90, 45, 135};
    ostringstream histName, histTitle;

    int t_bins = 10;

    TH1F *h_PhiMass_pol_t_[4][10];
    for (int i : polValues) {
        for (int j = 0; j < t_bins; j++) {
            
            histName.str("");
            histName << "h_PhiMass_pol" << i << "_t" << std::setw(2) << std::setfill('0') << j << std::setw(2) << std::setfill('0') << j + 1;
            //cout << histName.str() << endl;

            float t_lower = j * 0.1;
            float t_upper = (j + 1) * 0.1;

            histTitle.str("");
            histTitle << std::fixed << std::setprecision(2) << t_lower << " < -t < " << t_upper << ";M(#phi) [GeV/c^{2}]";
            //cout << histTitle.str() << endl;
            //cout << i << endl;

            h_PhiMass_pol_t_[i][j] = new TH1F(histName.str().c_str(), histTitle.str().c_str(), 100, 0.9, 1.2);
        }
    }

    TStyle *dStyle = new TStyle("JLab_Style", "JLab_Style");
    dStyle->Reset("Modern");

    TLorentzVector Pi0P4, PiMinusP4, PiPlusP4, PhiP4;

    Long64_t NEntries = tree->GetEntries();

    cout << "There are " << NEntries << " entries." << endl;

    for (Long64_t i_entry = 0; i_entry < NEntries; i_entry++) {
        
        tree->GetEntry(i_entry);

        if (i_entry % 400000 == 0) {
            cout << i_entry << " events processed" << endl;
        }

        PiMinusP4.SetPxPyPzE(pim_p4_kin->Px(), pim_p4_kin->Py(), pim_p4_kin->Pz(), pim_p4_kin->E());
        PiPlusP4.SetPxPyPzE(pip_p4_kin->Px(), pip_p4_kin->Py(), pip_p4_kin->Pz(), pip_p4_kin->E());
        Pi0P4.SetPxPyPzE(decaypi0_p4_kin->Px(), decaypi0_p4_kin->Py(), decaypi0_p4_kin->Pz(), decaypi0_p4_kin->E());

        PhiP4 = PiMinusP4 + PiPlusP4 + Pi0P4;

        double PhiMass = PhiP4.M();

        //fill the histograms loop
        for (int i : polValues) {
            for (int j = 0; j < t_bins; j++) {

                float t_lower = j * 0.1;
                float t_upper = (j + 1) * 0.1;

                if (pol == i) {
                    if (-Mandelstam_t > t_lower && -Mandelstam_t < t_upper) {
                        h_PhiMass_pol_t_[i][j]->Fill(PhiMass, tagWeight);
                    }
                }
            }
        }
    }

    // Size & Margins
    dStyle->SetCanvasDefH(800);
    dStyle->SetCanvasDefW(1200);

    // Basic object fill colors
    dStyle->SetCanvasBorderMode(0);
    dStyle->SetLegendFillColor(0);
    dStyle->SetCanvasColor(0);

    // Stat box
    dStyle->SetOptFit(112);
    dStyle->SetOptStat(10); // entries only //mean/rms should be replaced with a fit

    // Titles and Labels
    dStyle->SetLabelSize(0.07, "xyz");
    dStyle->SetTitleSize(0.075, "xyz");
    dStyle->SetTitleOffset(1.1, "x");
    dStyle->SetTitleOffset(0.8, "y");

    // Margins (correlated with title/label size)
    dStyle->SetPadBottomMargin(0.15);

    // Default Histogram Style Settings
    // dStyle->SetHistFillColor(kTeal);
    dStyle->SetHistFillStyle(1001); // solid fill (0 for hollow) //see http://root.cern.ch/root/html/TAttFill.html
    dStyle->SetHistLineColor(kBlack);
    dStyle->SetHistMinimumZero(kTRUE);

    // Default Function Style Settings
    dStyle->SetFuncColor(kBlack);
    dStyle->SetFuncStyle(1); // see http://root.cern.ch/root/html/TAttLine.html
    dStyle->SetFuncWidth(3);

    // Default Line Style Settings
    dStyle->SetLineColor(kBlack);
    dStyle->SetLineStyle(1); // see http://root.cern.ch/root/html/TAttLine.html
    dStyle->SetLineWidth(1); // is border of TLegend

    // Default Graph Style Settings
    dStyle->SetMarkerColor(kBlack);
    dStyle->SetMarkerSize(1);   // see http://root.cern.ch/root/html/TAttMarker.html
    dStyle->SetMarkerStyle(22); // see http://root.cern.ch/root/html/TAttMarker.html

    // Grid
    dStyle->SetPadGridX(kTRUE);
    dStyle->SetPadGridY(kTRUE);

    // Histogram/Graph Title Size
    dStyle->SetTitleSize(0.075, "t"); //"t": could be anything that is not "x" "y" or "z"

    // Palette
    dStyle->SetNumberContours(200);
    #if ROOT_VERSION_CODE >= ROOT_VERSION(6, 0, 0)
        dStyle->SetPalette(kBird); // 57
    #else
        dStyle->SetPalette(55); // rainbow
    #endif
        dStyle->cd();
        TLatex ytitle;
        TLatex maintitle;
        TLatex xtitle;
        xtitle.SetTextFont(42);
        ytitle.SetTextFont(42);
        gStyle->SetOptStat(0000);


    TCanvas *c1 = new TCanvas("c1", "Phi Masses", 800, 600);
    c1->Divide(5, 2);
    c1->cd(1);
    h_PhiMass_pol_t_[0][0]->Draw();


   /* for (int i : polValues) {
        for (int j = 0; j < t_bins; j++) {
            c1->cd(j + 1);
            if (i == 0) {
                h_PhiMass_pol_t_[i][j]->SetMarkerColor(kBlack);
                h_PhiMass_pol_t_[i][j]->SetMarkerStyle(20);     //circle
            }

            if (i == 90) {
                h_PhiMass_pol_t_[i][j]->SetMarkerColor(kRed);
                h_PhiMass_pol_t_[i][j]->SetMarkerStyle(21);    //square
            }

            if (i == 45) {
                h_PhiMass_pol_t_[i][j]->SetMarkerColor(kBlue);
                h_PhiMass_pol_t_[i][j]->SetMarkerStyle(22);  //triangle
            }

            if (i == 135) {
                h_PhiMass_pol_t_[i][j]->SetMarkerColor(kGreen);
                h_PhiMass_pol_t_[i][j]->SetMarkerStyle(34);  //plus
            }
            
            h_PhiMass_pol_t_[0][0]->Draw();

        }
    }*/
}

Hello @jbrom,

I would suggest to try first with 1 histogram to try to isolate the problem! Let me know what’s the output in that case.

Cheers,
Monica

I have commented out all of the “loop histograms” and defined:

TH1F *h_phimass_pol0_t0001_test = new TH1F("h_phimass_pol0_t0001_test", "title", 100, 0.9, 1.2);

filled it with:

if (pol == 0) {
            if (-Mandelstam_t > 0.0 && -Mandelstam_t < 0.1) {
                h_phimass_pol0_t0001_test->Fill(PhiMass, tagWeight);
            }
        }

and still the same issue

How are you running it? compiled? in the interactive prompt?.. And is this a stand-alone macro (run by itself), or part of a larger macro, etc? Try first removing all the stuff that’s not needed, like formatting, etc to get a smaller macro, and simplify it until you don’t see the problem, to find out the cause.
Just by looking at the lines above it’s hard to tell without more context; maybe you are not really reading the data correctly (you did not say whether you get any output from your cout; try adding more printout lines and protections for those cases), or something else; one issue could be, for example, that you are Drawing and then the macro ends, which closes any open canvases and might explain why you don’t “see” it (in that case, try adding a line to save the canvas before ending the macro and see if it gets saved correctly). If you can share the data file so we can run your macro (try to reduce it first) it would be better.

I have commented out some unnecessary bits so here is the reduced code:

void phiMass_t_pol_cut() {
    TFile *filein = new TFile("flat_pi0pippim__B4_cut.root");
    TTree *tree = (TTree *)filein->Get("pi0pippim__B4_cut");

    UInt_t run;
    Int_t pol;
    float tagWeight, Mandelstam_t;

    TLorentzVector *pim_p4_kin = 0;
    TLorentzVector *pip_p4_kin = 0;
    TLorentzVector *decaypi0_p4_kin = 0;

    tree->SetBranchAddress("decaypi0_p4_kin", &decaypi0_p4_kin);
    tree->SetBranchAddress("pim_p4_kin", &pim_p4_kin);
    tree->SetBranchAddress("pip_p4_kin", &pip_p4_kin);

    tree->SetBranchAddress("run", &run);
    tree->SetBranchAddress("tagWeight", &tagWeight);
    tree->SetBranchAddress("pol", &pol);
    tree->SetBranchAddress("Mandlestam_t", &Mandelstam_t);

    TH1F *h_phimass_pol0_t0001_test = new TH1F("h_phimass_pol0_t0001_test", "title", 100, 0.9, 1.2);

    TLorentzVector Pi0P4, PiMinusP4, PiPlusP4, PhiP4;

    Long64_t NEntries = tree->GetEntries();
    cout << "There are " << NEntries << " entries." << endl;

    for (Long64_t i_entry = 0; i_entry < NEntries; i_entry++) {
        
        tree->GetEntry(i_entry);

        if (i_entry % 400000 == 0) {
            cout << i_entry << " events processed" << endl;
        }

        PiMinusP4.SetPxPyPzE(pim_p4_kin->Px(), pim_p4_kin->Py(), pim_p4_kin->Pz(), pim_p4_kin->E());
        PiPlusP4.SetPxPyPzE(pip_p4_kin->Px(), pip_p4_kin->Py(), pip_p4_kin->Pz(), pip_p4_kin->E());
        Pi0P4.SetPxPyPzE(decaypi0_p4_kin->Px(), decaypi0_p4_kin->Py(), decaypi0_p4_kin->Pz(), decaypi0_p4_kin->E());

        PhiP4 = PiMinusP4 + PiPlusP4 + Pi0P4;

        double PhiMass = PhiP4.M();

        if (pol == 0) {
            if (-Mandelstam_t > 0.0 && -Mandelstam_t < 0.1) {
                h_phimass_pol0_t0001_test->Fill(PhiMass, tagWeight);
            }
        }
    TCanvas *c1 = new TCanvas("c1", "Phi Masses", 800, 600);
    c1->cd(1);
    h_phimass_pol0_t0001_test->Draw();
    c1->SaveAs("test.pdf");
}

This is a stand-alone macro and it being run via VS Code’s powershell extension. All of the print statements output normally, and I am now getting a canvas (after adding the SaveAs command). However, after the canvas is saved, I am getting this strange stacktrace message

==========================================
=============== STACKTRACE ===============
==========================================


================ Thread 0 ================
  libCore!TWinNTSystem::DispatchSignals()
  ucrtbase!log2f()
  root!Init_thread_header()
  VCRUNTIME140!_C_specific_handler()
  ntdll!_chkstk()
  ntdll!RtlFindCharInUnicodeString()
  ntdll!KiUserExceptionDispatcher()
  0x1b9792558b0 ??
  0x1b9792560d0 ??
  0x1b905daab30 ??
  0x1b905dacbb0 ??
  0x1b905daaf40 ??
  0x2fe47dcd20 ??
  0x2fe47dcc50 ??
  0x1b97997be80 ??
  libCling!cling::runtime::internal::setValueWithAlloc()
  libCling!TCling::GetUsingNamespaces()
  libCling!TCling::ProcessLine()
  libCling!TCling::ProcessLineSynch()
  libCore!TApplication::ExecuteFile()
  libCore!TApplication::ProcessLine()
  libRint!TRint::ProcessLineNr()
  libRint!TRint::Run()
  root!??
  root!??
  KERNEL32!??
  ntdll!RtlUserThreadStart()

================ Thread 1 ================
  ntdll!ZwDelayExecution()
  ntdll!RtlDelayExecution()
  ntdll!RtlDelayExecution()
  KERNELBASE!SleepEx()
  libCore!TWinNTSystem::TimerThread()
  KERNELBASE!SleepEx()
  libCore!TWinNTSystem::TimerThread()
  libCore!TWinNTSystem::ThreadStub()
  KERNEL32!??
  ntdll!RtlUserThreadStart()

================ Thread 2 ================
  win32u!NtUserGetMessage()
  USER32!GetMessageA()
  InProcessClient64!??
  InProcessClient64!??
  libCore!TWinNTSystem::FreeDirectory()
  KERNEL32!??
  ntdll!RtlUserThreadStart()

================ Thread 3 ================
  ntdll!NtWaitForWorkViaWorkerFactory()
  ntdll!RtlClearThreadWorkOnBehalfTicket()
  libCore!TWinNTSystem::ThreadStub()
  KERNEL32!??
  ntdll!RtlUserThreadStart()

================ Thread 2 ================
  win32u!NtUserGetMessage()
  USER32!GetMessageA()
  InProcessClient64!??
  InProcessClient64!??
  libCore!TWinNTSystem::FreeDirectory()
  KERNEL32!??
  ntdll!RtlUserThreadStart()

================ Thread 3 ================
  ntdll!NtWaitForWorkViaWorkerFactory()
  ntdll!RtlClearThreadWorkOnBehalfTicket()
  KERNEL32!??
  ntdll!RtlUserThreadStart()
  KERNEL32!??
  ntdll!RtlUserThreadStart()

================ Thread 2 ================
  win32u!NtUserGetMessage()
  USER32!GetMessageA()
  InProcessClient64!??
  InProcessClient64!??
  libCore!TWinNTSystem::FreeDirectory()
  KERNEL32!??
  ntdll!RtlUserThreadStart()

================ Thread 3 ================
  ntdll!NtWaitForWorkViaWorkerFactory()
  ntdll!RtlClearThreadWorkOnBehalfTicket()
  KERNEL32!??
  ntdll!RtlUserThreadStart()
================ Thread 2 ================
  win32u!NtUserGetMessage()
  USER32!GetMessageA()
  InProcessClient64!??
  InProcessClient64!??
  libCore!TWinNTSystem::FreeDirectory()
  KERNEL32!??
  ntdll!RtlUserThreadStart()

================ Thread 3 ================
  ntdll!NtWaitForWorkViaWorkerFactory()
  ntdll!RtlClearThreadWorkOnBehalfTicket()
  KERNEL32!??
  ntdll!RtlUserThreadStart()
  InProcessClient64!??
  libCore!TWinNTSystem::FreeDirectory()
  KERNEL32!??
  ntdll!RtlUserThreadStart()

================ Thread 3 ================
  ntdll!NtWaitForWorkViaWorkerFactory()
  ntdll!RtlClearThreadWorkOnBehalfTicket()
  KERNEL32!??
  ntdll!RtlUserThreadStart()
================ Thread 3 ================
  ntdll!NtWaitForWorkViaWorkerFactory()
  ntdll!RtlClearThreadWorkOnBehalfTicket()
  KERNEL32!??
  ntdll!RtlUserThreadStart()
  KERNEL32!??
  ntdll!RtlUserThreadStart()

  ntdll!RtlUserThreadStart()

================ Thread 4 ================
  ntdll!NtWaitForWorkViaWorkerFactory()
  ntdll!RtlClearThreadWorkOnBehalfTicket()
  KERNEL32!??
  ntdll!RtlUserThreadStart()

==========================================
============= END STACKTRACE =============
==========================================

To understand if it is due to the graphics part of your code can you try the very simple test:

{
   TCanvas *c1 = new TCanvas("c1", "Phi Masses", 800, 600);
   c1->cd(1);
   c1->DrawFrame(-4.,-4,4.,4);
   c1->SaveAs("test.pdf");
}

This works. The frame is drawn correctly, the canvas is saved correctly, and the window stays open until I close ROOT

Ok, so I have reworked my code and added multiple print statements. (I also switched to my laptop. ROOT version 6.32.10, Platform win64, Compiler MSVC 19.39.33521.0)
phiMass_t_pol_cut.C (7.5 KB)

I have encountered a new problem. When I run my code, my loop over the events stops after the first event and then my code fails. I am running the code from the integrated terminal in VSCode so usually there would be some sort of error message that pops up in the terminal, but instead there’s just a small red “X” next to the directory:

So it does not seem to be a graphics issue