Skip to content

[hist] Add tutorial for profile histograms - #23243

Open
hahnjo wants to merge 2 commits into
root-project:masterfrom
hahnjo:hist-tutorial-profile
Open

hahnjo wants to merge 2 commits into
root-project:masterfrom
hahnjo:hist-tutorial-profile

Conversation

@hahnjo

@hahnjo hahnjo commented Sep 3, 2026

Copy link
Copy Markdown
Member

No description provided.

@hahnjo hahnjo self-assigned this Sep 3, 2026
@hahnjo
hahnjo requested review from couet and dpiparo as code owners September 3, 2026 10:01

auto printBin = [&](ROOT::Experimental::RBinIndex bin) {
const auto &content = profile.GetBinContent(bin);
std::cout << "entries = " << content.fSum << ", mean = " << content.ComputeMean();

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here I wasn't sure what to print. Initially I wanted to do "errors", but there are several definitions so I kept it to the minimum... Let me know if you would like to see something else printed.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest mean(x) and variance (or stdDev), which should be close to 1.

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown

Test Results

    23 files      23 suites   3d 21h 21m 44s ⏱️
 3 862 tests  3 859 ✅ 0 💤 3 ❌
79 609 runs  79 605 ✅ 1 💤 3 ❌

For more details on these failures, see this check.

Results for commit 2b287fe.

@couet
couet removed their request for review September 7, 2026 14:43
@hahnjo

hahnjo commented Sep 24, 2026

Copy link
Copy Markdown
Member Author

ping

@hageboeck hageboeck left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest to extend RProfileBin, so that is can compute mean, variance, stdDev and standard error of mean.
For the plot, I suggest to show the means instead of the bin content to underline the "dimensionality reduction" that's the main job of the profile.

ROOT::Experimental::RRegularAxis axis(40, {0.0, 20.0});

// Create a profile histogram and fill with random values.
ROOT::Experimental::RProfile profile(40, {0.0, 20.0});

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ROOT::Experimental::RProfile profile(40, {0.0, 20.0});
ROOT::Experimental::RProfile profile(axis);

Comment on lines +29 to +37
// Create a first normal distribution with mean 10.0 and stddev 4.0.
std::normal_distribution normal1(10.0, 4.0);
// Create a second normal distribution for the value.
std::normal_distribution normal2(40.0, 10.0);
for (std::size_t i = 0; i < 1000; i++) {
double x = normal1(gen);
double v = normal2(gen);
profile.Fill(x, v);
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's more interesting to vary the distribution along y depending on x:

Suggested change
// Create a first normal distribution with mean 10.0 and stddev 4.0.
std::normal_distribution normal1(10.0, 4.0);
// Create a second normal distribution for the value.
std::normal_distribution normal2(40.0, 10.0);
for (std::size_t i = 0; i < 1000; i++) {
double x = normal1(gen);
double v = normal2(gen);
profile.Fill(x, v);
}
// Fill uniformly along x.
std::uniform_distribution normal1(0.0, 21.0);
for (std::size_t i = 0; i < 1000; i++) {
double x = normal1(gen);
// In y, use a normal distribution with a mean that depends on x.
std::normal_distribution normal2(x, 10.0);
double y = normal2(gen);
profile.Fill(x, y);
}

/// \f]
///
/// \return the arithmetic mean in this bin
double ComputeMean() const

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding Variance, StdDev and the error of the mean would be interesting, too.

// tutorial.
for (int row = 8; row > 0; row--) {
auto print = [&](ROOT::Experimental::RBinIndex bin) {
const auto &content = profile.GetBinContent(bin);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest to plot the mean for each bin in x. The scale might need a bit of adjustment, but we should see a rising line.

Suggested change
const auto &content = profile.GetBinContent(bin);
const auto &content = profile.GetBinContent(bin).ComputeMean();

@hageboeck hageboeck Oct 1, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found this to work reasonably well:

   for (int row = 8; row >= 0; row--) {                                                                                 
      auto print = [&](ROOT::Experimental::RBinIndex bin) {                                                             
         const auto &content = profile.GetBinContent(bin);                                                              
         const int targetRow = content.ComputeMean() / 25. * 8;                                                         
         std::cout << ((row == targetRow) ? '-' : ' ');                                                                 
      };     

Output:

entries = 1000
binned mean = 12.3241, stddev = 7.18306
 |                                        | 
 |                                        |-
 |                                     ---| 
 |                                -----   | 
 |                         -------        | 
 |                  -------               | 
 |            - ----                      | 
 |      ------ -                          | 
 |------                                  | 

value mean = 12.3319, stddev = 7.33413
underflow bin: entries = 0, mean = nan
bin #5: entries = 20, mean = 2.56564
bin #10: entries = 22, mean = 5.05397

/// \file
/// \ingroup tutorial_histv7
///
/// Profile histograms with RProfile.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Profile histograms with RProfile.
/// Profile histograms with RProfile.
///
/// Profiles can be used for dimensionality reduction by representing an N-D distribution in N-1 dimensions using summary statistics such as mean and variance.
/// In this tutorial, a 2-D distribution uniform in x and normal in y with changing mean is represented by its mean values in each bin along x.


auto printBin = [&](ROOT::Experimental::RBinIndex bin) {
const auto &content = profile.GetBinContent(bin);
std::cout << "entries = " << content.fSum << ", mean = " << content.ComputeMean();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest mean(x) and variance (or stdDev), which should be close to 1.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants