A weighted fit means each data point contributes to the fit according to its measurement uncertainty.
Points with smaller errors are given more weight, and points with larger errors are given less influence.

  • To make sure that more precise measurements dominate the fit.
  • Common in physics, engineering, and data analysis whenever error bars are known.

Mathematically, it minimizes
$$ \chi^2 = \sum_i \frac{(y_i - f(x_i))^2}{\sigma_i^2} $$ where $ \sigma_i $ is the error of each data point.

In ROOT:

graph->Fit(fitfunc, "QSW");

The "W" option automatically applies weights $ 1/\sigma_i^2 $ using the ey[i] values from TGraphErrors.

After fitting, you can compute the uncertainty of the fitted function $ f(x) $ at any x-value using:

TGraphErrors gpt(1);
gpt.SetPoint(0, x0, 0);
TVirtualFitter::GetFitter()->GetConfidenceIntervals(&gpt, 0.68);
double fx  = gpt.GetY()[0];   // fitted value
double efx = gpt.GetEY()[0];  // uncertainty of f(x)

ROOT automatically uses the covariance matrix of the fit parameters to calculate
$$ \sigma_{f(x)}^2 = J \, \text{Cov}(p) \, J^T $$ where $ J $ is the gradient of $ f(x) $ with respect to its parameters.

In [2]:
#include "TGraphErrors.h"
#include "TF1.h"
#include "TVirtualFitter.h"
#include "TCanvas.h"
#include "TLegend.h"
#include "TROOT.h"
#include "TStyle.h"
#include <iostream>

// ====== Data ======
double x[]  = {0,  2,  4,  6,  8, 10};
double y[]  = {5,  8, 14, 20, 24, 35};
double ey[] = {2, 1.5, 2.5, 1,  3,  2};
const int n = sizeof(x)/sizeof(double);

// ====== Graph & fit(pol1: p0 + p1*x)======
auto graph = new TGraphErrors(n, x, y, nullptr, ey);
graph->SetTitle("Linear fit; x; y");
graph->SetMarkerStyle(20);
graph->SetMarkerColor(kBlue+1);

double xmin = 0.0, xmax = 10.0;
auto fitfunc = new TF1("fitfunc", "pol1", xmin, xmax);
fitfunc->SetParNames("c","m");

// Q quiet, S save, W weighted fit, using 1/ey^2 for chi2
auto r = graph->Fit(fitfunc, "QSW");
std::cout << "c = " << fitfunc->GetParameter(0) << " +/- " << fitfunc->GetParError(0) << "\n";
std::cout << "m = " << fitfunc->GetParameter(1) << " +/- " << fitfunc->GetParError(1) << "\n";
std::cout << "chi2/ndf = " << r->Chi2() << " / " << r->Ndf()
          << " = " << (r->Ndf()>0 ? r->Chi2()/r->Ndf() : -1) << "\n";

// ======  68% confidence interval(GetConfidenceIntervals)======
const int nb = 200;
auto gMean = new TGraphErrors(nb);
for (int i = 0; i < nb; ++i) {
    double xi = xmin + (xmax - xmin) * i / (nb - 1.0);
    gMean->SetPoint(i, xi, 0.0);        // y、ey 将由 GetConfidenceIntervals 填充
    gMean->SetPointError(i, 0.0, 0.0);
}
TVirtualFitter::GetFitter()->GetConfidenceIntervals(gMean, 0.68); // 68% 均值带

// ====== f(5) with 1σ error======
double x0 = 5.0;
TGraphErrors gx0(1);
gx0.SetPoint(0, x0, 0.0);
gx0.SetPointError(0, 0.0, 0.0);
TVirtualFitter::GetFitter()->GetConfidenceIntervals(&gx0, 0.68);
double fx0  = gx0.GetY()[0];
double efx0 = gx0.GetEY()[0];
std::cout << "f(" << x0 << ") = " << fx0 << " +/- " << efx0 << " (68% CL)\n";

// ====== Error band ======
auto c1 = new TCanvas("c1","Mean band", 800, 600);
graph->Draw("AP");
gMean->SetFillColor(kOrange);
gMean->SetFillStyle(3001);
gMean->Draw("3 same");
fitfunc->SetLineColor(kGreen+2);
fitfunc->Draw("same");

// 在图上标出 x0 的 f(x0)±σ
auto px0 = new TGraphErrors(1);
px0->SetPoint(0, x0, fx0);
px0->SetPointError(0, 0.0, efx0);
px0->SetMarkerStyle(21);
px0->SetMarkerColor(kRed+1);
px0->SetLineColor(kRed+1);
px0->Draw("P same");
px0->Draw("E same");

// plot
auto leg1 = new TLegend(0.12, 0.72, 0.42, 0.90);
leg1->AddEntry(graph,   "Data", "PE");
leg1->AddEntry(fitfunc, "Fit (pol1)", "L");
leg1->AddEntry(gMean,   "68% mean band", "F");
leg1->AddEntry(px0,     "f(5) #pm 1#sigma", "PE");
leg1->Draw();

c1->Update();
c = 3.09524 +/- 1.56984
m = 2.91429 +/- 0.259251
chi2/ndf = 18.819 / 4 = 4.70476
f(5) = 17.6667 +/- 0.880602 (68% CL)
In [ ]: