5.3 Filling Histograms
Table of Contents
`Fill()`
The central operation for using a histogram in ROOT is to fill it with data. Every time you call the Fill() method, you add one entry to the histogram, usually corresponding to a single measurement or event.
For a one dimensional histogram like TH1F or TH1D, the most common form is:
h->Fill(x);
Here x is the value that will be placed into the appropriate bin according to the histogram range and binning that were defined when the histogram was created. ROOT automatically finds the correct bin for x and increases its content.
By default, each call to Fill(x) increases the selected bin by 1 and increases the total number of entries by 1. This is equivalent to counting how many times a particular value, or a value inside a particular interval, appears in your data.
There is also a weighted version of Fill():
h->Fill(x, w);
In this case, instead of incrementing the bin content by 1, ROOT increments it by the weight w. This is useful when each event should contribute with a different importance, for example when you have simulated events that represent different numbers of real events, or when you apply efficiency or luminosity corrections.
The histogram keeps track of the sum of weights internally, but the basic idea remains the same. Each call to Fill() modifies one bin and updates the entry count. Out of range values are handled with the underflow and overflow bins, which are updated automatically when x is smaller than the minimum or larger than the maximum of the histogram range.
Key rule: Use h->Fill(x) to add an unweighted event and h->Fill(x, w) to add an event with weight w. Every call to Fill() changes one bin and updates the histogram entries, including underflow or overflow for out of range values.
Filling histograms manually
Sometimes you work with a small number of values or want to check behavior interactively. In that case, you can fill a histogram directly from the ROOT prompt or inside a very short macro by typing explicit Fill() calls.
For example, suppose you have created a histogram:
TH1F *h = new TH1F("h", "Example;X;Counts", 10, 0.0, 10.0);You can now fill it manually:
h->Fill(1.2);
h->Fill(3.8);
h->Fill(3.8);
h->Fill(9.5);In this example, the bin that contains 3.8 will receive two counts, and the bins around 1.2 and 9.5 will receive one count each. You can then inspect the histogram with:
h->Draw();Manual filling is also useful when you want to test how binning behaves for specific values near bin edges. For instance, you might fill values at the exact edges:
h->Fill(0.0);
h->Fill(10.0);and then draw the histogram to see where these values end up. This helps you build intuition about how ROOT treats interval boundaries for bins.
You can also set bin contents directly without calling Fill(), using methods such as SetBinContent(bin, value), but that bypasses the automatic bin search, underflow and overflow handling, and the bookkeeping of entries and sums of weights. For learning and for most analyses where you have a list of measurements, it is better to use Fill() and let ROOT handle the internal details.
Important: For normal analysis with event data, prefer Fill() instead of directly setting bin contents. Direct bin manipulation skips some internal statistics and should only be used when you have a specific reason and know exactly what you are doing.
Filling histograms inside loops
In real analyses, you rarely call Fill() only a few times. Instead, you usually have a collection of many values and you want to accumulate them into a histogram. The standard pattern is to create the histogram once, then loop over your data and call Fill() inside the loop.
For example, if you have an array of measurements:
const int N = 5;
double data[N] = {1.0, 2.3, 2.3, 4.7, 9.1};
TH1F *h = new TH1F("h", "Data;X;Counts", 10, 0.0, 10.0);
for (int i = 0; i < N; ++i) {
h->Fill(data[i]);
}After this loop, the histogram contains all five entries from the array. You can then draw or analyze the histogram further.
If you have weights associated with each measurement, you include them in the call:
double weight[N] = {1.0, 0.5, 0.5, 2.0, 1.0};
for (int i = 0; i < N; ++i) {
h->Fill(data[i], weight[i]);
}Each data point now contributes according to its weight, which influences both bin contents and the statistical interpretation of the histogram.
In event based analysis with TTrees, the pattern is similar. You loop over events, extract the variable of interest from each event, and call Fill():
TH1F *hEnergy = new TH1F("hEnergy", "Energy;E (MeV);Events", 100, 0.0, 1000.0);
for (Long64_t i = 0; i < nEntries; ++i) {
tree->GetEntry(i);
double E = energy; // assume 'energy' is a branch variable
hEnergy->Fill(E);
}
This structure, a loop over data with Fill() calls inside, is the basic building block of almost every analysis in ROOT that uses histograms.
You can also combine calculations with filling. For example, if you want to histogram the square of a variable instead of the variable itself, you can compute it in the loop:
for (Long64_t i = 0; i < nEntries; ++i) {
tree->GetEntry(i);
double x2 = x * x;
h->Fill(x2);
}
Standard pattern: Create the histogram once, then loop over all your data and call Fill() for each event or measurement. This loop based filling is the core of practical histogram usage in ROOT.
Views: 14
KAHIBARO