Saving histograms in a list using PyROOT

Hello, I am opening a number of root files and accessing one histogram per root file. I would like to saves these histograms in a list and then later draw them all on the same histogram (after normalising). The code I have below does not work. Does anyone see the problem or can anyone suggest an alternative way to do this?

import ROOT

run_numbers = [1378, 1439, 1530, 1573, 1614, 1655, 1712, 1762, 1826, 1876, 1910, 1942, 1973, 2014, 2098]
hist_array = []

for i in range(len(run_numbers)):
    path_to_file = "output/single_run_" + str(run_numbers[i]) + ".root"
    rootfile = ROOT.TFile.Open(path_to_file)
    hist = rootfile.Get("AnalysisDUT/tp2_0/clusterChargeAssociated")
    rebin_factor = 8
    hist_rebinned = hist.Rebin(rebin_factor)
    hist_name = "run "+str(i)
    c1 = ROOT.TCanvas("c1", "", 800, 600)
    hist_rebinned.Draw()
    c1.Print("check_plot"+hist_name+".png")
    hist_array.append(hist_rebinned)
    rootfile.Close()


output_file = ROOT.TFile("array.root", "RECREATE")
c2 = ROOT.TCanvas("c2", "", 800, 600)
for i in range(len(hist_array)):
    if i ==0:
        hist_array[i].Draw()
    else:
        hist_array[i].Draw("same")
c2.Write()
output_file.Close()

When I run this, I successfully get the png’s but I get the error below when it tried to plot them all on the same canvas when looping the list I created.
Traceback (most recent call last):
File “*.py”, line 24, in
hist_array[i].Draw()
AttributeError: ‘CPyCppyy_NoneType’ object has no attribute ‘Draw’

Instead of adding them to a list, add them to THStack (in that same loop), then just draw the THStack. See this recent post with a similar case:

Yes–I also attempted adding them to a list at first–didn’t work. The THStack solved the problem. Here is an excerpt from my working code (with the exception of the file path) to give you an idea:

    c_i = 0
    l_i = 0
    for run in runs:
        path = f"/path/to/files/{run}_2023_HB3_ped.root"
        print(f"Opening file: {path}")

        # Select the file from which to extract histogram
        file = ROOT.TFile.Open(path)
        # Get the correct canvas from the file
        canvas = file.Get("HB3Charge/HB3/HB3-2-Charge")
        # Get the correct pad
        pad = canvas.GetPad(pads[tileindex]) #26 for tile 1
        # Get the histogram
        hist = pad.GetPrimitive(padnames[tileindex]) #"ChargeHB3-2-3-1" for tile 1
        
        # For some reason, color corresponding to 10 is invisible.
        if c_i == 9:
            c_i += 1

        hist.SetLineColor(c_i+1)
        # Add histograms to stack
        stack.Add(hist)

        legendEntry = "Run " + str(run) + ", T = " + str(temps[l_i]) + " C"
        legend.AddEntry(hist, legendEntry, "f")

        c_i += 1
        l_i += 1

Note that in my case, the histograms I was pulling from were drawn on a pad, so I had to account for that whereas you may not.

After adding all your histograms to the stack, you will create a ROOT.TCanvas and then stack.Draw("hist"). I also did a lot of axis adjustments to ensure all the histograms would automatically fit comfortably in the viewing window.

Hope this helps!

Thank you for this suggestion. I have written the below code but when I plot the stack, there is only the axis and the plot is empty.

import ROOT

run_numbers = [1378, 1439, 1530, 1573, 1614, 1655, 1712, 1762, 1826, 1876, 1910, 1942, 1973, 2014, 2098]
hist_array = []

hs = ROOT.THStack("hs", "Stacked Histograms")

for i in range(len(run_numbers)):
    path_to_file = "output/single_run_" + str(run_numbers[i]) + ".root"
    rootfile = ROOT.TFile.Open(path_to_file)
    hist = rootfile.Get("AnalysisDUT/tp2_0/clusterChargeAssociated")
    rebin_factor = 8
    hist_rebinned = hist.Rebin(rebin_factor)
    hs.Add(hist_rebinned)
    rootfile.Close()


output_file = ROOT.TFile("output.root", "RECREATE")
c2 = ROOT.TCanvas("c2", "", 800, 600)
hs.Draw("nostack,e1p")
c2.Write()
output_file.Close()

If I plot within the loop for example, if i ==6: plot… as above. Then I do get a single histogram only for i==6 and the previous histograms are missing. Any ideas?

This code is basically the same you have for plotting a stack and saving, and works fine for me on ROOT 6.32/02:

import ROOT

hs = ROOT.THStack("hs","")

h1 = ROOT.TH1F("h1","test hstack",10,-4,4)
h1.FillRandom("gaus",20000)
h1.SetFillColor(2)
h2 = ROOT.TH1F("h2","test hstack",10,-4,4)
h2.FillRandom("gaus",15000)
h2.SetFillColor(4)

hs.Add(h1)
hs.Add(h2)

output_file = ROOT.TFile("output.root", "RECREATE")
c = ROOT.TCanvas("c","c",10,10,600,600)
hs.Draw("nostack")
c.Write()
output_file.Close()

Maybe you are not getting the histograms correctly from the file/s, or the binnings are not the same (or your input file is damaged, or something else!). Check one by one and make sure all is as you expect.