On using a TList to store TH1 / TGraph objects?

Hello, for an application I am writing I need to extract a number of histograms (1d/2d) and graphs (including TGraphErrors) from a file. I figured a good way to keep track to all of them is to have them stored in a TList. I have a couple of questions related to the simple code below:
(1) What is the magic command(s) that allow me to keep my objects (and my list) in memory after I close the file? I have tried a number of things without success (involving moving the list to the “previous” directory which exists before the file is opened).
(2) How do I get the actual class name (TH1F, TH2F, TGraph…) of my objects in memory? See printout below. This has to be straightforward, but I cannot find an equivalent of GetClassName() for a TObject.

 OBJ: TList	TList	Doubly linked list : 0
 OBJ: TH1F	h_CopyHisto	T2 rate : 0 at: 0x7fbdd88b6c20
 OBJ: TH2F	h_Ex2D	detector 5 x 5 in LAB (detected) : 0 at: 0x7fbdd8904340
 OBJ: TGraph	g_T2rate	 : 0 at: 0x7fbdd8916e20
 OBJ: TGraph	g_AoP	 : 0 at: 0x7fbdd8916d70

Thanks in advance. Fred.

TList *GetObjects(char *filename)
{
  TList *myObjects = new TList();

  TFile *f = new TFile(filename);
  TIter next(f->GetListOfKeys());
  TKey *key;
  while (key = (TKey*)next()) {
    TClass *cl = gROOT->GetClass(key->GetClassName());
    if (cl->InheritsFrom("TH1") || cl->InheritsFrom("TGraph")) {
      myObjects->Add(key->ReadObj());
    }
  }

  // (1) HOW CAN I CLOSE THE FILE AND KEEP MY LIST AND ALL ITS OBJECTS IN MEMORY?
  // f->Close();
  myObjects->ls();

  return myObjects;
}

ReadObjects(char *filename)
{
  TObject *obj;
  TList *list_of_objects = GetObjects(filename);
  TIter next(list_of_objects);
  while (obj = next()) {
    // (2) HOW DO I GET THE ACTUAL CLASS NAME OF MY OBJECTS?
    cout << obj->GetName() << " is a " << "<TH1F/TH2F/TGraph/TGraphErrors/etc...>" << endl;
  }

  return 0;
}

Hi Fred,

  1. myHisto.SetDirectory(0) . See root.cern.ch/doc/master/classTH … 5d0a5462c3
  2. myObj.ClassName() . Other methods can be used though such as dynamic casts or getting the TClass pointer itself (GetClass()). See this post where a method to recursively explore a file is characterised: Load histograms in root files

Cheers,
D

Thanks for (2)!.. cannot believe I missed that!

With respect to (1)… I am not quite sure how this would work. I guess I could make a copy of all the objects outside of the file, then create the list. In this case, I could indeed use TH1::SetDirectory() but I found that the TGraph doesn’t have a SetDirectory() method. The work around is to add them to the directory using: dir->GetList()->Add(graph). This would work. I wonder if there is a way to do this all at once though, independently of the object class?

Hi,

[quote]The work around is to add them to the directory using[/quote]I am a bit confused, I thought you want the object to still be alive after you close the file, this would have the exact opposite effect!

And it also do not automatically attach itself to the file (and thus you do not need to remove it :slight_smile: ).

[quote]With respect to (1)… I am not quite sure how this would work. I guess I could make a copy of all the objects outside of the file, then create the list.[/quote]No need to make a copy. SetDirectory(0) says to detach the histogram from the TFile; from that moment on, the file no longer know anything about that object and you are the sole owner of the object.

Cheers,
Philippe.

Okay, got it. I didn’t realize the TGraphs are never attached to the file. I post my code in case someone has a similar question in the future.

TList *GetObjects(char *filename)
{
  TH1 *histo;
  TGraph *graph;
  TList *myObjects = new TList();
  myObjects->SetName("myObjects");

  TFile *f = new TFile(filename);
  TIter next(f->GetListOfKeys());
  TKey *key;
  while (key = (TKey*)next()) {
    TClass *cl = gROOT->GetClass(key->GetClassName());
    if (cl->InheritsFrom("TH1")) { 
      histo = (TH1*)key->ReadObj();
      histo->SetDirectory(0);
      myObjects->Add(histo);
    }
    else if (cl->InheritsFrom("TGraph")) {
      graph = (TGraph*)key->ReadObj();
      myObjects->Add(graph);
    }
  }
  f->Close();

  return myObjects;
}