TGraph TAxis SetTitle not working when writing to a TFile

Hi,

I’ve run into a strange situation and I can’t seem to determine what is happening. I am creating two graphs and setting the title and axis titles, then writing them to file without plotting them. When I open the output file and plot them only one has the axis titles set and the other has blank titles. Here is the smallest example I could produce with the issue.

#include <vector>

#include "TFile.h"
#include "TGraph.h"

void graph() {
   TFile f("out.root", "RECREATE");

   std::vector< TGraph > graphs;
   for (int i=0;i<2;i++) {
      graphs.push_back(TGraph(100));
      for (int j=0;j<graphs.back().GetN();j++) graphs.back().SetPoint(j,j,(i+1)*j);
      graphs.back().SetName(Form("graph%d", i));
      graphs.back().SetTitle(Form("Graph %d",i));
      graphs.back().GetXaxis()->SetTitle("X-axis");
      graphs.back().GetYaxis()->SetTitle("Y-axis");
   }

   for (auto itr = graphs.begin(); itr != graphs.end(); ++itr) {
      itr->Write();
   }
   f.Close();
}

Attached figure can be created with:

{
TFile f("out.root");
TCanvas *c = new TCanvas("c","Canvas");
c->DivideSquare(2);
c->cd(1);
f.Get("graph0")->Draw("ALP");
c->cd(2);
f.Get("graph1")->Draw("ALP");
}

Olivier @couet will most probably have an explanation to this…

I see that graph1 keeps its title but not graph0. I need to check.

If i use the following simple script then the titles are saved in the ROOT file:

void graphtitle() {
   TFile f("out.root", "RECREATE");
   auto *g1 = new TGraph();
   g1->SetName("g1");
   g1->GetXaxis()->SetTitle("X");
   g1->GetYaxis()->SetTitle("Y");
   g1->SetPoint(0,1.,1.);
   g1->SetPoint(1,2.,2.);
   g1->Write();
   auto *g2 = new TGraph();
   g2->SetName("g2");
   g2->GetXaxis()->SetTitle("X");
   g2->GetYaxis()->SetTitle("Y");
   g2->SetPoint(0,1.,1.);
   g2->SetPoint(1,2.,2.);
   g2->Write();
   f.Close();
}

Yes, you have changed the constructor to use dynamic memory. This does resolve the issue, but now I have to manage it and delete every graph at the end of the routine and ensure that the pointer values are cleaned up to avoid a segmentation fault.

Why does using the new operator resolve the issue? I would not have expected a difference between dynamic and static memory.

In addition, if I move my SetTitle calls about the SetPoint calls I no longer get titles even with dynamic memory allocation:

#include <vector>

#include "TFile.h"
#include "TGraph.h"

void graph() {
   TFile f("out.root", "RECREATE");

   std::vector< TGraph* > graphs;
   for (int i=0;i<2;i++) {
      graphs.push_back(new TGraph(100));
      graphs.back()->SetName(Form("graph%d", i));
      graphs.back()->SetTitle(Form("Graph %d",i));
      graphs.back()->GetXaxis()->SetTitle("X-axis");
      graphs.back()->GetYaxis()->SetTitle("Y-axis");
      for (int j=0;j<graphs.back()->GetN();j++) graphs.back()->SetPoint(j,j,(i+1)*j);
   }

   for (auto itr = graphs.begin(); itr != graphs.end(); ++itr) {
      (*itr)->Write();
      delete *itr;
   }
   graphs.clear();
   f.Close();
}

I am not sure… may be @pcanal will know.

1 Like

Why does using the new operator resolve the issue?

This is because of a bug/feature of the TGraph copy constructor. It does not copy the underlying histogram and thus the axis information. (And the copy constructor is used when resized an std::vector). You can work-around the issue with:

   std::vector< TGraph > graphs;
   graphs.reserve(2);
   for (int i=0;i<2;i++) {
      graphs.push_back(TGraph(100));
....

Cheers,
Philippe.

1 Like

Thanks! Your suggestion of reserve resolved both issues.

If this is a “bug” will it improved in the future or if it is considered a “feature” is there someway to document the issue?

@couet will most probably be able to give you an answer to that.

Yes, the underlying histogram for TGraph is a feature which is there since the very beginning of ROOT. Title and axis titles are hold by this histogram as you can see here. As stated at the beginning of the TGraph reference guide: " TGraph was a light weight object to start with"… I guess that’s why the copy constructor was kept like that. I have to check what is the best solution between modifying the copy constructor or adding a note in the TGraph documentation.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.