Datime missing in TGraph generated with TTree::Draw

I am trying to create TGraphs out of TTrees with its Draw method. So far so good, but I have problems with getting TDatimes after retrieving the TGraph

In my tree, I have a branch with three Double_ts and another one with a TDatime.
This is what I am doing:

// I plot a histogram out of a tree
TCanvas* c = new TCanvas();
myTree->Draw("example.mean:time", "", "*L");
// then i retrieve my graph
  if (auto graph = dynamic_cast<TGraph*>(c->GetPrimitive("Graph"))) {
    graph->SetName(plot.name.c_str());
    graph->SetTitle(plot.title.c_str());
    ...
    // when I save the canvas, the dates are preserved
    c->SaveAs("graph-canvas.root");
    // when I save just the graph, i get only incremental numbers on x axis 
    graph->SaveAs("graph-direct.root");
    ...
 }

I want to work only on the graph, not the canvas, but then I lose the dates when I retrieve it. Would you know what I might be doing wrong? I am attaching the tree, and the graph-direct saved by that piece of code.
Thanks for the help!

graph-direct.root (4.2 KB)
trend-tree.root (6.3 KB)

ROOT Version: 6.18.04
Platform: CC7
Compiler: GCC 7.3.0

The time units are not hold by the TGraph but by a TH2 drawn before the TGraph.
You can see that with the following macro:

{
   auto c = new TCanvas();
   auto f = new TFile("trend-tree.root ");
   ExampleTrend->Draw("example.mean:time", "", "*L");
   c->ls();
}

it gives:

Canvas Name=c1 Title=c1 Option=
 TCanvas fXlowNDC=0 fYlowNDC=0 fWNDC=1 fHNDC=1 Name= c1 Title= c1 Option=
  OBJ: TList	TList	Doubly linked list : 0
   TFrame  X1= 0.500000 Y1=5190.000000 X2=13.000000 Y2=5355.000000
   OBJ: TH2F	htemp	example.mean:time : 1 at: 0x7fb6c53c6c00
   OBJ: TPaveText	title  	X1= 4.108972 Y1=5362.609542 X2=9.391028 Y2=5374.593753
   OBJ: TGraph	Graph	Graph : 1 at: 0x7fb6930a0830

As you can see the TCanvas does not contain “just only” the TGraph. The TH2F htemp draws the axis. Thats why it is fine when you save the whole canvas.

Thank you, that explains a lot. Is it a limitation of TGraph, that it cannot store TDatimes?

This is more the way TTree::Draw() generate 2D plot. Time axis on graph work as shown in the following example:

{
   TDatime da1(2008,02,28,15,52,00); 
   TDatime da2(2008,02,28,15,53,00); 
 
   double x[2],y[2]; 
 
   y[0] = 1.; 
   y[1] = 2.; 
   x[0] = da1.Convert(); 
   x[1] = da2.Convert(); 
 
   TGraph mgr(2,x,y); 
   mgr.SetMarkerStyle(20); 
 
   mgr.Draw("ap"); 
   mgr.GetXaxis()->SetTimeDisplay(1); 
   mgr.GetXaxis()->SetNdivisions(-2403); 
   mgr.GetXaxis()->SetTimeFormat("#splitline{%Y-%m-%d}{%H:%M:%S}"); 
   mgr.GetXaxis()->SetTimeOffset(0); 
   mgr.GetXaxis()->SetLabelOffset(0.02); 
} 

I see, thank you very much!

I have one more question concerning this topic.
I am continuing to experiment with plotting graphs against time with TTree::Draw. The problem is, that with large number of data points, the dates become very small and congested on the x axis. I tried to fix that by doing:

if (auto histo = dynamic_cast<TH1*>(c->GetPrimitive("htemp"))) {
  histo->GetXaxis()->SetTimeDisplay(1);
  histo->GetXaxis()->SetNdivisions(505);
  histo->GetXaxis()->SetTimeFormat("%Y-%m-%d %H:%M");
}
c->SaveAs("graph.root");

