Hello,
I have recently made ‘brew upgrade’ (that was not a proper intension)
Now I can not get a list of TH1F from function in python 3.8 .
How should it be done?
The code takes a list of filenames and TH1F name and should give the list of TH1Fs
The code is below:
def get_hists(file_names, hist_name, mark):
NPoints = len(file_names)
h_array = [TH1F for y in range(0,NPoints)]
f = [TFile for y in range(0,NPoints)]
for i in range(0,NPoints):
f[i] = TFile.Open(file_names[i])
hist_new_name = hist_name+'_{0:d}'.format(i)+mark
h = f[i].Get(hist_name).Clone(hist_new_name)
h_array[i] = h
h_array[i].SetTitle(hist_new_name)
return h_array
This is how it is implemented:
files = ['FIle_0.root',...,'File_20.root']
h_array = [TH1F for i in range(0,NPoints)]
h_array = get_hists(files , 'h_y_endpoint', '_B0_i' )
c = TCanvas()
h_array[0].Draw()
All the list elements have ‘None’ type.
When I draw inside the function in the loop everything is OK.
But as soon as the file is changed, the histogram is ‘None’.
The error is:
File “./plot_Y.py”, line 268, in
h_array[0].Draw()
AttributeError: ‘CPyCppyy_NoneType’ object has no attribute ‘Draw’
Please read tips for efficient and successful posting and posting code
ROOT Version: 6.22/00
Platform: MAC OS 10.15.4
Compiler: Apple clang version 11.0.3 (clang-1103.0.32.59)
I think @etejedor can help you with this issue
Hi,
From reading the code I don’t see any obvious problem, since you are cloning the histograms, so that when the files are destroyed you should keep the cloned ones (their references are stored in h_array).
What happens if, after the loop (still inside the function), you try to Draw h_array[0]?
Hello,
Inside the function, it works without errors
Here is how print (h_array) works before (0), inside (1) and after (2) the function
`
print(h_array)
h_array = get_hists(files , ‘h_y_endpoint’, ‘_B0_i’ )
print(h_array)
`
Output:
0: [<class cppyy.gbl.TH1F at 0x7fbdd9606f80>, …, <class cppyy.gbl.TH1F at 0x7fbdd9606f80>]
1: [<cppyy.gbl.TH1F object at 0x7fbdd9d85840>, …, <cppyy.gbl.TH1F object at 0x7fbdd93e5560>]
2: [None, None, None, …, None]
Ok thank you, can you let me know what ROOT version you were using before so I can compare?
Hello,
I think it was 20.04, I will try to switch back to it
By the way,
Are you aware of this thing?
https://root.cern.ch/root/html524/src/TMath.h.html#411
It was strongly criticized and recommended never to use ROOT for calculations during the sPHENIX collaboration meeting 2 days ago:
cout << TMath::ACos(2) << endl;
0
cout << acos(2) << endl;
nan
Hi,
I tried the following example:
import ROOT
def foo():
f = ROOT.TFile.Open("./tutorials/hsimple.root")
h1 = f.Get('hpx')
h2 = h1.Clone('h2')
print("H1", h1)
print("H2", h2)
return h2
hist = foo()
print("FINAL HIST", hist)
both with 6.22 and 6.20 and the result is the same: the final histogram becomes None because, when its TFile is being destructed, it destroys its associated histograms too. I think this is what happens in your code too.
In any case, there is a solution to free the histogram from being tied to the TFile. You need to write:
def get_hists(file_names, hist_name, mark):
NPoints = len(file_names)
h_array = [TH1F for y in range(0,NPoints)]
f = [TFile for y in range(0,NPoints)]
for i in range(0,NPoints):
f[i] = TFile.Open(file_names[i])
hist_new_name = hist_name+'_{0:d}'.format(i)+mark
h = f[i].Get(hist_name).Clone(hist_new_name)
h.SetDirectory(0) # notice this line !!!!
h_array[i] = h
h_array[i].SetTitle(hist_new_name)
return h_array
As for the TMath question, perhaps @moneta can comment on it.
Hello @etejedor,
This solution is working
Thank you, the issue was probably due to the fact that previously I have not been using separate files, but was reading from one.
Cheers,
Evgeny
Hi,
Thank you for noticing that TMath::Acos(2) returns 0. A protection to avoid values outside the [-1,1] range was added many years ago. I don’t know the reason. I think it is more correct to return a NaN as in std::acos.
I will make a PR for this,
Thank you
Lorenzo