Display depth of non-canvas-primitive objects like stats

Greetings,

Often times I draw a histogram with stat options enabled, and the stat box covers a portion of the data. Rather than relocate the stat box, I would like to move it backwards in the arrangement of the objects displayed on the canvas. However, as the “stats” object is not a primitive of the canvas like the “title” object – why isn’t it by the way? – TObject::Pop() is not a solution. In fact, even if “stats” were available to Pop, it would not produce the aesthetic I am after.

Here are a few trivial CINT lines to see how the stat box covers a portion of the data:

gStyle->SetOptStat(111111)                   
TH1F* h1 = new TH1F("h1", "h1", 10, 0, 10)   
h1->SetLineColor(2)                          
for(int i = 0; i < 100; i++) { h1->Fill(9); }
h1->Draw()

Here is how I circumvent this to achieve the aesthetic I seek:

gStyle->SetOptStat(111111)                   
TH1F* h1 = new TH1F("h1", "h1", 10, 0, 10)   
h1->SetLineColor(2)                          
for(int i = 0; i < 100; i++) { h1->Fill(9); }
h1->Draw()                                   
TPaveStats* stats = h1->FindObject("stats")->Clone()
gStyle->SetOptStat(0)
stats->Draw()
h1->Draw("same")

If instead I replace h1->Draw(“same”) in the above example with h1->Pop() I am left with a different image: h1->Pop() appears to also move to the front the TFrame which obstructs the stat box in a completely different manner than do the histogram lines alone.

Is it possible to arrive at my desired aesthetic without the Clones and SetStyles? Any comments appreciated!

Jake

Move the stats box as explained in the documentation.
see section “Statistics Display” at root.cern.ch/root/html/THistPainter.html#HP07
and see example below

{ TCanvas *c1 = new TCanvas("c1"); gStyle->SetOptStat(111111) ; TH1F* h1 = new TH1F("h1", "h1", 10, 0, 10); h1->SetLineColor(2) ; for(int i = 0; i < 100; i++) { h1->Fill(9); } h1->Draw(); c1->Update(); //to force the generation of the stats box TPaveStats* stats = h1->FindObject("stats"); stats->SetX1NDC(0.4); stats->SetX2NDC(0.6); c1->Modified(); }

Rene

Hi Rene,

I know already how to relocate the stat box as per your instructions and the official documentation, but I explicitly said in my post that this is not what I want to do. Attached are two images to hopefully demonstrate what I want:

bad.png is the result of my first code snippet, and shows the stat box covering the red histogram line at the top of the bin. good.png is the result of my second code snippet, and shows the red histogram line at the top of the bin in front of the stat box.

The histogram line does not obstruct my view of the stat box enough to mind. This is useful, for example, when looping over a large number of histograms with unknown characteristics where it is difficult to know a priori for each histogram where best to position the stat box so as not to conceal the data.

Does this clarify what I am after?

Jake




Set the fill style to hollow, ie

{ TCanvas *c1 = new TCanvas("c1"); gStyle->SetOptStat(111111) ; TH1F* h1 = new TH1F("h1", "h1", 10, 0, 10); h1->SetLineColor(2) ; for(int i = 0; i < 100; i++) { h1->Fill(9); } h1->Draw(); c1->Update(); //to force the generation of the stats box TPaveStats* stats = h1->FindObject("stats"); stats->SetFillStyle(0); c1->Modified(); }

Rene

Thanks Rene, this is close enough to what I want that I will likely adopt the method.

However, the final plot using hollow fill style does not look exactly like the final plot in good.png (now I am being picky). Attached is hollowstats.png in which I utilize your code snippet.

In hollowstats.png, both the TFrame and histogram are displayed on top of (actually through) the stat box. However, in good.png, while the histogram is drawn on top of the stat box, the TFrame remains behind it.

In the hollowstats.png case, there are three canvas primitives: the TFrame, the TH1 and the title object (in that order), and the hollow fill style allows the TFrame and TH1 to be seen through the stat box.

In the good.png case, added to the back of the list of primitives are the cloned stats object and the TH1 object with stat option disabled. The TFrame is drawn first, then the stats object, and then the TH1, but since the TH1 was Draw(“same”)'d it does not draw a TFrame on top of the stat box.

So, is it possible to achieve the look of good.png without my example Clone and SetOptStat kludge? I guess this would require some combination of adding the stats object(s) to the canvas list of primitives, and some proper ordering of this list.

Jake


I can further clarify the points raised in my last post…

After a histogram is drawn and the stat box is displayed, I would like to do h1->Pop() to bring the histogram in front of the stat box without dragging along the TFrame. This, however, requires several things (as far as I can tell):

  1. The stats object(s) associated to histograms must be added to the canvas list of primitives. Of course, care must be taken in the case of Draw(“sames”). The default behavior of h1->Draw() when stat options are enabled would then be to place the stats object after the TH1 in the canvas list of primitives.

  2. For reasons I don’t understand, the TFrame is “attached” to the TH1 after an h1->Draw(). This can be seen by executing the following code snippet,

gStyle->SetOptStat(111111)                   
TH1F* h1 = new TH1F("h1", "h1", 10, 0, 10)   
h1->SetLineColor(2)                         
for(int i = 0; i < 100; i++) { h1->Fill(9); }
h1->Draw()                                   
TPaveStats* stats = h1->FindObject("stats")->Clone()
gStyle->SetOptStat(0) 
c1->Modified()
stats->Draw()
h1->Pop()

where h1->Pop() brings also to the front the TFrame. The TFrame would need to be “detached” from the TH1 so that the default behavior of h1->Draw() is to first draw the TFrame and the axes and whatnot, and then essentially do what is now h1->Draw(“sames”). If this were so, the above code snippet would essentially become something like the following (except of course for the missing axes and whatnots):

gStyle->SetOptStat(111111)                    
TH1F* h1 = new TH1F("h1", "h1", 10, 0, 10)   
h1->SetLineColor(2)                         
for(int i = 0; i < 100; i++) { h1->Fill(9); }
h1->Draw()                                   
TPaveStats* stats = h1->FindObject("stats")->Clone()
gStyle->SetOptStat(0) 
TFrame* frame = gPad->GetFrame()->Clone()     
c1->Clear()
frame->Draw()
h1->Draw("same")
stats->Draw()
h1->Pop()

which produces (almost) that which is seen in good.png. For sure I am beating a dead horse over trivial matters, but this is a forum for discussion after all :slight_smile:

Jake