TRatioPlot constructor can cause seg fault

In ROOT 6.09 the TRatioPlot constructor that accepts two TH1* objects will segfault if a TCanvas object does not exist in scope at the time the constructor is called.

Is there a specific reason that motivated this choice? If so, can the documentation please be updated to reflect this? If not, can this be changed? I only discovered this today while trying to pass the constructor as an argument to a user defined function and debugging the segfault.

As an example of what I’m talking about, the following will cause a segfault:

#include <TH1.h>
#include <TF1.h>
#include <TCanvas.h>
#include <TRatioPlot.h>

int main (int argc, char const *argv[]) {
  // TCanvas c1("c1", "A ratio example");
  TH1D h1("h1", "h1", 50, 0, 10);
  TH1D h2("h2", "h2", 50, 0, 10);
  TF1  f1("f1", "exp(- x/[0] )");

  f1.SetParameter(0, 3);
  h1.FillRandom("f1", 1900);
  h2.FillRandom("f1", 2000);
  h1.Sumw2();
  h2.Scale(1.9 / 2.);
  h1.GetXaxis()->SetTitle("x");
  h1.GetYaxis()->SetTitle("y");
  TRatioPlot rp(&h1, &h2);

  return 0;
} // main

but the following will compile and run just fine:

#include <TH1.h>
#include <TF1.h>
#include <TCanvas.h>
#include <TRatioPlot.h>

int main (int argc, char const *argv[]) {
  TCanvas c1("c1", "A ratio example");
  TH1D    h1("h1", "h1", 50, 0, 10);
  TH1D    h2("h2", "h2", 50, 0, 10);
  TF1     f1("f1", "exp(- x/[0] )");

  f1.SetParameter(0, 3);
  h1.FillRandom("f1", 1900);
  h2.FillRandom("f1", 2000);
  h1.Sumw2();
  h2.Scale(1.9 / 2.);
  h1.GetXaxis()->SetTitle("x");
  h1.GetYaxis()->SetTitle("y");
  TRatioPlot rp(&h1, &h2);
  c1.SetTicks(0, 1);
  rp.Draw();
  c1.Update();
  c1.SaveAs("ratio_plot.pdf");

  return 0;
} // main

My system Information:

$ uname -a
Linux mcf-ThinkPad-Edge-E540 4.4.0-59-generic #80-Ubuntu SMP Fri Jan 6 17:47:47 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
$ root-config --version
6.09/01

A protection was missing. Now added in the root master. Thanks to have seen it.

I pulled and rebuilt from master. However, the following will still cause a segfault:

#include <TH1.h>
#include <TF1.h>
#include <TCanvas.h>
#include <TRatioPlot.h>

int main (int argc, char const *argv[]) {
  // TCanvas c1("c1", "A ratio example");
  TH1D h1("h1", "h1", 50, 0, 10);
  TH1D h2("h2", "h2", 50, 0, 10);
  TF1  f1("f1", "exp(- x/[0] )");

  f1.SetParameter(0, 3);
  h1.FillRandom("f1", 1900);
  h2.FillRandom("f1", 2000);
  h1.Sumw2();
  h2.Scale(1.9 / 2.);
  h1.GetXaxis()->SetTitle("x");
  h1.GetYaxis()->SetTitle("y");
  TRatioPlot rp(&h1, &h2);

  return 0;
} // main

but now with the following error (log attached):
Error in TRatioPlot::SetupPads: There is no active pad
errorlog.out.txt (9.16 KB)

A protection was missing. Now added.
TRatioPlot requires that a TCanvas has been created first.

Okay, but this then prevents passing the constructor as an argument to a user defined function without having a TCanvas object existing floating around. Is there any possibility that a TRatioPlot constructor could be added where a TCanvas constructor could be passed to avoid this problem?

Can this statement “TRatioPlot requires that a TCanvas has been created first” be added to the documentation for TRatioPlot? It currently doesn’t appear anywhere.

TRatioPlot::Draw says it between the lines… But you are right I will make it more clear.
root.cern/doc/master/classTRati … 218dd2416e

Okay, great. I appreciate it very much.

It is now in and will be visible tomorrow in the online doc (TRatioPlot::Draw help make it clear now)