11.8. Fitting Graphs
Table of Contents
TGraph fitting
When you fit a graph in ROOT you are fitting a set of explicit points, not binned counts as in a histogram. The typical workflow is to attach a function to the graph and let ROOT adjust the function parameters to best describe the points.
A TGraph holds pairs $(x_i, y_i)$ without any uncertainties. ROOT uses a least squares minimization that, by default, assumes all points have the same uncertainty. This means each point contributes equally to the fit.
To perform a fit you first define a TF1 that describes your model. For example, a straight line can be written as
$$
f(x) = p_0 + p_1 x,
$$
where $p_0$ is the intercept and $p_1$ is the slope. In ROOT this might look like
TF1 *fline = new TF1("fline", "[0] + [1]*x", xmin, xmax);
fline->SetParameters(0.0, 1.0); // initial guesses
The range you give to the TF1 is the default fit range. You can later override it in the Fit call. Choosing a sensible initial parameter set and fit range often makes the fit more stable, especially for nonlinear models.
Once you have a graph and a function, you call
graph->Fit("fline"); // by nameor
graph->Fit(fline); // by pointer
If a canvas is open and the graph is drawn, the fit will draw the function on top of the graph and print the parameter values and their uncertainties in the ROOT terminal. You can suppress drawing with the option "N" and suppress printing with "Q", for instance
graph->Fit(fline, "QN");
The most important fit options used with graphs are the same as with histograms. For example "R" tells ROOT to use the function range, not the full data range, and "W" activates point weights if you have set them manually. The full list of options is described in the general fitting chapter, so here you only need to remember that the second argument to Fit is a string of characters that modify how the fit is performed.
After the fit finishes, you can read the parameters from the TF1:
double p0 = fline->GetParameter(0);
double e0 = fline->GetParError(0);
double p1 = fline->GetParameter(1);
double e1 = fline->GetParError(1);
These values can be used in subsequent calculations, for example to compute a predicted value at a given $x$ with fline->Eval(x) or to build derived quantities from the fit result.
ROOT also reports a chi square and number of degrees of freedom for the fit. You can access them with
double chi2 = fline->GetChisquare();
int ndf = fline->GetNDF();The detailed interpretation of these quantities and of goodness of fit is covered in the dedicated chapter on that topic.
It is useful to be aware of one limitation: since TGraph has no uncertainties, the chi square is computed under the assumption of equal errors. If your points have very different uncertainties, you should use TGraphErrors and weighted fits, which are described next.
Important rule: Fitting a TGraph treats all points as equally precise. If your data points have different uncertainties, use TGraphErrors or TGraphAsymmErrors so ROOT can weight the points correctly.
TGraphErrors fitting
TGraphErrors extends TGraph by including uncertainty information for each point. Every point carries $(x_i, y_i, \sigma_{x,i}, \sigma_{y,i})$. In most common fits only the vertical uncertainties $\sigma_{y,i}$ are used as statistical weights, since standard chi square fits minimize deviations in the $y$ direction.
The chi square minimized by ROOT for a fit to TGraphErrors, when only $y$ errors are used, has the form
$$
\chi^2 = \sum_i \frac{\left(y_i - f(x_i)\right)^2}{\sigma_{y,i}^2},
$$
so points with smaller $\sigma_{y,i}$ pull the fit more strongly. This is a weighted least squares fit.
You create a TGraphErrors similarly to TGraph, either from arrays or by adding points one by one. For each point you provide the coordinates and their errors:
TGraphErrors *g = new TGraphErrors();
g->SetPoint(i, x, y);
g->SetPointError(i, ex, ey); // ex = sigma_x, ey = sigma_y
If you do not have meaningful $x$ uncertainties, you can set ex to zero and only use ey. ROOT will then only use the $y$ errors in the chi square.
The fitting call is identical to the TGraph case:
TF1 *fmodel = new TF1("fmodel", "[0] + [1]*x", xmin, xmax);
g->Fit(fmodel);
Internally ROOT detects that this is a TGraphErrors and uses the $y$ errors to build the chi square. The fit result parameters and their uncertainties are accessed in exactly the same way as for TGraph.
When your points have very different uncertainties the effect of weighting can be substantial. A data point with a large error bar will influence the fit less, which is usually what you want for experimental measurements, because it reflects the fact that the point is less precise.
If you have purely statistical uncertainties from counting experiments, and you have converted those into errors on some derived quantity, you should pass these as the ey values. ROOT does not calculate errors for TGraphErrors automatically, you are responsible for setting SetPointError for each point.
Sometimes you may want to ignore the errors and treat all points equally even though TGraphErrors is used. In that case you can set all ey values to the same constant. The fit will then behave like a TGraph fit, but you still retain error bars on the plot for visual information.
ROOT can also include $x$ errors in some more advanced fits or when transforming coordinates, although the simple chi square above only uses $y$ errors. For many standard analyses, setting meaningful $y$ uncertainties and fitting with TGraphErrors is enough.
Important rule: For TGraphErrors, the default chi square fit uses the $y$ uncertainties as weights according to
$$
\chi^2 = \sum_i \frac{\left(y_i - f(x_i)\right)^2}{\sigma_{y,i}^2}.
$$
Set ey correctly for each point if you want a statistically meaningful fit.
The visual output of a fit to TGraphErrors shows both the fitted function and the error bars. This combination is very useful in real experimental work, because it lets you immediately see where the model agrees within the measurement uncertainties and where the deviations are larger than expected.
Views: 11
KAHIBARO