Home | News | Documentation | Download

Accessing each Leaf in a .root file over a loop to extract its data

Hello Root Experts!!

I have been trying to extract data from a .root file created via simulation to a .txt file with a comma after each entry (so I can use other programs to read it easily), but I’ve hit a wall.
I am a complete beginner in ROOT and C++ so I’ve been relying on past forum posts here and in Stack Exchange for guidance. I am running ROOT 6.16 on Ubuntu18.04.

I’ve managed to do so for a single leaf (mainly based off [https://stackoverflow.com/questions/28970124/cern-root-exporting-data-to-plain-text] )

#include <iostream>
#include "TFile.h"
#include "TTree.h"
#include <iomanip>
#include <sstream>
#include <string>
#include <fstream>
using namespace std;

void Extract(const char *filename, const char *treename, const char *leafname, const char *output){

  TFile *file=new TFile(filename); // opens the root file  
  TTree *tree=(TTree*)file->Get(treename); // creates the TTree object

  Float_t val[1];   //create variables of the same type

  ofstream myfile;
  myfile.open (output); // open file with name to the file as inputted at start  
  //printing header according to leaf name and entry 
  myfile << leafname<<"_1";
  myfile << '\n'; 
  Int_t n_events=(Int_t)tree->GetEntries(); // define vector of number of events

  for (Int_t i=0;i<n_events;i++){
    // loop over the tree 
    tree->GetEntry(i);
    val[0] = tree->GetLeaf(leafname)->GetValue(0); // get the entry number
    cout << val[0];
    cout << endl;    //print to the screen
    myfile << val[0];
    myfile << '\n';   //write to file
    }

  myfile.close();

}

But now, I wish to access each leaf automatically through loops so that I don’t have to manually extract each leaf/variable, since the .root file may contain anywhere between 20-100 leaves/variables.
I’ve come up with the following by changing a few things from above, giving:

#include <iostream>
#include "TFile.h"
#include "TTree.h"
#include <iomanip>
#include <sstream>
#include <string>
#include <fstream>
using namespace std;

void Extract(const char *filename, const char *treename, const char *output){

  TFile *file=new TFile(filename); // opens the root  
  TTree *tree=(TTree*)file->Get(treename); // creates the TTree object

  Float_t val;   //create variables of the same type as leaves to access

  // Store all leaves in a string vector ??
  vector<string> LeafNames;
  LeafNames->GetListOfLeaves();

  ofstream myfile;
  myfile.open (output); // open file with name to the file as inputted at start 
  
  Int_t n_leaves=(Int_t)tree->GetListOfLeaves(); // define vector of number of leaves

  for (Int_t i=0;i<n_leaves;i++){
  //printing header according to extracted leaf name 
  TLeaf* leaf = GetLeaf(LeafName[i]);
  myfile << leaf <<",";
  myfile << '\n'; 
  
	Int_t n_events=(Int_t)tree->GetEntries(); // define vector of number of events
	for (Int_t j=0;j<n_events;j++){
		// Get values for the particular leaf
		tree->GetEntry(j);
		val = tree->GetLeaf(leaf)->GetValue(0);
		//write to file
		myfile << val<<",";
		myfile << '\n';		
	}
  
  }

  myfile.close();

}

I know that this doesn’t work, and I am stuck particularly in a method to extract each leaf in the first loop. Most leaves are of type Float_t, but some may be Int_t or UInt_t so I’m also assuming that this may be an issue as I’ve read that the declared variable must be of the same type?

Any help would be muchly appreciated :slight_smile:

Kind Regards


ROOT Version: 6.16/00
Platform: Not Provided
Compiler: Not Provided


BTW. When you post “source code” or “output” here, do remember to enclose them into two lines which contain just three characters ```.

if your goal is to “just” have a CSV out of a ROOT TTree, then this might help:

Thank you for your response :slight_smile:
I’ve installed and attempted to use it as suggested but I’m unsure how it works still, as the documentation was rather confusing.
Was I meant to run a script? For example, like;

package main
package hep

import (
"go-hep.org/x/hep"
)

func main() {
root2csv -o out.csv -t tree_name -f /path_to_root_file
}

Thank you again.

hi,

(apologies for the belated answer)

yes, root2csv is a simple binary that’s meant to be executed either from a script or directly from your shell prompt.

I have put the binaries of the latest Go-HEP release here:

(you just have to choose accordingly to your OS and architecture)

On a Linux 64b box, you’d do:

$> wget https://binet.web.cern.ch/binet/go-hep/latest/root2csv-linux-amd64.exe 
$> chmod +x ./root2csv-linux-amd64.exe
$> ./root2csv-linux-amd64.exe -o out.csv -t mytree -f /data/input.root

but if you’ve installed the Go compiler, then it would just be:

$> go get go-hep.org/x/hep/cmd/root2csv
$> $GOPATH/bin/root2csv -o out.csv -t mytree -f /data/input.root

let me know if you need further assistance.

hth,
-s

Hello,

Thank you again for your response :slight_smile:
I’ve managed to run the program, however, it seems that many of the leaves in my root file are not compatible with it, as it reads an error message “TLeafElement not supported”.

Regards

bummer.

if you have a small example ROOT file with the same structure, I could try to improve root2csv. (root-dump knows how to handle some of these TLeafElement…)
or, if you could paste the output of:

$> root ./my/file.root
[root] auto t = (TTree*)_file0->Get("your tree name");
[root] t->Print();

that would help me knowing a bit more about your file&tree structures.

hth,
-s

I’ve improved root2csv to be able to understand fully-split TTrees with TLeafElements that are builtins (+std::string and TString).

if you update your go-hep installation you should be able to pick it up:

$> go get -u go-hep.org/x/hep/cmt/root2csv

alternatively, here is the updated binary for Linux/64b:

hth,
-s

Hi @kmac - keep in mind that this Go code is not part of ROOT - we should have a solution in ROOT proper! @pcanal wouldn’t XMLIO do?