22.7 Histogram Range Problems
Table of Contents
Understanding Histogram Range Problems
Histogram range problems occur when the numerical range of your data is not matched well to the binning and axis ranges of your histogram. In ROOT this often shows up as apparently empty plots, misleading statistics, or strange looking distributions even though the code runs without errors. This chapter explains how to recognize these issues and how to fix them in practice.
Typical Symptoms
The most common symptom is an empty looking histogram even though you are sure you called Fill(). A related symptom is a histogram that shows only a very small fraction of your expected data points at one edge of the axis. Another sign is a mismatch between what you expect for the mean, RMS, or maximum and the values reported by GetMean(), GetRMS(), or GetMaximum().
Sometimes the canvas shows a flat line at zero while the statistics box reports many entries. In other cases, two histograms that should be comparable have very different visual ranges because one of them has had its axis automatically rescaled by a draw or a fit. All of these situations are usually related to how the histogram range and binning is defined.
Misconfigured Histogram Binning
When you create a histogram manually you specify the number of bins and the minimum and maximum of the histogram. For example:
TH1F *h = new TH1F("h", "Example", 100, 0.0, 10.0);In this case the histogram accepts values between 0 and 10. If you fill it with data mainly around 100, then almost all entries go into the overflow bin and the visible bins remain empty. The code runs without complaint, but the result is misleading.
The basic rule is simple.
The visible histogram range for a 1D histogram is defined by the user at creation time as $(x_\text{min}, x_\text{max})$, and entries outside this range are not shown in the main bins but are stored in underflow and overflow bins.
Always think about the expected numerical range of your data before choosing nbins, xmin, and xmax. If you do not know the range in advance, it is often safer to start with a very wide range and later zoom in with axis controls rather than the reverse.
If you accidentally swap the order of xmin and xmax, for example:
TH1F *h = new TH1F("h", "Bad", 100, 10.0, 0.0);
ROOT internally still creates something, but the result is not what you want. Always check that xmin < xmax in the constructor. If the bin width becomes extremely small compared to the numerical precision of your data you can also suffer from rounding effects where many values fall into the same bin in a way you did not intend.
Underflow and Overflow
Every ROOT histogram has two special bins in addition to the normal bins: an underflow bin for values below xmin and an overflow bin for values above xmax. These bins are counted in the number of entries but are not drawn in the main plot region.
Imagine:
TH1F *hE = new TH1F("hE", "Energy", 100, 0.0, 5.0); // in MeV
If your real energies are between 5 and 10 MeV, then the statistics box might show a large number of entries, but the plot above the x axis from 0 to 5 MeV will be empty. All the counts live in the overflow bin at index nbins+1.
To diagnose this type of issue, inspect underflow and overflow explicitly. You can do this with the bin indices:
int nbins = hE->GetNbinsX();
double under = hE->GetBinContent(0); // underflow
double over = hE->GetBinContent(nbins+1); // overflow
If most of your counts are in under or over, then your visible range is not appropriate for the data. In that case you should recreate the histogram with a more suitable range or adapt the code that fills it.
If you want to inspect all bins quickly, including the special ones, you can also loop over bin = 0 to nbins+1 and print contents and centers. This is often the fastest way to verify where your data actually went.
Data Outside the Visible Axis Range
Even when the histogram range is set correctly, the axis display may not include the full bin range. This usually happens after you have drawn the histogram and then changed the axis limits or drawn another histogram on the same canvas.
For instance, if you call:
h->Draw();
h->GetXaxis()->SetRangeUser(2.0, 4.0);
gPad->Update();the visible x axis shows only bins that intersect the region from 2 to 4. All other bins still exist, and the statistics still include them unless you explicitly ask otherwise, but they are no longer shown. If your data mainly lives outside the chosen window, the histogram can again look empty.
Similarly, for 2D histograms or graphs, operations like SetRangeUser or using the mouse to zoom can hide large parts of the data. The problem here is the mismatch between the data range and the current axis window, not the histogram itself.
When you suspect this issue, you can reset the axis to show everything:
h->GetXaxis()->UnZoom();
h->GetYaxis()->UnZoom();
gPad->Update();or simply close the canvas and draw the histogram again, which restores the default axis ranges. Always distinguish between the range in which the histogram can accept data and the current zoom window of the axis.
Automatic vs Manual Axis Limits
ROOT chooses default axis limits based on the histogram range and contents. If you accept these defaults, the full occupied range is usually visible. Problems arise when you mix automatic behavior with manual overrides.
For example, if you change the maximum of the y axis manually with:
h->SetMaximum(10.0);
and later fill new entries so that the real maximum should be 100, the plot will still only show up to 10. The histogram is not empty, but everything above 10 is cut off visually. If you then draw another histogram with auto scaling on the same pad using the SAME option, ROOT keeps the previous axis limits and your new object might look very flat or completely invisible.
The same can happen on the x axis when you use SetRangeUser or SetRange. When you want ROOT to recompute the optimal range after changes, remove any manual constraints:
h->SetMaximum(0); // special value to allow automatic maximum again
h->SetMinimum(0); // or choose a suitable minimum
h->GetXaxis()->UnZoom();
gPad->Update();
Remember that axis limits in ROOT are attached to one histogram, typically the first one drawn on a pad. All subsequent drawings using SAME must live within these limits to be visible.
Comparing Histograms with Different Ranges
In many analyses you want to compare two histograms directly. Problems appear when their binning or ranges differ. For example, you might have:
TH1F *hData = new TH1F("hData", "Data", 100, 0.0, 10.0);
TH1F *hMC = new TH1F("hMC", "MC", 100, 0.0, 10.0);
TH1F *hWide = new TH1F("hWide", "Wide", 50, -5.0, 15.0);
If you draw hWide first, it sets the x axis from -5 to 15. When you draw hData on the same pad with:
hWide->Draw();
hData->Draw("SAME");
the axis range stays from -5 to 15, and hData will show up only in the 0 to 10 part. This is fine, but if you instead draw a narrow histogram first, the wider one may be cut at the edges when added with SAME.
You should always decide which histogram defines the axes. Usually this is the one with the widest range. Draw that one first to set the x and y limits appropriately, then overlay others. If you need two histograms with different ranges to be drawn on one canvas but still be fully visible, consider using two pads or adding a second axis for the one with a different scale.
When comparing histograms by subtraction, addition, or division, the binning also must be compatible. If the numbers of bins or the ranges differ, ROOT will either refuse to operate or silently produce unexpected results. Always verify that the histograms have matching bin edges before combining them.
Checking and Fixing Range Issues
A systematic way to debug histogram range problems is to check a small set of properties for each suspicious histogram. Start by printing the binning:
h->Print("all");This output includes the number of bins, minimum and maximum, and, if requested, the contents of all bins. This gives you an immediate picture of whether the histogram was defined as you thought and where the entries went.
If you suspect a mismatch between the data and the histogram range, you can also track the minimum and maximum of the raw values before you fill the histogram. For example:
double v;
double minV = 1e30;
double maxV = -1e30;
while (/* loop over events */) {
// compute v
if (v < minV) minV = v;
if (v > maxV) maxV = v;
h->Fill(v);
}
std::cout << "Observed data range: " << minV << " to " << maxV << std::endl;
If the observed data range lies almost entirely outside [xmin, xmax], then the histogram constructor needs adjustment.
You can also use GetXaxis() to query the current axis display range and to see if any zoom or manual setting is hiding data:
std::cout << "Axis display range: "
<< h->GetXaxis()->GetXmin() << " to "
<< h->GetXaxis()->GetXmax() << std::endl;If this does not match the histogram definition, then zooming or manual changes are active. Unzoom or reset as needed.
Finally, when you debug a script that creates and fills several histograms, it can be very helpful to write a small helper function that checks each histogram after filling. For example you can implement a function that prints the number of entries, mean, RMS, and contents of a few edge bins, including underflow and overflow. Calling this function systematically avoids many surprises when you later look at the plots.
Range Issues with 2D Histograms
Two dimensional histograms such as TH2F and TH2D have ranges and binning on both the x and y axes. Range problems here are similar to the 1D case but easier to miss visually.
If you create:
TH2F *hXY = new TH2F("hXY", "XY", 100, 0.0, 1.0, 100, 0.0, 1.0);
and then fill with coordinates around (10, 20), the entire data set ends up in overflow in both dimensions and the color plot appears empty. To diagnose this, check the projection histograms or use:
int nbx = hXY->GetNbinsX();
int nby = hXY->GetNbinsY();
double underX = hXY->GetBinContent(0, 1); // X underflow, first Y bin
double overX = hXY->GetBinContent(nbx+1, 1); // X overflow
double underY = hXY->GetBinContent(1, 0); // Y underflow, first X bin
double overY = hXY->GetBinContent(1, nby+1); // Y overflow
You can also project onto one axis with ProjectionX and ProjectionY to inspect the distribution separately on each axis. This helps you see whether one coordinate lies outside the defined range while the other is fine.
Zooming and axis range settings affect 2D histograms in the same way as 1D. For example, drawing with the COLZ option and then zooming with the mouse may hide parts of the distribution. If the color scale saturates at a low value because of manual settings, regions with high occupancy can appear uniformly saturated. Resetting the axis and color limits helps restore a realistic picture.
When you overlay contours, profiles, or projections on top of a 2D histogram, always ensure that the axis ranges match. Otherwise, lines can appear shifted or cut at the border, which again is a range mismatch and not a problem with the underlying data.
By building the habit of checking binning, underflow and overflow, and current axis limits whenever a plot looks suspicious, you can resolve most histogram range problems quickly and avoid drawing incorrect conclusions from misleading visualizations.
Views: 14
KAHIBARO