TTree::Draw to canvas/histogram simultaneously doesn't work?


I thought this was supposed to work? I try to fill a histogram using TTree::Draw and also draw on a canvas at the same time, but all I get is a blank canvas. Here’s the code boiled down to its essentials:

#include "TTree.h"
#include "TFile.h"
#include "TH1D.h"
#include "TString.h"
#include "TCanvas.h"

void tester()
  TFile f("hfraddam_runs202063-208492.root");
 // Get the input tree:
  TTree* mytree = (TTree*) f.Get("hfraddam/mytree");

  //TCanvas* c1 = new TCanvas("c1","c1",10,10, 1000, 700);
  TH1* th1var = (TH1*)(new TH1D("th1var","th1var",70,202000,209000));
  mytree->Draw("runnum>>th1var", "", "HIST");

When I remove “>>th1var”, the full plot appears on the canvas. But with “>>th1var” in place,
all I get is a blank canvas. I tried it with and without the TCanvas declaration, same result.
I also tried it by not declaring the th1var first, same result. This was tested with version 5.32/00.

I also tried it by setting the gopt to “goff” and then getting the histogram and drawing that
afterward, but no better. But if I print the histogram I can clearly see that the histogram is
filled properly.

Any help would be appreciated!

-Phil D.

Hi Phil,

the issue here is the very confusing rules where objects live inside ROOT and how histogram drawing is implemented:

  • when drawing (at least from TTree and everything inheriting from it) ROOT looks for the histogram to draw to in the current directory
  • histograms are by default created in the current directory
  • when creating an TDirectory-like object (e.g. a TFile) ROOT will automatically cd to that directory
  • when deleting a TDirectory object many (all?) objects in that directory (like e.g. histograms) are cleaned up

Your problem is that your histogram is created in the TFile you open, but at the end of the function the TFile gets cleaned-up and takes your histogram with it.

There are a number of ways to work around this. For me the most straight-forward approach would be to just cd back out of the TFile again right after creating it, e.g. to go to the default directory call gDirectory->cd("Rint://");. The way you get a pointer to the TTree will continue to work.

Another approach would be to create a dynamic TFile object which doesn’t get cleaned-up when leaving the function. Instead of a simple cd you would then have to manually manage its lifetime (potentially far away). Don’t do that.

Try to add:

Okay, thanks honk and Wile E.! It’s because “f” goes out of scope and everything assigned to it, including the histogram I created. It’s good to be reminded of those rules. Thanks for the tips!