Unfortunately, it has no effect if I save the canvas and observe the file with TBrowser. On the other hand, if I open it on https://root.cern/js/latest/ , the new dates format seems to be applied, but the dates are wrong (1995-01-01).

Would you know what I might be still doing wrong?
This is the mentioned graph.
graph.root (9.5 KB)

I do not understand how you can get that may labels asking for 5 primary divisions. Can you post a small running macro reproducing that plot . It is still using trend-tree.root ?

You might want to try reproduce it on a tree with larger amount of entries. Attaching a new one:
trend-tree-more-entries.root (6.7 KB)

This is how I obtain graph.root:

auto c = new TCanvas();
auto f = new TFile("trend-tree-more-entries.root");
ExampleTrend->Draw("example.mean:time", "", "*L");
if (auto histo = dynamic_cast<TH1*>(c->GetPrimitive("htemp"))) {
  histo->GetXaxis()->SetTimeDisplay(1);
  histo->GetXaxis()->SetNdivisions(505);
  histo->GetXaxis()->SetTimeFormat("%Y-%m-%d %H:%M");
}
c->SaveAs("graph.root");

if i do:

root [0] TFile *f = TFile::Open("trend-tree-more-entries.root")
root [1] ExampleTrend->Draw("time")

I get a 1D histogram with the same X axis with many bins. Seems to me it is a 1D histogram with alphanumeric labels.

I think I am missing your point here. Now I know that axes are drawn first by using a histogram. The “time” branch consists of TDatime values, so I expected that they would be supported, given the fact that I can add a branch with a TDatime variable.
I am not sure what is preventing me from correctly redrawing the X axis with less dates/alphanumberic labels, so it looks clearer.

I have to check more closely but it seems, in that case, the X axis is not a time axis but an axis with character strings (alphanumeric), therefore all the labels found in the tree are plotted.

To make sure, this is how I declare and fill a branch with time:

  mTrend = std::make_unique<TTree>();
  // mTime is of type TDatime
  mTrend->Branch("time", &mTime);
  ...
  // later in the loop
  while(...) {
    mTime = TDatime();
    // then updating other variables
    ...
    // when all are updated, I generate a new row
    mTrend->Fill();
  }

If do:

TFile *f = TFile::Open("trend-tree-more-entries.root");
ExampleTrend->Draw("time");
htemp->GetXaxis()->GetLabels()->ls();

I get:

