Home | News | Documentation | Download

How to use RDataFrame.Fill in python?

I am trying to use RDataFrame.Fill in pyroot.
My object has Fill ( double) method, and I am using

RDF = ROOT.RDataFrame

frame = ...

hh = frame.Fill ( myObject() , RDF.ColumnNames_t ( 1 , 'myvar' ) ) 

but I get an error:

TypeError: Template method resolution failed:
  Failed to instantiate "Fill(Ostap::StatEntity&,std::vector<string>&)"
  Failed to instantiate "Fill(Ostap::StatEntity*,std::vector<string>*)"
  Failed to instantiate "Fill(Ostap::StatEntity,std::vector<string>)"

I am also trying to use TH1D

hh = fr.Fill (ROOT.TH1D()  , RDF.ColumnNames_t ( 1 , 'myvar' ) ) 

but also get an error:

TypeError: Template method resolution failed:
  Failed to instantiate "Fill(TH1D&,std::vector<string>&)"
  Failed to instantiate "Fill(TH1D*,std::vector<string>*)"
  Failed to instantiate "Fill(TH1D,std::vector<string>)"

(I know that for case of histos I can use Histo1D, but bu purpose here is to use MyObject)

I am tried with ROOT 6.20 and with 6.25/1 from dev2 lcg-nightly slot on lxplus)

Hi @ibelyaev ,
there are two open issues regarding RDF’s Fill method (and Python): https://sft.its.cern.ch/jira/browse/ROOT-10396 and https://sft.its.cern.ch/jira/browse/ROOT-9737 .

Both can be worked around. Does Ostap::StatEntity inherit from TH1?

Cheers,
Enrico

Dear Enrico,

No, Ostap::StatEntity does not inheri from TH1, but it has methods Fill and Add with proper signatures

Ok,
so since you can pick up our nightly builds, I would suggest that I finally fix https://sft.its.cern.ch/jira/browse/ROOT-9737 so you don’t have to work around that issue, and then we can write a little helper function that works around https://sft.its.cern.ch/jira/browse/ROOT-10396 .

If that’s ok with you, I will be in touch asap (a couple of days, probably).
Cheers,
Enrico

Hi Enrico,
Thank you! It is fine for me!
cheers, Vanya

1 Like

A fix for https://sft.its.cern.ch/jira/browse/ROOT-9737 is up, I plan to merge it today so it should be available in tomorrow’s nightlies .

With that, you can do something like this (complicating it at will):

import ROOT

ROOT.gInterpreter.Declare("""
class SimpleFiller {
   TH1D fHisto;

public:
   SimpleFiller() : fHisto("", "", 128, 0., 0.) {}
   SimpleFiller(const SimpleFiller &) = default;
   SimpleFiller(SimpleFiller &&) = default;

   void Fill(double x) { fHisto.Fill(x); }
   void Merge(const std::vector<SimpleFiller *> &others)
   {
      TList l;
      for (auto *o : others)
         l.Add(&o->GetHisto());
      fHisto.Merge(&l);
   }

   TH1D &GetHisto() { return fHisto; }
};

template <typename RDF>
auto call_fill(RDF df) {
    return df.Fill(SimpleFiller(), {"x"});
}
""")

df = ROOT.RDataFrame(10).Define("x", "42")
simplefilled = ROOT.call_fill(df)
print(simplefilled.GetHisto().GetMean())

We plan to improve the situation by pythonizing Fillbut I don’t know yet how the end result will look like.

Cheers,
Enrico