Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TGraphErrors.cxx
Go to the documentation of this file.
1 // @(#)root/hist:$Id$
2 // Author: Rene Brun 15/09/96
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, 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 #include <string.h>
13 
14 #include "Riostream.h"
15 #include "TROOT.h"
16 #include "TGraphErrors.h"
17 #include "TStyle.h"
18 #include "TMath.h"
19 #include "TArrow.h"
20 #include "TBox.h"
21 #include "TVirtualPad.h"
22 #include "TH1.h"
23 #include "TF1.h"
24 #include "TVector.h"
25 #include "TVectorD.h"
26 #include "TStyle.h"
27 #include "TClass.h"
28 #include "TSystem.h"
29 #include <string>
30 
31 ClassImp(TGraphErrors);
32 
33 
34 ////////////////////////////////////////////////////////////////////////////////
35 
36 /** \class TGraphErrors
37  \ingroup Hist
38 A TGraphErrors is a TGraph with error bars.
39 
40 The TGraphErrors painting is performed thanks to the TGraphPainter
41 class. All details about the various painting options are given in this class.
42 
43 The picture below gives an example:
44 
45 Begin_Macro(source)
46 {
47  auto c1 = new TCanvas("c1","A Simple Graph with error bars",200,10,700,500);
48  c1->SetFillColor(42);
49  c1->SetGrid();
50  c1->GetFrame()->SetFillColor(21);
51  c1->GetFrame()->SetBorderSize(12);
52  const Int_t n = 10;
53  Double_t x[n] = {-0.22, 0.05, 0.25, 0.35, 0.5, 0.61,0.7,0.85,0.89,0.95};
54  Double_t y[n] = {1,2.9,5.6,7.4,9,9.6,8.7,6.3,4.5,1};
55  Double_t ex[n] = {.05,.1,.07,.07,.04,.05,.06,.07,.08,.05};
56  Double_t ey[n] = {.8,.7,.6,.5,.4,.4,.5,.6,.7,.8};
57  auto gr = new TGraphErrors(n,x,y,ex,ey);
58  gr->SetTitle("TGraphErrors Example");
59  gr->SetMarkerColor(4);
60  gr->SetMarkerStyle(21);
61  gr->Draw("ALP");
62 }
63 End_Macro
64 */
65 
66 
67 ////////////////////////////////////////////////////////////////////////////////
68 /// TGraphErrors default constructor.
69 
70 TGraphErrors::TGraphErrors(): TGraph()
71 {
72  if (!CtorAllocate()) return;
73 }
74 
75 
76 ////////////////////////////////////////////////////////////////////////////////
77 /// TGraphErrors normal constructor.
78 ///
79 /// the arrays are preset to zero
80 
81 TGraphErrors::TGraphErrors(Int_t n)
82  : TGraph(n)
83 {
84  if (!CtorAllocate()) return;
85  FillZero(0, fNpoints);
86 }
87 
88 
89 ////////////////////////////////////////////////////////////////////////////////
90 /// TGraphErrors normal constructor.
91 ///
92 /// if ex or ey are null, the corresponding arrays are preset to zero
93 
94 TGraphErrors::TGraphErrors(Int_t n, const Float_t *x, const Float_t *y, const Float_t *ex, const Float_t *ey)
95  : TGraph(n, x, y)
96 {
97  if (!CtorAllocate()) return;
98 
99  for (Int_t i = 0; i < n; i++) {
100  if (ex) fEX[i] = ex[i];
101  else fEX[i] = 0;
102  if (ey) fEY[i] = ey[i];
103  else fEY[i] = 0;
104  }
105 }
106 
107 
108 ////////////////////////////////////////////////////////////////////////////////
109 /// TGraphErrors normal constructor.
110 ///
111 /// if ex or ey are null, the corresponding arrays are preset to zero
112 
113 TGraphErrors::TGraphErrors(Int_t n, const Double_t *x, const Double_t *y, const Double_t *ex, const Double_t *ey)
114  : TGraph(n, x, y)
115 {
116  if (!CtorAllocate()) return;
117 
118  n = sizeof(Double_t) * fNpoints;
119  if (ex) memcpy(fEX, ex, n);
120  else memset(fEX, 0, n);
121  if (ey) memcpy(fEY, ey, n);
122  else memset(fEY, 0, n);
123 }
124 
125 
126 ////////////////////////////////////////////////////////////////////////////////
127 /// constructor with four vectors of floats in input
128 /// A grapherrors is built with the X coordinates taken from vx and Y coord from vy
129 /// and the errors from vectors vex and vey.
130 /// The number of points in the graph is the minimum of number of points
131 /// in vx and vy.
132 
133 TGraphErrors::TGraphErrors(const TVectorF &vx, const TVectorF &vy, const TVectorF &vex, const TVectorF &vey)
134  : TGraph(TMath::Min(vx.GetNrows(), vy.GetNrows()), vx.GetMatrixArray(), vy.GetMatrixArray() )
135 {
136  if (!CtorAllocate()) return;
137  Int_t ivexlow = vex.GetLwb();
138  Int_t iveylow = vey.GetLwb();
139  for (Int_t i = 0; i < fNpoints; i++) {
140  fEX[i] = vex(i + ivexlow);
141  fEY[i] = vey(i + iveylow);
142  }
143 }
144 
145 
146 ////////////////////////////////////////////////////////////////////////////////
147 /// constructor with four vectors of doubles in input
148 /// A grapherrors is built with the X coordinates taken from vx and Y coord from vy
149 /// and the errors from vectors vex and vey.
150 /// The number of points in the graph is the minimum of number of points
151 /// in vx and vy.
152 
153 TGraphErrors::TGraphErrors(const TVectorD &vx, const TVectorD &vy, const TVectorD &vex, const TVectorD &vey)
154  : TGraph(TMath::Min(vx.GetNrows(), vy.GetNrows()), vx.GetMatrixArray(), vy.GetMatrixArray() )
155 {
156  if (!CtorAllocate()) return;
157  Int_t ivexlow = vex.GetLwb();
158  Int_t iveylow = vey.GetLwb();
159  for (Int_t i = 0; i < fNpoints; i++) {
160  fEX[i] = vex(i + ivexlow);
161  fEY[i] = vey(i + iveylow);
162  }
163 }
164 
165 
166 ////////////////////////////////////////////////////////////////////////////////
167 /// TGraphErrors copy constructor
168 
169 TGraphErrors::TGraphErrors(const TGraphErrors &gr)
170  : TGraph(gr)
171 {
172  if (!CtorAllocate()) return;
173 
174  Int_t n = sizeof(Double_t) * fNpoints;
175  memcpy(fEX, gr.fEX, n);
176  memcpy(fEY, gr.fEY, n);
177 }
178 
179 
180 ////////////////////////////////////////////////////////////////////////////////
181 /// TGraphErrors assignment operator
182 
183 TGraphErrors& TGraphErrors::operator=(const TGraphErrors &gr)
184 {
185  if (this != &gr) {
186  TGraph::operator=(gr);
187  // N.B CtorAllocate does not delete arrays
188  if (fEX) delete [] fEX;
189  if (fEY) delete [] fEY;
190  if (!CtorAllocate()) return *this;
191 
192  Int_t n = sizeof(Double_t) * fNpoints;
193  memcpy(fEX, gr.fEX, n);
194  memcpy(fEY, gr.fEY, n);
195  }
196  return *this;
197 }
198 
199 
200 ////////////////////////////////////////////////////////////////////////////////
201 /// TGraphErrors constructor importing its parameters from the TH1 object passed as argument
202 
203 TGraphErrors::TGraphErrors(const TH1 *h)
204  : TGraph(h)
205 {
206  if (!CtorAllocate()) return;
207 
208  for (Int_t i = 0; i < fNpoints; i++) {
209  fEX[i] = h->GetBinWidth(i + 1) * gStyle->GetErrorX();
210  fEY[i] = h->GetBinError(i + 1);
211  }
212 }
213 
214 
215 ////////////////////////////////////////////////////////////////////////////////
216 /// GraphErrors constructor reading input from filename
217 /// filename is assumed to contain at least 2 columns of numbers
218 ///
219 /// Convention for format (default="%lg %lg %lg %lg)
220 /// - format = "%lg %lg" read only 2 first columns into X,Y
221 /// - format = "%lg %lg %lg" read only 3 first columns into X,Y and EY
222 /// - format = "%lg %lg %lg %lg" read only 4 first columns into X,Y,EX,EY.
223 ///
224 /// For files separated by a specific delimiter different from ' ' and '\t' (e.g. ';' in csv files)
225 /// you can avoid using %*s to bypass this delimiter by explicitly specify the "option" argument,
226 /// e.g. option=" \t,;" for columns of figures separated by any of these characters (' ', '\t', ',', ';')
227 /// used once (e.g. "1;1") or in a combined way (" 1;,;; 1").
228 /// Note in that case, the instantiation is about 2 times slower.
229 /// In case a delimiter is specified, the format "%lg %lg %lg" will read X,Y,EX.
230 
231 TGraphErrors::TGraphErrors(const char *filename, const char *format, Option_t *option)
232  : TGraph(100)
233 {
234  if (!CtorAllocate()) return;
235  Double_t x, y, ex, ey;
236  TString fname = filename;
237  gSystem->ExpandPathName(fname);
238  std::ifstream infile(fname.Data());
239  if (!infile.good()) {
240  MakeZombie();
241  Error("TGraphErrors", "Cannot open file: %s, TGraphErrors is Zombie", filename);
242  fNpoints = 0;
243  return;
244  }
245  std::string line;
246  Int_t np = 0;
247 
248  if (strcmp(option, "") == 0) { // No delimiters specified (standard constructor).
249 
250  Int_t ncol = CalculateScanfFields(format); //count number of columns in format
251  Int_t res;
252  while (std::getline(infile, line, '\n')) {
253  ex = ey = 0;
254  if (ncol < 3) {
255  res = sscanf(line.c_str(), format, &x, &y);
256  } else if (ncol < 4) {
257  res = sscanf(line.c_str(), format, &x, &y, &ey);
258  } else {
259  res = sscanf(line.c_str(), format, &x, &y, &ex, &ey);
260  }
261  if (res < 2) {
262  continue; //skip empty and ill-formed lines
263  }
264  SetPoint(np, x, y);
265  SetPointError(np, ex, ey);
266  np++;
267  }
268  Set(np);
269 
270  } else { // A delimiter has been specified in "option"
271 
272  // Checking format and creating its boolean equivalent
273  TString format_ = TString(format) ;
274  format_.ReplaceAll(" ", "") ;
275  format_.ReplaceAll("\t", "") ;
276  format_.ReplaceAll("lg", "") ;
277  format_.ReplaceAll("s", "") ;
278  format_.ReplaceAll("%*", "0") ;
279  format_.ReplaceAll("%", "1") ;
280  if (!format_.IsDigit()) {
281  Error("TGraphErrors", "Incorrect input format! Allowed format tags are {\"%%lg\",\"%%*lg\" or \"%%*s\"}");
282  return ;
283  }
284  Int_t ntokens = format_.Length() ;
285  if (ntokens < 2) {
286  Error("TGraphErrors", "Incorrect input format! Only %d tag(s) in format whereas at least 2 \"%%lg\" tags are expected!", ntokens);
287  return ;
288  }
289  Int_t ntokensToBeSaved = 0 ;
290  Bool_t * isTokenToBeSaved = new Bool_t [ntokens] ;
291  for (Int_t idx = 0; idx < ntokens; idx++) {
292  isTokenToBeSaved[idx] = TString::Format("%c", format_[idx]).Atoi() ; //atoi(&format_[idx]) does not work for some reason...
293  if (isTokenToBeSaved[idx] == 1) {
294  ntokensToBeSaved++ ;
295  }
296  }
297  if (ntokens >= 2 && (ntokensToBeSaved < 2 || ntokensToBeSaved > 4)) { //first condition not to repeat the previous error message
298  Error("TGraphErrors", "Incorrect input format! There are %d \"%%lg\" tag(s) in format whereas 2,3 or 4 are expected!", ntokensToBeSaved);
299  delete [] isTokenToBeSaved ;
300  return ;
301  }
302 
303  // Initializing loop variables
304  Bool_t isLineToBeSkipped = kFALSE ; //empty and ill-formed lines
305  char * token = NULL ;
306  TString token_str = "" ;
307  Int_t token_idx = 0 ;
308  Double_t * value = new Double_t [4] ; //x,y,ex,ey buffers
309  for (Int_t k = 0; k < 4; k++) {
310  value[k] = 0. ;
311  }
312  Int_t value_idx = 0 ;
313 
314  // Looping
315  char *rest;
316  while (std::getline(infile, line, '\n')) {
317  if (line != "") {
318  if (line[line.size() - 1] == char(13)) { // removing DOS CR character
319  line.erase(line.end() - 1, line.end()) ;
320  }
321  token = R__STRTOK_R(const_cast<char *>(line.c_str()), option, &rest);
322  while (token != NULL && value_idx < ntokensToBeSaved) {
323  if (isTokenToBeSaved[token_idx]) {
324  token_str = TString(token) ;
325  token_str.ReplaceAll("\t", "") ;
326  if (!token_str.IsFloat()) {
327  isLineToBeSkipped = kTRUE ;
328  break ;
329  } else {
330  value[value_idx] = token_str.Atof() ;
331  value_idx++ ;
332  }
333  }
334  token = R__STRTOK_R(NULL, option, &rest); // next token
335  token_idx++ ;
336  }
337  if (!isLineToBeSkipped && value_idx > 1) { //i.e. 2,3 or 4
338  x = value[0] ;
339  y = value[1] ;
340  ex = value[2] ;
341  ey = value[3] ;
342  SetPoint(np, x, y) ;
343  SetPointError(np, ex, ey);
344  np++ ;
345  }
346  }
347  isLineToBeSkipped = kFALSE ;
348  token = NULL ;
349  token_idx = 0 ;
350  value_idx = 0 ;
351  }
352  Set(np) ;
353 
354  // Cleaning
355  delete [] isTokenToBeSaved ;
356  delete [] value ;
357  delete token ;
358  }
359  infile.close();
360 }
361 
362 
363 ////////////////////////////////////////////////////////////////////////////////
364 /// TGraphErrors default destructor.
365 
366 TGraphErrors::~TGraphErrors()
367 {
368  delete [] fEX;
369  delete [] fEY;
370 }
371 
372 
373 ////////////////////////////////////////////////////////////////////////////////
374 /// apply function to all the data points
375 /// y = f(x,y)
376 ///
377 /// The error is calculated as ey=(f(x,y+ey)-f(x,y-ey))/2
378 /// This is the same as error(fy) = df/dy * ey for small errors
379 ///
380 /// For generic functions the symmetric errors might become non-symmetric
381 /// and are averaged here. Use TGraphAsymmErrors if desired.
382 ///
383 /// error on x doesn't change
384 /// function suggested/implemented by Miroslav Helbich <helbich@mail.desy.de>
385 
386 void TGraphErrors::Apply(TF1 *f)
387 {
388  Double_t x, y, ex, ey;
389 
390  if (fHistogram) {
391  delete fHistogram;
392  fHistogram = 0;
393  }
394  for (Int_t i = 0; i < GetN(); i++) {
395  GetPoint(i, x, y);
396  ex = GetErrorX(i);
397  ey = GetErrorY(i);
398 
399  SetPoint(i, x, f->Eval(x, y));
400  SetPointError(i, ex, TMath::Abs(f->Eval(x, y + ey) - f->Eval(x, y - ey)) / 2.);
401  }
402  if (gPad) gPad->Modified();
403 }
404 
405 
406 ////////////////////////////////////////////////////////////////////////////////
407 /// Calculate scan fields.
408 
409 Int_t TGraphErrors::CalculateScanfFields(const char *fmt)
410 {
411  Int_t fields = 0;
412  while ((fmt = strchr(fmt, '%'))) {
413  Bool_t skip = kFALSE;
414  while (*(++fmt)) {
415  if ('[' == *fmt) {
416  if (*++fmt && '^' == *fmt) ++fmt; // "%[^]a]"
417  if (*++fmt && ']' == *fmt) ++fmt; // "%[]a]" or "%[^]a]"
418  while (*fmt && *fmt != ']')
419  ++fmt;
420  if (!skip) ++fields;
421  break;
422  }
423  if ('%' == *fmt) break; // %% literal %
424  if ('*' == *fmt) {
425  skip = kTRUE; // %*d -- skip a number
426  } else if (strchr("dDiouxXxfegEscpn", *fmt)) {
427  if (!skip) ++fields;
428  break;
429  }
430  // skip modifiers & field width
431  }
432  }
433  return fields;
434 }
435 
436 
437 ////////////////////////////////////////////////////////////////////////////////
438 /// Compute range.
439 
440 void TGraphErrors::ComputeRange(Double_t &xmin, Double_t &ymin, Double_t &xmax, Double_t &ymax) const
441 {
442  TGraph::ComputeRange(xmin, ymin, xmax, ymax);
443 
444  for (Int_t i = 0; i < fNpoints; i++) {
445  if (fX[i] - fEX[i] < xmin) {
446  if (gPad && gPad->GetLogx()) {
447  if (fEX[i] < fX[i]) xmin = fX[i] - fEX[i];
448  else xmin = TMath::Min(xmin, fX[i] / 3);
449  } else {
450  xmin = fX[i] - fEX[i];
451  }
452  }
453  if (fX[i] + fEX[i] > xmax) xmax = fX[i] + fEX[i];
454  if (fY[i] - fEY[i] < ymin) {
455  if (gPad && gPad->GetLogy()) {
456  if (fEY[i] < fY[i]) ymin = fY[i] - fEY[i];
457  else ymin = TMath::Min(ymin, fY[i] / 3);
458  } else {
459  ymin = fY[i] - fEY[i];
460  }
461  }
462  if (fY[i] + fEY[i] > ymax) ymax = fY[i] + fEY[i];
463  }
464 }
465 
466 
467 ////////////////////////////////////////////////////////////////////////////////
468 /// Copy and release.
469 
470 void TGraphErrors::CopyAndRelease(Double_t **newarrays,
471  Int_t ibegin, Int_t iend, Int_t obegin)
472 {
473  CopyPoints(newarrays, ibegin, iend, obegin);
474  if (newarrays) {
475  delete[] fX;
476  fX = newarrays[2];
477  delete[] fY;
478  fY = newarrays[3];
479  delete[] fEX;
480  fEX = newarrays[0];
481  delete[] fEY;
482  fEY = newarrays[1];
483  delete[] newarrays;
484  }
485 }
486 
487 
488 ////////////////////////////////////////////////////////////////////////////////
489 /// Copy errors from fEX and fEY to arrays[0] and arrays[1]
490 /// or to fX and fY. Copy points.
491 
492 Bool_t TGraphErrors::CopyPoints(Double_t **arrays, Int_t ibegin, Int_t iend,
493  Int_t obegin)
494 {
495  if (TGraph::CopyPoints(arrays ? arrays + 2 : 0, ibegin, iend, obegin)) {
496  Int_t n = (iend - ibegin) * sizeof(Double_t);
497  if (arrays) {
498  memmove(&arrays[0][obegin], &fEX[ibegin], n);
499  memmove(&arrays[1][obegin], &fEY[ibegin], n);
500  } else {
501  memmove(&fEX[obegin], &fEX[ibegin], n);
502  memmove(&fEY[obegin], &fEY[ibegin], n);
503  }
504  return kTRUE;
505  } else {
506  return kFALSE;
507  }
508 }
509 
510 
511 ////////////////////////////////////////////////////////////////////////////////
512 /// Constructor allocate.
513 ///Note: This function should be called only from the constructor
514 /// since it does not delete previously existing arrays
515 
516 Bool_t TGraphErrors::CtorAllocate()
517 {
518 
519  if (!fNpoints) {
520  fEX = fEY = 0;
521  return kFALSE;
522  } else {
523  fEX = new Double_t[fMaxSize];
524  fEY = new Double_t[fMaxSize];
525  }
526  return kTRUE;
527 }
528 
529 ////////////////////////////////////////////////////////////////////////////////
530 /// protected function to perform the merge operation of a graph with errors
531 
532 Bool_t TGraphErrors::DoMerge(const TGraph *g)
533 {
534  if (g->GetN() == 0) return kFALSE;
535 
536  Double_t * ex = g->GetEX();
537  Double_t * ey = g->GetEY();
538  if (ex == 0 || ey == 0 ) {
539  if (g->IsA() != TGraph::Class() )
540  Warning("DoMerge","Merging a %s is not compatible with a TGraphErrors - errors will be ignored",g->IsA()->GetName());
541  return TGraph::DoMerge(g);
542  }
543  for (Int_t i = 0 ; i < g->GetN(); i++) {
544  Int_t ipoint = GetN();
545  Double_t x = g->GetX()[i];
546  Double_t y = g->GetY()[i];
547  SetPoint(ipoint, x, y);
548  SetPointError( ipoint, ex[i], ey[i] );
549  }
550  return kTRUE;
551 }
552 
553 
554 ////////////////////////////////////////////////////////////////////////////////
555 /// Set zero values for point arrays in the range [begin, end]
556 
557 void TGraphErrors::FillZero(Int_t begin, Int_t end, Bool_t from_ctor)
558 {
559  if (!from_ctor) {
560  TGraph::FillZero(begin, end, from_ctor);
561  }
562  Int_t n = (end - begin) * sizeof(Double_t);
563  memset(fEX + begin, 0, n);
564  memset(fEY + begin, 0, n);
565 }
566 
567 
568 ////////////////////////////////////////////////////////////////////////////////
569 /// This function is called by GraphFitChisquare.
570 /// It returns the error along X at point i.
571 
572 Double_t TGraphErrors::GetErrorX(Int_t i) const
573 {
574  if (i < 0 || i >= fNpoints) return -1;
575  if (fEX) return fEX[i];
576  return -1;
577 }
578 
579 
580 ////////////////////////////////////////////////////////////////////////////////
581 /// This function is called by GraphFitChisquare.
582 /// It returns the error along Y at point i.
583 
584 Double_t TGraphErrors::GetErrorY(Int_t i) const
585 {
586  if (i < 0 || i >= fNpoints) return -1;
587  if (fEY) return fEY[i];
588  return -1;
589 }
590 
591 
592 ////////////////////////////////////////////////////////////////////////////////
593 /// This function is called by GraphFitChisquare.
594 /// It returns the error along X at point i.
595 
596 Double_t TGraphErrors::GetErrorXhigh(Int_t i) const
597 {
598  if (i < 0 || i >= fNpoints) return -1;
599  if (fEX) return fEX[i];
600  return -1;
601 }
602 
603 
604 ////////////////////////////////////////////////////////////////////////////////
605 /// This function is called by GraphFitChisquare.
606 /// It returns the error along X at point i.
607 
608 Double_t TGraphErrors::GetErrorXlow(Int_t i) const
609 {
610  if (i < 0 || i >= fNpoints) return -1;
611  if (fEX) return fEX[i];
612  return -1;
613 }
614 
615 
616 ////////////////////////////////////////////////////////////////////////////////
617 /// This function is called by GraphFitChisquare.
618 /// It returns the error along X at point i.
619 
620 Double_t TGraphErrors::GetErrorYhigh(Int_t i) const
621 {
622  if (i < 0 || i >= fNpoints) return -1;
623  if (fEY) return fEY[i];
624  return -1;
625 }
626 
627 
628 ////////////////////////////////////////////////////////////////////////////////
629 /// This function is called by GraphFitChisquare.
630 /// It returns the error along X at point i.
631 
632 Double_t TGraphErrors::GetErrorYlow(Int_t i) const
633 {
634  if (i < 0 || i >= fNpoints) return -1;
635  if (fEY) return fEY[i];
636  return -1;
637 }
638 
639 ////////////////////////////////////////////////////////////////////////////////
640 /// Adds all graphs with errors from the collection to this graph.
641 /// Returns the total number of poins in the result or -1 in case of an error.
642 
643 Int_t TGraphErrors::Merge(TCollection* li)
644 {
645  TIter next(li);
646  while (TObject* o = next()) {
647  TGraph *g = dynamic_cast<TGraph*>(o);
648  if (!g) {
649  Error("Merge",
650  "Cannot merge - an object which doesn't inherit from TGraph found in the list");
651  return -1;
652  }
653  int n0 = GetN();
654  int n1 = n0+g->GetN();
655  Set(n1);
656  Double_t * x = g->GetX();
657  Double_t * y = g->GetY();
658  Double_t * ex = g->GetEX();
659  Double_t * ey = g->GetEY();
660  for (Int_t i = 0 ; i < g->GetN(); i++) {
661  SetPoint(n0+i, x[i], y[i]);
662  if (ex) fEX[n0+i] = ex[i];
663  if (ey) fEY[n0+i] = ey[i];
664  }
665  }
666  return GetN();
667 }
668 
669 ////////////////////////////////////////////////////////////////////////////////
670 /// Print graph and errors values.
671 
672 void TGraphErrors::Print(Option_t *) const
673 {
674  for (Int_t i = 0; i < fNpoints; i++) {
675  printf("x[%d]=%g, y[%d]=%g, ex[%d]=%g, ey[%d]=%g\n", i, fX[i], i, fY[i], i, fEX[i], i, fEY[i]);
676  }
677 }
678 
679 
680 ////////////////////////////////////////////////////////////////////////////////
681 /// Save primitive as a C++ statement(s) on output stream out
682 
683 void TGraphErrors::SavePrimitive(std::ostream &out, Option_t *option /*= ""*/)
684 {
685  char quote = '"';
686  out << " " << std::endl;
687  static Int_t frameNumber = 1000;
688  frameNumber++;
689 
690  Int_t i;
691  TString fXName = TString(GetName()) + Form("_fx%d",frameNumber);
692  TString fYName = TString(GetName()) + Form("_fy%d",frameNumber);
693  TString fEXName = TString(GetName()) + Form("_fex%d",frameNumber);
694  TString fEYName = TString(GetName()) + Form("_fey%d",frameNumber);
695  out << " Double_t " << fXName << "[" << fNpoints << "] = {" << std::endl;
696  for (i = 0; i < fNpoints-1; i++) out << " " << fX[i] << "," << std::endl;
697  out << " " << fX[fNpoints-1] << "};" << std::endl;
698  out << " Double_t " << fYName << "[" << fNpoints << "] = {" << std::endl;
699  for (i = 0; i < fNpoints-1; i++) out << " " << fY[i] << "," << std::endl;
700  out << " " << fY[fNpoints-1] << "};" << std::endl;
701  out << " Double_t " << fEXName << "[" << fNpoints << "] = {" << std::endl;
702  for (i = 0; i < fNpoints-1; i++) out << " " << fEX[i] << "," << std::endl;
703  out << " " << fEX[fNpoints-1] << "};" << std::endl;
704  out << " Double_t " << fEYName << "[" << fNpoints << "] = {" << std::endl;
705  for (i = 0; i < fNpoints-1; i++) out << " " << fEY[i] << "," << std::endl;
706  out << " " << fEY[fNpoints-1] << "};" << std::endl;
707 
708  if (gROOT->ClassSaved(TGraphErrors::Class())) out << " ";
709  else out << " TGraphErrors *";
710  out << "gre = new TGraphErrors(" << fNpoints << ","
711  << fXName << "," << fYName << ","
712  << fEXName << "," << fEYName << ");"
713  << std::endl;
714 
715  out << " gre->SetName(" << quote << GetName() << quote << ");" << std::endl;
716  out << " gre->SetTitle(" << quote << GetTitle() << quote << ");" << std::endl;
717 
718  SaveFillAttributes(out, "gre", 0, 1001);
719  SaveLineAttributes(out, "gre", 1, 1, 1);
720  SaveMarkerAttributes(out, "gre", 1, 1, 1);
721 
722  if (fHistogram) {
723  TString hname = fHistogram->GetName();
724  hname += frameNumber;
725  fHistogram->SetName(Form("Graph_%s", hname.Data()));
726  fHistogram->SavePrimitive(out, "nodraw");
727  out << " gre->SetHistogram(" << fHistogram->GetName() << ");" << std::endl;
728  out << " " << std::endl;
729  }
730 
731  // save list of functions
732  TIter next(fFunctions);
733  TObject *obj;
734  while ((obj = next())) {
735  obj->SavePrimitive(out, Form("nodraw #%d\n",++frameNumber));
736  if (obj->InheritsFrom("TPaveStats")) {
737  out << " gre->GetListOfFunctions()->Add(ptstats);" << std::endl;
738  out << " ptstats->SetParent(gre->GetListOfFunctions());" << std::endl;
739  } else {
740  TString objname;
741  objname.Form("%s%d",obj->GetName(),frameNumber);
742  if (obj->InheritsFrom("TF1")) {
743  out << " " << objname << "->SetParent(gre);\n";
744  }
745  out << " gre->GetListOfFunctions()->Add("
746  << objname << ");" << std::endl;
747  }
748  }
749 
750  const char *l = strstr(option, "multigraph");
751  if (l) {
752  out << " multigraph->Add(gre," << quote << l + 10 << quote << ");" << std::endl;
753  } else {
754  out << " gre->Draw(" << quote << option << quote << ");" << std::endl;
755  }
756 }
757 
758 
759 ////////////////////////////////////////////////////////////////////////////////
760 /// Set ex and ey values for point pointed by the mouse.
761 
762 void TGraphErrors::SetPointError(Double_t ex, Double_t ey)
763 {
764  Int_t px = gPad->GetEventX();
765  Int_t py = gPad->GetEventY();
766 
767  //localize point to be deleted
768  Int_t ipoint = -2;
769  Int_t i;
770  // start with a small window (in case the mouse is very close to one point)
771  for (i = 0; i < fNpoints; i++) {
772  Int_t dpx = px - gPad->XtoAbsPixel(gPad->XtoPad(fX[i]));
773  Int_t dpy = py - gPad->YtoAbsPixel(gPad->YtoPad(fY[i]));
774  if (dpx * dpx + dpy * dpy < 25) {
775  ipoint = i;
776  break;
777  }
778  }
779  if (ipoint == -2) return;
780 
781  fEX[ipoint] = ex;
782  fEY[ipoint] = ey;
783  gPad->Modified();
784 }
785 
786 
787 ////////////////////////////////////////////////////////////////////////////////
788 /// Set ex and ey values for point number i.
789 
790 void TGraphErrors::SetPointError(Int_t i, Double_t ex, Double_t ey)
791 {
792  if (i < 0) return;
793  if (i >= fNpoints) {
794  // re-allocate the object
795  TGraphErrors::SetPoint(i, 0, 0);
796  }
797  fEX[i] = ex;
798  fEY[i] = ey;
799 }
800 
801 
802 ////////////////////////////////////////////////////////////////////////////////
803 /// Stream an object of class TGraphErrors.
804 
805 void TGraphErrors::Streamer(TBuffer &b)
806 {
807  if (b.IsReading()) {
808  UInt_t R__s, R__c;
809  Version_t R__v = b.ReadVersion(&R__s, &R__c);
810  if (R__v > 2) {
811  b.ReadClassBuffer(TGraphErrors::Class(), this, R__v, R__s, R__c);
812  return;
813  }
814  //====process old versions before automatic schema evolution
815  TGraph::Streamer(b);
816  fEX = new Double_t[fNpoints];
817  fEY = new Double_t[fNpoints];
818  if (R__v < 2) {
819  Float_t *ex = new Float_t[fNpoints];
820  Float_t *ey = new Float_t[fNpoints];
821  b.ReadFastArray(ex, fNpoints);
822  b.ReadFastArray(ey, fNpoints);
823  for (Int_t i = 0; i < fNpoints; i++) {
824  fEX[i] = ex[i];
825  fEY[i] = ey[i];
826  }
827  delete [] ey;
828  delete [] ex;
829  } else {
830  b.ReadFastArray(fEX, fNpoints);
831  b.ReadFastArray(fEY, fNpoints);
832  }
833  b.CheckByteCount(R__s, R__c, TGraphErrors::IsA());
834  //====end of old versions
835 
836  } else {
837  b.WriteClassBuffer(TGraphErrors::Class(), this);
838  }
839 }
840 
841 
842 ////////////////////////////////////////////////////////////////////////////////
843 /// Swap points
844 
845 void TGraphErrors::SwapPoints(Int_t pos1, Int_t pos2)
846 {
847  SwapValues(fEX, pos1, pos2);
848  SwapValues(fEY, pos1, pos2);
849  TGraph::SwapPoints(pos1, pos2);
850 }