Draw many functions to one canvas and save

Dear experts,

I try to draw several lines to a canvas and then save everything into a rootfile.
I just need the plot, I do not want to store all the TF1 objects that I draw.

However, I experience a difference between PyROOT and a ROOT macro:

from ROOT import TCanvas, TH1I, TF1

f = TF1("line", "[0]*x + [1]", 0, 2000)
f.SetParameters( 200, 0 ) 

f.Draw("l")

g = TF1("line2", "[0]*x + [1]", 0, 2000)
g.SetParameters( 220, 0 ) 

g.DrawClone("lsame")

g.SetParameters( 250, 0 ) 

g.DrawClone("lsame")
{
    
TF1 *f = new TF1("linie", "[1]+[0]*x", 0,2000);
f->SetParameters(200,0);
    
f->Draw("l");

TF1 *g = new TF1("linie", "[1]+[0]*x", 0,2000);
g->SetParameters(220,0);
    
g->DrawClone("lsame");

g->SetParameters(250,0);
g->DrawClone("lsame");
}

I am using ROOT 5.30/03.

The macro is doing what it should (3 lines), the PyROOT example only draws 2 lines.

I need a solution in PyROOT. Can you help? What am I missing?

Cheers
Michael

In your ROOT macro, in general, I think you should rename one of your TF1 functions. They should not be both named “linie” (i.e. they should have different names).
I tried your original PyROOT macro with ROOT 5.28 and 5.32 and in both cases I get three lines drawn.
Try to replace the first:
f.Draw("l")
with:
f.DrawClone("l")
Well, there is something spooky around. After I replaced “Draw” with “DrawClone”, I get two lines without axes, but it works fine as soon as I add three DIFFERENT “temp_… =”:

from ROOT import TCanvas, TH1I, TF1
f = TF1("line", "[0]*x + [1]", 0, 2000)
f.SetParameters( 200, 0 )
temp_0 = f.DrawClone("l")
g = TF1("line2", "[0]*x + [1]", 0, 2000)
g.SetParameters( 220, 0 )
temp_1 = g.DrawClone("l same")
g.SetParameters( 250, 0 )
temp_2 = g.DrawClone("l same")

Thank you, Pepe,

Your example also worked in version 5.30/03.
And I found out the difference.
When performing the DrawClone method, I need to save the clone in a variable. So, creating an array, e.g. works.
Without that, the object is immediately deleted again.

Thanks for your help!

Cheers
Michael

from ROOT import TCanvas, TH1I, TF1

f = TF1("line", "[0]*x + [1]", 0, 2000)
f.SetParameters( 200, 0 ) 

f.Draw("l")

g = TF1("line2", "[0]*x + [1]", 0, 2000)
g.SetParameters( 220, 0 ) 

temp = []
temp.append(g.DrawClone("lsame"))

g.SetParameters( 250, 0 ) 

temp.append(g.DrawClone("lsame"))

Not so much spooky, but rather that DrawClone() returns a new object and PyROOT takes ownership to prevent a potential memory leak. The TCanvas and PyROOT communicate for when the object goes away, so this won’t ever lead to crashes, but does lead to the behavior seen if the python-side ref-count goes to zero.

One of those things where I just don’t know a good solution.

However, if you want to change the behavior, you can do so at the level of the function:from ROOT import TF1 TF1.DrawClone._creates = False
This is generally true: all functions carry access to an internal flag through a _creates property, and certain functions (such as DrawClone(), but also all constructors) have it set to True by default.

Cheers,
Wim

Well, there’s something I don’t get.
The DrawClone creates a new object but this object is automatically referenced by a canvas so why is its ref-count zero? Shouldn’t this canvas own this object then?

Hi,

the reference count is the count on the python-side object, in which the TCanvas does not participate. The clone itself has no refcount on it. The problem is/was that a cloned object only gets added to the list of primitives if a selected pad exists.

Cheers,
Wim