Home | News | Documentation | Download

BuildLegend() takes ages with TGraph with many points

I simply don’t understand that…

  1. Download ROOT file
  2. Run the following script (it works fine)
  3. Try to BuildLegend in the GUI (freezes for eternity after pressing OK)
  4. Try to uncomment canvas.BuildLegend() (freezes for eternity)
  5. Change .Range(100000) to .Range(100) (now it takes ~10 sec for Legend to appear after pressing BuildLegend in GUI or code to finish if BuildLegend() inside the code)
import ROOT

methods = [["pTrackAtCalo", "lengthTrackCalo", "Frank", "0.0"],
            ["pTrackAtIP", "lengthTrackIP", "FrankAvg", "0.0"]]

def beta_vs_p(tree_name):
    canvas = ROOT.TCanvas("beta_vs_p")
    df = ROOT.RDataFrame(tree_name, tree_name + ".root").Range(100000).Filter('if(rdfentry_ == 0) {cout << "Running evtloop" << endl; return true;} return true;')
    gr_bg = df.Filter("abs(PDG) != 2212 && abs(PDG) != 321 && abs(PDG) != 211").Graph("mom", "beta")
    gr_pion = df.Filter("abs(PDG) == 211").Graph("mom", "beta")
    gr_kaon = df.Filter("abs(PDG) == 321").Graph("mom", "beta")
    gr_proton = df.Filter("abs(PDG) == 2212").Graph("mom", "beta")

    gr_bg.SetTitle("Background;p, [GeV];#beta")
    gr_bg.GetXaxis().SetRangeUser(1., 10.)
    gr_bg.GetYaxis().SetRangeUser(0.7, 1.1)




    # canvas.BuildLegend()
    # gr_bg.SetTitle(tree_name)


I waited around an hour thinking my code is running just long, but it simply break at building the legend…

I tried and could not reproduce it with any more simple example. So I attach the root file for tests.

ROOT file is here.

ROOT Version: 6.22/00
Python 3

@couet There seems to be a bug in drawing the legend, which is visible due to another bug in its creation.
The line:
(quickly / immediately) creates a buggy (note X1=X2 and Y1=Y2):
OBJ: TLegend TPave X1= 0.300000 Y1=0.210000 X2=0.300000 Y2=0.210000
and then the actual drawing triggered by canvas.Update() hangs forever.

@FoxWise A fix:
canvas.BuildLegend(0.5, 0.2, 0.8, 0.5)

1 Like

I will check. The legend coordinates are wrong anyway but it should not take ages. I guess a protection is needed.

How have you seen that ?
Do you have a reproducer ?
I can not reproduce this.

I took the original macro and added “canvas.ls()” before and after “BuildLegend” and “Update” statements.

Here one ca read:

Automatic placement of the legend

If x1 is equal to x2 and y1 is equal to y2 the legend will be automatically placed to avoid overlapping with the existing primitives already displayed. x1 is considered as the width of the legend and y1 the height. By default the legend is automatically placed with width = x1= x2= 0.3 and height = y1= y2 = 0.21.

… We are in that case.

This mechanism is working See legendautoplaced here. Could it be a Python issue ? have you tried your example in C++ ?

I am debugging the automatic placement. It might be we enter an infinite loop there.

1 Like

I checked in C++, freeze is still occurs.

Here is the reproduction code:

int test(){
    auto canvas = new TCanvas("test");
    ROOT::RDataFrame df("pTrackAtCalo_lengthTrackCalo_Frank_0.0", "./final_roots/pTrackAtCalo_lengthTrackCalo_Frank_0.0.root");
    //~1 minute executing time
    auto gr = df.Filter("abs(PDG) == 321").Range(100).Graph("mom", "beta");
    // freeze
    // auto gr = df.Filter("abs(PDG) == 321").Range(100000).Graph("mom", "beta");

    gr->GetXaxis()->SetRangeUser(1., 10.);
    gr->GetYaxis()->SetRangeUser(0.7, 1.1);

    cout<<"Starting building the legend"<<endl;

    cout<<"Starting to Update the canvas"<<endl;
    cout<<"I am working!"<<endl;
    return 0;

Warning in <TLegend::Paint>: Legend too large to be automatically placed; a default position is used
showed in the output.

And freeze occure at canvas.Update()

While you’re at it … have also a look at this … in the “legendautoplaced” macro I used “c4->BuildLegend()->Print();” and the output was:

 TLegendEntry: Object hpx Label This is the hpx distribution Option lpf <- 1 x lpf
 TLegendEntry: Object h1 Label A green histogram Option lpflpf  <- 2 x lpf
 TLegendEntry: Object  Label This is a TGraph Option lpflpflpf <- 3 x lpf

BTW. You’re right … also in a C++ code, the correct legend coordinates appear only after the canvas has been “physically updated”.

I am debugging. I will let you know.
Meanwhile do not use automatic placement.
BTW I saw your plot and there is no space inside the frame to place a legend without overlapping the plot.

Understood: The TGraphs you have in your plot have 64035 points each. Only scanning the first
one, to check if the legend “collide” it or not, takes ages. I will need to improve the algorithm in order to not check all the points but may be just a few in the graphs. So, yes, right now do not use the automatic placement.

1 Like

Which is normal. The automatic coordinates can only be computed when everything is in the canvas so at painting time.

Yes … 3 entries in the legend … that’s fine …

The PR fixing this issue is here:

1 Like

Which is normal. The automatic coordinates can only be computed when everything is in the canvas so at painting time.

Yes, I understand now that the “legend” belongs to the same category as “stats” (i.e., fully accessible first after “physical update”).

Yes … 3 entries in the legend … that’s fine …

It’s not about the number of entries. It’s about their options … the first one “lpf”, the second one “lpflpf” and the third one “lpflpflpf”.

Good catch. I updated the PR to fix that.

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