Skip to content

Commit d7bcd98

Browse files
MehkaanKhanvepadulano
authored andcommitted
[tutorial] Add example filling a bar chart from a categorical column
Per @vepadulano's review on #22802, a new BarChart() RDataFrame method tied to TH1D would risk deprecation once ROOT's new histogram system (RCategoricalAxis in hist/histv7) gains plotting support and becomes the preferred way to handle alphanumeric bins. This tutorial instead shows the same result using RDataFrame's existing generic Fill() action with a small adapter class, requiring no core API changes. Verified against the same cernstaff.root/Nation dataset used in hist006_TH1_bar_charts.C: 15 bins, labels and counts match TTree::Draw("Nation","","hbar2").
1 parent 68e67f0 commit d7bcd98

1 file changed

Lines changed: 81 additions & 0 deletions

File tree

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/// \file
2+
/// \ingroup tutorial_dataframe
3+
/// \notebook
4+
/// Fill and draw a bar chart from a categorical/string column with RDataFrame.
5+
///
6+
/// RDataFrame has no dedicated action for categorical/string columns, but the
7+
/// generic RDataFrame::Fill() action can fill any user-provided object that
8+
/// exposes Fill() and Merge() methods. This shows how to use it to build and
9+
/// draw a bar chart from a string column, reusing the "Nation" column of the
10+
/// classic CERN staff dataset also used in hist006_TH1_bar_charts.C.
11+
///
12+
/// Classic ROOT trees often store short strings in fixed-size char[] branches
13+
/// (leaf type "C"), which RDataFrame reads as ROOT::VecOps::RVec<char> rather
14+
/// than std::string. A one-line Define() converts such a column into a real
15+
/// std::string column before filling.
16+
///
17+
/// \macro_image
18+
/// \macro_code
19+
/// \macro_output
20+
///
21+
/// \date July 2026
22+
/// \author Mehkaan Khan
23+
24+
// A small adapter around TH1D that lets RDataFrame's generic Fill() action
25+
// build a histogram from a std::string column: TH1D::Fill(const char*, Double_t)
26+
// takes no default weight and std::string has no implicit conversion to
27+
// const char*, so RDataFrame can't call it directly on a plain TH1D. Wrapping
28+
// it in a class with our own Fill(const std::string&) sidesteps both issues.
29+
struct AlphaNumHist {
30+
TH1D h;
31+
32+
AlphaNumHist(const char *name, const char *title) : h(name, title, 1, 0, 1)
33+
{
34+
h.GetXaxis()->SetAlphanumeric(true);
35+
h.SetCanExtend(TH1::kAllAxes);
36+
}
37+
38+
void Fill(const std::string &s) { h.Fill(s.c_str(), 1.); }
39+
40+
// Required so RDataFrame can merge partial per-slot results when run with
41+
// implicit multi-threading enabled.
42+
void Merge(const std::vector<AlphaNumHist *> &others)
43+
{
44+
TList l;
45+
for (auto *o : others)
46+
l.Add(&o->h);
47+
h.Merge(&l);
48+
}
49+
};
50+
51+
void df041_alphanumericHistograms()
52+
{
53+
// Reuse the same "cernstaff.root" dataset as hist006_TH1_bar_charts.C,
54+
// generating it first if it doesn't already exist.
55+
TString filedir = gROOT->GetTutorialDir();
56+
filedir += TString("/io/tree/");
57+
TString filename = "cernstaff.root";
58+
bool fileNotFound = gSystem->AccessPathName(filename);
59+
if (fileNotFound) {
60+
TString macroName = filedir + "tree500_cernbuild.C";
61+
if (!gInterpreter->IsLoaded(macroName))
62+
gInterpreter->LoadMacro(macroName);
63+
gROOT->ProcessLineFast("tree500_cernbuild()");
64+
}
65+
66+
ROOT::RDataFrame df0("T", filename.Data());
67+
68+
// "Nation" is a classic char[] branch, read by RDataFrame as
69+
// ROOT::VecOps::RVec<char>. Converting it to a real std::string column
70+
// makes it fillable through the AlphaNumHist adapter above.
71+
auto df = df0.Define("NationStr", [](const ROOT::VecOps::RVec<char> &c) { return std::string(c.begin(), c.end()); },
72+
{"Nation"});
73+
74+
AlphaNumHist model("hNation", "Staff by nation;Nation;Count");
75+
auto h = df.Fill<std::string>(model, {"NationStr"});
76+
h->h.LabelsDeflate("X");
77+
78+
auto c1 = new TCanvas("c1", "Bar chart from RDataFrame", 700, 500);
79+
h->h.SetFillColor(45);
80+
h->h.DrawCopy("bar2");
81+
}

0 commit comments

Comments
 (0)