Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TGraphSmooth.cxx
Go to the documentation of this file.
1// @(#)root/hist:$Id$
2// Author: Christian Stratowa 30/09/2001
3
4/*************************************************************************
5 * Copyright (C) 2006, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12/******************************************************************************
13* Copyright(c) 2001-2006, Dr. Christian Stratowa, Vienna, Austria. *
14* Author: Christian Stratowa with help from Rene Brun. *
15* *
16* Algorithms for smooth regression adapted from: *
17* R: A Computer Language for Statistical Data Analysis *
18* *
19******************************************************************************/
20
21
22#include "Riostream.h"
23#include "TMath.h"
24#include "TGraphSmooth.h"
25#include "TGraphErrors.h"
26
28
29//______________________________________________________________________
30/** \class TGraphSmooth
31 \ingroup Graphs
32A helper class to smooth TGraph.
33see examples in $ROOTSYS/tutorials/visualisation/graphs/gr010_approx_smooth.C and $ROOTSYS/tutorials/visualisation/graphs/gr015_smooth.C
34*/
35
37{
38 fNin = 0;
39 fNout = 0;
40 fGin = nullptr;
41 fGout = nullptr;
42 fMinX = 0;
43 fMaxX = 0;
44}
45
46////////////////////////////////////////////////////////////////////////////////
47/// GraphSmooth constructor
48
50{
51 fNin = 0;
52 fNout = 0;
53 fGin = nullptr;
54 fGout = nullptr;
55 fMinX = 0;
56 fMaxX = 0;
57}
58
59////////////////////////////////////////////////////////////////////////////////
60/// GraphSmooth destructor
61
63{
64 if (fGout) delete fGout;
65 fGin = nullptr;
66 fGout = nullptr;
67}
68
69////////////////////////////////////////////////////////////////////////////////
70/// Sort input data points
71
73{
74 if (fGout) {delete fGout; fGout = nullptr;}
75 fGin = grin;
76
77 fNin = fGin->GetN();
78 Double_t *xin = new Double_t[fNin];
79 Double_t *yin = new Double_t[fNin];
80 Int_t i;
81 for (i=0;i<fNin;i++) {
82 xin[i] = fGin->GetX()[i];
83 yin[i] = fGin->GetY()[i];
84 }
85
86// sort input x, y
87 Int_t *index = new Int_t[fNin];
89 for (i=0;i<fNin;i++) {
90 fGin->SetPoint(i, xin[index[i]], yin[index[i]]);
91 }
92
93 fMinX = fGin->GetX()[0]; //already sorted!
94 fMaxX = fGin->GetX()[fNin-1];
95
96 delete [] index;
97 delete [] xin;
98 delete [] yin;
99}
100
101////////////////////////////////////////////////////////////////////////////////
102/// Smooth data with Kernel smoother. Smooth grin with the Nadaraya-Watson kernel regression estimate.
103///
104/// \param[in] grin input graph
105/// \param[in] option the kernel to be used: "box", "normal"
106/// \param[in] bandwidth the bandwidth. The kernels are scaled so that their quartiles
107/// (viewed as probability densities) are at +/- 0.25*bandwidth.
108/// \param[in] nout If xout is not specified, interpolation takes place at equally
109/// spaced points spanning the interval [min(x), max(x)], where nout = max(nout, number of input data).
110/// \param[in] xout an optional set of values at which to evaluate the fit
111
114{
115 TString opt = option;
116 opt.ToLower();
117 Int_t kernel = 1;
118 if (opt.Contains("normal")) kernel = 2;
119
120 Smoothin(grin);
121
122 Double_t delta = 0;
123 Int_t *index = nullptr;
124 if (xout == nullptr) {
126 delta = (fMaxX - fMinX)/(fNout - 1);
127 } else {
128 fNout = nout;
129 index = new Int_t[nout];
131 }
132
133 fGout = new TGraph(fNout);
134 // To calculate x coordinates and avoid a rounding issue in last point,
135 // (fMin + (fNout-1)* delta > fMaxX) if fNout is large,
136 // we split the calculation in two loops,
137 // the left half of x points is calculated as min + i*delta
138 // the right half of x points as max - j*delta
139 for (Int_t i=0;i<fNout/2;i++) {
140 if (xout == nullptr) fGout->SetPoint(i,fMinX + i*delta, 0);
141 else fGout->SetPoint(i,xout[index[i]], 0);
142 }
143 for (Int_t i=fNout/2;i<fNout;i++) {
144 if (xout == nullptr) fGout->SetPoint(i,fMaxX + (i + 1 - fNout)*delta, 0);
145 else fGout->SetPoint(i,xout[index[i]], 0);
146 }
147
150
151 if (index) {delete [] index; index = nullptr;}
152
153 return fGout;
154}
155
156////////////////////////////////////////////////////////////////////////////////
157/// Smooth data with specified kernel.
158/// Based on R function ksmooth: Translated to C++ by C. Stratowa
159/// (R source file: ksmooth.c by B.D.Ripley Copyright (C) 1998)
160
163{
164 Int_t imin = 0;
165 Double_t cutoff = 0.0;
166
167// bandwidth is in units of half inter-quartile range
168 if (kernel == 1) {
169 bw *= 0.5;
170 cutoff = bw;
171 }
172 if (kernel == 2) {
173 bw *= 0.3706506;
174 cutoff = 4*bw;
175 }
176
177 while ((imin < n) && (x[imin] < xp[0] - cutoff))
178 imin++;
179
180 for (Int_t j=0;j<np;j++) {
181 Double_t xx, w;
182 Double_t num = 0.0;
183 Double_t den = 0.0;
184 Double_t x0 = xp[j];
185 for (Int_t i=imin;i<n;i++) {
186 if (x[i] < x0 - cutoff) imin = i;
187 if (x[i] > x0 + cutoff) break;
188 xx = TMath::Abs(x[i] - x0)/bw;
189 if (kernel == 1) w = 1;
190 else w = TMath::Exp(-0.5*xx*xx);
191 num += w*y[i];
192 den += w;
193 }
194 if (den > 0) {
195 yp[j] = num/den;
196 } else {
197 yp[j] = 0; //should be NA_REAL (see R.h) or nan("NAN")
198 }
199 }
200}
201
202
203////////////////////////////////////////////////////////////////////////////////
204/// Smooth data with Lowess smoother
205///
206/// This function performs the computations for the LOWESS smoother
207/// (see the reference below). Lowess returns the output points
208/// x and y which give the coordinates of the smooth.
209///
210/// \param[in] grin Input graph
211/// \param[in] option specific options
212/// \param[in] span the smoother span. This gives the proportion of points in the plot
213/// which influence the smooth at each value. Larger values give more smoothness.
214/// \param[in] iter the number of robustifying iterations which should be performed.
215/// Using smaller values of iter will make lowess run faster.
216/// \param[in] delta values of x which lie within delta of each other replaced by a
217/// single value in the output from lowess.
218/// For delta = 0, delta will be calculated.
219///
220/// References:
221///
222/// - Cleveland, W. S. (1979) Robust locally weighted regression and smoothing
223/// scatterplots. J. Amer. Statist. Assoc. 74, 829-836.
224/// - Cleveland, W. S. (1981) LOWESS: A program for smoothing scatterplots
225/// by robust locally weighted regression.
226/// The American Statistician, 35, 54.
227
229 Double_t span, Int_t iter, Double_t delta)
230{
231 TString opt = option;
232 opt.ToLower();
233
234 Smoothin(grin);
235
236 if (delta == 0) {delta = 0.01*(TMath::Abs(fMaxX - fMinX));}
237
238// output X, Y
239 fNout = fNin;
240 fGout = new TGraphErrors(fNout);
241
242 for (Int_t i=0;i<fNout;i++) {
243 fGout->SetPoint(i,fGin->GetX()[i], 0);
244 }
245
246 Lowess(fGin->GetX(), fGin->GetY(), fNin, fGout->GetY(), span, iter, delta);
247
248 return fGout;
249}
250
251////////////////////////////////////////////////////////////////////////////////
252/// Lowess regression smoother.
253/// Based on R function clowess: Translated to C++ by C. Stratowa
254/// (R source file: lowess.c by R Development Core Team (C) 1999-2001)
255
257 Double_t span, Int_t iter, Double_t delta)
258{
259 Int_t i, iiter, j, last, m1, m2, nleft, nright, ns;
260 Double_t alpha, c1, c9, cmad, cut, d1, d2, denom, r;
261 Bool_t ok;
262
263 if (n < 2) {
264 ys[0] = y[0];
265 return;
266 }
267
268// nleft, nright, last, etc. must all be shifted to get rid of these:
269 x--;
270 y--;
271 ys--;
272
273 Double_t *rw = ((TGraphErrors*)fGout)->GetEX();
274 Double_t *res = ((TGraphErrors*)fGout)->GetEY();
275
276// at least two, at most n points
277 ns = TMath::Max(2, TMath::Min(n, (Int_t)(span*n + 1e-7)));
278
279// robustness iterations
280 iiter = 1;
281 while (iiter <= iter+1) {
282 nleft = 1;
283 nright = ns;
284 last = 0; // index of prev estimated point
285 i = 1; // index of current point
286
287 for(;;) {
288 if (nright < n) {
289 // move nleft, nright to right if radius decreases
290 d1 = x[i] - x[nleft];
291 d2 = x[nright+1] - x[i];
292
293 // if d1 <= d2 with x[nright+1] == x[nright], lowest fixes
294 if (d1 > d2) {
295 // radius will not decrease by move right
296 nleft++;
297 nright++;
298 continue;
299 }
300 }
301
302 // fitted value at x[i]
303 Bool_t iterg1 = iiter>1;
304 Lowest(&x[1], &y[1], n, x[i], ys[i], nleft, nright,
305 res, iterg1, rw, ok);
306 if (!ok) ys[i] = y[i];
307
308 // all weights zero copy over value (all rw==0)
309 if (last < i-1) {
310 denom = x[i]-x[last];
311
312 // skipped points -- Int_terpolate non-zero - proof?
313 for(j = last+1; j < i; j++) {
314 alpha = (x[j]-x[last])/denom;
315 ys[j] = alpha*ys[i] + (1.-alpha)*ys[last];
316 }
317 }
318
319 // last point actually estimated
320 last = i;
321
322 // x coord of close points
323 cut = x[last] + delta;
324 for (i = last+1; i <= n; i++) {
325 if (x[i] > cut)
326 break;
327 if (x[i] == x[last]) {
328 ys[i] = ys[last];
329 last = i;
330 }
331 }
332 i = TMath::Max(last+1, i-1);
333 if (last >= n)
334 break;
335 }
336
337 // residuals
338 for(i=0; i < n; i++)
339 res[i] = y[i+1] - ys[i+1];
340
341 // compute robustness weights except last time
342 if (iiter > iter)
343 break;
344 for(i=0 ; i<n ; i++)
345 rw[i] = TMath::Abs(res[i]);
346
347 // compute cmad := 6 * median(rw[], n)
348 m1 = n/2;
349 // partial sort, for m1 & m2
350 Psort(rw, n, m1);
351 if(n % 2 == 0) {
352 m2 = n-m1-1;
353 Psort(rw, n, m2);
354 cmad = 3.*(rw[m1]+rw[m2]);
355 } else { /* n odd */
356 cmad = 6.*rw[m1];
357 }
358
359 c9 = 0.999*cmad;
360 c1 = 0.001*cmad;
361 for(i=0 ; i<n ; i++) {
362 r = TMath::Abs(res[i]);
363 if (r <= c1)
364 rw[i] = 1.;
365 else if (r <= c9)
366 rw[i] = (1.-(r/cmad)*(r/cmad))*(1.-(r/cmad)*(r/cmad));
367 else
368 rw[i] = 0.;
369 }
370 iiter++;
371 }
372}
373
374////////////////////////////////////////////////////////////////////////////////
375/// Fit value at x[i]
376/// Based on R function lowest: Translated to C++ by C. Stratowa
377/// (R source file: lowess.c by R Development Core Team (C) 1999-2001)
378
382{
383 Int_t nrt, j;
384 Double_t a, b, c, d, h, h1, h9, r, range;
385
386 x--;
387 y--;
388 w--;
389 rw--;
390
391 range = x[n]-x[1];
392 h = TMath::Max(xs-x[nleft], x[nright]-xs);
393 h9 = 0.999*h;
394 h1 = 0.001*h;
395
396// sum of weights
397 a = 0.;
398 j = nleft;
399 while (j <= n) {
400 // compute weights (pick up all ties on right)
401 w[j] = 0.;
402 r = TMath::Abs(x[j] - xs);
403 if (r <= h9) {
404 if (r <= h1) {
405 w[j] = 1.;
406 } else {
407 d = (r/h)*(r/h)*(r/h);
408 w[j] = (1.- d)*(1.- d)*(1.- d);
409 }
410 if (userw)
411 w[j] *= rw[j];
412 a += w[j];
413 } else if (x[j] > xs)
414 break;
415 j = j+1;
416 }
417
418// rightmost pt (may be greater than nright because of ties)
419 nrt = j-1;
420 if (a <= 0.)
421 ok = kFALSE;
422 else {
423 ok = kTRUE;
424 // weighted least squares: make sum of w[j] == 1
425 for(j=nleft ; j<=nrt ; j++)
426 w[j] /= a;
427 if (h > 0.) {
428 a = 0.;
429 // use linear fit weighted center of x values
430 for(j=nleft ; j<=nrt ; j++)
431 a += w[j] * x[j];
432 b = xs - a;
433 c = 0.;
434 for(j=nleft ; j<=nrt ; j++)
435 c += w[j]*(x[j]-a)*(x[j]-a);
436 if (TMath::Sqrt(c) > 0.001*range) {
437 b /= c;
438 // points are spread out enough to compute slope
439 for(j=nleft; j <= nrt; j++)
440 w[j] *= (b*(x[j]-a) + 1.);
441 }
442 }
443 ys = 0.;
444 for(j=nleft; j <= nrt; j++)
445 ys += w[j] * y[j];
446 }
447}
448
449////////////////////////////////////////////////////////////////////////////////
450/// Smooth data with Super smoother.
451/// Smooth the (x, y) values by Friedman's ``super smoother''.
452///
453/// \param[in] grin graph for smoothing
454/// \param[in] option specific options
455/// \param[in] span the fraction of the observations in the span of the running lines
456/// smoother, or 0 to choose this by leave-one-out cross-validation.
457/// \param[in] bass controls the smoothness of the fitted curve.
458/// Values of up to 10 indicate increasing smoothness.
459/// \param[in] isPeriodic if TRUE, the x values are assumed to be in [0, 1]
460/// and of period 1.
461/// \param[in] w case weights
462///
463/// Details:
464///
465/// supsmu is a running lines smoother which chooses between three spans for
466/// the lines. The running lines smoothers are symmetric, with k/2 data points
467/// each side of the predicted point, and values of k as 0.5 * n, 0.2 * n and
468/// 0.05 * n, where n is the number of data points. If span is specified,
469/// a single smoother with span span * n is used.
470///
471/// The best of the three smoothers is chosen by cross-validation for each
472/// prediction. The best spans are then smoothed by a running lines smoother
473/// and the final prediction chosen by linear interpolation.
474///
475/// The FORTRAN code says: ``For small samples (n < 40) or if there are
476/// substantial serial correlations between observations close in x - value,
477/// then a prespecified fixed span smoother (span > 0) should be used.
478/// Reasonable span values are 0.2 to 0.4.''
479///
480/// References:
481/// - Friedman, J. H. (1984) SMART User's Guide.
482/// Laboratory for Computational Statistics,
483/// Stanford University Technical Report No. 1.
484/// - Friedman, J. H. (1984) A variable span scatterplot smoother.
485/// Laboratory for Computational Statistics,
486/// Stanford University Technical Report No. 5.
487
490{
491 if (span < 0 || span > 1) {
492 std::cout << "Error: Span must be between 0 and 1" << std::endl;
493 return nullptr;
494 }
495 TString opt = option;
496 opt.ToLower();
497
498 Smoothin(grin);
499
500 Int_t iper = 1;
501 if (isPeriodic) {
502 iper = 2;
503 if (fMinX < 0 || fMaxX > 1) {
504 std::cout << "Error: x must be between 0 and 1 for periodic smooth" << std::endl;
505 return nullptr;
506 }
507 }
508
509// output X, Y
510 fNout = fNin;
511 fGout = new TGraph(fNout);
512 Int_t i;
513 for (i=0; i<fNout; i++) {
514 fGout->SetPoint(i,fGin->GetX()[i], 0);
515 }
516
517// weights
518 Double_t *weight = new Double_t[fNin];
519 for (i=0; i<fNin; i++) {
520 if (w == nullptr) weight[i] = 1;
521 else weight[i] = w[i];
522 }
523
524// temporary storage array
525 Int_t nTmp = (fNin+1)*8;
526 Double_t *tmp = new Double_t[nTmp];
527 for (i=0; i<nTmp; i++) {
528 tmp[i] = 0;
529 }
530
531 BDRsupsmu(fNin, fGin->GetX(), fGin->GetY(), weight, iper, span, bass, fGout->GetY(), tmp);
532
533 delete [] tmp;
534 delete [] weight;
535
536 return fGout;
537}
538
539////////////////////////////////////////////////////////////////////////////////
540/// Friedmanns super smoother (Friedman, 1984).
541///
542/// version 10/10/84
543/// coded and copyright (c) 1984 by:
544///
545/// Jerome H. Friedman
546/// department of statistics
547/// and
548/// stanford linear accelerator center
549/// stanford university
550///
551/// all rights reserved.
552///
553/// \param[in] n number of observations (x,y - pairs).
554/// \param[in] x ordered abscissa values.
555/// \param[in] y corresponding ordinate (response) values.
556/// \param[in] w weight for each (x,y) observation.
557/// \param[in] iper periodic variable flag.
558/// - iper=1 => x is ordered interval variable.
559/// - iper=2 => x is a periodic variable with values
560/// in the range (0.0,1.0) and period 1.0.
561/// \param[in] span smoother span (fraction of observations in window).
562/// - span=0.0 => automatic (variable) span selection.
563/// \param[in] alpha controls high frequency (small span) penality
564/// used with automatic span selection (bass tone control).
565/// (alpha.le.0.0 or alpha.gt.10.0 => no effect.)
566/// \param[out] smo smoothed ordinate (response) values.
567/// \param sc internal working storage.
568///
569/// note:
570///
571/// for small samples (n < 40) or if there are substantial serial
572/// correlations between observations close in x - value, then
573/// a prespecified fixed span smoother (span > 0) should be
574/// used. reasonable span values are 0.2 to 0.4.
575///
576/// current implementation:
577///
578/// Based on R function supsmu: Translated to C++ by C. Stratowa
579/// (R source file: ppr.f by B.D.Ripley Copyright (C) 1994-97)
580
583{
584// Local variables
586 Int_t i, j, jper;
587 Double_t a, f;
590 Double_t d1, d2;
591
592 Double_t spans[3] = { 0.05, 0.2, 0.5 };
593 Double_t big = 1e20;
594 Double_t sml = 1e-7;
595 Double_t eps = 0.001;
596
597// Parameter adjustments
598 sc_offset = n + 1;
599 sc -= sc_offset;
600 --smo;
601 --w;
602 --y;
603 --x;
604
605// Function Body
606 if (x[n] <= x[1]) {
607 sy = 0.0;
608 sw = sy;
609 for (j=1;j<=n;++j) {
610 sy += w[j] * y[j];
611 sw += w[j];
612 }
613
614 a = 0.0;
615 if (sw > 0.0) a = sy / sw;
616 for (j=1;j<=n;++j) smo[j] = a;
617 return;
618 }
619
620 i = (Int_t)(n / 4);
621 j = i * 3;
622 scale = x[j] - x[i];
623 while (scale <= 0.0) {
624 if (j < n) ++j;
625 if (i > 1) --i;
626 scale = x[j] - x[i];
627 }
628
629// Computing 2nd power
630 d1 = eps * scale;
631 vsmlsq = d1 * d1;
632 jper = iper;
633 if (iper == 2 && (x[1] < 0.0 || x[n] > 1.0)) {
634 jper = 1;
635 }
636 if (jper < 1 || jper > 2) {
637 jper = 1;
638 }
639 if (span > 0.0) {
640 BDRsmooth(n, &x[1], &y[1], &w[1], span, jper, vsmlsq,
641 &smo[1], &sc[sc_offset]);
642 return;
643 }
644
645 Double_t *h = new Double_t[n+1];
646 for (i = 1; i <= 3; ++i) {
647 BDRsmooth(n, &x[1], &y[1], &w[1], spans[i - 1], jper, vsmlsq,
648 &sc[((i<<1)-1)*n + 1], &sc[n*7 + 1]);
649 BDRsmooth(n, &x[1], &sc[n*7 + 1], &w[1], spans[1], -jper, vsmlsq,
650 &sc[(i<<1)*n + 1], &h[1]);
651 }
652
653 for (j=1; j<=n; ++j) {
654 resmin = big;
655 for (i=1; i<=3; ++i) {
656 if (sc[j + (i<<1)*n] < resmin) {
657 resmin = sc[j + (i<<1)*n];
658 sc[j + n*7] = spans[i-1];
659 }
660 }
661
662 if (alpha>0.0 && alpha<=10.0 && resmin<sc[j + n*6] && resmin>0.0) {
663 // Computing MAX
664 d1 = TMath::Max(sml,(resmin/sc[j + n*6]));
665 d2 = 10. - alpha;
666 sc[j + n*7] += (spans[2] - sc[j + n*7]) * TMath::Power(d1, d2);
667 }
668 }
669
670 BDRsmooth(n, &x[1], &sc[n*7 + 1], &w[1], spans[1], -jper, vsmlsq,
671 &sc[(n<<1) + 1], &h[1]);
672
673 for (j=1; j<=n; ++j) {
674 if (sc[j + (n<<1)] <= spans[0]) {
675 sc[j + (n<<1)] = spans[0];
676 }
677 if (sc[j + (n<<1)] >= spans[2]) {
678 sc[j + (n<<1)] = spans[2];
679 }
680 f = sc[j + (n<<1)] - spans[1];
681 if (f < 0.0) {
682 f = -f / (spans[1] - spans[0]);
683 sc[j + (n<<2)] = (1.0 - f) * sc[j + n*3] + f * sc[j + n];
684 } else {
685 f /= spans[2] - spans[1];
686 sc[j + (n<<2)] = (1.0 - f) * sc[j + n*3] + f * sc[j + n*5];
687 }
688 }
689
690 BDRsmooth(n, &x[1], &sc[(n<<2) + 1], &w[1], spans[0], -jper, vsmlsq,
691 &smo[1], &h[1]);
692
693 delete [] h;
694 return;
695}
696
697////////////////////////////////////////////////////////////////////////////////
698/// Function for super smoother
699/// Based on R function supsmu: Translated to C++ by C. Stratowa
700/// (R source file: ppr.f by B.D.Ripley Copyright (C) 1994-97)
701
704{
705// Local variables
706 Int_t i, j, j0, in, out, it, jper, ibw;
707 Double_t a, h1, d1;
708 Double_t xm, ym, wt, sy, fbo, fbw;
709 Double_t cvar, var, tmp, xti, xto;
710
711// Parameter adjustments
712 --acvr;
713 --smo;
714 --w;
715 --y;
716 --x;
717
718// Function Body
719 xm = 0.;
720 ym = xm;
721 var = ym;
722 cvar = var;
723 fbw = cvar;
725
726 ibw = (Int_t)(span * 0.5 * n + 0.5);
727 if (ibw < 2) {
728 ibw = 2;
729 }
730
731 it = 2*ibw + 1;
732 for (i=1; i<=it; ++i) {
733 j = i;
734 if (jper == 2) {
735 j = i - ibw - 1;
736 }
737 xti = x[j];
738 if (j < 1) {
739 j = n + j;
740 xti = x[j] - 1.0;
741 }
742 wt = w[j];
743 fbo = fbw;
744 fbw += wt;
745 if (fbw > 0.0) {
746 xm = (fbo * xm + wt * xti) / fbw;
747 ym = (fbo * ym + wt * y[j]) / fbw;
748 }
749 tmp = 0.0;
750 if (fbo > 0.0) {
751 tmp = fbw * wt * (xti - xm) / fbo;
752 }
753 var += tmp * (xti - xm);
754 cvar += tmp * (y[j] - ym);
755 }
756
757 for (j=1; j<=n; ++j) {
758 out = j - ibw - 1;
759 in = j + ibw;
760 if (!(jper != 2 && (out < 1 || in > n))) {
761 if (out < 1) {
762 out = n + out;
763 xto = x[out] - 1.0;
764 xti = x[in];
765 } else if (in > n) {
766 in -= n;
767 xti = x[in] + 1.0;
768 xto = x[out];
769 } else {
770 xto = x[out];
771 xti = x[in];
772 }
773
774 wt = w[out];
775 fbo = fbw;
776 fbw -= wt;
777 tmp = 0.0;
778 if (fbw > 0.0) {
779 tmp = fbo * wt * (xto - xm) / fbw;
780 }
781 var -= tmp * (xto - xm);
782 cvar -= tmp * (y[out] - ym);
783 if (fbw > 0.0) {
784 xm = (fbo * xm - wt * xto) / fbw;
785 ym = (fbo * ym - wt * y[out]) / fbw;
786 }
787 wt = w[in];
788 fbo = fbw;
789 fbw += wt;
790 if (fbw > 0.0) {
791 xm = (fbo * xm + wt * xti) / fbw;
792 ym = (fbo * ym + wt * y[in]) / fbw;
793 }
794 tmp = 0.0;
795 if (fbo > 0.0) {
796 tmp = fbw * wt * (xti - xm) / fbo;
797 }
798 var += tmp * (xti - xm);
799 cvar += tmp * (y[in] - ym);
800 }
801
802 a = 0.0;
803 if (var > vsmlsq) {
804 a = cvar / var;
805 }
806 smo[j] = a * (x[j] - xm) + ym;
807
808 if (iper <= 0) {
809 continue;
810 }
811
812 h1 = 0.0;
813 if (fbw > 0.0) {
814 h1 = 1.0 / fbw;
815 }
816 if (var > vsmlsq) {
817 // Computing 2nd power
818 d1 = x[j] - xm;
819 h1 += d1 * d1 / var;
820 }
821
822 acvr[j] = 0.0;
823 a = 1.0 - w[j] * h1;
824 if (a > 0.0) {
825 acvr[j] = TMath::Abs(y[j] - smo[j]) / a;
826 continue;
827 }
828 if (j > 1) {
829 acvr[j] = acvr[j-1];
830 }
831 }
832
833 j = 1;
834 do {
835 j0 = j;
836 sy = smo[j] * w[j];
837 fbw = w[j];
838 if (j < n) {
839 do {
840 if (x[j + 1] > x[j]) {
841 break;
842 }
843 ++j;
844 sy += w[j] * smo[j];
845 fbw += w[j];
846 } while (j < n);
847 }
848
849 if (j > j0) {
850 a = 0.0;
851 if (fbw > 0.0) {
852 a = sy / fbw;
853 }
854 for (i=j0; i<=j; ++i) {
855 smo[i] = a;
856 }
857 }
858 ++j;
859 } while (j <= n);
860
861 return;
862}
863
864////////////////////////////////////////////////////////////////////////////////
865/// Sort data points and eliminate double x values
866
869{
870 if (fGout) {delete fGout; fGout = nullptr;}
871 fGin = grin;
872
873 fNin = fGin->GetN();
874 Double_t *xin = new Double_t[fNin];
875 Double_t *yin = new Double_t[fNin];
876 Int_t i;
877 for (i=0;i<fNin;i++) {
878 xin[i] = fGin->GetX()[i];
879 yin[i] = fGin->GetY()[i];
880 }
881
882// sort/rank input x, y
883 Int_t *index = new Int_t[fNin];
884 Int_t *rank = new Int_t[fNin];
886
887// input X, Y
888 Int_t vNDup = 0;
889 Int_t k = 0;
890 Int_t *dup = new Int_t[fNin];
891 Double_t *x = new Double_t[fNin];
892 Double_t *y = new Double_t[fNin];
894 for (i=1;i<fNin+1;i++) {
895 Int_t ndup = 1;
896 vMin = vMean = vMax = yin[index[i-1]];
897 while ((i < fNin) && (rank[index[i]] == rank[index[i-1]])) {
898 vMean += yin[index[i]];
899 vMax = (vMax < yin[index[i]]) ? yin[index[i]] : vMax;
900 vMin = (vMin > yin[index[i]]) ? yin[index[i]] : vMin;
901 dup[vNDup] = i;
902 i++;
903 ndup++;
904 vNDup++;
905 }
906 x[k] = xin[index[i-1]];
907 if (ndup == 1) {y[k++] = yin[index[i-1]];}
908 else switch(iTies) {
909 case 1:
910 y[k++] = vMean/ndup;
911 break;
912 case 2:
913 y[k++] = vMin;
914 break;
915 case 3:
916 y[k++] = vMax;
917 break;
918 default:
919 y[k++] = vMean/ndup;
920 break;
921 }
922 }
923 fNin = k;
924
925// set unique sorted input data x,y as final graph points
926 fGin->Set(fNin);
927 for (i=0;i<fNin;i++) {
928 fGin->SetPoint(i, x[i], y[i]);
929 }
930
931 fMinX = fGin->GetX()[0]; //already sorted!
932 fMaxX = fGin->GetX()[fNin-1];
933
934// interpolate outside interval [min(x),max(x)]
935 switch(rule) {
936 case 1:
937 ylow = 0; // = nan("NAN") ??
938 yhigh = 0; // = nan("NAN") ??
939 break;
940 case 2:
941 ylow = fGin->GetY()[0];
942 yhigh = fGin->GetY()[fNin-1];
943 break;
944 default:
945 break;
946 }
947
948// cleanup
949 delete [] x;
950 delete [] y;
951 delete [] dup;
952 delete [] rank;
953 delete [] index;
954 delete [] xin;
955 delete [] yin;
956}
957
958////////////////////////////////////////////////////////////////////////////////
959/// Approximate data points
960/// \param[in] grin graph giving the coordinates of the points to be interpolated.
961/// Alternatively a single plotting structure can be specified:
962/// \param[in] option specifies the interpolation method to be used.
963/// Choices are "linear" (iKind = 1) or "constant" (iKind = 2).
964/// \param[in] nout If xout is not specified, interpolation takes place at n equally
965/// spaced points spanning the interval [min(x), max(x)], where
966/// nout = max(nout, number of input data).
967/// \param[in] xout an optional set of values specifying where interpolation is to
968/// take place.
969/// \param[in] yleft the value to be returned when input x values less than min(x).
970/// The default is defined by the value of rule given below.
971/// \param[in] yright the value to be returned when input x values greater than max(x).
972/// The default is defined by the value of rule given below.
973/// \param[in] rule an integer describing how interpolation is to take place outside
974/// the interval [min(x), max(x)]. If rule is 0 then the given yleft
975/// and yright values are returned, if it is 1 then 0 is returned
976/// for such points and if it is 2, the value at the closest data
977/// extreme is used.
978/// \param[in] f For method="constant" a number between 0 and 1 inclusive,
979/// indicating a compromise between left- and right-continuous step
980/// functions. If y0 and y1 are the values to the left and right of
981/// the point then the value is y0*f+y1*(1-f) so that f=0 is
982/// right-continuous and f=1 is left-continuous
983/// \param[in] ties Handling of tied x values. An integer describing a function with
984/// a single vector argument returning a single number result:
985/// - ties = "ordered" (iTies = 0): input x are "ordered"
986/// - ties = "mean" (iTies = 1): function "mean"
987/// - ties = "min" (iTies = 2): function "min"
988/// - ties = "max" (iTies = 3): function "max"
989///
990/// Details:
991///
992/// At least two complete (x, y) pairs are required.
993/// If there are duplicated (tied) x values and ties is a function it is
994/// applied to the y values for each distinct x value. Useful functions in
995/// this context include mean, min, and max.
996/// If ties="ordered" the x values are assumed to be already ordered. The
997/// first y value will be used for interpolation to the left and the last
998/// one for interpolation to the right.
999///
1000/// Value:
1001///
1002/// approx returns a graph with components x and y, containing n coordinates
1003/// which interpolate the given data points according to the method (and rule)
1004/// desired.
1005
1008{
1009 TString opt = option;
1010 opt.ToLower();
1011 Int_t iKind = 0;
1012 if (opt.Contains("linear")) iKind = 1;
1013 else if (opt.Contains("constant")) iKind = 2;
1014
1015 if (f < 0 || f > 1) {
1016 std::cout << "Error: Invalid f value" << std::endl;
1017 return nullptr;
1018 }
1019
1020 opt = ties;
1021 opt.ToLower();
1022 Int_t iTies = 0;
1023 if (opt.Contains("ordered")) {
1024 iTies = 0;
1025 } else if (opt.Contains("mean")) {
1026 iTies = 1;
1027 } else if (opt.Contains("min")) {
1028 iTies = 2;
1029 } else if (opt.Contains("max")) {
1030 iTies = 3;
1031 } else {
1032 std::cout << "Error: Method not known: " << ties << std::endl;
1033 return nullptr;
1034 }
1035
1036// input X, Y
1037 Double_t ylow = yleft;
1039 Approxin(grin, iKind, ylow, yhigh, rule, iTies);
1040
1041// output X, Y
1042 Double_t delta = 0;
1043 fNout = nout;
1044 if (xout == nullptr) {
1046 delta = (fMaxX - fMinX)/(fNout - 1);
1047 }
1048
1049 fGout = new TGraph(fNout);
1050
1051 Double_t x;
1052 for (Int_t i=0;i<fNout/2;i++) {
1053 if (xout == nullptr) x = fMinX + i*delta;
1054 else x = xout[i];
1055 Double_t yout = Approx1(x, f, fGin->GetX(), fGin->GetY(), fNin, iKind, ylow, yhigh);
1056 fGout->SetPoint(i, x, yout);
1057 }
1058 for (Int_t i=fNout/2;i<fNout;i++) {
1059 if (xout == nullptr) x = fMaxX + delta*(i + 1 - fNout);
1060 else x = xout[i];
1061 Double_t yout = Approx1(x, f, fGin->GetX(), fGin->GetY(), fNin, iKind, ylow, yhigh);
1062 fGout->SetPoint(i, x, yout);
1063 }
1064
1065 return fGout;
1066}
1067
1068////////////////////////////////////////////////////////////////////////////////
1069/// Approximate one data point.
1070/// Approximate y(v), given (x,y)[i], i = 0,..,n-1
1071/// Based on R function approx1: Translated to C++ by Christian Stratowa
1072/// (R source file: approx.c by R Development Core Team (C) 1999-2001)
1073
1076{
1077 Int_t i = 0;
1078 Int_t j = n - 1;
1079
1080// handle out-of-domain points
1081 if(v < x[i]) return ylow;
1082 if(v > x[j]) return yhigh;
1083
1084// find the correct interval by bisection
1085 while(i < j - 1) {
1086 Int_t ij = (i + j)/2;
1087 if(v < x[ij]) j = ij;
1088 else i = ij;
1089 }
1090
1091// interpolation
1092 if(v == x[j]) return y[j];
1093 if(v == x[i]) return y[i];
1094
1095 if(iKind == 1) { // linear
1096 return y[i] + (y[j] - y[i]) * ((v - x[i])/(x[j] - x[i]));
1097 } else { // 2 : constant
1098 return y[i] * (1-f) + y[j] * f;
1099 }
1100}
1101
1102// helper functions
1103////////////////////////////////////////////////////////////////////////////////
1104/// Static function
1105/// if (ISNAN(x)) return 1;
1106/// if (ISNAN(y)) return -1;
1107
1109{
1110 if (x < y) return -1;
1111 if (x > y) return 1;
1112 return 0;
1113}
1114
1115////////////////////////////////////////////////////////////////////////////////
1116/// Static function
1117/// based on R function rPsort: adapted to C++ by Christian Stratowa
1118/// (R source file: R_sort.c by R Development Core Team (C) 1999-2001)
1119
1121{
1122 Double_t v, w;
1123 Int_t pL, pR, i, j;
1124
1125 for (pL = 0, pR = n - 1; pL < pR; ) {
1126 v = x[k];
1127 for(i = pL, j = pR; i <= j;) {
1128 while (TGraphSmooth::Rcmp(x[i], v) < 0) i++;
1129 while (TGraphSmooth::Rcmp(v, x[j]) < 0) j--;
1130 if (i <= j) { w = x[i]; x[i++] = x[j]; x[j--] = w; }
1131 }
1132 if (j < k) pL = i;
1133 if (k < i) pR = j;
1134 }
1135}
1136
1137////////////////////////////////////////////////////////////////////////////////
1138/// static function
1139
1141{
1142 if (n <= 0) return;
1143 if (n == 1) {
1144 index[0] = 0;
1145 rank[0] = 0;
1146 return;
1147 }
1148
1150
1151 Int_t k = 0;
1152 for (Int_t i=0;i<n;i++) {
1153 if ((i > 0) && (a[index[i]] == a[index[i-1]])) {
1154 rank[index[i]] = i-1;
1155 k++;
1156 }
1157 rank[index[i]] = i-k;
1158 }
1159}
#define d(i)
Definition RSha256.hxx:102
#define b(i)
Definition RSha256.hxx:100
#define f(i)
Definition RSha256.hxx:104
#define c(i)
Definition RSha256.hxx:101
#define a(i)
Definition RSha256.hxx:99
#define h(i)
Definition RSha256.hxx:106
#define e(i)
Definition RSha256.hxx:103
int Int_t
Definition RtypesCore.h:45
constexpr Bool_t kFALSE
Definition RtypesCore.h:94
constexpr Bool_t kTRUE
Definition RtypesCore.h:93
const char Option_t
Definition RtypesCore.h:66
#define ClassImp(name)
Definition Rtypes.h:374
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
Option_t Option_t option
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t np
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t r
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t index
char name[80]
Definition TGX11.cxx:110
A TGraphErrors is a TGraph with error bars.
A helper class to smooth TGraph.
Double_t fMinX
Minimum value of array X.
TGraph * fGin
Input graph.
Double_t fMaxX
Maximum value of array X.
static Int_t Rcmp(Double_t x, Double_t y)
Static function if (ISNAN(x)) return 1; if (ISNAN(y)) return -1;.
TGraph * SmoothLowess(TGraph *grin, Option_t *option="", Double_t span=0.67, Int_t iter=3, Double_t delta=0)
Smooth data with Lowess smoother.
~TGraphSmooth() override
GraphSmooth destructor.
TGraph * SmoothSuper(TGraph *grin, Option_t *option="", Double_t bass=0, Double_t span=0, Bool_t isPeriodic=kFALSE, Double_t *w=nullptr)
Smooth data with Super smoother.
static void Rank(Int_t n, Double_t *a, Int_t *index, Int_t *rank, Bool_t down=kTRUE)
static function
Int_t fNout
Number of output points.
static void BDRksmooth(Double_t *x, Double_t *y, Int_t n, Double_t *xp, Double_t *yp, Int_t np, Int_t kernel, Double_t bw)
Smooth data with specified kernel.
Int_t fNin
Number of input points.
void Smoothin(TGraph *grin)
Sort input data points.
TGraph * SmoothKern(TGraph *grin, Option_t *option="normal", Double_t bandwidth=0.5, Int_t nout=100, Double_t *xout=nullptr)
Smooth data with Kernel smoother.
TGraph * Approx(TGraph *grin, Option_t *option="linear", Int_t nout=50, Double_t *xout=nullptr, Double_t yleft=0, Double_t yright=0, Int_t rule=0, Double_t f=0, Option_t *ties="mean")
Approximate data points.
static void BDRsupsmu(Int_t n, Double_t *x, Double_t *y, Double_t *w, Int_t iper, Double_t span, Double_t alpha, Double_t *smo, Double_t *sc)
Friedmanns super smoother (Friedman, 1984).
static void Psort(Double_t *x, Int_t n, Int_t k)
Static function based on R function rPsort: adapted to C++ by Christian Stratowa (R source file: R_so...
TGraph * fGout
Output graph.
static void Lowest(Double_t *x, Double_t *y, Int_t n, Double_t &xs, Double_t &ys, Int_t nleft, Int_t nright, Double_t *w, Bool_t userw, Double_t *rw, Bool_t &ok)
Fit value at x[i] Based on R function lowest: Translated to C++ by C.
static void BDRsmooth(Int_t n, Double_t *x, Double_t *y, Double_t *w, Double_t span, Int_t iper, Double_t vsmlsq, Double_t *smo, Double_t *acvr)
Function for super smoother Based on R function supsmu: Translated to C++ by C.
static Double_t Approx1(Double_t v, Double_t f, Double_t *x, Double_t *y, Int_t n, Int_t iKind, Double_t Ylow, Double_t Yhigh)
Approximate one data point.
void Lowess(Double_t *x, Double_t *y, Int_t n, Double_t *ys, Double_t span, Int_t iter, Double_t delta)
Lowess regression smoother.
void Approxin(TGraph *grin, Int_t iKind, Double_t &Ylow, Double_t &Yhigh, Int_t rule, Int_t iTies)
Sort data points and eliminate double x values.
A TGraph is an object made of two arrays X and Y with npoints each.
Definition TGraph.h:41
virtual void SetPoint(Int_t i, Double_t x, Double_t y)
Set x and y values for point number i.
Definition TGraph.cxx:2291
Double_t * GetY() const
Definition TGraph.h:139
Int_t GetN() const
Definition TGraph.h:131
Double_t * GetX() const
Definition TGraph.h:138
virtual void Set(Int_t n)
Set number of points in the graph Existing coordinates are preserved New coordinates above fNpoints a...
Definition TGraph.cxx:2226
The TNamed class is the base class for all named ROOT classes.
Definition TNamed.h:29
Basic string class.
Definition TString.h:139
void ToLower()
Change string to lower-case.
Definition TString.cxx:1182
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition TString.h:632
Double_t y[n]
Definition legend1.C:17
return c1
Definition legend1.C:41
Double_t x[n]
Definition legend1.C:17
const Int_t n
Definition legend1.C:16
TH1F * h1
Definition legend1.C:5
Short_t Max(Short_t a, Short_t b)
Returns the largest of a and b.
Definition TMathBase.h:250
Double_t Exp(Double_t x)
Returns the base-e exponential function of x, which is e raised to the power x.
Definition TMath.h:713
Double_t Sqrt(Double_t x)
Returns the square root of x.
Definition TMath.h:666
LongDouble_t Power(LongDouble_t x, LongDouble_t y)
Returns x raised to the power y.
Definition TMath.h:725
Short_t Min(Short_t a, Short_t b)
Returns the smallest of a and b.
Definition TMathBase.h:198
void Sort(Index n, const Element *a, Index *index, Bool_t down=kTRUE)
Sort the n elements of the array a of generic templated type Element.
Definition TMathBase.h:431
Short_t Abs(Short_t d)
Returns the absolute value of parameter Short_t d.
Definition TMathBase.h:123