Strange behaviour of pyroot (?) when drawing a cloned histogram in ratio pad

Hello

I am reading some histograms from a file and given that I have different processes, categories and systematics, I use dictionaries. My problem is the following.

I am creating 2 TPads, one to draw the nominal and overlay the systematics, and a ratio where the idea is to plot the systematic/nominal. So what I do is to make a clone of the systematic plot (h1[syst][group][cat]) that goes on the the top canvas and then divide it with the “nominal” template (h[group][cat] - Note that the nominal template does not come into X syst copies, but still one per group and per category)

                #top canvas, plot systematic - nominal shape is already plotted from a previous step
                cP[group][cat].cd()
                cP[group][cat].SetLogy()
                h1[sys][group][cat].Draw("hist same p")
                cT[group].Update()

                #go to the bottom pad to plot the ratio
                cPr[group][cat].cd()
                #make a clone of the systematic
                h2r=h1[sys][group][cat].Clone("h2r")

                if isys ==0 :      
                    #if this is the first systematic, change some properties 
                    h2.GetYaxis().SetRangeUser(0.5,1.5)
                    h2r.Divide(h[group][cat])
                    h2r.Draw("hist  p")
                else :
                    h2r.Draw("hist  same p")
               cPr[group][cat].Update()

The problem is that the ratio pad is drawn, but it always empty (see attached picture). One the other hand, if I do

                #top canvas, plot systematic - nominal shape is already plotted from a previous step
                cP[group][cat].cd()
                cP[group][cat].SetLogy()
                h1[sys][group][cat].Draw("hist same p")
                cT[group].Update()

                #go to the bottom pad to plot the ratio
                cPr[group][cat].cd()
                # do not make a clone of the systematic, just divide it directly with the nominal shape
                h1[sys][group][cat].Clone("h2r")

                if isys ==0 :      
                    #if this is the first systematic, change some properties 
                    h1[sys][group][cat].GetYaxis().SetRangeUser(0.5,1.5)
                    h1[sys][group][cat].Divide(h[group][cat])
                    h1[sys][group][cat].Draw("hist  p")
                else :
                    h1[sys][group][cat].Draw("hist  same p")
               cPr[group][cat].Update()

then the ratio pat is filled, but the “ratio” is also propagagated to the top pad as well (see other attached pic).

Anyway, it looks like I cannot get it to work for either case, so any hep would be appreciated (although I can probably understand that in the second case, I modify the histo that also goes in the top canvas and this is why that happens, however I cannot understand why when working with clones the pad is empty).

Thanks in advance,
Alex

Screen Shot 2020-12-08 at 13.24.31.pdf (452.3 KB) Screen Shot 2020-12-08 at 13.13.55.pdf (400.0 KB)

Hello,

Usually, when doing graphics in PyROOT and seeing an empty pad / canvas, what happened is that the objects that were supposed to be drawn there (histograms in your case) went out of scope and were garbage collected by Python.

Looking at your code, you seem to be storing references in a dictionary to the histograms you read (that’s good, they will survive as long as the dictionary does) but the problem could be that the clone you create (bound to h2r) is garbage collected at some point. I would store a reference to it in a list / dictionary to try to keep it alive.

Hello

thanks for your input. However, I cannot see where the h2r could be garbage collected anywhere, since it is a direct clone of the h[group][cat] (which I can still call and draw). Also, I am not sure as I said in the second case scenario, why the “ratio” is propaged to the top canvas, given that I only .cd() in the bottom one…

Is the first code snippet that you posted inside a function? If yes, h2r will be garbage collected when returning from that function. In this line:

h2r=h1[sys][group][cat].Clone("h2r")

you create a new C++ object (the clone) which is proxied by a new Python object, bound to h2r. The life of h1[sys][group][cat] and h2f are thus independent. If h2f is drawn and it is deleted afterwards, it won’t be shown in the canvas independently of whether h1[sys][group][cat] is alive or not.

Regarding your question about cding into the bottom canvas, I think this is not PyROOT related and thus we’ll need @couet.

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