OBJ: THashList	THashList	Doubly linked list with hashtable for lookup : 0
 OBJ: TObjString	Wed Dec 18 15:06:31 2019	Collectable string class : 0 at: 0x7f8db744bb90
 OBJ: TObjString	Wed Dec 18 15:06:36 2019	Collectable string class : 0 at: 0x7f8db74436c0
 OBJ: TObjString	Wed Dec 18 15:06:41 2019	Collectable string class : 0 at: 0x7f8db7443940
 OBJ: TObjString	Wed Dec 18 15:06:46 2019	Collectable string class : 0 at: 0x7f8db7445ba0
 OBJ: TObjString	Wed Dec 18 15:06:51 2019	Collectable string class : 0 at: 0x7f8db7445d20
 OBJ: TObjString	Wed Dec 18 15:06:56 2019	Collectable string class : 0 at: 0x7f8db7445ea0
 OBJ: TObjString	Wed Dec 18 15:07:01 2019	Collectable string class : 0 at: 0x7f8db7446020
 OBJ: TObjString	Wed Dec 18 15:07:06 2019	Collectable string class : 0 at: 0x7f8db74461a0
 OBJ: TObjString	Wed Dec 18 15:07:11 2019	Collectable string class : 0 at: 0x7f8db7446320
 OBJ: TObjString	Wed Dec 18 15:07:16 2019	Collectable string class : 0 at: 0x7f8db74464a0
 OBJ: TObjString	Wed Dec 18 15:07:21 2019	Collectable string class : 0 at: 0x7f8db7446620
 OBJ: TObjString	Wed Dec 18 15:07:26 2019	Collectable string class : 0 at: 0x7f8db74467a0
 OBJ: TObjString	Wed Dec 18 15:07:31 2019	Collectable string class : 0 at: 0x7f8db7446920
 OBJ: TObjString	Wed Dec 18 15:07:36 2019	Collectable string class : 0 at: 0x7f8db7446aa0
 OBJ: TObjString	Wed Dec 18 15:07:41 2019	Collectable string class : 0 at: 0x7f8db7446c20
 OBJ: TObjString	Wed Dec 18 15:07:46 2019	Collectable string class : 0 at: 0x7f8db7446da0
 OBJ: TObjString	Wed Dec 18 15:07:51 2019	Collectable string class : 0 at: 0x7f8db7446f20
 OBJ: TObjString	Wed Dec 18 15:07:56 2019	Collectable string class : 0 at: 0x7f8db74470a0
 OBJ: TObjString	Wed Dec 18 15:08:01 2019	Collectable string class : 0 at: 0x7f8db7447220
 OBJ: TObjString	Wed Dec 18 15:08:06 2019	Collectable string class : 0 at: 0x7f8db74473a0
 OBJ: TObjString	Wed Dec 18 15:08:11 2019	Collectable string class : 0 at: 0x7f8db7447520
 OBJ: TObjString	Wed Dec 18 15:08:16 2019	Collectable string class : 0 at: 0x7f8db74476a0
 OBJ: TObjString	Wed Dec 18 15:08:21 2019	Collectable string class : 0 at: 0x7f8db7447820
 OBJ: TObjString	Wed Dec 18 15:08:26 2019	Collectable string class : 0 at: 0x7f8db74479a0
 OBJ: TObjString	Wed Dec 18 15:08:31 2019	Collectable string class : 0 at: 0x7f8db7447b20
 OBJ: TObjString	Wed Dec 18 15:08:36 2019	Collectable string class : 0 at: 0x7f8db7447ca0
 OBJ: TObjString	Wed Dec 18 15:08:41 2019	Collectable string class : 0 at: 0x7f8db7447e20
 OBJ: TObjString	Wed Dec 18 15:08:46 2019	Collectable string class : 0 at: 0x7f8db7447fa0
 OBJ: TObjString	Wed Dec 18 15:08:51 2019	Collectable string class : 0 at: 0x7f8db7448120
 OBJ: TObjString	Wed Dec 18 15:08:56 2019	Collectable string class : 0 at: 0x7f8db7448230
 OBJ: TObjString	Wed Dec 18 15:09:01 2019	Collectable string class : 0 at: 0x7f8db74483b0
 OBJ: TObjString	Wed Dec 18 15:09:06 2019	Collectable string class : 0 at: 0x7f8db7448530
 OBJ: TObjString	Wed Dec 18 15:09:11 2019	Collectable string class : 0 at: 0x7f8db74486b0

So clearly the X axis is labeled with strings.

So I should have used another type for storing the time, so it is not interpreted as a string?
I have just tried using TTimeStamp instead and with these corrections it shows time correctly:

    if (auto histo = dynamic_cast<TH1*>(c->GetPrimitive("htemp"))) {
        histo->GetXaxis()->SetTimeDisplay(1);
        histo->GetXaxis()->SetNdivisions(505);
        histo->GetXaxis()->SetTimeOffset(0.0);
        histo->GetXaxis()->SetTimeFormat("%Y-%m-%d %H:%M");
    }

Initially I have avoided TTimeStamp because of the time_t overflow and there is a little risk it may concern this piece of code. Is there any extended version of TTimeStamp in ROOT available?

As you can see for example in this example the axis limits for tie axis are defined with TDatime::Convert(); which returns an int. Then the axis is set as a time one using SetTimeDisplay(1);. But the axis limits are int not char.

Indeed, that works as well.
Thank you again for the quick support!

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