From 34ad3b3707ef5aeb5aca38247abb750edbe636a5 Mon Sep 17 00:00:00 2001 From: Mehkaan Khan Date: Mon, 13 Jul 2026 20:15:39 +0500 Subject: [PATCH 1/4] [RDF] Add BarChart() action for categorical/string columns Histo1D only supports numeric columns; there was no way to fill a histogram from a string/categorical column (e.g. particle type, detector region labels) without manual workarounds. This adds a BarChart() lazy action that fills a label-binned, auto-extending TH1D from either std::string columns or classic C-style char[] tree branches (inferred as RVec by RDataFrame). - ActionTags::BarChart + a dedicated BuildAction overload - BarChartHelper, since FillHelper cannot compile against either std::string or RVec (no implicit conversion to the const char* Fill overload) - RInterface::BarChart(vName, name, title) - Test coverage in dataframe_histomodels.cxx (bin ordering/counts) and dataframe_simple.cxx (auto name/title derivation) Closes #17057 --- tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx | 60 +++++++++++++++++++ .../dataframe/inc/ROOT/RDF/InterfaceUtils.hxx | 13 ++++ tree/dataframe/inc/ROOT/RDF/RInterface.hxx | 29 +++++++++ tree/dataframe/test/dataframe_histomodels.cxx | 18 ++++++ tree/dataframe/test/dataframe_simple.cxx | 12 ++++ 5 files changed, 132 insertions(+) diff --git a/tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx b/tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx index c64870a0e0c48..2ee30d8dfb1dd 100644 --- a/tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx +++ b/tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx @@ -483,6 +483,66 @@ public: } }; +// BarChartHelper: fills a TH1D from string/categorical columns via TH1D::Fill(const char*). +// FillHelper::Exec cannot do this: std::string has no implicit conversion to const char*, +// so its non-container Exec overload's decltype(Fill(x...)) SFINAEs out, and std::string is +// explicitly excluded from IsDataContainer (see Utils.hxx), so the container-fill overload +// SFINAEs out too -- FillHelper simply won't compile for a std::string column. +class R__CLING_PTRCHECK(off) BarChartHelper : public RActionImpl { + std::vector<::TH1D *> fObjects; + +public: + BarChartHelper(BarChartHelper &&) = default; + BarChartHelper(const BarChartHelper &) = delete; + + BarChartHelper(const std::shared_ptr<::TH1D> &h, const unsigned int nSlots) : fObjects(nSlots, nullptr) + { + fObjects[0] = h.get(); + for (unsigned int i = 1; i < nSlots; ++i) { + fObjects[i] = new ::TH1D(*fObjects[0]); + UnsetDirectoryIfPossible(fObjects[i]); + } + } + + void InitTask(TTreeReader *, unsigned int) {} + + void Exec(unsigned int slot, const std::string &label) { fObjects[slot]->Fill(label.c_str(), 1.0); } + + void Exec(unsigned int slot, const ROOT::VecOps::RVec &label) + { + fObjects[slot]->Fill(std::string(label.begin(), label.end()).c_str(), 1.0); + } + + void Initialize() { /* noop */ } + + void Finalize() + { + if (fObjects.size() > 1) { + TList l; + for (auto it = ++fObjects.begin(); it != fObjects.end(); ++it) + l.Add(*it); + fObjects[0]->Merge(&l); + + for (auto it = ++fObjects.begin(); it != fObjects.end(); ++it) + delete *it; + } + fObjects[0]->LabelsDeflate("X"); + } + + ::TH1D &PartialUpdate(unsigned int slot) { return *fObjects[slot]; } + + std::string GetActionName() { return std::string("BarChart\n") + fObjects[0]->GetName(); } + + BarChartHelper MakeNew(void *newResult, std::string_view /*variation*/ = "nominal") + { + auto &result = *static_cast *>(newResult); + ResetIfPossible(result.get()); + UnsetDirectoryIfPossible(result.get()); + return BarChartHelper(result, fObjects.size()); + } +}; + + #ifdef R__HAS_ROOT7 template class R__CLING_PTRCHECK(off) RHistFillHelper diff --git a/tree/dataframe/inc/ROOT/RDF/InterfaceUtils.hxx b/tree/dataframe/inc/ROOT/RDF/InterfaceUtils.hxx index 7b241022750d7..979bd5cfcfeff 100644 --- a/tree/dataframe/inc/ROOT/RDF/InterfaceUtils.hxx +++ b/tree/dataframe/inc/ROOT/RDF/InterfaceUtils.hxx @@ -87,6 +87,7 @@ public: /// This namespace defines types to be used for tag dispatching in RInterface. namespace ActionTags { struct Histo1D{}; +struct BarChart{}; struct Histo2D{}; struct Histo3D{}; struct HistoND{}; @@ -153,6 +154,18 @@ BuildAction(const ColumnNames_t &bl, const std::shared_ptr<::TH1D> &h, const uns } } +// BarChart filling: always uses BarChartHelper (labels have no numeric axis limits to check) +template +std::unique_ptr +BuildAction(const ColumnNames_t &bl, const std::shared_ptr<::TH1D> &h, const unsigned int nSlots, + std::shared_ptr prevNode, ActionTags::BarChart, const RColumnRegister &colRegister) +{ + using Helper_t = BarChartHelper; + using Action_t = RAction>; + return std::make_unique(Helper_t(h, nSlots), bl, std::move(prevNode), colRegister); +} + + // Action for Histo3D, where thread safe filling might be supported to save memory template std::unique_ptr diff --git a/tree/dataframe/inc/ROOT/RDF/RInterface.hxx b/tree/dataframe/inc/ROOT/RDF/RInterface.hxx index aa3bb93285d00..e1e51e10132c8 100644 --- a/tree/dataframe/inc/ROOT/RDF/RInterface.hxx +++ b/tree/dataframe/inc/ROOT/RDF/RInterface.hxx @@ -1499,6 +1499,35 @@ public: return Histo1D({h_name.c_str(), h_title.c_str(), 128u, 0., 0.}, vName); } + //////////////////////////////////////////////////////////////////////////// + /// \brief Fill and return a one-dimensional histogram with the values of a categorical/string column (*lazy action*). + /// \tparam V The type of the column used to fill the histogram (must be std::string). + /// \param[in] vName The name of the column that will fill the histogram. + /// \param[in] name The name of the returned histogram. Defaults to the column name. + /// \param[in] title The title of the returned histogram. Defaults to ";;count". + /// \return the bar chart histogram wrapped in a RResultPtr, one bin per distinct label encountered. + /// + /// The returned TH1D has an extendable axis (TH1::kAllAxes) that grows a new bin for each + /// previously-unseen label; bins are ordered by first-encounter order, not sorted. + /// + /// ### Example usage: + /// ~~~{.cpp} + /// auto h = myDf.BarChart("Nation"); + /// ~~~ + template + RResultPtr<::TH1D> BarChart(std::string_view vName, std::string_view name = "", std::string_view title = "") + { + const auto h_name = name.empty() ? std::string(vName) : std::string(name); + const auto h_title = title.empty() ? (h_name + ";" + h_name + ";count") : std::string(title); + const auto userColumns = ColumnNames_t({std::string(vName)}); + const auto validatedColumns = GetValidatedColumnNames(1, userColumns); + + std::shared_ptr<::TH1D> h(new ::TH1D(h_name.c_str(), h_title.c_str(), 1, 0., 1.)); + h->SetCanExtend(::TH1::kAllAxes); + return CreateAction(validatedColumns, h, h, fProxiedPtr); + } + + //////////////////////////////////////////////////////////////////////////// /// \brief Fill and return a one-dimensional histogram with the weighted values of a column (*lazy action*). /// \tparam V The type of the column used to fill the histogram. diff --git a/tree/dataframe/test/dataframe_histomodels.cxx b/tree/dataframe/test/dataframe_histomodels.cxx index 5ea6adfb057fe..2921ac69768d1 100644 --- a/tree/dataframe/test/dataframe_histomodels.cxx +++ b/tree/dataframe/test/dataframe_histomodels.cxx @@ -62,6 +62,24 @@ TEST(RDataFrameHistoModels, Histo1D) CheckBins(h2edgesd->GetXaxis(), edgesd); } +TEST(RDataFrameHistoModels, BarChart) +{ + ROOT::RDataFrame tdf(6); + std::vector labels{"a", "b", "a", "c", "b", "a"}; + auto i = 0u; + auto d = tdf.Define("x", [&i, &labels]() { return labels[i++]; }); + auto h = d.BarChart("x"); + + ASSERT_EQ(h->GetNbinsX(), 3); + EXPECT_STREQ(h->GetXaxis()->GetBinLabel(1), "a"); + EXPECT_STREQ(h->GetXaxis()->GetBinLabel(2), "b"); + EXPECT_STREQ(h->GetXaxis()->GetBinLabel(3), "c"); + EXPECT_DOUBLE_EQ(h->GetBinContent(1), 3); + EXPECT_DOUBLE_EQ(h->GetBinContent(2), 2); + EXPECT_DOUBLE_EQ(h->GetBinContent(3), 1); +} + + TEST(RDataFrameHistoModels, Prof1D) { ROOT::RDataFrame tdf(10); diff --git a/tree/dataframe/test/dataframe_simple.cxx b/tree/dataframe/test/dataframe_simple.cxx index 6e1461e3f9a7b..3f0016a607bcd 100644 --- a/tree/dataframe/test/dataframe_simple.cxx +++ b/tree/dataframe/test/dataframe_simple.cxx @@ -824,6 +824,18 @@ TEST(RDFSimpleTests, AutomaticNamesOfHisto1DAndGraph) EXPECT_STREQ(gxy->GetYaxis()->GetTitle(), "y"); } +TEST(RDFSimpleTests, AutomaticNamesOfBarChart) +{ + auto df = RDataFrame(1).Define("x", []() { return std::string("a"); }); + auto hx = df.BarChart("x"); + + EXPECT_STREQ(hx->GetName(), "x"); + EXPECT_STREQ(hx->GetTitle(), "x"); + EXPECT_STREQ(hx->GetXaxis()->GetTitle(), "x"); + EXPECT_STREQ(hx->GetYaxis()->GetTitle(), "count"); +} + + TEST_P(RDFSimpleTests, DifferentTreesInDifferentThreads) { const auto filename = "DifferentTreesInDifferentThreads.root"; From f18220177ffa9a4e65c01db40575e88ac30c02cb Mon Sep 17 00:00:00 2001 From: Mehkaan Khan Date: Tue, 14 Jul 2026 18:24:42 +0500 Subject: [PATCH 2/4] Revert "[RDF] Add BarChart() action for categorical/string columns" This reverts commit 34ad3b3707ef5aeb5aca38247abb750edbe636a5. --- tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx | 60 ------------------- .../dataframe/inc/ROOT/RDF/InterfaceUtils.hxx | 13 ---- tree/dataframe/inc/ROOT/RDF/RInterface.hxx | 29 --------- tree/dataframe/test/dataframe_histomodels.cxx | 18 ------ tree/dataframe/test/dataframe_simple.cxx | 12 ---- 5 files changed, 132 deletions(-) diff --git a/tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx b/tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx index 2ee30d8dfb1dd..c64870a0e0c48 100644 --- a/tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx +++ b/tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx @@ -483,66 +483,6 @@ public: } }; -// BarChartHelper: fills a TH1D from string/categorical columns via TH1D::Fill(const char*). -// FillHelper::Exec cannot do this: std::string has no implicit conversion to const char*, -// so its non-container Exec overload's decltype(Fill(x...)) SFINAEs out, and std::string is -// explicitly excluded from IsDataContainer (see Utils.hxx), so the container-fill overload -// SFINAEs out too -- FillHelper simply won't compile for a std::string column. -class R__CLING_PTRCHECK(off) BarChartHelper : public RActionImpl { - std::vector<::TH1D *> fObjects; - -public: - BarChartHelper(BarChartHelper &&) = default; - BarChartHelper(const BarChartHelper &) = delete; - - BarChartHelper(const std::shared_ptr<::TH1D> &h, const unsigned int nSlots) : fObjects(nSlots, nullptr) - { - fObjects[0] = h.get(); - for (unsigned int i = 1; i < nSlots; ++i) { - fObjects[i] = new ::TH1D(*fObjects[0]); - UnsetDirectoryIfPossible(fObjects[i]); - } - } - - void InitTask(TTreeReader *, unsigned int) {} - - void Exec(unsigned int slot, const std::string &label) { fObjects[slot]->Fill(label.c_str(), 1.0); } - - void Exec(unsigned int slot, const ROOT::VecOps::RVec &label) - { - fObjects[slot]->Fill(std::string(label.begin(), label.end()).c_str(), 1.0); - } - - void Initialize() { /* noop */ } - - void Finalize() - { - if (fObjects.size() > 1) { - TList l; - for (auto it = ++fObjects.begin(); it != fObjects.end(); ++it) - l.Add(*it); - fObjects[0]->Merge(&l); - - for (auto it = ++fObjects.begin(); it != fObjects.end(); ++it) - delete *it; - } - fObjects[0]->LabelsDeflate("X"); - } - - ::TH1D &PartialUpdate(unsigned int slot) { return *fObjects[slot]; } - - std::string GetActionName() { return std::string("BarChart\n") + fObjects[0]->GetName(); } - - BarChartHelper MakeNew(void *newResult, std::string_view /*variation*/ = "nominal") - { - auto &result = *static_cast *>(newResult); - ResetIfPossible(result.get()); - UnsetDirectoryIfPossible(result.get()); - return BarChartHelper(result, fObjects.size()); - } -}; - - #ifdef R__HAS_ROOT7 template class R__CLING_PTRCHECK(off) RHistFillHelper diff --git a/tree/dataframe/inc/ROOT/RDF/InterfaceUtils.hxx b/tree/dataframe/inc/ROOT/RDF/InterfaceUtils.hxx index 979bd5cfcfeff..7b241022750d7 100644 --- a/tree/dataframe/inc/ROOT/RDF/InterfaceUtils.hxx +++ b/tree/dataframe/inc/ROOT/RDF/InterfaceUtils.hxx @@ -87,7 +87,6 @@ public: /// This namespace defines types to be used for tag dispatching in RInterface. namespace ActionTags { struct Histo1D{}; -struct BarChart{}; struct Histo2D{}; struct Histo3D{}; struct HistoND{}; @@ -154,18 +153,6 @@ BuildAction(const ColumnNames_t &bl, const std::shared_ptr<::TH1D> &h, const uns } } -// BarChart filling: always uses BarChartHelper (labels have no numeric axis limits to check) -template -std::unique_ptr -BuildAction(const ColumnNames_t &bl, const std::shared_ptr<::TH1D> &h, const unsigned int nSlots, - std::shared_ptr prevNode, ActionTags::BarChart, const RColumnRegister &colRegister) -{ - using Helper_t = BarChartHelper; - using Action_t = RAction>; - return std::make_unique(Helper_t(h, nSlots), bl, std::move(prevNode), colRegister); -} - - // Action for Histo3D, where thread safe filling might be supported to save memory template std::unique_ptr diff --git a/tree/dataframe/inc/ROOT/RDF/RInterface.hxx b/tree/dataframe/inc/ROOT/RDF/RInterface.hxx index e1e51e10132c8..aa3bb93285d00 100644 --- a/tree/dataframe/inc/ROOT/RDF/RInterface.hxx +++ b/tree/dataframe/inc/ROOT/RDF/RInterface.hxx @@ -1499,35 +1499,6 @@ public: return Histo1D({h_name.c_str(), h_title.c_str(), 128u, 0., 0.}, vName); } - //////////////////////////////////////////////////////////////////////////// - /// \brief Fill and return a one-dimensional histogram with the values of a categorical/string column (*lazy action*). - /// \tparam V The type of the column used to fill the histogram (must be std::string). - /// \param[in] vName The name of the column that will fill the histogram. - /// \param[in] name The name of the returned histogram. Defaults to the column name. - /// \param[in] title The title of the returned histogram. Defaults to ";;count". - /// \return the bar chart histogram wrapped in a RResultPtr, one bin per distinct label encountered. - /// - /// The returned TH1D has an extendable axis (TH1::kAllAxes) that grows a new bin for each - /// previously-unseen label; bins are ordered by first-encounter order, not sorted. - /// - /// ### Example usage: - /// ~~~{.cpp} - /// auto h = myDf.BarChart("Nation"); - /// ~~~ - template - RResultPtr<::TH1D> BarChart(std::string_view vName, std::string_view name = "", std::string_view title = "") - { - const auto h_name = name.empty() ? std::string(vName) : std::string(name); - const auto h_title = title.empty() ? (h_name + ";" + h_name + ";count") : std::string(title); - const auto userColumns = ColumnNames_t({std::string(vName)}); - const auto validatedColumns = GetValidatedColumnNames(1, userColumns); - - std::shared_ptr<::TH1D> h(new ::TH1D(h_name.c_str(), h_title.c_str(), 1, 0., 1.)); - h->SetCanExtend(::TH1::kAllAxes); - return CreateAction(validatedColumns, h, h, fProxiedPtr); - } - - //////////////////////////////////////////////////////////////////////////// /// \brief Fill and return a one-dimensional histogram with the weighted values of a column (*lazy action*). /// \tparam V The type of the column used to fill the histogram. diff --git a/tree/dataframe/test/dataframe_histomodels.cxx b/tree/dataframe/test/dataframe_histomodels.cxx index 2921ac69768d1..5ea6adfb057fe 100644 --- a/tree/dataframe/test/dataframe_histomodels.cxx +++ b/tree/dataframe/test/dataframe_histomodels.cxx @@ -62,24 +62,6 @@ TEST(RDataFrameHistoModels, Histo1D) CheckBins(h2edgesd->GetXaxis(), edgesd); } -TEST(RDataFrameHistoModels, BarChart) -{ - ROOT::RDataFrame tdf(6); - std::vector labels{"a", "b", "a", "c", "b", "a"}; - auto i = 0u; - auto d = tdf.Define("x", [&i, &labels]() { return labels[i++]; }); - auto h = d.BarChart("x"); - - ASSERT_EQ(h->GetNbinsX(), 3); - EXPECT_STREQ(h->GetXaxis()->GetBinLabel(1), "a"); - EXPECT_STREQ(h->GetXaxis()->GetBinLabel(2), "b"); - EXPECT_STREQ(h->GetXaxis()->GetBinLabel(3), "c"); - EXPECT_DOUBLE_EQ(h->GetBinContent(1), 3); - EXPECT_DOUBLE_EQ(h->GetBinContent(2), 2); - EXPECT_DOUBLE_EQ(h->GetBinContent(3), 1); -} - - TEST(RDataFrameHistoModels, Prof1D) { ROOT::RDataFrame tdf(10); diff --git a/tree/dataframe/test/dataframe_simple.cxx b/tree/dataframe/test/dataframe_simple.cxx index 3f0016a607bcd..6e1461e3f9a7b 100644 --- a/tree/dataframe/test/dataframe_simple.cxx +++ b/tree/dataframe/test/dataframe_simple.cxx @@ -824,18 +824,6 @@ TEST(RDFSimpleTests, AutomaticNamesOfHisto1DAndGraph) EXPECT_STREQ(gxy->GetYaxis()->GetTitle(), "y"); } -TEST(RDFSimpleTests, AutomaticNamesOfBarChart) -{ - auto df = RDataFrame(1).Define("x", []() { return std::string("a"); }); - auto hx = df.BarChart("x"); - - EXPECT_STREQ(hx->GetName(), "x"); - EXPECT_STREQ(hx->GetTitle(), "x"); - EXPECT_STREQ(hx->GetXaxis()->GetTitle(), "x"); - EXPECT_STREQ(hx->GetYaxis()->GetTitle(), "count"); -} - - TEST_P(RDFSimpleTests, DifferentTreesInDifferentThreads) { const auto filename = "DifferentTreesInDifferentThreads.root"; From 21b4706b59bda67a8715d647dff9597bdc55c8d4 Mon Sep 17 00:00:00 2001 From: Mehkaan Khan Date: Tue, 14 Jul 2026 18:26:06 +0500 Subject: [PATCH 3/4] [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"). --- .../dataframe/df041_alphanumericHistograms.C | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 tutorials/analysis/dataframe/df041_alphanumericHistograms.C diff --git a/tutorials/analysis/dataframe/df041_alphanumericHistograms.C b/tutorials/analysis/dataframe/df041_alphanumericHistograms.C new file mode 100644 index 0000000000000..b3be0101b495b --- /dev/null +++ b/tutorials/analysis/dataframe/df041_alphanumericHistograms.C @@ -0,0 +1,81 @@ +/// \file +/// \ingroup tutorial_dataframe +/// \notebook +/// Fill and draw a bar chart from a categorical/string column with RDataFrame. +/// +/// RDataFrame has no dedicated action for categorical/string columns, but the +/// generic RDataFrame::Fill() action can fill any user-provided object that +/// exposes Fill() and Merge() methods. This shows how to use it to build and +/// draw a bar chart from a string column, reusing the "Nation" column of the +/// classic CERN staff dataset also used in hist006_TH1_bar_charts.C. +/// +/// Classic ROOT trees often store short strings in fixed-size char[] branches +/// (leaf type "C"), which RDataFrame reads as ROOT::VecOps::RVec rather +/// than std::string. A one-line Define() converts such a column into a real +/// std::string column before filling. +/// +/// \macro_image +/// \macro_code +/// \macro_output +/// +/// \date July 2026 +/// \author Mehkaan Khan + +// A small adapter around TH1D that lets RDataFrame's generic Fill() action +// build a histogram from a std::string column: TH1D::Fill(const char*, Double_t) +// takes no default weight and std::string has no implicit conversion to +// const char*, so RDataFrame can't call it directly on a plain TH1D. Wrapping +// it in a class with our own Fill(const std::string&) sidesteps both issues. +struct AlphaNumHist { + TH1D h; + + AlphaNumHist(const char *name, const char *title) : h(name, title, 1, 0, 1) + { + h.GetXaxis()->SetAlphanumeric(true); + h.SetCanExtend(TH1::kAllAxes); + } + + void Fill(const std::string &s) { h.Fill(s.c_str(), 1.); } + + // Required so RDataFrame can merge partial per-slot results when run with + // implicit multi-threading enabled. + void Merge(const std::vector &others) + { + TList l; + for (auto *o : others) + l.Add(&o->h); + h.Merge(&l); + } +}; + +void df041_alphanumericHistograms() +{ + // Reuse the same "cernstaff.root" dataset as hist006_TH1_bar_charts.C, + // generating it first if it doesn't already exist. + TString filedir = gROOT->GetTutorialDir(); + filedir += TString("/io/tree/"); + TString filename = "cernstaff.root"; + bool fileNotFound = gSystem->AccessPathName(filename); + if (fileNotFound) { + TString macroName = filedir + "tree500_cernbuild.C"; + if (!gInterpreter->IsLoaded(macroName)) + gInterpreter->LoadMacro(macroName); + gROOT->ProcessLineFast("tree500_cernbuild()"); + } + + ROOT::RDataFrame df0("T", filename.Data()); + + // "Nation" is a classic char[] branch, read by RDataFrame as + // ROOT::VecOps::RVec. Converting it to a real std::string column + // makes it fillable through the AlphaNumHist adapter above. + auto df = df0.Define("NationStr", [](const ROOT::VecOps::RVec &c) { return std::string(c.begin(), c.end()); }, + {"Nation"}); + + AlphaNumHist model("hNation", "Staff by nation;Nation;Count"); + auto h = df.Fill(model, {"NationStr"}); + h->h.LabelsDeflate("X"); + + auto c1 = new TCanvas("c1", "Bar chart from RDataFrame", 700, 500); + h->h.SetFillColor(45); + h->h.DrawCopy("bar2"); +} From a26db7b2fbd7f01d5d37035f7ded1c10cd99a1b3 Mon Sep 17 00:00:00 2001 From: Mehkaan Khan Date: Tue, 14 Jul 2026 18:57:01 +0500 Subject: [PATCH 4/4] [tutorial] Fix clang-format indentation --- tutorials/analysis/dataframe/df041_alphanumericHistograms.C | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tutorials/analysis/dataframe/df041_alphanumericHistograms.C b/tutorials/analysis/dataframe/df041_alphanumericHistograms.C index b3be0101b495b..2f0064f3c1dd7 100644 --- a/tutorials/analysis/dataframe/df041_alphanumericHistograms.C +++ b/tutorials/analysis/dataframe/df041_alphanumericHistograms.C @@ -69,7 +69,7 @@ void df041_alphanumericHistograms() // ROOT::VecOps::RVec. Converting it to a real std::string column // makes it fillable through the AlphaNumHist adapter above. auto df = df0.Define("NationStr", [](const ROOT::VecOps::RVec &c) { return std::string(c.begin(), c.end()); }, - {"Nation"}); + {"Nation"}); AlphaNumHist model("hNation", "Staff by nation;Nation;Count"); auto h = df.Fill(model, {"NationStr"});