RNTuple python interface existing?

Dear experts,

I am experimenting some tupling using RNTuple with ROOT master ( or most recent one) for the simplicity of filling new tuples to make.

I looked at the tutorials in ROOT: tutorials/v7/ntuple/ntpl002_vector.C File Reference but i do not find any python example.
Does it mean that the RNTuple cannot be “looped” with python or maybe, once i read a RNTuple, i can proceed with it as a normal TTree in pyroot?

Thanks in advance

Renato

I guess @jblomer can help with RNTuple

Hi Renato,

we implemented some basic RNTuple Python API end of last year, but you are right that there are no dedicated Python tutorials yet while we are trying to understand the use cases. For basic filling and looping, RNTupleWriter and RNTupleReader should work as documented for C++. You can also get an idea of the basics by looking at the test file: root/tree/ntuple/v7/test/ntuple_basics.py at ddde39fbfa26987604bb4c0a1b28a41432ed161b · root-project/root · GitHub

Note that for reading RNTuple data, especially from Python, you can also use RDataFrame with zero changes compared to the TTree version: Just pass the RNTuple name and file to the constructor and all Filters and Defines will work as usual. This has the additional benefit of better ergonomics and performance, for example with implicit multi-threading.

Hope this helps,
Jonas

2 Likes

Thanks a lot @hahnjo , using RDataFrame to read directly the RNtuple in the file is what i will use then.

Reading the file directly with uproot might be useful as well, i recently came back to use it and reading RVec columns is very handy with uproot for fast inspection of the content. Not sure if uproot is natively able to read RNTuples. In any case, i am fine with Dataframe for the moment.

Thanks a lot!

Please note that uproot is not developed by the ROOT team and we cannot comment on whether it supports RNTuple. You are able to read RNTuple data directly with PyROOT and RNTupleReader though.

Dear @hahnjo

I am trying to run a macro example with RDataFrame reading of the example i get with

wget http://root.cern.ch/files/tutorials/ntpl004_dimuon_v1rc1.root

when i run the example macro in attachment , example.C


R__LOAD_LIBRARY(ROOTNTuple)

#include <ROOT/RDataFrame.hxx>
#include <ROOT/RNTuple.hxx>
#include <ROOT/RNTupleDS.hxx>
#include <ROOT/RVec.hxx>
 
#include <TCanvas.h>
#include <TH1D.h>
#include <TLatex.h>
#include <TStyle.h>
 
#include <cassert>
#include <cmath>
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <utility>
 
// Import classes from experimental namespace for the time being
using RNTupleReader = ROOT::Experimental::RNTupleReader;
using RNTupleDS = ROOT::Experimental::RNTupleDS;
 
constexpr char const* kNTupleFileName = "ntpl004_dimuon_v1rc1.root";
 
using namespace ROOT::VecOps;
 
void example() {
   // Use all available CPU cores
   ROOT::EnableImplicitMT();
 
   auto df = ROOT::RDF::Experimental::FromRNTuple("Events", kNTupleFileName);
 
   // The tutorial is identical to df102_NanoAODDimuonAnalysis except the use of
   // InvariantMassStdVector instead of InvariantMass (to be fixed in a later version of RNTuple)
 
   // For simplicity, select only events with exactly two muons and require opposite charge
   auto df_2mu = df.Filter("#Muon == 2", "Events with exactly two muons");
   auto df_os = df_2mu.Filter("Muon.charge[0] != Muon.charge[1]", "Muons with opposite charge");
 
   // Compute invariant mass of the dimuon system
   auto df_mass = df_os.Define("Dimuon_mass", InvariantMass<float>, {"Muon.pt", "Muon.eta", "Muon.phi", "Muon.mass"});
 
   // Make histogram of dimuon mass spectrum
   auto h = df_mass.Histo1D({"Dimuon_mass", "Dimuon_mass", 30000, 0.25, 300}, "Dimuon_mass");
 
   // Request cut-flow report
   auto report = df_mass.Report();
 
   // Produce plot
   gStyle->SetOptStat(0); gStyle->SetTextFont(42);
   auto c = new TCanvas("c", "", 800, 700);
   c->SetLogx(); c->SetLogy();
 
   h->SetTitle("");
   h->GetXaxis()->SetTitle("m_{#mu#mu} (GeV)"); h->GetXaxis()->SetTitleSize(0.04);
   h->GetYaxis()->SetTitle("N_{Events}"); h->GetYaxis()->SetTitleSize(0.04);
   h->DrawCopy();
 
   TLatex label; label.SetNDC(true);
   label.DrawLatex(0.175, 0.740, "#eta");
   label.DrawLatex(0.205, 0.775, "#rho,#omega");
   label.DrawLatex(0.270, 0.740, "#phi");
   label.DrawLatex(0.400, 0.800, "J/#psi");
   label.DrawLatex(0.415, 0.670, "#psi'");
   label.DrawLatex(0.485, 0.700, "Y(1,2,3S)");
   label.DrawLatex(0.755, 0.680, "Z");
   label.SetTextSize(0.040); label.DrawLatex(0.100, 0.920, "#bf{CMS Open Data}");
   label.SetTextSize(0.030); label.DrawLatex(0.630, 0.920, "#sqrt{s} = 8 TeV, L_{int} = 11.6 fb^{-1}");
 
   // Print cut-flow report
   report->Print();
}

I get :

libc++abi: terminating due to uncaught exception of type ROOT::Experimental::RException: no RNTuple named 'Events' in file 'ntpl004_dimuon_v1rc1.root' (unchecked RResult access!)
At:
  ROOT::Experimental::RResult<ROOT::RNTuple> ROOT::Experimental::Internal::RMiniFileReader::GetNTupleProper(std::string_view) [/Users/renato/AppSrcs/root_src/tree/ntuple/v7/src/RMiniFile.cxx:759]

Do you have suggestions why this is not working on my mac?

this is the root–version

$|=>root --version
ROOT Version: 6.34.04
Built for macosxarm64 on Mar 06 2025, 07:33:01
From tags/v6-34-04@v6-34-04

tough, in pyroot with a custom file i produced with RNTuple, i can work with it fine

import numpy as np
import matplotlib.pyplot as plt
from collections import Counter
import mplhep as hep
plt.style.use(hep.style.LHCb2)  # LHCb2 is the updated style; LHCb is also available
import glob 
import ROOT 
ROOT.gSystem.Load("libROOTNtuple")
df = ROOT.RDF.Experimental.FromRNTuple("name", "file.root");   
for c in df.GetColumnNames(): print(c)
dfNp = df.AsNumpy()

Hi,

please note that the macro is C++, so this isn’t anymore about Python. I would suggest opening a topic (if there are further questions after my answer below).

The reason RDataFrame cannot find the Events RNTuple is that the file contains, as the file name suggests, release candidate 1 (rc1) of the RNTuple format. This is actually very old (ROOT 6.30) and in ROOT 6.34 we released the final v1 binary format. If you look at ROOT: tutorials/v7/ntuple/ntpl004_dimuon.C File Reference you will find the new URL: http://root.cern/files/tutorials/ntpl004_dimuon_v1.root

Regards
Jonas

1 Like

Thanks for the reply, indeed the issue was an outdated file. With what i produce, i can read and work with fine. Thanks!