How to access TGraph stored in TTree

Hello,

I would like to access TGraph stored in TTree with PyROOT. I tested the TTree in Cint and it works when I set the branch address to some graph, than perform GetEntry() and draw the graph.

However, in PyROOT I am not sure how to do this. When I just try to print tree.graph_name I get a segfault. When I create a graph, like:

g = ROOT.TGraph()
t.SetBranchAddress("branch", g)

the program does not crash, but the g is None. I also tried “AddressOf(g)” but with similar result. How it should be done?

Hi,

the way one can access elements stored in events collected in trees in pyroot is

# this loops on the tree
for event in myFile.MyTreeName:
  # this extracts the object from the "event"
  myGraph = event.MyGraphName

Cheers,
Danilo

Crashes on attempt to access the graph. I attach my tree. I try to use it with the following code:

import numpy as np
import ROOT
import sys

f = ROOT.TFile(sys.argv[1], "open")
t = f.Get("tscurves")
c = ROOT.TCanvas()
entries = t.GetEntriesFast()
t.Print()

g = ROOT.TGraph()

#for i in xrange(entries):
for event in f.tscurves:
	print event
	myg = t.SCurve
	print "something"
	print myg

gains.root (1.28 MB)

Hi,

I can reproduce the issue with your file with this python program:

import ROOT
ROOT.gSystem.Load("libHist.so")
f = ROOT.TFile("gains.root")
theTree = f.tscurves
print theTree
for event in theTree:
  print getattr(event,"SCurve")

Now, I produce a rootfile by myself with a tree with a TGraph instance per event with this trivial macro:

void fillTree(){

  TFile f("gains.root","RECREATE");

  TTree* tree = new TTree("tscurves","Example tree");
  TGraph* g = new TGraph(10);

  tree->Branch("SCurve",&g);

  Int_t nevent=10;
  for (Int_t iev=0;iev<nevent;iev++) {
    for (int j=0;j<10;++j) g->SetPoint(j,j,j);
    tree->Fill();
  }
  tree->Write();
  f.Close();
}

And everything works as expected.
How did you produce the rootfile you shared?

Cheers,
Danilo

It is a part of a big python program. I’ll try to paste relevant parts:

			fg = ROOT.TFile("gains.root", "recreate")
			tg = ROOT.TTree("tscurves", "SCurves, SPE Spectrum, etc.")
			g = ROOT.TGraph()
			(pix_x, pix_y, pix, spe_val, spe_p) = (np.zeros(1, dtype=np.int32) for x in xrange(5))
			tg.Branch("SCurve", "TGraph", g, 32000, 0)
			tg.Branch("first_der", "TGraph", g, 32000, 0)
			tg.Branch("sec_der", "TGraph", g, 32000, 0)
			tg.Branch("pix_x", pix_x, "pix_x/I")
			tg.Branch("pix_y", pix_y, "pix_y/I")
			tg.Branch("pix", pix, "pix/I")
			tg.Branch("spe_valley", spe_val, "spe_valley/I")
			tg.Branch("spe_peak", spe_p, "spe_peak/I")
			
			# Loop through all pixels - different loops depending on shape (type of tree)
			for index,val in np.ndenumerate(self.pcd):

[...]

					g = ROOT.TGraph(data.size, threshold.astype(np.float64), data.astype(np.float64))
					g1 = ROOT.TGraph(first_derivative.size, threshold.astype(np.float64), first_derivative.astype(np.float64))
					g2 = ROOT.TGraph(second_derivative.size, threshold.astype(np.float64), second_derivative.astype(np.float64))
					

					tg.SetBranchAddress("SCurve", g)
					tg.SetBranchAddress("first_der", g1)
					tg.SetBranchAddress("sec_der", g2)

[...]

						spe_valley[index] = threshold[ext_flexes[i+1]]
						spe_peak[index] = threshold[ext_flexes[i+2]]
						spe_val[0] = np.int(spe_valley[index])
						spe_p[0] = np.int(spe_peak[index])
						print spe_val[0],index,pix_x[0],pix_y[0] 
						tg.Fill()

			fg.Write()
			fg.Close()


the interesting thing is, that I can read those graphs in Cint.

Hi,

not sure how things work in CINT when reading, but this may be one source of problems:

[quote=“LeWhoo”]

[code]
g = ROOT.TGraph()
(pix_x, pix_y, pix, spe_val, spe_p) = (np.zeros(1, dtype=np.int32) for x in xrange(5))
tg.Branch(“SCurve”, “TGraph”, g, 32000, 0)
tg.Branch(“first_der”, “TGraph”, g, 32000, 0)
tg.Branch(“sec_der”, “TGraph”, g, 32000, 0)

				g = ROOT.TGraph(data.size, threshold.astype(np.float64), data.astype(np.float64))

				tg.SetBranchAddress("SCurve", g)
				tg.SetBranchAddress("first_der", g1)
				tg.SetBranchAddress("sec_der", g2)

[/code][/quote]
Once g is re-assigned, the original ROOT.TGraph is dodo-bird, due to the reference counting. I did not see a tg.Fill() in between in the code you showed.

Cheers,
Wim

Hi,

in the python reading code above, this gives TGraphs (don’t know whether they’re correctly filled; haven’t tried):g = ROOT.TGraph() t.SetBranchAddress("SCurve", g)
and then loop as before.

In the pythonization, GetBranch(“SCurve”) returns a proper TBranch, but the GetAddress() call on it fails (I don’t understand why). The TGraph can be found as a leaf, but the pythonization does not go down that path (only does so if the TBranch itself can not be found).

The lines above make sure the address points to a valid object to be filled.

Cheers,
Wim

[quote=“wlav”]Hi,

not sure how things work in CINT when reading, but this may be one source of problems:

Hmm, so how should it be properly done? I should have one graph to which I set branch before filling, then modify this graph, it’s number of points, etc.?

[quote=“wlav”]Hi,

in the python reading code above, this gives TGraphs (don’t know whether they’re correctly filled; haven’t tried):g = ROOT.TGraph() t.SetBranchAddress("SCurve", g)
and then loop as before.

The lines above make sure the address points to a valid object to be filled.
[/quote]

If I have it before loop, than loop with GetEntry() in each iteration, the “g” is unfortunately “None”…

Hi,

yes, but in the code you posted, you did not use g, but rather t.SCurve. This works for me (i.e. one-line adjustment to the original code you posted):[code]import ROOT
import sys

f = ROOT.TFile(sys.argv[1], “open”)
t = f.Get(“tscurves”)
c = ROOT.TCanvas()
entries = t.GetEntriesFast()
t.Print()

g = ROOT.TGraph()
t.SetBranchAddress(“SCurve”, g)

#for i in xrange(entries):
for event in t:#f.tscurves:
print event
myg = t.SCurve
print "something"
print myg[/code]
Cheers,
Wim

Works, thanks!

Maybe it is worth some entry in manual? Not very intuitive…

Hi,

it’s not supposed to be this way, and an automatic recover from GetAddress() being NULL has been added to v5-34-00-patches and master already. Of course, that doesn’t help you right now, hence this manual workaround.

Cheers,
Wim