c_cpp ROOT图表突出显示

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c_cpp ROOT图表突出显示相关的知识,希望对你有一定的参考价值。

ROOT Graph Highlight (extended)
// @(#)root/hist:$Id$
// Author: Rene Brun, Olivier Couet   12/12/94

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include <string.h>

#include "Riostream.h"
#include "TROOT.h"
#include "TEnv.h"
#include "TGraph.h"
#include "TGaxis.h"
#include "TH1.h"
#include "TF1.h"
#include "TStyle.h"
#include "TMath.h"
#include "TFrame.h"
#include "TVector.h"
#include "TVectorD.h"
#include "Foption.h"
#include "TRandom.h"
#include "TSpline.h"
#include "TVirtualFitter.h"
#include "TVirtualPad.h"
#include "TVirtualGraphPainter.h"
#include "TBrowser.h"
#include "TClass.h"
#include "TSystem.h"
#include "TPluginManager.h"
#include <stdlib.h>
#include <string>
#include <cassert>

#include "HFitInterface.h"
#include "Fit/DataRange.h"
#include "Math/MinimizerOptions.h"

extern void H1LeastSquareSeqnd(Int_t n, Double_t *a, Int_t idim, Int_t &ifail, Int_t k, Double_t *b);

ClassImp(TGraph)


//______________________________________________________________________________
/* Begin_Html
<center><h2>Graph class</h2></center>
A Graph is a graphics object made of two arrays X and Y with npoints each.
</p>
The TGraph painting is performed thanks to the
<a href="http://root.cern.ch/root/html/TGraphPainter.html">TGraphPainter</a>
class. All details about the various painting options are given in
<a href="http://root.cern.ch/root/html/TGraphPainter.html">this class</a>.
</p>
<i>Note:</i>Unlike histogram or tree (or even TGraph2D), TGraph objects
 are not automatically attached to the current TFile, in order to keep the
 management and size of the TGraph has small as possible.
</p>
The picture below gives an example:
End_Html
Begin_Macro(source)
{
   TCanvas *c1 = new TCanvas("c1","A Simple Graph Example",200,10,700,500);
   Double_t x[100], y[100];
   Int_t n = 20;
   for (Int_t i=0;i<n;i++) {
     x[i] = i*0.1;
     y[i] = 10*sin(x[i]+0.2);
   }
   gr = new TGraph(n,x,y);
   gr->Draw("AC*");
   return c1;
}
End_Macro */


//______________________________________________________________________________
TGraph::TGraph(): TNamed(), TAttLine(), TAttFill(1, 1001), TAttMarker()
{
   // Graph default constructor.

   fNpoints = -1;  //will be reset to 0 in CtorAllocate
   if (!CtorAllocate()) return;
}


//______________________________________________________________________________
TGraph::TGraph(Int_t n)
   : TNamed("Graph", "Graph"), TAttLine(), TAttFill(1, 1001), TAttMarker()
{
   // Constructor with only the number of points set
   // the arrays x and y will be set later

   fNpoints = n;
   if (!CtorAllocate()) return;
   FillZero(0, fNpoints);
}


//______________________________________________________________________________
TGraph::TGraph(Int_t n, const Int_t *x, const Int_t *y)
   : TNamed("Graph", "Graph"), TAttLine(), TAttFill(1, 1001), TAttMarker()
{
   // Graph normal constructor with ints.

   if (!x || !y) {
      fNpoints = 0;
   } else {
      fNpoints = n;
   }
   if (!CtorAllocate()) return;
   for (Int_t i = 0; i < n; i++) {
      fX[i] = (Double_t)x[i];
      fY[i] = (Double_t)y[i];
   }
}


//______________________________________________________________________________
TGraph::TGraph(Int_t n, const Float_t *x, const Float_t *y)
   : TNamed("Graph", "Graph"), TAttLine(), TAttFill(1, 1001), TAttMarker()
{
   // Graph normal constructor with floats.

   if (!x || !y) {
      fNpoints = 0;
   } else {
      fNpoints = n;
   }
   if (!CtorAllocate()) return;
   for (Int_t i = 0; i < n; i++) {
      fX[i] = x[i];
      fY[i] = y[i];
   }
}


//______________________________________________________________________________
TGraph::TGraph(Int_t n, const Double_t *x, const Double_t *y)
   : TNamed("Graph", "Graph"), TAttLine(), TAttFill(1, 1001), TAttMarker()
{
   // Graph normal constructor with doubles.

   if (!x || !y) {
      fNpoints = 0;
   } else {
      fNpoints = n;
   }
   if (!CtorAllocate()) return;
   n = fNpoints * sizeof(Double_t);
   memcpy(fX, x, n);
   memcpy(fY, y, n);
}


//______________________________________________________________________________
TGraph::TGraph(const TGraph &gr)
   : TNamed(gr), TAttLine(gr), TAttFill(gr), TAttMarker(gr)
{
   // Copy constructor for this graph

   fNpoints = gr.fNpoints;
   fMaxSize = gr.fMaxSize;
   if (gr.fFunctions) fFunctions = (TList*)gr.fFunctions->Clone();
   else fFunctions = new TList;
   fHistogram = 0;
   fMinimum = gr.fMinimum;
   fMaximum = gr.fMaximum;
   if (!fMaxSize) {
      fX = fY = 0;
      return;
   } else {
      fX = new Double_t[fMaxSize];
      fY = new Double_t[fMaxSize];
   }

   Int_t n = gr.GetN() * sizeof(Double_t);
   memcpy(fX, gr.fX, n);
   memcpy(fY, gr.fY, n);
}


//______________________________________________________________________________
TGraph& TGraph::operator=(const TGraph &gr)
{
   // Equal operator for this graph

   if (this != &gr) {
      TNamed::operator=(gr);
      TAttLine::operator=(gr);
      TAttFill::operator=(gr);
      TAttMarker::operator=(gr);

      fNpoints = gr.fNpoints;
      fMaxSize = gr.fMaxSize;

      // delete list of functions and their contents before copying it
      if (fFunctions) {
         // delete previous lists of functions
         if (!fFunctions->IsEmpty()) {
            fFunctions->SetBit(kInvalidObject);
            // use TList::Remove to take into account the case the same object is
            // added multiple times in the list
            TObject *obj;
            while ((obj  = fFunctions->First())) {
               while (fFunctions->Remove(obj)) { }
               delete obj;
            }
         }
         delete fFunctions;
      }

      if (gr.fFunctions) fFunctions = (TList*)gr.fFunctions->Clone();
      else fFunctions = new TList;

      if (fHistogram) delete fHistogram;
      if (gr.fHistogram) fHistogram = new TH1F(*(gr.fHistogram));
      else fHistogram = 0;

      fMinimum = gr.fMinimum;
      fMaximum = gr.fMaximum;
      if (fX) delete [] fX;
      if (fY) delete [] fY;
      if (!fMaxSize) {
         fX = fY = 0;
         return *this;
      } else {
         fX = new Double_t[fMaxSize];
         fY = new Double_t[fMaxSize];
      }

      Int_t n = gr.GetN() * sizeof(Double_t);
      if (n > 0) {
         memcpy(fX, gr.fX, n);
         memcpy(fY, gr.fY, n);
      }
   }
   return *this;
}


//______________________________________________________________________________
TGraph::TGraph(const TVectorF &vx, const TVectorF &vy)
   : TNamed("Graph", "Graph"), TAttLine(), TAttFill(1, 1001), TAttMarker()
{
   // Graph constructor with two vectors of floats in input
   // A graph is build with the X coordinates taken from vx and Y coord from vy
   // The number of points in the graph is the minimum of number of points
   // in vx and vy.

   fNpoints = TMath::Min(vx.GetNrows(), vy.GetNrows());
   if (!CtorAllocate()) return;
   Int_t ivxlow  = vx.GetLwb();
   Int_t ivylow  = vy.GetLwb();
   for (Int_t i = 0; i < fNpoints; i++) {
      fX[i]  = vx(i + ivxlow);
      fY[i]  = vy(i + ivylow);
   }
}


//______________________________________________________________________________
TGraph::TGraph(const TVectorD &vx, const TVectorD &vy)
   : TNamed("Graph", "Graph"), TAttLine(), TAttFill(1, 1001), TAttMarker()
{
   // Graph constructor with two vectors of doubles in input
   // A graph is build with the X coordinates taken from vx and Y coord from vy
   // The number of points in the graph is the minimum of number of points
   // in vx and vy.

   fNpoints = TMath::Min(vx.GetNrows(), vy.GetNrows());
   if (!CtorAllocate()) return;
   Int_t ivxlow  = vx.GetLwb();
   Int_t ivylow  = vy.GetLwb();
   for (Int_t i = 0; i < fNpoints; i++) {
      fX[i]  = vx(i + ivxlow);
      fY[i]  = vy(i + ivylow);
   }
}


//______________________________________________________________________________
TGraph::TGraph(const TH1 *h)
   : TNamed("Graph", "Graph"), TAttLine(), TAttFill(1, 1001), TAttMarker()
{
   // Graph constructor importing its parameters from the TH1 object passed as argument

   if (!h) {
      Error("TGraph", "Pointer to histogram is null");
      fNpoints = 0;
      return;
   }
   if (h->GetDimension() != 1) {
      Error("TGraph", "Histogram must be 1-D; h %s is %d-D", h->GetName(), h->GetDimension());
      fNpoints = 0;
   } else {
      fNpoints = ((TH1*)h)->GetXaxis()->GetNbins();
   }

   if (!CtorAllocate()) return;

   TAxis *xaxis = ((TH1*)h)->GetXaxis();
   for (Int_t i = 0; i < fNpoints; i++) {
      fX[i] = xaxis->GetBinCenter(i + 1);
      fY[i] = h->GetBinContent(i + 1);
   }
   h->TAttLine::Copy(*this);
   h->TAttFill::Copy(*this);
   h->TAttMarker::Copy(*this);

   std::string gname = "Graph_from_" + std::string(h->GetName());
   SetName(gname.c_str());
   SetTitle(h->GetTitle());
}


//______________________________________________________________________________
TGraph::TGraph(const TF1 *f, Option_t *option)
   : TNamed("Graph", "Graph"), TAttLine(), TAttFill(1, 1001), TAttMarker()
{
   // Graph constructor importing its parameters from the TF1 object passed as argument
   // if option =="" (default), a TGraph is created with points computed
   //                at the fNpx points of f.
   // if option =="d", a TGraph is created with points computed with the derivatives
   //                at the fNpx points of f.
   // if option =="i", a TGraph is created with points computed with the integral
   //                at the fNpx points of f.
   // if option =="I", a TGraph is created with points computed with the integral
   //                at the fNpx+1 points of f and the integral is normalized to 1.

   char coption = ' ';
   if (!f) {
      Error("TGraph", "Pointer to function is null");
      fNpoints = 0;
   } else {
      fNpoints   = f->GetNpx();
      if (option) coption = *option;
      if (coption == 'i' || coption == 'I') fNpoints++;
   }
   if (!CtorAllocate()) return;

   Double_t xmin = f->GetXmin();
   Double_t xmax = f->GetXmax();
   Double_t dx   = (xmax - xmin) / fNpoints;
   Double_t integ = 0;
   Int_t i;
   for (i = 0; i < fNpoints; i++) {
      if (coption == 'i' || coption == 'I') {
         fX[i] = xmin + i * dx;
         if (i == 0) fY[i] = 0;
         else        fY[i] = integ + ((TF1*)f)->Integral(fX[i] - dx, fX[i]);
         integ = fY[i];
      } else if (coption == 'd' || coption == 'D') {
         fX[i] = xmin + (i + 0.5) * dx;
         fY[i] = ((TF1*)f)->Derivative(fX[i]);
      } else {
         fX[i] = xmin + (i + 0.5) * dx;
         fY[i] = ((TF1*)f)->Eval(fX[i]);
      }
   }
   if (integ != 0 && coption == 'I') {
      for (i = 1; i < fNpoints; i++) fY[i] /= integ;
   }

   f->TAttLine::Copy(*this);
   f->TAttFill::Copy(*this);
   f->TAttMarker::Copy(*this);

   SetName(f->GetName());
   SetTitle(f->GetTitle());
}


//______________________________________________________________________________
TGraph::TGraph(const char *filename, const char *format, Option_t *option)
   : TNamed("Graph", filename), TAttLine(), TAttFill(1, 1001), TAttMarker()
{
   // Graph constructor reading input from filename.
   // filename is assumed to contain at least two columns of numbers.
   // the string format is by default "%lg %lg".
   // this is a standard c formatting for scanf. If columns of numbers should be
   // skipped, a "%*lg" or "%*s" for each column can be added,
   // e.g. "%lg %*lg %lg" would read x-values from the first and y-values from
   // the third column.
   // For files separated by a specific delimiter different from ' ' and '\t' (e.g. ';' in csv files)
   // you can avoid using %*s to bypass this delimiter by explicitly specify the "option" argument,
   // e.g. option=" \t,;" for columns of figures separated by any of these characters (' ', '\t', ',', ';')
   // used once (e.g. "1;1") or in a combined way (" 1;,;;  1").
   // Note in that case, the instanciation is about 2 times slower.

   Double_t x, y;
   TString fname = filename;
   gSystem->ExpandPathName(fname);

   ifstream infile(fname.Data());
   if (!infile.good()) {
      MakeZombie();
      Error("TGraph", "Cannot open file: %s, TGraph is Zombie", filename);
      fNpoints = 0;
      return;
   } else {
      fNpoints = 100;  //initial number of points
   }
   if (!CtorAllocate()) return;
   std::string line;
   Int_t np = 0;

   // No delimiters specified (standard constructor).
   if (strcmp(option, "") == 0) {

      while (std::getline(infile, line, '\n')) {
         if (2 != sscanf(line.c_str(), format, &x, &y)) {
            continue; //skip empty and ill-formed lines
         }
         SetPoint(np, x, y);
         np++;
      }
      Set(np);

      // A delimiter has been specified in "option"
   } else {

      // Checking format and creating its boolean counterpart
      TString format_ = TString(format) ;
      format_.ReplaceAll(" ", "") ;
      format_.ReplaceAll("\t", "") ;
      format_.ReplaceAll("lg", "") ;
      format_.ReplaceAll("s", "") ;
      format_.ReplaceAll("%*", "0") ;
      format_.ReplaceAll("%", "1") ;
      if (!format_.IsDigit()) {
         Error("TGraph", "Incorrect input format! Allowed formats are {\"%%lg\",\"%%*lg\" or \"%%*s\"}");
         return;
      }
      Int_t ntokens = format_.Length() ;
      if (ntokens < 2) {
         Error("TGraph", "Incorrect input format! Only %d tag(s) in format whereas 2 \"%%lg\" tags are expected!", ntokens);
         return;
      }
      Int_t ntokensToBeSaved = 0 ;
      Bool_t * isTokenToBeSaved = new Bool_t [ntokens] ;
      for (Int_t idx = 0; idx < ntokens; idx++) {
         isTokenToBeSaved[idx] = TString::Format("%c", format_[idx]).Atoi() ; //atoi(&format_[idx]) does not work for some reason...
         if (isTokenToBeSaved[idx] == 1) {
            ntokensToBeSaved++ ;
         }
      }
      if (ntokens >= 2 && ntokensToBeSaved != 2) { //first condition not to repeat the previous error message
         Error("TGraph", "Incorrect input format! There are %d \"%%lg\" tag(s) in format whereas 2 and only 2 are expected!", ntokensToBeSaved);
         delete [] isTokenToBeSaved ;
         return;
      }

      // Initializing loop variables
      Bool_t isLineToBeSkipped = kFALSE ; //empty and ill-formed lines
      char * token = NULL ;
      TString token_str = "" ;
      Int_t token_idx = 0 ;
      Double_t * value = new Double_t [2] ; //x,y buffers
      Int_t value_idx = 0 ;

      // Looping
      while (std::getline(infile, line, '\n')) {
         if (line != "") {
            if (line[line.size() - 1] == char(13)) {  // removing DOS CR character
               line.erase(line.end() - 1, line.end()) ;
            }
            token = strtok(const_cast<char*>(line.c_str()), option) ;
            while (token != NULL && value_idx < 2) {
               if (isTokenToBeSaved[token_idx]) {
                  token_str = TString(token) ;
                  token_str.ReplaceAll("\t", "") ;
                  if (!token_str.IsFloat()) {
                     isLineToBeSkipped = kTRUE ;
                     break ;
                  } else {
                     value[value_idx] = token_str.Atof() ;
                     value_idx++ ;
                  }
               }
               token = strtok(NULL, option) ; //next token
               token_idx++ ;
            }
            if (!isLineToBeSkipped && value_idx == 2) {
               x = value[0] ;
               y = value[1] ;
               SetPoint(np, x, y) ;
               np++ ;
            }
         }
         isLineToBeSkipped = kFALSE ;
         token = NULL ;
         token_idx = 0 ;
         value_idx = 0 ;
      }
      Set(np) ;

      // Cleaning
      delete [] isTokenToBeSaved ;
      delete [] value ;
      delete token ;
   }
   infile.close();
}


//______________________________________________________________________________
TGraph::~TGraph()
{
   // Graph default destructor.

   delete [] fX;
   delete [] fY;
   if (fFunctions) {
      fFunctions->SetBit(kInvalidObject);
      //special logic to support the case where the same object is
      //added multiple times in fFunctions.
      //This case happens when the same object is added with different
      //drawing modes
      TObject *obj;
      while ((obj  = fFunctions->First())) {
         while (fFunctions->Remove(obj)) { }
         delete obj;
      }
      delete fFunctions;
      fFunctions = 0; //to avoid accessing a deleted object in RecursiveRemove
   }
   delete fHistogram;
}


//______________________________________________________________________________
Double_t** TGraph::AllocateArrays(Int_t Narrays, Int_t arraySize)
{
   // Allocate arrays.

   if (arraySize < 0) {
      arraySize = 0;
   }
   Double_t **newarrays = new Double_t*[Narrays];
   if (!arraySize) {
      for (Int_t i = 0; i < Narrays; ++i)
         newarrays[i] = 0;
   } else {
      for (Int_t i = 0; i < Narrays; ++i)
         newarrays[i] = new Double_t[arraySize];
   }
   fMaxSize = arraySize;
   return newarrays;
}


//______________________________________________________________________________
void TGraph::Apply(TF1 *f)
{
   // Apply function f to all the data points
   // f may be a 1-D function TF1 or 2-d function TF2
   // The Y values of the graph are replaced by the new values computed
   // using the function

   if (fHistogram) {
      delete fHistogram;
      fHistogram = 0;
   }
   for (Int_t i = 0; i < fNpoints; i++) {
      fY[i] = f->Eval(fX[i], fY[i]);
   }
   if (gPad) gPad->Modified();
}


//______________________________________________________________________________
void TGraph::Browse(TBrowser *b)
{
   // Browse

   TString opt = gEnv->GetValue("TGraph.BrowseOption", "");
   if (opt.IsNull()) {
      opt = b ? b->GetDrawOption() : "alp";
      opt = (opt == "") ? "alp" : opt.Data();
   }
   Draw(opt.Data());
   gPad->Update();
}


//______________________________________________________________________________
Double_t TGraph::Chisquare(const TF1 *f1, Option_t * option) const
{
   // Return the chisquare of this graph with respect to f1.
   // The chisquare is computed as the sum of the quantity below at each point:
   // Begin_Latex
   // #frac{(y-f1(x))^{2}}{ey^{2}+(#frac{1}{2}(exl+exh)f1'(x))^{2}}
   // End_latex
   // where x and y are the graph point coordinates and f1'(x) is the derivative of function f1(x).
   // This method to approximate the uncertainty in y because of the errors in x, is called
   // "effective variance" method.
   // In case of a pure TGraph, the denominator is 1.
   // In case of a TGraphErrors or TGraphAsymmErrors the errors are taken
   // into account.
   // By default the range of the graph is used whatever function range.
   //  Use option "R" to use the function range

   // need to cast away the const - since it requires evaluating the function which is not const
   TF1 * func = const_cast<TF1*>(f1);
   if (!func) {
      Error("Chisquare","Function pointer is Null - return -1");
      return -1;
   }

   TString opt(option); opt.ToUpper();
   bool useRange = opt.Contains("R");

   return ROOT::Fit::Chisquare(*this, *func,useRange);
}


//    Double_t cu, eu, exh, exl, ey, eux, fu, fsum;
//    Double_t x[1];
//    Double_t chi2 = 0;
//    TF1 *func = (TF1*)f1; //EvalPar is not const !
//    for (Int_t i = 0; i < fNpoints; i++) {
//       func->InitArgs(x, 0); //must be inside the loop because of TF1::Derivative calling InitArgs
//       x[0] = fX[i];
//       if (!func->IsInside(x)) continue;
//       cu   = fY[i];
//       TF1::RejectPoint(kFALSE);
//       fu   = func->EvalPar(x);
//       if (TF1::RejectedPoint()) continue;
//       fsum = (cu - fu);
//       //npfits++;
//       exh = GetErrorXhigh(i);
//       exl = GetErrorXlow(i);
//       if (fsum < 0)
//          ey = GetErrorYhigh(i);
//       else
//          ey = GetErrorYlow(i);
//       if (exl < 0) exl = 0;
//       if (exh < 0) exh = 0;
//       if (ey < 0)  ey  = 0;
//       if (exh > 0 || exl > 0) {
//          //"Effective Variance" method introduced by Anna Kreshuk
//          //a copy of the algorithm in GraphFitChisquare from TFitter
//          eux = 0.5 * (exl + exh) * func->Derivative(x[0]);
//       } else
//          eux = 0.;
//       eu = ey * ey + eux * eux;
//       if (eu <= 0) eu = 1;
//       chi2 += fsum * fsum / eu;
//    }
//    return chi2;
// }


//______________________________________________________________________________
Bool_t TGraph::CompareArg(const TGraph* gr, Int_t left, Int_t right)
{
   // Return kTRUE if point number "left"'s argument (angle with respect to positive
   // x-axis) is bigger than that of point number "right". Can be used by Sort.

   Double_t xl, yl, xr, yr;
   gr->GetPoint(left, xl, yl);
   gr->GetPoint(right, xr, yr);
   return (TMath::ATan2(yl, xl) > TMath::ATan2(yr, xr));
}


//______________________________________________________________________________
Bool_t TGraph::CompareX(const TGraph* gr, Int_t left, Int_t right)
{
   // Return kTRUE if fX[left] > fX[right]. Can be used by Sort.

   return gr->fX[left] > gr->fX[right];
}


//______________________________________________________________________________
Bool_t TGraph::CompareY(const TGraph* gr, Int_t left, Int_t right)
{
   // Return kTRUE if fY[left] > fY[right]. Can be used by Sort.

   return gr->fY[left] > gr->fY[right];
}


//______________________________________________________________________________
Bool_t TGraph::CompareRadius(const TGraph* gr, Int_t left, Int_t right)
{
   // Return kTRUE if point number "left"'s distance to origin is bigger than
   // that of point number "right". Can be used by Sort.

   return gr->fX[left] * gr->fX[left] + gr->fY[left] * gr->fY[left]
          > gr->fX[right] * gr->fX[right] + gr->fY[right] * gr->fY[right];
}


//______________________________________________________________________________
void TGraph::ComputeRange(Double_t &xmin, Double_t &ymin, Double_t &xmax, Double_t &ymax) const
{
   // Compute the x/y range of the points in this graph
   if (fNpoints <= 0) {
      xmin = xmax = ymin = ymax = 0;
      return;
   }
   xmin = xmax = fX[0];
   ymin = ymax = fY[0];
   for (Int_t i = 1; i < fNpoints; i++) {
      if (fX[i] < xmin) xmin = fX[i];
      if (fX[i] > xmax) xmax = fX[i];
      if (fY[i] < ymin) ymin = fY[i];
      if (fY[i] > ymax) ymax = fY[i];
   }
}


//______________________________________________________________________________
void TGraph::CopyAndRelease(Double_t **newarrays, Int_t ibegin, Int_t iend,
                            Int_t obegin)
{
   // Copy points from fX and fY to arrays[0] and arrays[1]
   // or to fX and fY if arrays == 0 and ibegin != iend.
   // If newarrays is non null, replace fX, fY with pointers from newarrays[0,1].
   // Delete newarrays, old fX and fY

   CopyPoints(newarrays, ibegin, iend, obegin);
   if (newarrays) {
      delete[] fX;
      fX = newarrays[0];
      delete[] fY;
      fY = newarrays[1];
      delete[] newarrays;
   }
}


//______________________________________________________________________________
Bool_t TGraph::CopyPoints(Double_t **arrays, Int_t ibegin, Int_t iend,
                          Int_t obegin)
{
   // Copy points from fX and fY to arrays[0] and arrays[1]
   // or to fX and fY if arrays == 0 and ibegin != iend.

   if (ibegin < 0 || iend <= ibegin || obegin < 0) { // Error;
      return kFALSE;
   }
   if (!arrays && ibegin == obegin) { // No copying is needed
      return kFALSE;
   }
   Int_t n = (iend - ibegin) * sizeof(Double_t);
   if (arrays) {
      memmove(&arrays[0][obegin], &fX[ibegin], n);
      memmove(&arrays[1][obegin], &fY[ibegin], n);
   } else {
      memmove(&fX[obegin], &fX[ibegin], n);
      memmove(&fY[obegin], &fY[ibegin], n);
   }
   return kTRUE;
}


//______________________________________________________________________________
Bool_t TGraph::CtorAllocate()
{
   // In constructors set fNpoints than call this method.
   // Return kFALSE if the graph will contain no points.
   //Note: This function should be called only from the constructor
   // since it does not delete previously existing arrays

   fHistogram = 0;
   fMaximum = -1111;
   fMinimum = -1111;
   SetBit(kClipFrame);
   fFunctions = new TList;
   if (fNpoints <= 0) {
      fNpoints = 0;
      fMaxSize   = 0;
      fX         = 0;
      fY         = 0;
      return kFALSE;
   } else {
      fMaxSize   = fNpoints;
      fX = new Double_t[fMaxSize];
      fY = new Double_t[fMaxSize];
   }
   return kTRUE;
}


//______________________________________________________________________________
void TGraph::Draw(Option_t *option)
{
   /* Begin_Html
   Draw this graph with its current attributes.
   <p>
   The options to draw a graph are described in
   <a href="http://root.cern.ch/root/html/TGraphPainter.html">TGraphPainter</a>
   class.
   End_Html */

   TString opt = option;
   opt.ToLower();

   if (opt.Contains("same")) {
      opt.ReplaceAll("same", "");
   }

   // in case of option *, set marker style to 3 (star) and replace
   // * option by option P.
   Ssiz_t pos;
   if ((pos = opt.Index("*")) != kNPOS) {
      SetMarkerStyle(3);
      opt.Replace(pos, 1, "p");
   }

   // If no option is specified, it is defined as "alp" in case there
   // no current pad or if the current pad as no axis defined.
   if (!strlen(option)) {
      if (gPad) {
         if (!gPad->GetListOfPrimitives()->FindObject("TFrame")) opt = "alp";
      } else {
         opt = "alp";
      }
   }

   if (gPad) {
      if (!gPad->IsEditable()) gROOT->MakeDefCanvas();
      if (opt.Contains("a")) gPad->Clear();
   }

   AppendPad(opt);
}


//______________________________________________________________________________
Int_t TGraph::DistancetoPrimitive(Int_t px, Int_t py)
{
   // Compute distance from point px,py to a graph.
   //
   //  Compute the closest distance of approach from point px,py to this line.
   //  The distance is computed in pixels units.

   TVirtualGraphPainter *painter = TVirtualGraphPainter::GetPainter();
   if (painter) return painter->DistancetoPrimitiveHelper(this, px, py);
   else return 0;
}


//______________________________________________________________________________
void TGraph::DrawGraph(Int_t n, const Int_t *x, const Int_t *y, Option_t *option)
{
   // Draw this graph with new attributes.

   TGraph *newgraph = new TGraph(n, x, y);
   TAttLine::Copy(*newgraph);
   TAttFill::Copy(*newgraph);
   TAttMarker::Copy(*newgraph);
   newgraph->SetBit(kCanDelete);
   newgraph->AppendPad(option);
}


//______________________________________________________________________________
void TGraph::DrawGraph(Int_t n, const Float_t *x, const Float_t *y, Option_t *option)
{
   // Draw this graph with new attributes.

   TGraph *newgraph = new TGraph(n, x, y);
   TAttLine::Copy(*newgraph);
   TAttFill::Copy(*newgraph);
   TAttMarker::Copy(*newgraph);
   newgraph->SetBit(kCanDelete);
   newgraph->AppendPad(option);
}


//______________________________________________________________________________
void TGraph::DrawGraph(Int_t n, const Double_t *x, const Double_t *y, Option_t *option)
{
   // Draw this graph with new attributes.

   const Double_t *xx = x;
   const Double_t *yy = y;
   if (!xx) xx = fX;
   if (!yy) yy = fY;
   TGraph *newgraph = new TGraph(n, xx, yy);
   TAttLine::Copy(*newgraph);
   TAttFill::Copy(*newgraph);
   TAttMarker::Copy(*newgraph);
   newgraph->SetBit(kCanDelete);
   newgraph->AppendPad(option);
}


//______________________________________________________________________________
void TGraph::DrawPanel()
{
   // Display a panel with all graph drawing options.

   TVirtualGraphPainter *painter = TVirtualGraphPainter::GetPainter();
   if (painter) painter->DrawPanelHelper(this);
}


//______________________________________________________________________________
Double_t TGraph::Eval(Double_t x, TSpline *spline, Option_t *option) const
{
   // Interpolate points in this graph at x using a TSpline
   //  -if spline==0 and option="" a linear interpolation between the two points
   //   close to x is computed. If x is outside the graph range, a linear
   //   extrapolation is computed.
   //  -if spline==0 and option="S" a TSpline3 object is created using this graph
   //   and the interpolated value from the spline is returned.
   //   the internally created spline is deleted on return.
   //  -if spline is specified, it is used to return the interpolated value.


   if (!spline) {

      if (fNpoints == 0) return 0;
      if (fNpoints == 1) return fY[0];


      TString opt = option;
      opt.ToLower();
      if (opt.Contains("s")) {

         // points must be sorted before using a TSpline
         std::vector<Double_t> xsort(fNpoints);
         std::vector<Double_t> ysort(fNpoints);
         std::vector<Int_t> indxsort(fNpoints);
         TMath::Sort(fNpoints, fX, &indxsort[0], false);
         for (Int_t i = 0; i < fNpoints; ++i) {
            xsort[i] = fX[ indxsort[i] ];
            ysort[i] = fY[ indxsort[i] ];
         }

         // spline interpolation creating a new spline
         TSpline3 *s = new TSpline3("", &xsort[0], &ysort[0], fNpoints);
         Double_t result = s->Eval(x);
         delete s;
         return result;
      }
      //linear interpolation
      //In case x is < fX[0] or > fX[fNpoints-1] return the extrapolated point

      //find points in graph around x assuming points are not sorted
      // (if point are sorted could use binary search)

      // find neighbours simply looping  all points
      // and find also the 2 adjacent points: (low2 < low < x < up < up2 )
      // needed in case x is outside the graph ascissa interval
      Int_t low  = -1;
      Int_t up  = -1;
      Int_t low2 = -1;
      Int_t up2 = -1;

      for (Int_t i = 0; i < fNpoints; ++i) {
         if (fX[i] < x) {
            if (low == -1 || fX[i] > fX[low])  {
               low2 = low;
               low = i;
            } else if (low2 == -1) low2 = i;
         } else if (fX[i] > x) {
            if (up  == -1 || fX[i] < fX[up])  {
               up2 = up;
               up = i;
            } else if (up2 == -1) up2 = i;
         } else // case x == fX[i]
            return fY[i]; // no interpolation needed
      }

      // treat cases when x is outside graph min max abscissa
      if (up == -1)  {
         up  = low;
         low = low2;
      }
      if (low == -1) {
         low = up;
         up  = up2;
      }

      assert(low != -1 && up != -1);

      if (fX[low] == fX[up]) return fY[low];
      Double_t yn = fY[up] + (x - fX[up]) * (fY[low] - fY[up]) / (fX[low] - fX[up]);
      return yn;
   } else {
      //spline interpolation using the input spline
      return spline->Eval(x);
   }
}


//______________________________________________________________________________
void TGraph::ExecuteEvent(Int_t event, Int_t px, Int_t py)
{
   // Execute action corresponding to one event.
   //
   //  This member function is called when a graph is clicked with the locator
   //
   //  If Left button clicked on one of the line end points, this point
   //     follows the cursor until button is released.
   //
   //  if Middle button clicked, the line is moved parallel to itself
   //     until the button is released.

   TVirtualGraphPainter *painter = TVirtualGraphPainter::GetPainter();
   if (painter) painter->ExecuteEventHelper(this, event, px, py);
}


//______________________________________________________________________________
void TGraph::Expand(Int_t newsize)
{
   // If array sizes <= newsize, expand storage to 2*newsize.

   Double_t **ps = ExpandAndCopy(newsize, fNpoints);
   CopyAndRelease(ps, 0, 0, 0);
}


//______________________________________________________________________________
void TGraph::Expand(Int_t newsize, Int_t step)
{
   // If graph capacity is less than newsize points then make array sizes
   // equal to least multiple of step to contain newsize points.
   // Returns kTRUE if size was altered

   if (newsize <= fMaxSize) {
      return;
   }
   Double_t **ps = Allocate(step * (newsize / step + (newsize % step ? 1 : 0)));
   CopyAndRelease(ps, 0, fNpoints, 0);
}


//______________________________________________________________________________
Double_t **TGraph::ExpandAndCopy(Int_t size, Int_t iend)
{
   // if size > fMaxSize allocate new arrays of 2*size points
   //  and copy oend first points.
   // Return pointer to new arrays.

   if (size <= fMaxSize) {
      return 0;
   }
   Double_t **newarrays = Allocate(2 * size);
   CopyPoints(newarrays, 0, iend, 0);
   return newarrays;
}


//______________________________________________________________________________
void TGraph::FillZero(Int_t begin, Int_t end, Bool_t)
{
   // Set zero values for point arrays in the range [begin, end)
   // Should be redefined in descendant classes

   memset(fX + begin, 0, (end - begin)*sizeof(Double_t));
   memset(fY + begin, 0, (end - begin)*sizeof(Double_t));
}


//______________________________________________________________________________
TObject *TGraph::FindObject(const char *name) const
{
   // Search object named name in the list of functions

   if (fFunctions) return fFunctions->FindObject(name);
   return 0;
}


//______________________________________________________________________________
TObject *TGraph::FindObject(const TObject *obj) const
{
   // Search object obj in the list of functions

   if (fFunctions) return fFunctions->FindObject(obj);
   return 0;
}


//______________________________________________________________________________
TFitResultPtr TGraph::Fit(const char *fname, Option_t *option, Option_t *, Axis_t xmin, Axis_t xmax)
{
   // Fit this graph with function with name fname.
   //
   //  interface to TGraph::Fit(TF1 *f1...
   //
   //      fname is the name of an already predefined function created by TF1 or TF2
   //      Predefined functions such as gaus, expo and poln are automatically
   //      created by ROOT.
   //      fname can also be a formula, accepted by the linear fitter (linear parts divided
   //      by "++" sign), for example "x++sin(x)" for fitting "[0]*x+[1]*sin(x)"

   char *linear;
   linear = (char*) strstr(fname, "++");
   TF1 *f1 = 0;
   if (linear)
      f1 = new TF1(fname, fname, xmin, xmax);
   else {
      f1 = (TF1*)gROOT->GetFunction(fname);
      if (!f1) {
         Printf("Unknown function: %s", fname);
         return -1;
      }
   }
   return Fit(f1, option, "", xmin, xmax);
}


//______________________________________________________________________________
TFitResultPtr TGraph::Fit(TF1 *f1, Option_t *option, Option_t *goption, Axis_t rxmin, Axis_t rxmax)
{
   // Fit this graph with function f1.
   //
   //   f1 is an already predefined function created by TF1.
   //   Predefined functions such as gaus, expo and poln are automatically
   //   created by ROOT.
   //
   //   The list of fit options is given in parameter option.
   //      option = "W" Set all weights to 1; ignore error bars
   //             = "U" Use a User specified fitting algorithm (via SetFCN)
   //             = "Q" Quiet mode (minimum printing)
   //             = "V" Verbose mode (default is between Q and V)
   //             = "E"  Perform better Errors estimation using Minos technique
   //             = "B"  User defined parameter settings are used for predefined functions
   //                    like "gaus", "expo", "poln", "landau".
   //                    Use this option when you want to fix one or more parameters for these functions.
   //             = "M"  More. Improve fit results.
   //                    It uses the IMPROVE command of TMinuit (see TMinuit::mnimpr)
   //                    This algorithm attempts to improve the found local minimum by
   //                    searching for a better one.
   //             = "R" Use the Range specified in the function range
   //             = "N" Do not store the graphics function, do not draw
   //             = "0" Do not plot the result of the fit. By default the fitted function
   //                   is drawn unless the option "N" above is specified.
   //             = "+" Add this new fitted function to the list of fitted functions
   //                   (by default, any previous function is deleted)
   //             = "C" In case of linear fitting, do not calculate the chisquare
   //                    (saves time)
   //             = "F" If fitting a polN, use the minuit fitter
   //             = "EX0" When fitting a TGraphErrors or TGraphAsymErrors do not consider errors in the coordinate
   //             = "ROB" In case of linear fitting, compute the LTS regression
   //                     coefficients (robust (resistant) regression), using
   //                     the default fraction of good points
   //               "ROB=0.x" - compute the LTS regression coefficients, using
   //                           0.x as a fraction of good points
   //             = "S"  The result of the fit is returned in the TFitResultPtr
   //                     (see below Access to the Fit Result)
   //
   //   When the fit is drawn (by default), the parameter goption may be used
   //   to specify a list of graphics options. See TGraphPainter for a complete
   //   list of these options.
   //
   //   In order to use the Range option, one must first create a function
   //   with the expression to be fitted. For example, if your graph
   //   has a defined range between -4 and 4 and you want to fit a gaussian
   //   only in the interval 1 to 3, you can do:
   //        TF1 *f1 = new TF1("f1","gaus",1,3);
   //        graph->Fit("f1","R");
   //
   //
   // Who is calling this function:
   //
   //   Note that this function is called when calling TGraphErrors::Fit
   //   or TGraphAsymmErrors::Fit ot TGraphBentErrors::Fit
   //   See the discussion below on error calulation.
   //
   // Linear fitting:
   // ===============
   //
   //   When the fitting function is linear (contains the "++" sign) or the fitting
   //   function is a polynomial, a linear fitter is initialised.
   //   To create a linear function, use the following syntax: linear parts
   //   separated by "++" sign.
   //   Example: to fit the parameters of "[0]*x + [1]*sin(x)", create a
   //    TF1 *f1=new TF1("f1", "x++sin(x)", xmin, xmax);
   //   For such a TF1 you don't have to set the initial conditions.
   //   Going via the linear fitter for functions, linear in parameters, gives a
   //   considerable advantage in speed.
   //
   // Setting initial conditions:
   // ===========================
   //
   //   Parameters must be initialized before invoking the Fit function.
   //   The setting of the parameter initial values is automatic for the
   //   predefined functions : poln, expo, gaus, landau. One can however disable
   //   this automatic computation by specifying the option "B".
   //   You can specify boundary limits for some or all parameters via
   //        f1->SetParLimits(p_number, parmin, parmax);
   //   If parmin>=parmax, the parameter is fixed
   //   Note that you are not forced to fix the limits for all parameters.
   //   For example, if you fit a function with 6 parameters, you can do:
   //     func->SetParameters(0,3.1,1.e-6,0.1,-8,100);
   //     func->SetParLimits(4,-10,-4);
   //     func->SetParLimits(5, 1,1);
   //   With this setup, parameters 0->3 can vary freely.
   //   Parameter 4 has boundaries [-10,-4] with initial value -8.
   //   Parameter 5 is fixed to 100.
   //
   // Fit range:
   // ==========
   //
   //   The fit range can be specified in two ways:
   //     - specify rxmax > rxmin (default is rxmin=rxmax=0)
   //     - specify the option "R". In this case, the function will be taken
   //       instead of the full graph range.
   //
   // Changing the fitting function:
   // ==============================
   //
   //   By default a chi2 fitting function is used for fitting a TGraph.
   //   The function is implemented in FitUtil::EvaluateChi2.
   //   In case of TGraphErrors an effective chi2 is used (see below TGraphErrors fit)
   //   To specify a User defined fitting function, specify option "U" and
   //   call the following functions:
   //     TVirtualFitter::Fitter(mygraph)->SetFCN(MyFittingFunction)
   //   where MyFittingFunction is of type:
   //   extern void MyFittingFunction(Int_t &npar, Double_t *gin, Double_t &f,
   //                                 Double_t *u, Int_t flag);
   //
   //
   // TGraphErrors fit:
   // =================
   //
   //   In case of a TGraphErrors object, when x errors are present, the error along x,
   //   is projected along the y-direction by calculating the function at the points x-exlow and
   //   x+exhigh. The chisquare is then computed as the sum of the quantity below at each point:
   //
   // Begin_Latex
   // #frac{(y-f(x))^{2}}{ey^{2}+(#frac{1}{2}(exl+exh)f'(x))^{2}}
   // End_Latex
   //
   //   where x and y are the point coordinates, and f'(x) is the derivative of the
   //   function f(x).
   //
   //   In case the function lies below (above) the data point, ey is ey_low (ey_high).
   //
   //   thanks to Andy Haas (haas@yahoo.com) for adding the case with TGraphAsymmErrors
   //             University of Washington
   //
   //   The approach used to approximate the uncertainty in y because of the
   //   errors in x is to make it equal the error in x times the slope of the line.
   //   The improvement, compared to the first method (f(x+ exhigh) - f(x-exlow))/2
   //   is of (error of x)**2 order. This approach is called "effective variance method".
   //   This improvement has been made in version 4.00/08 by Anna Kreshuk.
   //   The implementation is provided in the function FitUtil::EvaluateChi2Effective
   //
   // NOTE:
   //   1) By using the "effective variance" method a simple linear regression
   //      becomes a non-linear case, which takes several iterations
   //      instead of 0 as in the linear case.
   //
   //   2) The effective variance technique assumes that there is no correlation
   //      between the x and y coordinate.
   //
   //   3) The standard chi2 (least square) method without error in the coordinates (x) can
   //       be forced by using option "EX0"
   //
   //   4)  The linear fitter doesn't take into account the errors in x. When fitting a
   //       TGraphErrors with a linear functions the errors in x willnot be considere.
   //        If errors in x are important, go through minuit (use option "F" for polynomial fitting).
   //
   //   5) When fitting a TGraph (i.e. no errors associated with each point),
   //   a correction is applied to the errors on the parameters with the following
   //   formula:
   //      errorp *= sqrt(chisquare/(ndf-1))
   //
   //   Access to the fit result
   //   ========================
   //  The function returns a TFitResultPtr which can hold a  pointer to a TFitResult object.
   //  By default the TFitResultPtr contains only the status of the fit which is return by an
   //  automatic conversion of the TFitResultPtr to an integer. One can write in this case
   //  directly:
   //  Int_t fitStatus =  h->Fit(myFunc)
   //
   //  If the option "S" is instead used, TFitResultPtr contains the TFitResult and behaves
   //  as a smart pointer to it. For example one can do:
   //  TFitResultPtr r = h->Fit(myFunc,"S");
   //  TMatrixDSym cov = r->GetCovarianceMatrix();  //  to access the covariance matrix
   //  Double_t chi2   = r->Chi2(); // to retrieve the fit chi2
   //  Double_t par0   = r->Value(0); // retrieve the value for the parameter 0
   //  Double_t err0   = r->ParError(0); // retrieve the error for the parameter 0
   //  r->Print("V");     // print full information of fit including covariance matrix
   //  r->Write();        // store the result in a file
   //
   //  The fit parameters, error and chi2 (but not covariance matrix) can be retrieved also
   //  from the fitted function.
   //  If the histogram is made persistent, the list of
   //  associated functions is also persistent. Given a pointer (see above)
   //  to an associated function myfunc, one can retrieve the function/fit
   //  parameters with calls such as:
   //    Double_t chi2 = myfunc->GetChisquare();
   //    Double_t par0 = myfunc->GetParameter(0); //value of 1st parameter
   //    Double_t err0 = myfunc->GetParError(0);  //error on first parameter
   //
   //
   //  Access to the fit status
   //  =====================
   //  The status of the fit can be obtained converting the TFitResultPtr to an integer
   //  indipendently if the fit option "S" is used or not:
   //  TFitResultPtr r = h->Fit(myFunc,opt);
   //  Int_t fitStatus = r;
   //
   //  The fitStatus is 0 if the fit is OK (i.e. no error occurred).
   //  The value of the fit status code is negative in case of an error not connected with the
   //  minimization procedure, for example when a wrong function is used.
   //  Otherwise the return value is the one returned from the minimization procedure.
   //  When TMinuit (default case) or Minuit2 are used as minimizer the status returned is :
   //  fitStatus =  migradResult + 10*minosResult + 100*hesseResult + 1000*improveResult.
   //  TMinuit will return 0 (for migrad, minos, hesse or improve) in case of success and 4 in
   //  case of error (see the documentation of TMinuit::mnexcm). So for example, for an error
   //  only in Minos but not in Migrad a fitStatus of 40 will be returned.
   //  Minuit2 will return also 0 in case of success and different values in migrad, minos or
   //  hesse depending on the error.   See in this case the documentation of
   //  Minuit2Minimizer::Minimize for the migradResult, Minuit2Minimizer::GetMinosError for the
   //  minosResult and Minuit2Minimizer::Hesse for the hesseResult.
   //  If other minimizers are used see their specific documentation for the status code
   //  returned. For example in the case of Fumili, for the status returned see TFumili::Minimize.
   //
   // Associated functions:
   // =====================
   //
   //   One or more object (typically a TF1*) can be added to the list
   //   of functions (fFunctions) associated with each graph.
   //   When TGraph::Fit is invoked, the fitted function is added to this list.
   //   Given a graph gr, one can retrieve an associated function
   //   with:  TF1 *myfunc = gr->GetFunction("myfunc");
   //
   //   If the graph is made persistent, the list of associated functions is also
   //   persistent. Given a pointer (see above) to an associated function myfunc,
   //   one can retrieve the function/fit parameters with calls such as:
   //     Double_t chi2 = myfunc->GetChisquare();
   //     Double_t par0 = myfunc->GetParameter(0); //value of 1st parameter
   //     Double_t err0 = myfunc->GetParError(0);  //error on first parameter
   //
   // Fit Statistics
   // ==============
   //
   //   You can change the statistics box to display the fit parameters with
   //   the TStyle::SetOptFit(mode) method. This mode has four digits.
   //   mode = pcev  (default = 0111)
   //     v = 1;  print name/values of parameters
   //     e = 1;  print errors (if e=1, v must be 1)
   //     c = 1;  print Chisquare/Number of degress of freedom
   //     p = 1;  print Probability
   //
   //   For example: gStyle->SetOptFit(1011);
   //   prints the fit probability, parameter names/values, and errors.
   //   You can change the position of the statistics box with these lines
   //   (where g is a pointer to the TGraph):
   //
   //   Root > TPaveStats *st = (TPaveStats*)g->GetListOfFunctions()->FindObject("stats")
   //   Root > st->SetX1NDC(newx1); //new x start position
   //   Root > st->SetX2NDC(newx2); //new x end position
   //

   Foption_t fitOption;
   ROOT::Fit::FitOptionsMake(option, fitOption);
   // create range and minimizer options with default values
   ROOT::Fit::DataRange range(rxmin, rxmax);
   ROOT::Math::MinimizerOptions minOption;
   return ROOT::Fit::FitObject(this, f1 , fitOption , minOption, goption, range);
}


//______________________________________________________________________________
void TGraph::FitPanel()
{
   // Display a GUI panel with all graph fit options.
   //
   //   See class TFitEditor for example

   if (!gPad)
      gROOT->MakeDefCanvas();

   if (!gPad) {
      Error("FitPanel", "Unable to create a default canvas");
      return;
   }

   // use plugin manager to create instance of TFitEditor
   TPluginHandler *handler = gROOT->GetPluginManager()->FindHandler("TFitEditor");
   if (handler && handler->LoadPlugin() != -1) {
      if (handler->ExecPlugin(2, gPad, this) == 0)
         Error("FitPanel", "Unable to crate the FitPanel");
   } else
      Error("FitPanel", "Unable to find the FitPanel plug-in");
}


//______________________________________________________________________________
Double_t TGraph::GetCorrelationFactor() const
{
   // Return graph correlation factor

   Double_t rms1 = GetRMS(1);
   if (rms1 == 0) return 0;
   Double_t rms2 = GetRMS(2);
   if (rms2 == 0) return 0;
   return GetCovariance() / rms1 / rms2;
}


//______________________________________________________________________________
Double_t TGraph::GetCovariance() const
{
   // Return covariance of vectors x,y

   if (fNpoints <= 0) return 0;
   Double_t sum = fNpoints, sumx = 0, sumy = 0, sumxy = 0;

   for (Int_t i = 0; i < fNpoints; i++) {
      sumx  += fX[i];
      sumy  += fY[i];
      sumxy += fX[i] * fY[i];
   }
   return sumxy / sum - sumx / sum * sumy / sum;
}


//______________________________________________________________________________
Double_t TGraph::GetMean(Int_t axis) const
{
   // Return mean value of X (axis=1)  or Y (axis=2)

   if (axis < 1 || axis > 2) return 0;
   if (fNpoints <= 0) return 0;
   Double_t sumx = 0;
   for (Int_t i = 0; i < fNpoints; i++) {
      if (axis == 1) sumx += fX[i];
      else           sumx += fY[i];
   }
   return sumx / fNpoints;
}


//______________________________________________________________________________
Double_t TGraph::GetRMS(Int_t axis) const
{
   // Return RMS of X (axis=1)  or Y (axis=2)

   if (axis < 1 || axis > 2) return 0;
   if (fNpoints <= 0) return 0;
   Double_t sumx = 0, sumx2 = 0;
   for (Int_t i = 0; i < fNpoints; i++) {
      if (axis == 1) {
         sumx += fX[i];
         sumx2 += fX[i] * fX[i];
      } else           {
         sumx += fY[i];
         sumx2 += fY[i] * fY[i];
      }
   }
   Double_t x = sumx / fNpoints;
   Double_t rms2 = TMath::Abs(sumx2 / fNpoints - x * x);
   return TMath::Sqrt(rms2);
}


//______________________________________________________________________________
Double_t TGraph::GetErrorX(Int_t) const
{
   // This function is called by GraphFitChisquare.
   // It always returns a negative value. Real implementation in TGraphErrors

   return -1;
}


//______________________________________________________________________________
Double_t TGraph::GetErrorY(Int_t) const
{
   // This function is called by GraphFitChisquare.
   // It always returns a negative value. Real implementation in TGraphErrors

   return -1;
}


//______________________________________________________________________________
Double_t TGraph::GetErrorXhigh(Int_t) const
{
   // This function is called by GraphFitChisquare.
   // It always returns a negative value. Real implementation in TGraphErrors
   // and TGraphAsymmErrors

   return -1;
}


//______________________________________________________________________________
Double_t TGraph::GetErrorXlow(Int_t) const
{
   // This function is called by GraphFitChisquare.
   // It always returns a negative value. Real implementation in TGraphErrors
   // and TGraphAsymmErrors

   return -1;
}


//______________________________________________________________________________
Double_t TGraph::GetErrorYhigh(Int_t) const
{
   // This function is called by GraphFitChisquare.
   // It always returns a negative value. Real implementation in TGraphErrors
   // and TGraphAsymmErrors

   return -1;
}


//______________________________________________________________________________
Double_t TGraph::GetErrorYlow(Int_t) const
{
   // This function is called by GraphFitChisquare.
   // It always returns a negative value. Real implementation in TGraphErrors
   // and TGraphAsymmErrors

   return -1;
}


//______________________________________________________________________________
TF1 *TGraph::GetFunction(const char *name) const
{
   // Return pointer to function with name.
   //
   // Functions such as TGraph::Fit store the fitted function in the list of
   // functions of this graph.

   if (!fFunctions) return 0;
   return (TF1*)fFunctions->FindObject(name);
}


//______________________________________________________________________________
TH1F *TGraph::GetHistogram() const
{
   // Returns a pointer to the histogram used to draw the axis
   // Takes into account the two following cases.
   //    1- option 'A' was specified in TGraph::Draw. Return fHistogram
   //    2- user had called TPad::DrawFrame. return pointer to hframe histogram

   Double_t rwxmin, rwxmax, rwymin, rwymax, maximum, minimum, dx, dy;
   Double_t uxmin, uxmax;

   ComputeRange(rwxmin, rwymin, rwxmax, rwymax);  //this is redefined in TGraphErrors

   // (if fHistogram exist) && (if the log scale is on) &&
   // (if the computed range minimum is > 0) && (if the fHistogram minimum is zero)
   // then it means fHistogram limits have been computed in linear scale
   // therefore they might be too strict and cut some points. In that case the
   // fHistogram limits should be recomputed ie: the existing fHistogram
   // should not be returned.
   TH1F *historg = 0;
   if (fHistogram) {
      if (gPad && gPad->GetLogx()) {
         if (rwxmin <= 0 || fHistogram->GetXaxis()->GetXmin() != 0) return fHistogram;
      } else if (gPad && gPad->GetLogy()) {
         if (rwymin <= 0 || fHistogram->GetMinimum() != 0) return fHistogram;
      } else {
         return fHistogram;
      }
      historg = fHistogram;
   }

   if (rwxmin == rwxmax) rwxmax += 1.;
   if (rwymin == rwymax) rwymax += 1.;
   dx = 0.1 * (rwxmax - rwxmin);
   dy = 0.1 * (rwymax - rwymin);
   uxmin    = rwxmin - dx;
   uxmax    = rwxmax + dx;
   minimum  = rwymin - dy;
   maximum  = rwymax + dy;
   if (fMinimum != -1111) minimum = fMinimum;
   if (fMaximum != -1111) maximum = fMaximum;

   // the graph is created with at least as many channels as there are points
   // to permit zooming on the full range
   if (uxmin < 0 && rwxmin >= 0) {
      if (gPad && gPad->GetLogx()) uxmin = 0.9 * rwxmin;
      else                 uxmin = 0;
   }
   if (uxmax > 0 && rwxmax <= 0) {
      if (gPad && gPad->GetLogx()) uxmax = 1.1 * rwxmax;
      else                 uxmax = 0;
   }
   if (minimum < 0 && rwymin >= 0) {
      if (gPad && gPad->GetLogy()) minimum = 0.9 * rwymin;
      else                minimum = 0;
   }
   if (minimum <= 0 && gPad && gPad->GetLogy()) minimum = 0.001 * maximum;
   if (uxmin <= 0 && gPad && gPad->GetLogx()) {
      if (uxmax > 1000) uxmin = 1;
      else              uxmin = 0.001 * uxmax;
   }

   rwxmin = uxmin;
   rwxmax = uxmax;
   Int_t npt = 100;
   if (fNpoints > npt) npt = fNpoints;
   const char *gname = GetName();
   if (strlen(gname) == 0) gname = "Graph";
   ((TGraph*)this)->fHistogram = new TH1F(gname, GetTitle(), npt, rwxmin, rwxmax);
   if (!fHistogram) return 0;
   fHistogram->SetMinimum(minimum);
   fHistogram->SetBit(TH1::kNoStats);
   fHistogram->SetMaximum(maximum);
   fHistogram->GetYaxis()->SetLimits(minimum, maximum);
   fHistogram->SetDirectory(0);
   // Restore the axis attributes if needed
   if (historg) {
      fHistogram->GetXaxis()->SetTitle(historg->GetXaxis()->GetTitle());
      fHistogram->GetXaxis()->CenterTitle(historg->GetXaxis()->GetCenterTitle());
      fHistogram->GetXaxis()->RotateTitle(historg->GetXaxis()->GetRotateTitle());
      fHistogram->GetXaxis()->SetNoExponent(historg->GetXaxis()->GetNoExponent());
      fHistogram->GetXaxis()->SetNdivisions(historg->GetXaxis()->GetNdivisions());
      fHistogram->GetXaxis()->SetLabelFont(historg->GetXaxis()->GetLabelFont());
      fHistogram->GetXaxis()->SetLabelOffset(historg->GetXaxis()->GetLabelOffset());
      fHistogram->GetXaxis()->SetLabelSize(historg->GetXaxis()->GetLabelSize());
      fHistogram->GetXaxis()->SetTitleSize(historg->GetXaxis()->GetTitleSize());
      fHistogram->GetXaxis()->SetTitleOffset(historg->GetXaxis()->GetTitleOffset());
      fHistogram->GetXaxis()->SetTitleFont(historg->GetXaxis()->GetTitleFont());

      fHistogram->GetYaxis()->SetTitle(historg->GetYaxis()->GetTitle());
      fHistogram->GetYaxis()->CenterTitle(historg->GetYaxis()->GetCenterTitle());
      fHistogram->GetYaxis()->RotateTitle(historg->GetYaxis()->GetRotateTitle());
      fHistogram->GetYaxis()->SetNoExponent(historg->GetYaxis()->GetNoExponent());
      fHistogram->GetYaxis()->SetNdivisions(historg->GetYaxis()->GetNdivisions());
      fHistogram->GetYaxis()->SetLabelFont(historg->GetYaxis()->GetLabelFont());
      fHistogram->GetYaxis()->SetLabelOffset(historg->GetYaxis()->GetLabelOffset());
      fHistogram->GetYaxis()->SetLabelSize(historg->GetYaxis()->GetLabelSize());
      fHistogram->GetYaxis()->SetTitleSize(historg->GetYaxis()->GetTitleSize());
      fHistogram->GetYaxis()->SetTitleOffset(historg->GetYaxis()->GetTitleOffset());
      fHistogram->GetYaxis()->SetTitleFont(historg->GetYaxis()->GetTitleFont());

      delete historg;
   }
   return fHistogram;
}


//______________________________________________________________________________
Int_t TGraph::GetPoint(Int_t i, Double_t &x, Double_t &y) const
{
   // Get x and y values for point number i.
   // The function returns -1 in case of an invalid request or the point number otherwise

   if (i < 0 || i >= fNpoints) return -1;
   if (!fX || !fY) return -1;
   x = fX[i];
   y = fY[i];
   return i;
}


//______________________________________________________________________________
TAxis *TGraph::GetXaxis() const
{
   // Get x axis of the graph.

   TH1 *h = GetHistogram();
   if (!h) return 0;
   return h->GetXaxis();
}


//______________________________________________________________________________
TAxis *TGraph::GetYaxis() const
{
   // Get y axis of the graph.

   TH1 *h = GetHistogram();
   if (!h) return 0;
   return h->GetYaxis();
}


//______________________________________________________________________________
void TGraph::InitGaus(Double_t xmin, Double_t xmax)
{
   // Compute Initial values of parameters for a gaussian.

   Double_t allcha, sumx, sumx2, x, val, rms, mean;
   Int_t bin;
   const Double_t sqrtpi = 2.506628;

   // Compute mean value and RMS of the graph in the given range
   if (xmax <= xmin) {
      xmin = fX[0];
      xmax = fX[fNpoints-1];
   }
   Int_t np = 0;
   allcha = sumx = sumx2 = 0;
   for (bin = 0; bin < fNpoints; bin++) {
      x       = fX[bin];
      if (x < xmin || x > xmax) continue;
      np++;
      val     = fY[bin];
      sumx   += val * x;
      sumx2  += val * x * x;
      allcha += val;
   }
   if (np == 0 || allcha == 0) return;
   mean = sumx / allcha;
   rms  = TMath::Sqrt(sumx2 / allcha - mean * mean);
   Double_t binwidx = TMath::Abs((xmax - xmin) / np);
   if (rms == 0) rms = 1;
   TVirtualFitter *grFitter = TVirtualFitter::GetFitter();
   TF1 *f1 = (TF1*)grFitter->GetUserFunc();
   f1->SetParameter(0, binwidx * allcha / (sqrtpi * rms));
   f1->SetParameter(1, mean);
   f1->SetParameter(2, rms);
   f1->SetParLimits(2, 0, 10 * rms);
}


//______________________________________________________________________________
void TGraph::InitExpo(Double_t xmin, Double_t xmax)
{
   // Compute Initial values of parameters for an exponential.

   Double_t constant, slope;
   Int_t ifail;
   if (xmax <= xmin) {
      xmin = fX[0];
      xmax = fX[fNpoints-1];
   }
   Int_t nchanx = fNpoints;

   LeastSquareLinearFit(-nchanx, constant, slope, ifail, xmin, xmax);

   TVirtualFitter *grFitter = TVirtualFitter::GetFitter();
   TF1 *f1 = (TF1*)grFitter->GetUserFunc();
   f1->SetParameter(0, constant);
   f1->SetParameter(1, slope);
}


//______________________________________________________________________________
void TGraph::InitPolynom(Double_t xmin, Double_t xmax)
{
   // Compute Initial values of parameters for a polynom.

   Double_t fitpar[25];

   TVirtualFitter *grFitter = TVirtualFitter::GetFitter();
   TF1 *f1 = (TF1*)grFitter->GetUserFunc();
   Int_t npar   = f1->GetNpar();
   if (xmax <= xmin) {
      xmin = fX[0];
      xmax = fX[fNpoints-1];
   }

   LeastSquareFit(npar, fitpar, xmin, xmax);

   for (Int_t i = 0; i < npar; i++) f1->SetParameter(i, fitpar[i]);
}


//______________________________________________________________________________
Int_t TGraph::InsertPoint()
{
   // Insert a new point at the mouse position

   Int_t px = gPad->GetEventX();
   Int_t py = gPad->GetEventY();

   //localize point where to insert
   Int_t ipoint = -2;
   Int_t i, d = 0;
   // start with a small window (in case the mouse is very close to one point)
   for (i = 0; i < fNpoints - 1; i++) {
      d = DistancetoLine(px, py, gPad->XtoPad(fX[i]), gPad->YtoPad(fY[i]), gPad->XtoPad(fX[i+1]), gPad->YtoPad(fY[i+1]));
      if (d < 5) {
         ipoint = i + 1;
         break;
      }
   }
   if (ipoint == -2) {
      //may be we are far from one point, try again with a larger window
      for (i = 0; i < fNpoints - 1; i++) {
         d = DistancetoLine(px, py, gPad->XtoPad(fX[i]), gPad->YtoPad(fY[i]), gPad->XtoPad(fX[i+1]), gPad->YtoPad(fY[i+1]));
         if (d < 10) {
            ipoint = i + 1;
            break;
         }
      }
   }
   if (ipoint == -2) {
      //distinguish between first and last point
      Int_t dpx = px - gPad->XtoAbsPixel(gPad->XtoPad(fX[0]));
      Int_t dpy = py - gPad->YtoAbsPixel(gPad->XtoPad(fY[0]));
      if (dpx * dpx + dpy * dpy < 25) ipoint = 0;
      else                      ipoint = fNpoints;
   }
   Double_t **ps = ExpandAndCopy(fNpoints + 1, ipoint);
   CopyAndRelease(ps, ipoint, fNpoints++, ipoint + 1);

   // To avoid redefenitions in descendant classes
   FillZero(ipoint, ipoint + 1);

   fX[ipoint] = gPad->PadtoX(gPad->AbsPixeltoX(px));
   fY[ipoint] = gPad->PadtoY(gPad->AbsPixeltoY(py));
   gPad->Modified();
   return ipoint;
}

//______________________________________________________________________________
Double_t TGraph::Integral(Int_t first, Int_t last) const
{
   // Integrate the TGraph data within a given (index) range
   // Note that this function computes the area of the polygon enclosed by the points of the TGraph.
   // The polygon segments, which are defined by the points of the TGraph, do not need to form a closed polygon,
   // since the last polygon segment, which closes the polygon, is taken as the line connecting the last TGraph point
   // with the first one. It is clear that the order of the point is essential in defining the polygon.
   // Also note that the segments should not intersect.
   //
   // NB: if last=-1 (default) last is set to the last point.
   //     if (first <0) the first point (0) is taken.
   //
   //Method:
   // There are many ways to calculate the surface of a polygon. It all depends on what kind of data
   // you have to deal with. The most evident solution would be to divide the polygon in triangles and
   // calculate the surface of them. But this can quickly become complicated as you will have to test
   // every segments of every triangles and check if they are intersecting with a current polygon's
   // segment or if it goes outside the polygon. Many calculations that would lead to many problems...
   //      The solution (implemented by R.Brun)
   // Fortunately for us, there is a simple way to solve this problem, as long as the polygon's
   // segments don't intersect.
   // It takes the x coordinate of the current vertex and multiply it by the y coordinate of the next
   // vertex. Then it subtracts from it the result of the y coordinate of the current vertex multiplied
   // by the x coordinate of the next vertex. Then divide the result by 2 to get the surface/area.
   //      Sources
   //      http://forums.wolfram.com/mathgroup/archive/1998/Mar/msg00462.html
   //      http://stackoverflow.com/questions/451426/how-do-i-calculate-the-surface-area-of-a-2d-polygon

   if (first < 0) first = 0;
   if (last < 0) last = fNpoints - 1;
   if (last >= fNpoints) last = fNpoints - 1;
   if (first >= last) return 0;
   Int_t np = last - first + 1;
   Double_t sum = 0.0;
   //for(Int_t i=first;i<=last;i++) {
   //   Int_t j = first + (i-first+1)%np;
   //   sum += TMath::Abs(fX[i]*fY[j]);
   //   sum -= TMath::Abs(fY[i]*fX[j]);
   //}
   for (Int_t i = first; i <= last; i++) {
      Int_t j = first + (i - first + 1) % np;
      sum += (fY[i] + fY[j]) * (fX[j] - fX[i]);
   }
   return 0.5 * TMath::Abs(sum);
}


//______________________________________________________________________________
Int_t TGraph::IsInside(Double_t x, Double_t y) const
{
   // Return 1 if the point (x,y) is inside the polygon defined by
   // the graph vertices 0 otherwise.
   //
   // Algorithm:
   // The loop is executed with the end-point coordinates of a line segment
   // (X1,Y1)-(X2,Y2) and the Y-coordinate of a horizontal line.
   // The counter inter is incremented if the line (X1,Y1)-(X2,Y2) intersects
   // the horizontal line. In this case XINT is set to the X-coordinate of the
   // intersection point. If inter is an odd number, then the point x,y is within
   // the polygon.

   return (Int_t)TMath::IsInside(x, y, fNpoints, fX, fY);
}


//______________________________________________________________________________
void TGraph::LeastSquareFit(Int_t m, Double_t *a, Double_t xmin, Double_t xmax)
{
   // Least squares polynomial fitting without weights.
   //
   //  m     number of parameters
   //  a     array of parameters
   //  first 1st point number to fit (default =0)
   //  last  last point number to fit (default=fNpoints-1)
   //
   //   based on CERNLIB routine LSQ: Translated to C++ by Rene Brun

   const Double_t zero = 0.;
   const Double_t one = 1.;
   const Int_t idim = 20;

   Double_t  b[400]        /* was [20][20] */;
   Int_t i, k, l, ifail;
   Double_t power;
   Double_t da[20], xk, yk;
   Int_t n = fNpoints;
   if (xmax <= xmin) {
      xmin = fX[0];
      xmax = fX[fNpoints-1];
   }

   if (m <= 2) {
      LeastSquareLinearFit(n, a[0], a[1], ifail, xmin, xmax);
      return;
   }
   if (m > idim || m > n) return;
   da[0] = zero;
   for (l = 2; l <= m; ++l) {
      b[l-1]           = zero;
      b[m + l*20 - 21] = zero;
      da[l-1]          = zero;
   }
   Int_t np = 0;
   for (k = 0; k < fNpoints; ++k) {
      xk     = fX[k];
      if (xk < xmin || xk > xmax) continue;
      np++;
      yk     = fY[k];
      power  = one;
      da[0] += yk;
      for (l = 2; l <= m; ++l) {
         power   *= xk;
         b[l-1]  += power;
         da[l-1] += power * yk;
      }
      for (l = 2; l <= m; ++l) {
         power            *= xk;
         b[m + l*20 - 21] += power;
      }
   }
   b[0]  = Double_t(np);
   for (i = 3; i <= m; ++i) {
      for (k = i; k <= m; ++k) {
         b[k - 1 + (i-1)*20 - 21] = b[k + (i-2)*20 - 21];
      }
   }
   H1LeastSquareSeqnd(m, b, idim, ifail, 1, da);

   if (ifail < 0) {
      a[0] = fY[0];
      for (i = 1; i < m; ++i) a[i] = 0;
      return;
   }
   for (i = 0; i < m; ++i) a[i] = da[i];
}


//______________________________________________________________________________
void TGraph::LeastSquareLinearFit(Int_t ndata, Double_t &a0, Double_t &a1, Int_t &ifail, Double_t xmin, Double_t xmax)
{
   // Least square linear fit without weights.
   //
   //  Fit a straight line (a0 + a1*x) to the data in this graph.
   //  ndata:  if ndata<0, fits the logarithm of the graph (used in InitExpo() to set
   //          the initial parameter values for a fit with exponential function.
   //  a0:     constant
   //  a1:     slope
   //  ifail:  return parameter indicating the status of the fit (ifail=0, fit is OK)
   //  xmin, xmax: fitting range
   //
   //  extracted from CERNLIB LLSQ: Translated to C++ by Rene Brun

   Double_t xbar, ybar, x2bar;
   Int_t i;
   Double_t xybar;
   Double_t fn, xk, yk;
   Double_t det;
   if (xmax <= xmin) {
      xmin = fX[0];
      xmax = fX[fNpoints-1];
   }

   ifail = -2;
   xbar  = ybar = x2bar = xybar = 0;
   Int_t np = 0;
   for (i = 0; i < fNpoints; ++i) {
      xk = fX[i];
      if (xk < xmin || xk > xmax) continue;
      np++;
      yk = fY[i];
      if (ndata < 0) {
         if (yk <= 0) yk = 1e-9;
         yk = TMath::Log(yk);
      }
      xbar  += xk;
      ybar  += yk;
      x2bar += xk * xk;
      xybar += xk * yk;
   }
   fn    = Double_t(np);
   det   = fn * x2bar - xbar * xbar;
   ifail = -1;
   if (det <= 0) {
      if (fn > 0) a0 = ybar / fn;
      else        a0 = 0;
      a1 = 0;
      return;
   }
   ifail = 0;
   a0 = (x2bar * ybar - xbar * xybar) / det;
   a1 = (fn * xybar - xbar * ybar) / det;
}


//______________________________________________________________________________
void TGraph::Paint(Option_t *option)
{
   // Draw this graph with its current attributes.

   TVirtualGraphPainter *painter = TVirtualGraphPainter::GetPainter();
   if (painter) painter->PaintHelper(this, option);
}


//______________________________________________________________________________
void TGraph::PaintGraph(Int_t npoints, const Double_t *x, const Double_t *y, Option_t *chopt)
{
   // Draw the (x,y) as a graph.

   TVirtualGraphPainter *painter = TVirtualGraphPainter::GetPainter();
   if (painter) painter->PaintGraph(this, npoints, x, y, chopt);
}


//______________________________________________________________________________
void TGraph::PaintGrapHist(Int_t npoints, const Double_t *x, const Double_t *y, Option_t *chopt)
{
   // Draw the (x,y) as a histogram.

   TVirtualGraphPainter *painter = TVirtualGraphPainter::GetPainter();
   if (painter) painter->PaintGrapHist(this, npoints, x, y, chopt);
}


//______________________________________________________________________________
void TGraph::PaintStats(TF1 *fit)
{
   // Draw the stats

   TVirtualGraphPainter *painter = TVirtualGraphPainter::GetPainter();
   if (painter) painter->PaintStats(this, fit);
}


//______________________________________________________________________________
void TGraph::Print(Option_t *) const
{
   // Print graph values.

   for (Int_t i = 0; i < fNpoints; i++) {
      printf("x[%d]=%g, y[%d]=%g\n", i, fX[i], i, fY[i]);
   }
}


//______________________________________________________________________________
void TGraph::RecursiveRemove(TObject *obj)
{
   // Recursively remove object from the list of functions

   if (fFunctions) {
      if (!fFunctions->TestBit(kInvalidObject)) fFunctions->RecursiveRemove(obj);
   }
   if (fHistogram == obj) fHistogram = 0;
}


//______________________________________________________________________________
Int_t TGraph::RemovePoint()
{
   // Delete point close to the mouse position

   Int_t px = gPad->GetEventX();
   Int_t py = gPad->GetEventY();

   //localize point to be deleted
   Int_t ipoint = -2;
   Int_t i;
   // start with a small window (in case the mouse is very close to one point)
   for (i = 0; i < fNpoints; i++) {
      Int_t dpx = px - gPad->XtoAbsPixel(gPad->XtoPad(fX[i]));
      Int_t dpy = py - gPad->YtoAbsPixel(gPad->YtoPad(fY[i]));
      if (dpx * dpx + dpy * dpy < 100) {
         ipoint = i;
         break;
      }
   }
   return RemovePoint(ipoint);
}


//______________________________________________________________________________
Int_t TGraph::RemovePoint(Int_t ipoint)
{
   // Delete point number ipoint

   if (ipoint < 0) return -1;
   if (ipoint >= fNpoints) return -1;

   Double_t **ps = ShrinkAndCopy(fNpoints - 1, ipoint);
   CopyAndRelease(ps, ipoint + 1, fNpoints--, ipoint);
   if (gPad) gPad->Modified();
   return ipoint;
}


//______________________________________________________________________________
void TGraph::SavePrimitive(ostream &out, Option_t *option /*= ""*/)
{
   // Save primitive as a C++ statement(s) on output stream out

   char quote = '"';
   out << "   " << endl;
   if (gROOT->ClassSaved(TGraph::Class())) {
      out << "   ";
   } else {
      out << "   TGraph *";
   }
   out << "graph = new TGraph(" << fNpoints << ");" << endl;
   out << "   graph->SetName(" << quote << GetName() << quote << ");" << endl;
   out << "   graph->SetTitle(" << quote << GetTitle() << quote << ");" << endl;

   SaveFillAttributes(out, "graph", 0, 1001);
   SaveLineAttributes(out, "graph", 1, 1, 1);
   SaveMarkerAttributes(out, "graph", 1, 1, 1);

   if (fNpoints >= 1) {
      streamsize prec = out.precision();
      out.precision(10);
      for (Int_t i = 0; i < fNpoints; i++) {
         out << "   graph->SetPoint(" << i << "," << fX[i] << "," << fY[i] << ");" << endl;
      }
      out.precision(prec);
   }

   static Int_t frameNumber = 0;
   if (fHistogram) {
      frameNumber++;
      TString hname = fHistogram->GetName();
      hname += frameNumber;
      fHistogram->SetName(Form("Graph_%s", hname.Data()));
      fHistogram->SavePrimitive(out, "nodraw");
      out << "   graph->SetHistogram(" << fHistogram->GetName() << ");" << endl;
      out << "   " << endl;
   }

   // save list of functions
   TIter next(fFunctions);
   TObject *obj;
   while ((obj = next())) {
      obj->SavePrimitive(out, "nodraw");
      if (obj->InheritsFrom("TPaveStats")) {
         out << "   graph->GetListOfFunctions()->Add(ptstats);" << endl;
         out << "   ptstats->SetParent(graph->GetListOfFunctions());" << endl;
      } else {
         out << "   graph->GetListOfFunctions()->Add(" << obj->GetName() << ");" << endl;
      }
   }

   const char *l;
   l = strstr(option, "multigraph");
   if (l) {
      out << "   multigraph->Add(graph," << quote << l + 10 << quote << ");" << endl;
      return;
   }
   l = strstr(option, "th2poly");
   if (l) {
      out << "   " << l + 7 << "->AddBin(graph);" << endl;
      return;
   }
   out << "   graph->Draw(" << quote << option << quote << ");" << endl;
}


//______________________________________________________________________________
void TGraph::Set(Int_t n)
{
   // Set number of points in the graph
   // Existing coordinates are preserved
   // New coordinates above fNpoints are preset to 0.

   if (n < 0) n = 0;
   if (n == fNpoints) return;
   Double_t **ps = Allocate(n);
   CopyAndRelease(ps, 0, TMath::Min(fNpoints, n), 0);
   if (n > fNpoints) {
      FillZero(fNpoints, n, kFALSE);
   }
   fNpoints = n;
}


//______________________________________________________________________________
Bool_t TGraph::GetEditable() const
{
   // Return kTRUE if kNotEditable bit is not set, kFALSE otherwise.

   return TestBit(kNotEditable) ? kFALSE : kTRUE;
}


//______________________________________________________________________________
void TGraph::SetEditable(Bool_t editable)
{
   // if editable=kFALSE, the graph cannot be modified with the mouse
   //  by default a TGraph is editable

   if (editable) ResetBit(kNotEditable);
   else          SetBit(kNotEditable);
}


//______________________________________________________________________________
void TGraph::SetMaximum(Double_t maximum)
{
   // Set the maximum of the graph.

   fMaximum = maximum;
   GetHistogram()->SetMaximum(maximum);
}


//______________________________________________________________________________
void TGraph::SetMinimum(Double_t minimum)
{
   // Set the minimum of the graph.

   fMinimum = minimum;
   GetHistogram()->SetMinimum(minimum);
}


//______________________________________________________________________________
void TGraph::SetPoint(Int_t i, Double_t x, Double_t y)
{
   // Set x and y values for point number i.

   if (i < 0) return;
   if (fHistogram) {
      delete fHistogram;
      fHistogram = 0;
   }
   if (i >= fMaxSize) {
      Double_t **ps = ExpandAndCopy(i + 1, fNpoints);
      CopyAndRelease(ps, 0, 0, 0);
   }
   if (i >= fNpoints) {
      // points above i can be not initialized
      // set zero up to i-th point to avoid redefenition
      // of this method in descendant classes
      FillZero(fNpoints, i + 1);
      fNpoints = i + 1;
   }
   fX[i] = x;
   fY[i] = y;
   if (gPad) gPad->Modified();
}


//______________________________________________________________________________
void TGraph::SetTitle(const char* title)
{
   // Set graph title.

   fTitle = title;
   if (fHistogram) fHistogram->SetTitle(title);
}


//______________________________________________________________________________
Double_t **TGraph::ShrinkAndCopy(Int_t size, Int_t oend)
{
   // if size*2 <= fMaxSize allocate new arrays of size points,
   // copy points [0,oend).
   // Return newarray (passed or new instance if it was zero
   // and allocations are needed)
   if (size * 2 > fMaxSize || !fMaxSize) {
      return 0;
   }
   Double_t **newarrays = Allocate(size);
   CopyPoints(newarrays, 0, oend, 0);
   return newarrays;
}


//______________________________________________________________________________
void TGraph::Sort(Bool_t (*greaterfunc)(const TGraph*, Int_t, Int_t) /*=TGraph::CompareX()*/,
                  Bool_t ascending /*=kTRUE*/, Int_t low /* =0 */, Int_t high /* =-1111 */)
{
   // Sorts the points of this TGraph using in-place quicksort (see e.g. older glibc).
   // To compare two points the function parameter greaterfunc is used (see TGraph::CompareX for an
   // example of such a method, which is also the default comparison function for Sort). After
   // the sort, greaterfunc(this, i, j) will return kTRUE for all i>j if ascending == kTRUE, and
   // kFALSE otherwise.
   //
   // The last two parameters are used for the recursive quick sort, stating the range to be sorted
   //
   // Examples:
   //   // sort points along x axis
   //   graph->Sort();
   //   // sort points along their distance to origin
   //   graph->Sort(&TGraph::CompareRadius);
   //
   //   Bool_t CompareErrors(const TGraph* gr, Int_t i, Int_t j) {
   //     const TGraphErrors* ge=(const TGraphErrors*)gr;
   //     return (ge->GetEY()[i]>ge->GetEY()[j]); }
   //   // sort using the above comparison function, largest errors first
   //   graph->Sort(&CompareErrors, kFALSE);

   if (high == -1111) high = GetN() - 1;
   //  Termination condition
   if (high <= low) return;

   int left, right;
   left = low; // low is the pivot element
   right = high;
   while (left < right) {
      // move left while item < pivot
      while (left <= high && greaterfunc(this, left, low) != ascending)
         left++;
      // move right while item > pivot
      while (right > low && greaterfunc(this, right, low) == ascending)
         right--;
      if (left < right && left < high && right > low)
         SwapPoints(left, right);
   }
   // right is final position for the pivot
   if (right > low)
      SwapPoints(low, right);
   Sort(greaterfunc, ascending, low, right - 1);
   Sort(greaterfunc, ascending, right + 1, high);
}


//______________________________________________________________________________
void TGraph::Streamer(TBuffer &b)
{
   // Stream an object of class TGraph.

   if (b.IsReading()) {
      UInt_t R__s, R__c;
      Version_t R__v = b.ReadVersion(&R__s, &R__c);
      if (R__v > 2) {
         b.ReadClassBuffer(TGraph::Class(), this, R__v, R__s, R__c);
         if (fHistogram) fHistogram->SetDirectory(0);
         TIter next(fFunctions);
         TObject *obj;
         while ((obj = next())) {
            if (obj->InheritsFrom(TF1::Class())) {
               TF1 *f1 = (TF1*)obj;
               f1->SetParent(this);
            }
         }
         fMaxSize = fNpoints;
         return;
      }
      //====process old versions before automatic schema evolution
      TNamed::Streamer(b);
      TAttLine::Streamer(b);
      TAttFill::Streamer(b);
      TAttMarker::Streamer(b);
      b >> fNpoints;
      fMaxSize = fNpoints;
      fX = new Double_t[fNpoints];
      fY = new Double_t[fNpoints];
      if (R__v < 2) {
         Float_t *x = new Float_t[fNpoints];
         Float_t *y = new Float_t[fNpoints];
         b.ReadFastArray(x, fNpoints);
         b.ReadFastArray(y, fNpoints);
         for (Int_t i = 0; i < fNpoints; i++) {
            fX[i] = x[i];
            fY[i] = y[i];
         }
         delete [] y;
         delete [] x;
      } else {
         b.ReadFastArray(fX, fNpoints);
         b.ReadFastArray(fY, fNpoints);
      }
      b >> fFunctions;
      b >> fHistogram;
      if (fHistogram) fHistogram->SetDirectory(0);
      if (R__v < 2) {
         Float_t mi, ma;
         b >> mi;
         b >> ma;
         fMinimum = mi;
         fMaximum = ma;
      } else {
         b >> fMinimum;
         b >> fMaximum;
      }
      b.CheckByteCount(R__s, R__c, TGraph::IsA());
      //====end of old versions

   } else {
      b.WriteClassBuffer(TGraph::Class(), this);
   }
}


//______________________________________________________________________________
void TGraph::SwapPoints(Int_t pos1, Int_t pos2)
{
   // Swap points.

   SwapValues(fX, pos1, pos2);
   SwapValues(fY, pos1, pos2);
}


//______________________________________________________________________________
void TGraph::SwapValues(Double_t* arr, Int_t pos1, Int_t pos2)
{
   // Swap values.

   Double_t tmp = arr[pos1];
   arr[pos1] = arr[pos2];
   arr[pos2] = tmp;
}


//______________________________________________________________________________
void TGraph::UseCurrentStyle()
{
   // Set current style settings in this graph
   // This function is called when either TCanvas::UseCurrentStyle
   // or TROOT::ForceStyle have been invoked.

   if (gStyle->IsReading()) {
      SetFillColor(gStyle->GetHistFillColor());
      SetFillStyle(gStyle->GetHistFillStyle());
      SetLineColor(gStyle->GetHistLineColor());
      SetLineStyle(gStyle->GetHistLineStyle());
      SetLineWidth(gStyle->GetHistLineWidth());
      SetMarkerColor(gStyle->GetMarkerColor());
      SetMarkerStyle(gStyle->GetMarkerStyle());
      SetMarkerSize(gStyle->GetMarkerSize());
   } else {
      gStyle->SetHistFillColor(GetFillColor());
      gStyle->SetHistFillStyle(GetFillStyle());
      gStyle->SetHistLineColor(GetLineColor());
      gStyle->SetHistLineStyle(GetLineStyle());
      gStyle->SetHistLineWidth(GetLineWidth());
      gStyle->SetMarkerColor(GetMarkerColor());
      gStyle->SetMarkerStyle(GetMarkerStyle());
      gStyle->SetMarkerSize(GetMarkerSize());
   }
   if (fHistogram) fHistogram->UseCurrentStyle();

   TIter next(GetListOfFunctions());
   TObject *obj;

   while ((obj = next())) {
      obj->UseCurrentStyle();
   }
}


//______________________________________________________________________________
Int_t TGraph::Merge(TCollection* li)
{
   // Adds all graphs from the collection to this graph.
   // Returns the total number of poins in the result or -1 in case of an error.

   TIter next(li);
   while (TObject* o = next()) {
      TGraph *g = dynamic_cast<TGraph*>(o);
      if (!g) {
         Error("Merge",
               "Cannot merge - an object which doesn't inherit from TGraph found in the list");
         return -1;
      }
      DoMerge(g);
   }
   return GetN();
}
//______________________________________________________________________________
Bool_t TGraph::DoMerge(const TGraph* g)
{
   //  protected function to perform the merge operation of a graph

   Double_t x, y;
   for (Int_t i = 0 ; i < g->GetN(); i++) {
      g->GetPoint(i, x, y);
      SetPoint(GetN(), x, y);
   }
   return kTRUE;
}
//______________________________________________________________________________
void TGraph::Zero(Int_t &k, Double_t AZ, Double_t BZ, Double_t E2, Double_t &X, Double_t &Y
                  , Int_t maxiterations)
{
   // Find zero of a continuous function.
   // This function finds a real zero of the continuous real
   // function Y(X) in a given interval (A,B). See accompanying
   // notes for details of the argument list and calling sequence

   static Double_t a, b, ya, ytest, y1, x1, h;
   static Int_t j1, it, j3, j2;
   Double_t yb, x2;
   yb = 0;

   //       Calculate Y(X) at X=AZ.
   if (k <= 0) {
      a  = AZ;
      b  = BZ;
      X  = a;
      j1 = 1;
      it = 1;
      k  = j1;
      return;
   }

   //       Test whether Y(X) is sufficiently small.

   if (TMath::Abs(Y) <= E2) {
      k = 2;
      return;
   }

   //       Calculate Y(X) at X=BZ.

   if (j1 == 1) {
      ya = Y;
      X  = b;
      j1 = 2;
      return;
   }
   //       Test whether the signs of Y(AZ) and Y(BZ) are different.
   //       if not, begin the binary subdivision.

   if (j1 != 2) goto L100;
   if (ya * Y < 0) goto L120;
   x1 = a;
   y1 = ya;
   j1 = 3;
   h  = b - a;
   j2 = 1;
   x2 = a + 0.5 * h;
   j3 = 1;
   it++;      //*-*-   Check whether (maxiterations) function values have been calculated.
   if (it >= maxiterations) k = j1;
   else                     X = x2;
   return;

   //      Test whether a bracket has been found .
   //      If not,continue the search

L100:
   if (j1 > 3) goto L170;
   if (ya*Y >= 0) {
      if (j3 >= j2) {
         h  = 0.5 * h;
         j2 = 2 * j2;
         a  = x1;
         ya = y1;
         x2 = a + 0.5 * h;
         j3 = 1;
      } else {
         a  = X;
         ya = Y;
         x2 = X + h;
         j3++;
      }
      it++;
      if (it >= maxiterations) k = j1;
      else                     X = x2;
      return;
   }

   //       The first bracket has been found.calculate the next X by the
   //       secant method based on the bracket.

L120:
   b  = X;
   yb = Y;
   j1 = 4;
L130:
   if (TMath::Abs(ya) > TMath::Abs(yb)) {
      x1 = a;
      y1 = ya;
      X  = b;
      Y  = yb;
   } else                                 {
      x1 = b;
      y1 = yb;
      X  = a;
      Y  = ya;
   }

   //       Use the secant method based on the function values y1 and Y.
   //       check that x2 is inside the interval (a,b).

L150:
   x2    = X - Y * (X - x1) / (Y - y1);
   x1    = X;
   y1    = Y;
   ytest = 0.5 * TMath::Min(TMath::Abs(ya), TMath::Abs(yb));
   if ((x2 - a)*(x2 - b) < 0) {
      it++;
      if (it >= maxiterations) k = j1;
      else                     X = x2;
      return;
   }

   //       Calculate the next value of X by bisection . Check whether
   //       the maximum accuracy has been achieved.

L160:
   x2    = 0.5 * (a + b);
   ytest = 0;
   if ((x2 - a)*(x2 - b) >= 0) {
      k = 2;
      return;
   }
   it++;
   if (it >= maxiterations) k = j1;
   else                     X = x2;
   return;


   //       Revise the bracket (a,b).

L170:
   if (j1 != 4) return;
   if (ya * Y < 0) {
      b  = X;
      yb = Y;
   } else          {
      a  = X;
      ya = Y;
   }

   //       Use ytest to decide the method for the next value of X.

   if (ytest <= 0) goto L130;
   if (TMath::Abs(Y) - ytest <= 0) goto L150;
   goto L160;
}
// @(#)root/hist:$Id$
// Author: Rene Brun, Olivier Couet   12/12/94

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#ifndef ROOT_TGraph
#define ROOT_TGraph


//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TGraph                                                               //
//                                                                      //
// Graph graphics class.                                                //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#ifndef ROOT_TNamed
#include "TNamed.h"
#endif
#ifndef ROOT_TAttLine
#include "TAttLine.h"
#endif
#ifndef ROOT_TAttFill
#include "TAttFill.h"
#endif
#ifndef ROOT_TAttMarker
#include "TAttMarker.h"
#endif
#ifndef ROOT_TVectorFfwd
#include "TVectorFfwd.h"
#endif
#ifndef ROOT_TVectorDfwd
#include "TVectorDfwd.h"
#endif

class TBrowser;
class TAxis;
class TH1;
class TH1F;
class TCollection;
class TF1;
class TSpline;

#include "TFitResultPtr.h"

class TGraph : public TNamed, public TAttLine, public TAttFill, public TAttMarker {

protected:

   Int_t              fMaxSize;   //!Current dimension of arrays fX and fY
   Int_t              fNpoints;   //Number of points <= fMaxSize
   Double_t          *fX;         //[fNpoints] array of X points
   Double_t          *fY;         //[fNpoints] array of Y points
   TList             *fFunctions; //Pointer to list of functions (fits and user)
   TH1F              *fHistogram; //Pointer to histogram used for drawing axis
   Double_t           fMinimum;   //Minimum value for plotting along y
   Double_t           fMaximum;   //Maximum value for plotting along y

   static void        SwapValues(Double_t* arr, Int_t pos1, Int_t pos2);
   virtual void       SwapPoints(Int_t pos1, Int_t pos2);

   virtual Double_t **Allocate(Int_t newsize);
   Double_t         **AllocateArrays(Int_t Narrays, Int_t arraySize);
   virtual Bool_t     CopyPoints(Double_t **newarrays, Int_t ibegin, Int_t iend, Int_t obegin);
   virtual void       CopyAndRelease(Double_t **newarrays, Int_t ibegin, Int_t iend, Int_t obegin);
   Bool_t             CtorAllocate();
   Double_t         **ExpandAndCopy(Int_t size, Int_t iend);
   virtual void       FillZero(Int_t begin, Int_t end, Bool_t from_ctor = kTRUE);
   Double_t         **ShrinkAndCopy(Int_t size, Int_t iend);
   virtual Bool_t     DoMerge(const TGraph * g);       

public:
   // TGraph status bits
   enum {
      kClipFrame     = BIT(10),  // clip to the frame boundary
      kNotEditable   = BIT(18)   // bit set if graph is non editable
   };

   TGraph();
   TGraph(Int_t n);
   TGraph(Int_t n, const Int_t *x, const Int_t *y);
   TGraph(Int_t n, const Float_t *x, const Float_t *y);
   TGraph(Int_t n, const Double_t *x, const Double_t *y);
   TGraph(const TGraph &gr);
   TGraph& operator=(const TGraph&);
   TGraph(const TVectorF &vx, const TVectorF &vy);
   TGraph(const TVectorD &vx, const TVectorD &vy);
   TGraph(const TH1 *h);
   TGraph(const TF1 *f, Option_t *option="");
   TGraph(const char *filename, const char *format="%lg %lg", Option_t *option="");
   virtual ~TGraph();

   virtual void          Apply(TF1 *f);
   virtual void          Browse(TBrowser *b);
   virtual Double_t      Chisquare(const TF1 *f1, Option_t *option="") const;
   static Bool_t         CompareArg(const TGraph* gr, Int_t left, Int_t right);
   static Bool_t         CompareX(const TGraph* gr, Int_t left, Int_t right);
   static Bool_t         CompareY(const TGraph* gr, Int_t left, Int_t right);
   static Bool_t         CompareRadius(const TGraph* gr, Int_t left, Int_t right);
   virtual void          ComputeRange(Double_t &xmin, Double_t &ymin, Double_t &xmax, Double_t &ymax) const;
   virtual Int_t         DistancetoPrimitive(Int_t px, Int_t py);
   virtual void          Draw(Option_t *chopt="");
   virtual void          DrawGraph(Int_t n, const Int_t *x, const Int_t *y, Option_t *option="");
   virtual void          DrawGraph(Int_t n, const Float_t *x, const Float_t *y, Option_t *option="");
   virtual void          DrawGraph(Int_t n, const Double_t *x=0, const Double_t *y=0, Option_t *option="");
   virtual void          DrawPanel(); // *MENU*
   virtual Double_t      Eval(Double_t x, TSpline *spline=0, Option_t *option="") const;
   virtual void          ExecuteEvent(Int_t event, Int_t px, Int_t py);
   virtual void          Expand(Int_t newsize);
   virtual void          Expand(Int_t newsize, Int_t step);
   virtual TObject      *FindObject(const char *name) const;
   virtual TObject      *FindObject(const TObject *obj) const;
   virtual TFitResultPtr Fit(const char *formula ,Option_t *option="" ,Option_t *goption="", Axis_t xmin=0, Axis_t xmax=0); // *MENU*
   virtual TFitResultPtr Fit(TF1 *f1 ,Option_t *option="" ,Option_t *goption="", Axis_t xmin=0, Axis_t xmax=0);
   virtual void          FitPanel(); // *MENU*
   Bool_t                GetEditable() const;
   TF1                  *GetFunction(const char *name) const;
   TH1F                 *GetHistogram() const;
   TList                *GetListOfFunctions() const { return fFunctions; }
   virtual Double_t      GetCorrelationFactor() const;
   virtual Double_t      GetCovariance() const;
   virtual Double_t      GetMean(Int_t axis=1) const;
   virtual Double_t      GetRMS(Int_t axis=1) const;
   Int_t                 GetMaxSize() const {return fMaxSize;}
   Int_t                 GetN() const {return fNpoints;}
   virtual Double_t      GetErrorX(Int_t bin) const;
   virtual Double_t      GetErrorY(Int_t bin) const;
   virtual Double_t      GetErrorXhigh(Int_t bin) const;
   virtual Double_t      GetErrorXlow(Int_t bin)  const;
   virtual Double_t      GetErrorYhigh(Int_t bin) const;
   virtual Double_t      GetErrorYlow(Int_t bin)  const;
   Double_t             *GetX()  const {return fX;}
   Double_t             *GetY()  const {return fY;}
   virtual Double_t     *GetEX() const {return 0;}
   virtual Double_t     *GetEY() const {return 0;}
   virtual Double_t     *GetEXhigh() const {return 0;}
   virtual Double_t     *GetEXlow()  const {return 0;}
   virtual Double_t     *GetEYhigh() const {return 0;}
   virtual Double_t     *GetEYlow()  const {return 0;}
   virtual Double_t     *GetEXlowd()  const {return 0;}
   virtual Double_t     *GetEXhighd() const {return 0;}
   virtual Double_t     *GetEYlowd()  const {return 0;}
   virtual Double_t     *GetEYhighd() const {return 0;}
   Double_t              GetMaximum()  const {return fMaximum;}
   Double_t              GetMinimum()  const {return fMinimum;}
   TAxis                *GetXaxis() const ;
   TAxis                *GetYaxis() const ;
   virtual Int_t         GetPoint(Int_t i, Double_t &x, Double_t &y) const;
   
   virtual void          InitExpo(Double_t xmin=0, Double_t xmax=0);
   virtual void          InitGaus(Double_t xmin=0, Double_t xmax=0);
   virtual void          InitPolynom(Double_t xmin=0, Double_t xmax=0);
   virtual Int_t         InsertPoint(); // *MENU*
   virtual Double_t      Integral(Int_t first=0, Int_t last=-1) const;
   virtual Bool_t        IsEditable() const {return !TestBit(kNotEditable);}
   virtual Int_t         IsInside(Double_t x, Double_t y) const;
   virtual void          LeastSquareFit(Int_t m, Double_t *a, Double_t xmin=0, Double_t xmax=0);
   virtual void          LeastSquareLinearFit(Int_t n, Double_t &a0, Double_t &a1, Int_t &ifail, Double_t xmin=0, Double_t xmax=0);
   virtual Int_t         Merge(TCollection* list);
   virtual void          Paint(Option_t *chopt="");
   void                  PaintGraph(Int_t npoints, const Double_t *x, const Double_t *y, Option_t *chopt);
   void                  PaintGrapHist(Int_t npoints, const Double_t *x, const Double_t *y, Option_t *chopt); 
   virtual void          PaintStats(TF1 *fit);
   virtual void          Print(Option_t *chopt="") const;
   virtual void          RecursiveRemove(TObject *obj);
   virtual Int_t         RemovePoint(); // *MENU*
   virtual Int_t         RemovePoint(Int_t ipoint);
   virtual void          SavePrimitive(ostream &out, Option_t *option = "");
   virtual void          SetEditable(Bool_t editable=kTRUE); // *TOGGLE* *GETTER=GetEditable
   virtual void          SetHistogram(TH1F *h) {fHistogram = h;}
   virtual void          SetMaximum(Double_t maximum=-1111); // *MENU*
   virtual void          SetMinimum(Double_t minimum=-1111); // *MENU*
   virtual void          Set(Int_t n);
   virtual void          SetPoint(Int_t i, Double_t x, Double_t y);
   virtual void          SetTitle(const char *title="");    // *MENU*
   virtual void          Sort(Bool_t (*greater)(const TGraph*, Int_t, Int_t)=&TGraph::CompareX,
                              Bool_t ascending=kTRUE, Int_t low=0, Int_t high=-1111);
   virtual void          UseCurrentStyle();
   void                  Zero(Int_t &k,Double_t AZ,Double_t BZ,Double_t E2,Double_t &X,Double_t &Y,Int_t maxiterations);

   ClassDef(TGraph,4)  //Graph graphics class
};

inline Double_t **TGraph::Allocate(Int_t newsize) {
   return AllocateArrays(2, newsize);
}

#endif
// @(#)root/hist:$Id$
// Author: Rene Brun, Olivier Couet   12/12/94

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include <string.h>

#include "Riostream.h"
#include "TROOT.h"
#include "TEnv.h"
#include "TGraph.h"
#include "TGaxis.h"
#include "TH1.h"
#include "TF1.h"
#include "TStyle.h"
#include "TMath.h"
#include "TFrame.h"
#include "TVector.h"
#include "TVectorD.h"
#include "Foption.h"
#include "TRandom.h"
#include "TSpline.h"
#include "TVirtualFitter.h"
#include "TVirtualPad.h"
#include "TVirtualGraphPainter.h"
#include "TBrowser.h"
#include "TClass.h"
#include "TSystem.h"
#include "TPluginManager.h"
#include <stdlib.h>
#include <string>
#include <cassert>

#include "HFitInterface.h"
#include "Fit/DataRange.h"
#include "Math/MinimizerOptions.h"

extern void H1LeastSquareSeqnd(Int_t n, Double_t *a, Int_t idim, Int_t &ifail, Int_t k, Double_t *b);

ClassImp(TGraph)


//______________________________________________________________________________
/* Begin_Html
<center><h2>Graph class</h2></center>
A Graph is a graphics object made of two arrays X and Y with npoints each.
</p>
The TGraph painting is performed thanks to the
<a href="http://root.cern.ch/root/html/TGraphPainter.html">TGraphPainter</a>
class. All details about the various painting options are given in
<a href="http://root.cern.ch/root/html/TGraphPainter.html">this class</a>.
</p>
<i>Note:</i>Unlike histogram or tree (or even TGraph2D), TGraph objects
 are not automatically attached to the current TFile, in order to keep the
 management and size of the TGraph has small as possible.
</p>
The picture below gives an example:
End_Html
Begin_Macro(source)
{
   TCanvas *c1 = new TCanvas("c1","A Simple Graph Example",200,10,700,500);
   Double_t x[100], y[100];
   Int_t n = 20;
   for (Int_t i=0;i<n;i++) {
     x[i] = i*0.1;
     y[i] = 10*sin(x[i]+0.2);
   }
   gr = new TGraph(n,x,y);
   gr->Draw("AC*");
   return c1;
}
End_Macro */


//______________________________________________________________________________
TGraph::TGraph(): TNamed(), TAttLine(), TAttFill(1, 1001), TAttMarker()
{
   // Graph default constructor.

   fNpoints = -1;  //will be reset to 0 in CtorAllocate
   if (!CtorAllocate()) return;
}


//______________________________________________________________________________
TGraph::TGraph(Int_t n)
   : TNamed("Graph", "Graph"), TAttLine(), TAttFill(1, 1001), TAttMarker()
{
   // Constructor with only the number of points set
   // the arrays x and y will be set later

   fNpoints = n;
   if (!CtorAllocate()) return;
   FillZero(0, fNpoints);
}


//______________________________________________________________________________
TGraph::TGraph(Int_t n, const Int_t *x, const Int_t *y)
   : TNamed("Graph", "Graph"), TAttLine(), TAttFill(1, 1001), TAttMarker()
{
   // Graph normal constructor with ints.

   if (!x || !y) {
      fNpoints = 0;
   } else {
      fNpoints = n;
   }
   if (!CtorAllocate()) return;
   for (Int_t i = 0; i < n; i++) {
      fX[i] = (Double_t)x[i];
      fY[i] = (Double_t)y[i];
   }
}


//______________________________________________________________________________
TGraph::TGraph(Int_t n, const Float_t *x, const Float_t *y)
   : TNamed("Graph", "Graph"), TAttLine(), TAttFill(1, 1001), TAttMarker()
{
   // Graph normal constructor with floats.

   if (!x || !y) {
      fNpoints = 0;
   } else {
      fNpoints = n;
   }
   if (!CtorAllocate()) return;
   for (Int_t i = 0; i < n; i++) {
      fX[i] = x[i];
      fY[i] = y[i];
   }
}


//______________________________________________________________________________
TGraph::TGraph(Int_t n, const Double_t *x, const Double_t *y)
   : TNamed("Graph", "Graph"), TAttLine(), TAttFill(1, 1001), TAttMarker()
{
   // Graph normal constructor with doubles.

   if (!x || !y) {
      fNpoints = 0;
   } else {
      fNpoints = n;
   }
   if (!CtorAllocate()) return;
   n = fNpoints * sizeof(Double_t);
   memcpy(fX, x, n);
   memcpy(fY, y, n);
}


//______________________________________________________________________________
TGraph::TGraph(const TGraph &gr)
   : TNamed(gr), TAttLine(gr), TAttFill(gr), TAttMarker(gr)
{
   // Copy constructor for this graph

   fNpoints = gr.fNpoints;
   fMaxSize = gr.fMaxSize;
   if (gr.fFunctions) fFunctions = (TList*)gr.fFunctions->Clone();
   else fFunctions = new TList;
   fHighlights = 0;
   fHistogram = 0;
   fMinimum = gr.fMinimum;
   fMaximum = gr.fMaximum;
   if (!fMaxSize) {
      fX = fY = 0;
      return;
   } else {
      fX = new Double_t[fMaxSize];
      fY = new Double_t[fMaxSize];
   }

   Int_t n = gr.GetN() * sizeof(Double_t);
   memcpy(fX, gr.fX, n);
   memcpy(fY, gr.fY, n);
}


//______________________________________________________________________________
TGraph& TGraph::operator=(const TGraph &gr)
{
   // Equal operator for this graph

   if (this != &gr) {
      TNamed::operator=(gr);
      TAttLine::operator=(gr);
      TAttFill::operator=(gr);
      TAttMarker::operator=(gr);

      fNpoints = gr.fNpoints;
      fMaxSize = gr.fMaxSize;

      // delete list of functions and their contents before copying it
      if (fFunctions) {
         // delete previous lists of functions
         if (!fFunctions->IsEmpty()) {
            fFunctions->SetBit(kInvalidObject);
            // use TList::Remove to take into account the case the same object is
            // added multiple times in the list
            TObject *obj;
            while ((obj  = fFunctions->First())) {
               while (fFunctions->Remove(obj)) { }
               delete obj;
            }
         }
         delete fFunctions;
      }

      if (gr.fFunctions) fFunctions = (TList*)gr.fFunctions->Clone();
      else fFunctions = new TList;

      SafeDelete(fHighlights);

      if (fHistogram) delete fHistogram;
      if (gr.fHistogram) fHistogram = new TH1F(*(gr.fHistogram));
      else fHistogram = 0;

      fMinimum = gr.fMinimum;
      fMaximum = gr.fMaximum;
      if (fX) delete [] fX;
      if (fY) delete [] fY;
      if (!fMaxSize) {
         fX = fY = 0;
         return *this;
      } else {
         fX = new Double_t[fMaxSize];
         fY = new Double_t[fMaxSize];
      }

      Int_t n = gr.GetN() * sizeof(Double_t);
      if (n > 0) {
         memcpy(fX, gr.fX, n);
         memcpy(fY, gr.fY, n);
      }
   }
   return *this;
}


//______________________________________________________________________________
TGraph::TGraph(const TVectorF &vx, const TVectorF &vy)
   : TNamed("Graph", "Graph"), TAttLine(), TAttFill(1, 1001), TAttMarker()
{
   // Graph constructor with two vectors of floats in input
   // A graph is build with the X coordinates taken from vx and Y coord from vy
   // The number of points in the graph is the minimum of number of points
   // in vx and vy.

   fNpoints = TMath::Min(vx.GetNrows(), vy.GetNrows());
   if (!CtorAllocate()) return;
   Int_t ivxlow  = vx.GetLwb();
   Int_t ivylow  = vy.GetLwb();
   for (Int_t i = 0; i < fNpoints; i++) {
      fX[i]  = vx(i + ivxlow);
      fY[i]  = vy(i + ivylow);
   }
}


//______________________________________________________________________________
TGraph::TGraph(const TVectorD &vx, const TVectorD &vy)
   : TNamed("Graph", "Graph"), TAttLine(), TAttFill(1, 1001), TAttMarker()
{
   // Graph constructor with two vectors of doubles in input
   // A graph is build with the X coordinates taken from vx and Y coord from vy
   // The number of points in the graph is the minimum of number of points
   // in vx and vy.

   fNpoints = TMath::Min(vx.GetNrows(), vy.GetNrows());
   if (!CtorAllocate()) return;
   Int_t ivxlow  = vx.GetLwb();
   Int_t ivylow  = vy.GetLwb();
   for (Int_t i = 0; i < fNpoints; i++) {
      fX[i]  = vx(i + ivxlow);
      fY[i]  = vy(i + ivylow);
   }
}


//______________________________________________________________________________
TGraph::TGraph(const TH1 *h)
   : TNamed("Graph", "Graph"), TAttLine(), TAttFill(1, 1001), TAttMarker()
{
   // Graph constructor importing its parameters from the TH1 object passed as argument

   if (!h) {
      Error("TGraph", "Pointer to histogram is null");
      fNpoints = 0;
      return;
   }
   if (h->GetDimension() != 1) {
      Error("TGraph", "Histogram must be 1-D; h %s is %d-D", h->GetName(), h->GetDimension());
      fNpoints = 0;
   } else {
      fNpoints = ((TH1*)h)->GetXaxis()->GetNbins();
   }

   if (!CtorAllocate()) return;

   TAxis *xaxis = ((TH1*)h)->GetXaxis();
   for (Int_t i = 0; i < fNpoints; i++) {
      fX[i] = xaxis->GetBinCenter(i + 1);
      fY[i] = h->GetBinContent(i + 1);
   }
   h->TAttLine::Copy(*this);
   h->TAttFill::Copy(*this);
   h->TAttMarker::Copy(*this);

   std::string gname = "Graph_from_" + std::string(h->GetName());
   SetName(gname.c_str());
   SetTitle(h->GetTitle());
}


//______________________________________________________________________________
TGraph::TGraph(const TF1 *f, Option_t *option)
   : TNamed("Graph", "Graph"), TAttLine(), TAttFill(1, 1001), TAttMarker()
{
   // Graph constructor importing its parameters from the TF1 object passed as argument
   // if option =="" (default), a TGraph is created with points computed
   //                at the fNpx points of f.
   // if option =="d", a TGraph is created with points computed with the derivatives
   //                at the fNpx points of f.
   // if option =="i", a TGraph is created with points computed with the integral
   //                at the fNpx points of f.
   // if option =="I", a TGraph is created with points computed with the integral
   //                at the fNpx+1 points of f and the integral is normalized to 1.

   char coption = ' ';
   if (!f) {
      Error("TGraph", "Pointer to function is null");
      fNpoints = 0;
   } else {
      fNpoints   = f->GetNpx();
      if (option) coption = *option;
      if (coption == 'i' || coption == 'I') fNpoints++;
   }
   if (!CtorAllocate()) return;

   Double_t xmin = f->GetXmin();
   Double_t xmax = f->GetXmax();
   Double_t dx   = (xmax - xmin) / fNpoints;
   Double_t integ = 0;
   Int_t i;
   for (i = 0; i < fNpoints; i++) {
      if (coption == 'i' || coption == 'I') {
         fX[i] = xmin + i * dx;
         if (i == 0) fY[i] = 0;
         else        fY[i] = integ + ((TF1*)f)->Integral(fX[i] - dx, fX[i]);
         integ = fY[i];
      } else if (coption == 'd' || coption == 'D') {
         fX[i] = xmin + (i + 0.5) * dx;
         fY[i] = ((TF1*)f)->Derivative(fX[i]);
      } else {
         fX[i] = xmin + (i + 0.5) * dx;
         fY[i] = ((TF1*)f)->Eval(fX[i]);
      }
   }
   if (integ != 0 && coption == 'I') {
      for (i = 1; i < fNpoints; i++) fY[i] /= integ;
   }

   f->TAttLine::Copy(*this);
   f->TAttFill::Copy(*this);
   f->TAttMarker::Copy(*this);

   SetName(f->GetName());
   SetTitle(f->GetTitle());
}


//______________________________________________________________________________
TGraph::TGraph(const char *filename, const char *format, Option_t *option)
   : TNamed("Graph", filename), TAttLine(), TAttFill(1, 1001), TAttMarker()
{
   // Graph constructor reading input from filename.
   // filename is assumed to contain at least two columns of numbers.
   // the string format is by default "%lg %lg".
   // this is a standard c formatting for scanf. If columns of numbers should be
   // skipped, a "%*lg" or "%*s" for each column can be added,
   // e.g. "%lg %*lg %lg" would read x-values from the first and y-values from
   // the third column.
   // For files separated by a specific delimiter different from ' ' and '\t' (e.g. ';' in csv files)
   // you can avoid using %*s to bypass this delimiter by explicitly specify the "option" argument,
   // e.g. option=" \t,;" for columns of figures separated by any of these characters (' ', '\t', ',', ';')
   // used once (e.g. "1;1") or in a combined way (" 1;,;;  1").
   // Note in that case, the instanciation is about 2 times slower.

   Double_t x, y;
   TString fname = filename;
   gSystem->ExpandPathName(fname);

   ifstream infile(fname.Data());
   if (!infile.good()) {
      MakeZombie();
      Error("TGraph", "Cannot open file: %s, TGraph is Zombie", filename);
      fNpoints = 0;
      return;
   } else {
      fNpoints = 100;  //initial number of points
   }
   if (!CtorAllocate()) return;
   std::string line;
   Int_t np = 0;

   // No delimiters specified (standard constructor).
   if (strcmp(option, "") == 0) {

      while (std::getline(infile, line, '\n')) {
         if (2 != sscanf(line.c_str(), format, &x, &y)) {
            continue; //skip empty and ill-formed lines
         }
         SetPoint(np, x, y);
         np++;
      }
      Set(np);

      // A delimiter has been specified in "option"
   } else {

      // Checking format and creating its boolean counterpart
      TString format_ = TString(format) ;
      format_.ReplaceAll(" ", "") ;
      format_.ReplaceAll("\t", "") ;
      format_.ReplaceAll("lg", "") ;
      format_.ReplaceAll("s", "") ;
      format_.ReplaceAll("%*", "0") ;
      format_.ReplaceAll("%", "1") ;
      if (!format_.IsDigit()) {
         Error("TGraph", "Incorrect input format! Allowed formats are {\"%%lg\",\"%%*lg\" or \"%%*s\"}");
         return;
      }
      Int_t ntokens = format_.Length() ;
      if (ntokens < 2) {
         Error("TGraph", "Incorrect input format! Only %d tag(s) in format whereas 2 \"%%lg\" tags are expected!", ntokens);
         return;
      }
      Int_t ntokensToBeSaved = 0 ;
      Bool_t * isTokenToBeSaved = new Bool_t [ntokens] ;
      for (Int_t idx = 0; idx < ntokens; idx++) {
         isTokenToBeSaved[idx] = TString::Format("%c", format_[idx]).Atoi() ; //atoi(&format_[idx]) does not work for some reason...
         if (isTokenToBeSaved[idx] == 1) {
            ntokensToBeSaved++ ;
         }
      }
      if (ntokens >= 2 && ntokensToBeSaved != 2) { //first condition not to repeat the previous error message
         Error("TGraph", "Incorrect input format! There are %d \"%%lg\" tag(s) in format whereas 2 and only 2 are expected!", ntokensToBeSaved);
         delete [] isTokenToBeSaved ;
         return;
      }

      // Initializing loop variables
      Bool_t isLineToBeSkipped = kFALSE ; //empty and ill-formed lines
      char * token = NULL ;
      TString token_str = "" ;
      Int_t token_idx = 0 ;
      Double_t * value = new Double_t [2] ; //x,y buffers
      Int_t value_idx = 0 ;

      // Looping
      while (std::getline(infile, line, '\n')) {
         if (line != "") {
            if (line[line.size() - 1] == char(13)) {  // removing DOS CR character
               line.erase(line.end() - 1, line.end()) ;
            }
            token = strtok(const_cast<char*>(line.c_str()), option) ;
            while (token != NULL && value_idx < 2) {
               if (isTokenToBeSaved[token_idx]) {
                  token_str = TString(token) ;
                  token_str.ReplaceAll("\t", "") ;
                  if (!token_str.IsFloat()) {
                     isLineToBeSkipped = kTRUE ;
                     break ;
                  } else {
                     value[value_idx] = token_str.Atof() ;
                     value_idx++ ;
                  }
               }
               token = strtok(NULL, option) ; //next token
               token_idx++ ;
            }
            if (!isLineToBeSkipped && value_idx == 2) {
               x = value[0] ;
               y = value[1] ;
               SetPoint(np, x, y) ;
               np++ ;
            }
         }
         isLineToBeSkipped = kFALSE ;
         token = NULL ;
         token_idx = 0 ;
         value_idx = 0 ;
      }
      Set(np) ;

      // Cleaning
      delete [] isTokenToBeSaved ;
      delete [] value ;
      delete token ;
   }
   infile.close();
}


//______________________________________________________________________________
TGraph::~TGraph()
{
   // Graph default destructor.

   delete [] fX;
   delete [] fY;
   if (fFunctions) {
      fFunctions->SetBit(kInvalidObject);
      //special logic to support the case where the same object is
      //added multiple times in fFunctions.
      //This case happens when the same object is added with different
      //drawing modes
      TObject *obj;
      while ((obj  = fFunctions->First())) {
         while (fFunctions->Remove(obj)) { }
         delete obj;
      }
      delete fFunctions;
      fFunctions = 0; //to avoid accessing a deleted object in RecursiveRemove
   }
   SafeDelete(fHighlights); // objects by default are not deleted (user or SetOwner)
   delete fHistogram;
}


//______________________________________________________________________________
void TGraph::AddHighlight(Int_t ipoint, TObject *obj)
{
   // Allow add highlight object associated with i-th point
   // by default graph does not own the objects

   if ((fNpoints <= 0) || !obj) return;
   if ((ipoint < 0) || (ipoint >= fNpoints)) {
      Warning("AddHighlight", "%d-th point is outside of interval", ipoint);
      return;
   }

   if (!fHighlights) {
      fHighlights = new TObjArray(fNpoints);
      fHighlights->SetName("Highlights");
      fHighlights->SetBit(kMustCleanup); // protect fCleanups if graph/fHighlights was deleted
      gROOT->GetListOfCleanups()->Add(fHighlights);
   }

   obj->SetBit(kMustCleanup); // protect fHighlights if obj was deleted
   fHighlights->AddAt(obj, ipoint);
}


//______________________________________________________________________________
void TGraph::ShiftHighlights(Int_t pos, Bool_t insert)
{
   // After insert/remove point it is needed shifting fHighlights by one position

   if (!fHighlights) return;
   if (pos > fHighlights->GetLast()) {
      if (insert) fHighlights->Expand(fHighlights->GetSize() + 1);
      else        fHighlights->Expand(fHighlights->GetSize() - 1);
      return;
   }

   TObject *obj = 0;
   if (insert) { // insert point
      fHighlights->Expand(fHighlights->GetSize() + 1);
      for (Int_t i = fHighlights->GetLast(); i >= pos; i--) {
         obj = fHighlights->At(i);
         if (obj) fHighlights->AddAt(obj, i+1); // don't shift empty slot
         else     fHighlights->RemoveAt(i+1);
      }
      fHighlights->RemoveAt(pos);

   } else {      // remove point
      obj = fHighlights->At(pos);
      if (obj && fHighlights->IsOwner()) delete obj; // if owner, then deleting associated obj
      for (Int_t i = pos; i < fHighlights->GetLast(); i++) {
         obj = fHighlights->At(i+1);
         if (obj) fHighlights->AddAt(obj, i);   // don't shift empty slot
         else     fHighlights->RemoveAt(i);
      }
      fHighlights->RemoveAt(fHighlights->GetLast());
      fHighlights->Expand(fHighlights->GetSize() - 1);
   }
}


//______________________________________________________________________________
Double_t** TGraph::AllocateArrays(Int_t Narrays, Int_t arraySize)
{
   // Allocate arrays.

   if (arraySize < 0) {
      arraySize = 0;
   }
   Double_t **newarrays = new Double_t*[Narrays];
   if (!arraySize) {
      for (Int_t i = 0; i < Narrays; ++i)
         newarrays[i] = 0;
   } else {
      for (Int_t i = 0; i < Narrays; ++i)
         newarrays[i] = new Double_t[arraySize];
   }
   fMaxSize = arraySize;
   return newarrays;
}


//______________________________________________________________________________
void TGraph::Apply(TF1 *f)
{
   // Apply function f to all the data points
   // f may be a 1-D function TF1 or 2-d function TF2
   // The Y values of the graph are replaced by the new values computed
   // using the function

   if (fHistogram) {
      delete fHistogram;
      fHistogram = 0;
   }
   for (Int_t i = 0; i < fNpoints; i++) {
      fY[i] = f->Eval(fX[i], fY[i]);
   }
   if (gPad) gPad->Modified();
}


//______________________________________________________________________________
void TGraph::Browse(TBrowser *b)
{
   // Browse

   TString opt = gEnv->GetValue("TGraph.BrowseOption", "");
   if (opt.IsNull()) {
      opt = b ? b->GetDrawOption() : "alp";
      opt = (opt == "") ? "alp" : opt.Data();
   }
   Draw(opt.Data());
   gPad->Update();
}


//______________________________________________________________________________
Double_t TGraph::Chisquare(const TF1 *f1, Option_t * option) const
{
   // Return the chisquare of this graph with respect to f1.
   // The chisquare is computed as the sum of the quantity below at each point:
   // Begin_Latex
   // #frac{(y-f1(x))^{2}}{ey^{2}+(#frac{1}{2}(exl+exh)f1'(x))^{2}}
   // End_latex
   // where x and y are the graph point coordinates and f1'(x) is the derivative of function f1(x).
   // This method to approximate the uncertainty in y because of the errors in x, is called
   // "effective variance" method.
   // In case of a pure TGraph, the denominator is 1.
   // In case of a TGraphErrors or TGraphAsymmErrors the errors are taken
   // into account.
   // By default the range of the graph is used whatever function range.
   //  Use option "R" to use the function range

   // need to cast away the const - since it requires evaluating the function which is not const
   TF1 * func = const_cast<TF1*>(f1);
   if (!func) {
      Error("Chisquare","Function pointer is Null - return -1");
      return -1;
   }

   TString opt(option); opt.ToUpper();
   bool useRange = opt.Contains("R");

   return ROOT::Fit::Chisquare(*this, *func,useRange);
}


//    Double_t cu, eu, exh, exl, ey, eux, fu, fsum;
//    Double_t x[1];
//    Double_t chi2 = 0;
//    TF1 *func = (TF1*)f1; //EvalPar is not const !
//    for (Int_t i = 0; i < fNpoints; i++) {
//       func->InitArgs(x, 0); //must be inside the loop because of TF1::Derivative calling InitArgs
//       x[0] = fX[i];
//       if (!func->IsInside(x)) continue;
//       cu   = fY[i];
//       TF1::RejectPoint(kFALSE);
//       fu   = func->EvalPar(x);
//       if (TF1::RejectedPoint()) continue;
//       fsum = (cu - fu);
//       //npfits++;
//       exh = GetErrorXhigh(i);
//       exl = GetErrorXlow(i);
//       if (fsum < 0)
//          ey = GetErrorYhigh(i);
//       else
//          ey = GetErrorYlow(i);
//       if (exl < 0) exl = 0;
//       if (exh < 0) exh = 0;
//       if (ey < 0)  ey  = 0;
//       if (exh > 0 || exl > 0) {
//          //"Effective Variance" method introduced by Anna Kreshuk
//          //a copy of the algorithm in GraphFitChisquare from TFitter
//          eux = 0.5 * (exl + exh) * func->Derivative(x[0]);
//       } else
//          eux = 0.;
//       eu = ey * ey + eux * eux;
//       if (eu <= 0) eu = 1;
//       chi2 += fsum * fsum / eu;
//    }
//    return chi2;
// }


//______________________________________________________________________________
Bool_t TGraph::CompareArg(const TGraph* gr, Int_t left, Int_t right)
{
   // Return kTRUE if point number "left"'s argument (angle with respect to positive
   // x-axis) is bigger than that of point number "right". Can be used by Sort.

   Double_t xl, yl, xr, yr;
   gr->GetPoint(left, xl, yl);
   gr->GetPoint(right, xr, yr);
   return (TMath::ATan2(yl, xl) > TMath::ATan2(yr, xr));
}


//______________________________________________________________________________
Bool_t TGraph::CompareX(const TGraph* gr, Int_t left, Int_t right)
{
   // Return kTRUE if fX[left] > fX[right]. Can be used by Sort.

   return gr->fX[left] > gr->fX[right];
}


//______________________________________________________________________________
Bool_t TGraph::CompareY(const TGraph* gr, Int_t left, Int_t right)
{
   // Return kTRUE if fY[left] > fY[right]. Can be used by Sort.

   return gr->fY[left] > gr->fY[right];
}


//______________________________________________________________________________
Bool_t TGraph::CompareRadius(const TGraph* gr, Int_t left, Int_t right)
{
   // Return kTRUE if point number "left"'s distance to origin is bigger than
   // that of point number "right". Can be used by Sort.

   return gr->fX[left] * gr->fX[left] + gr->fY[left] * gr->fY[left]
          > gr->fX[right] * gr->fX[right] + gr->fY[right] * gr->fY[right];
}


//______________________________________________________________________________
void TGraph::ComputeRange(Double_t &xmin, Double_t &ymin, Double_t &xmax, Double_t &ymax) const
{
   // Compute the x/y range of the points in this graph
   if (fNpoints <= 0) {
      xmin = xmax = ymin = ymax = 0;
      return;
   }
   xmin = xmax = fX[0];
   ymin = ymax = fY[0];
   for (Int_t i = 1; i < fNpoints; i++) {
      if (fX[i] < xmin) xmin = fX[i];
      if (fX[i] > xmax) xmax = fX[i];
      if (fY[i] < ymin) ymin = fY[i];
      if (fY[i] > ymax) ymax = fY[i];
   }
}


//______________________________________________________________________________
void TGraph::CopyAndRelease(Double_t **newarrays, Int_t ibegin, Int_t iend,
                            Int_t obegin)
{
   // Copy points from fX and fY to arrays[0] and arrays[1]
   // or to fX and fY if arrays == 0 and ibegin != iend.
   // If newarrays is non null, replace fX, fY with pointers from newarrays[0,1].
   // Delete newarrays, old fX and fY

   CopyPoints(newarrays, ibegin, iend, obegin);
   if (newarrays) {
      delete[] fX;
      fX = newarrays[0];
      delete[] fY;
      fY = newarrays[1];
      delete[] newarrays;
   }
}


//______________________________________________________________________________
Bool_t TGraph::CopyPoints(Double_t **arrays, Int_t ibegin, Int_t iend,
                          Int_t obegin)
{
   // Copy points from fX and fY to arrays[0] and arrays[1]
   // or to fX and fY if arrays == 0 and ibegin != iend.

   if (ibegin < 0 || iend <= ibegin || obegin < 0) { // Error;
      return kFALSE;
   }
   if (!arrays && ibegin == obegin) { // No copying is needed
      return kFALSE;
   }
   Int_t n = (iend - ibegin) * sizeof(Double_t);
   if (arrays) {
      memmove(&arrays[0][obegin], &fX[ibegin], n);
      memmove(&arrays[1][obegin], &fY[ibegin], n);
   } else {
      memmove(&fX[obegin], &fX[ibegin], n);
      memmove(&fY[obegin], &fY[ibegin], n);
   }
   return kTRUE;
}


//______________________________________________________________________________
Bool_t TGraph::CtorAllocate()
{
   // In constructors set fNpoints than call this method.
   // Return kFALSE if the graph will contain no points.
   //Note: This function should be called only from the constructor
   // since it does not delete previously existing arrays

   fHistogram = 0;
   fMaximum = -1111;
   fMinimum = -1111;
   SetBit(kClipFrame);
   fFunctions = new TList;
   fHighlights = 0;
   if (fNpoints <= 0) {
      fNpoints = 0;
      fMaxSize   = 0;
      fX         = 0;
      fY         = 0;
      return kFALSE;
   } else {
      fMaxSize   = fNpoints;
      fX = new Double_t[fMaxSize];
      fY = new Double_t[fMaxSize];
   }
   return kTRUE;
}


//______________________________________________________________________________
void TGraph::Draw(Option_t *option)
{
   /* Begin_Html
   Draw this graph with its current attributes.
   <p>
   The options to draw a graph are described in
   <a href="http://root.cern.ch/root/html/TGraphPainter.html">TGraphPainter</a>
   class.
   End_Html */

   TString opt = option;
   opt.ToLower();

   if (opt.Contains("same")) {
      opt.ReplaceAll("same", "");
   }

   // in case of option *, set marker style to 3 (star) and replace
   // * option by option P.
   Ssiz_t pos;
   if ((pos = opt.Index("*")) != kNPOS) {
      SetMarkerStyle(3);
      opt.Replace(pos, 1, "p");
   }

   // If no option is specified, it is defined as "alp" in case there
   // no current pad or if the current pad as no axis defined.
   if (!strlen(option)) {
      if (gPad) {
         if (!gPad->GetListOfPrimitives()->FindObject("TFrame")) opt = "alp";
      } else {
         opt = "alp";
      }
   }

   if (gPad) {
      if (!gPad->IsEditable()) gROOT->MakeDefCanvas();
      if (opt.Contains("a")) gPad->Clear();
   }

   AppendPad(opt);
}


//______________________________________________________________________________
Int_t TGraph::DistancetoPrimitive(Int_t px, Int_t py)
{
   // Compute distance from point px,py to a graph.
   //
   //  Compute the closest distance of approach from point px,py to this line.
   //  The distance is computed in pixels units.

   TVirtualGraphPainter *painter = TVirtualGraphPainter::GetPainter();
   if (painter) return painter->DistancetoPrimitiveHelper(this, px, py);
   else return 0;
}


//______________________________________________________________________________
void TGraph::DrawGraph(Int_t n, const Int_t *x, const Int_t *y, Option_t *option)
{
   // Draw this graph with new attributes.

   TGraph *newgraph = new TGraph(n, x, y);
   TAttLine::Copy(*newgraph);
   TAttFill::Copy(*newgraph);
   TAttMarker::Copy(*newgraph);
   newgraph->SetBit(kCanDelete);
   newgraph->AppendPad(option);
}


//______________________________________________________________________________
void TGraph::DrawGraph(Int_t n, const Float_t *x, const Float_t *y, Option_t *option)
{
   // Draw this graph with new attributes.

   TGraph *newgraph = new TGraph(n, x, y);
   TAttLine::Copy(*newgraph);
   TAttFill::Copy(*newgraph);
   TAttMarker::Copy(*newgraph);
   newgraph->SetBit(kCanDelete);
   newgraph->AppendPad(option);
}


//______________________________________________________________________________
void TGraph::DrawGraph(Int_t n, const Double_t *x, const Double_t *y, Option_t *option)
{
   // Draw this graph with new attributes.

   const Double_t *xx = x;
   const Double_t *yy = y;
   if (!xx) xx = fX;
   if (!yy) yy = fY;
   TGraph *newgraph = new TGraph(n, xx, yy);
   TAttLine::Copy(*newgraph);
   TAttFill::Copy(*newgraph);
   TAttMarker::Copy(*newgraph);
   newgraph->SetBit(kCanDelete);
   newgraph->AppendPad(option);
}


//______________________________________________________________________________
void TGraph::DrawPanel()
{
   // Display a panel with all graph drawing options.

   TVirtualGraphPainter *painter = TVirtualGraphPainter::GetPainter();
   if (painter) painter->DrawPanelHelper(this);
}


//______________________________________________________________________________
Double_t TGraph::Eval(Double_t x, TSpline *spline, Option_t *option) const
{
   // Interpolate points in this graph at x using a TSpline
   //  -if spline==0 and option="" a linear interpolation between the two points
   //   close to x is computed. If x is outside the graph range, a linear
   //   extrapolation is computed.
   //  -if spline==0 and option="S" a TSpline3 object is created using this graph
   //   and the interpolated value from the spline is returned.
   //   the internally created spline is deleted on return.
   //  -if spline is specified, it is used to return the interpolated value.


   if (!spline) {

      if (fNpoints == 0) return 0;
      if (fNpoints == 1) return fY[0];


      TString opt = option;
      opt.ToLower();
      if (opt.Contains("s")) {

         // points must be sorted before using a TSpline
         std::vector<Double_t> xsort(fNpoints);
         std::vector<Double_t> ysort(fNpoints);
         std::vector<Int_t> indxsort(fNpoints);
         TMath::Sort(fNpoints, fX, &indxsort[0], false);
         for (Int_t i = 0; i < fNpoints; ++i) {
            xsort[i] = fX[ indxsort[i] ];
            ysort[i] = fY[ indxsort[i] ];
         }

         // spline interpolation creating a new spline
         TSpline3 *s = new TSpline3("", &xsort[0], &ysort[0], fNpoints);
         Double_t result = s->Eval(x);
         delete s;
         return result;
      }
      //linear interpolation
      //In case x is < fX[0] or > fX[fNpoints-1] return the extrapolated point

      //find points in graph around x assuming points are not sorted
      // (if point are sorted could use binary search)

      // find neighbours simply looping  all points
      // and find also the 2 adjacent points: (low2 < low < x < up < up2 )
      // needed in case x is outside the graph ascissa interval
      Int_t low  = -1;
      Int_t up  = -1;
      Int_t low2 = -1;
      Int_t up2 = -1;

      for (Int_t i = 0; i < fNpoints; ++i) {
         if (fX[i] < x) {
            if (low == -1 || fX[i] > fX[low])  {
               low2 = low;
               low = i;
            } else if (low2 == -1) low2 = i;
         } else if (fX[i] > x) {
            if (up  == -1 || fX[i] < fX[up])  {
               up2 = up;
               up = i;
            } else if (up2 == -1) up2 = i;
         } else // case x == fX[i]
            return fY[i]; // no interpolation needed
      }

      // treat cases when x is outside graph min max abscissa
      if (up == -1)  {
         up  = low;
         low = low2;
      }
      if (low == -1) {
         low = up;
         up  = up2;
      }

      assert(low != -1 && up != -1);

      if (fX[low] == fX[up]) return fY[low];
      Double_t yn = fY[up] + (x - fX[up]) * (fY[low] - fY[up]) / (fX[low] - fX[up]);
      return yn;
   } else {
      //spline interpolation using the input spline
      return spline->Eval(x);
   }
}


//______________________________________________________________________________
void TGraph::ExecuteEvent(Int_t event, Int_t px, Int_t py)
{
   // Execute action corresponding to one event.
   //
   //  This member function is called when a graph is clicked with the locator
   //
   //  If Left button clicked on one of the line end points, this point
   //     follows the cursor until button is released.
   //
   //  if Middle button clicked, the line is moved parallel to itself
   //     until the button is released.

   TVirtualGraphPainter *painter = TVirtualGraphPainter::GetPainter();
   if (painter) painter->ExecuteEventHelper(this, event, px, py);
}


//______________________________________________________________________________
void TGraph::Expand(Int_t newsize)
{
   // If array sizes <= newsize, expand storage to 2*newsize.

   Double_t **ps = ExpandAndCopy(newsize, fNpoints);
   CopyAndRelease(ps, 0, 0, 0);
}


//______________________________________________________________________________
void TGraph::Expand(Int_t newsize, Int_t step)
{
   // If graph capacity is less than newsize points then make array sizes
   // equal to least multiple of step to contain newsize points.
   // Returns kTRUE if size was altered

   if (newsize <= fMaxSize) {
      return;
   }
   Double_t **ps = Allocate(step * (newsize / step + (newsize % step ? 1 : 0)));
   CopyAndRelease(ps, 0, fNpoints, 0);
}


//______________________________________________________________________________
Double_t **TGraph::ExpandAndCopy(Int_t size, Int_t iend)
{
   // if size > fMaxSize allocate new arrays of 2*size points
   //  and copy oend first points.
   // Return pointer to new arrays.

   if (size <= fMaxSize) {
      return 0;
   }
   Double_t **newarrays = Allocate(2 * size);
   CopyPoints(newarrays, 0, iend, 0);
   return newarrays;
}


//______________________________________________________________________________
void TGraph::FillZero(Int_t begin, Int_t end, Bool_t)
{
   // Set zero values for point arrays in the range [begin, end)
   // Should be redefined in descendant classes

   memset(fX + begin, 0, (end - begin)*sizeof(Double_t));
   memset(fY + begin, 0, (end - begin)*sizeof(Double_t));
}


//______________________________________________________________________________
TObject *TGraph::FindObject(const char *name) const
{
   // Search object named name in the list of functions

   if (fFunctions) return fFunctions->FindObject(name);
   return 0;
}


//______________________________________________________________________________
TObject *TGraph::FindObject(const TObject *obj) const
{
   // Search object obj in the list of functions

   if (fFunctions) return fFunctions->FindObject(obj);
   return 0;
}


//______________________________________________________________________________
TFitResultPtr TGraph::Fit(const char *fname, Option_t *option, Option_t *, Axis_t xmin, Axis_t xmax)
{
   // Fit this graph with function with name fname.
   //
   //  interface to TGraph::Fit(TF1 *f1...
   //
   //      fname is the name of an already predefined function created by TF1 or TF2
   //      Predefined functions such as gaus, expo and poln are automatically
   //      created by ROOT.
   //      fname can also be a formula, accepted by the linear fitter (linear parts divided
   //      by "++" sign), for example "x++sin(x)" for fitting "[0]*x+[1]*sin(x)"

   char *linear;
   linear = (char*) strstr(fname, "++");
   TF1 *f1 = 0;
   if (linear)
      f1 = new TF1(fname, fname, xmin, xmax);
   else {
      f1 = (TF1*)gROOT->GetFunction(fname);
      if (!f1) {
         Printf("Unknown function: %s", fname);
         return -1;
      }
   }
   return Fit(f1, option, "", xmin, xmax);
}


//______________________________________________________________________________
TFitResultPtr TGraph::Fit(TF1 *f1, Option_t *option, Option_t *goption, Axis_t rxmin, Axis_t rxmax)
{
   // Fit this graph with function f1.
   //
   //   f1 is an already predefined function created by TF1.
   //   Predefined functions such as gaus, expo and poln are automatically
   //   created by ROOT.
   //
   //   The list of fit options is given in parameter option.
   //      option = "W" Set all weights to 1; ignore error bars
   //             = "U" Use a User specified fitting algorithm (via SetFCN)
   //             = "Q" Quiet mode (minimum printing)
   //             = "V" Verbose mode (default is between Q and V)
   //             = "E"  Perform better Errors estimation using Minos technique
   //             = "B"  User defined parameter settings are used for predefined functions
   //                    like "gaus", "expo", "poln", "landau".
   //                    Use this option when you want to fix one or more parameters for these functions.
   //             = "M"  More. Improve fit results.
   //                    It uses the IMPROVE command of TMinuit (see TMinuit::mnimpr)
   //                    This algorithm attempts to improve the found local minimum by
   //                    searching for a better one.
   //             = "R" Use the Range specified in the function range
   //             = "N" Do not store the graphics function, do not draw
   //             = "0" Do not plot the result of the fit. By default the fitted function
   //                   is drawn unless the option "N" above is specified.
   //             = "+" Add this new fitted function to the list of fitted functions
   //                   (by default, any previous function is deleted)
   //             = "C" In case of linear fitting, do not calculate the chisquare
   //                    (saves time)
   //             = "F" If fitting a polN, use the minuit fitter
   //             = "EX0" When fitting a TGraphErrors or TGraphAsymErrors do not consider errors in the coordinate
   //             = "ROB" In case of linear fitting, compute the LTS regression
   //                     coefficients (robust (resistant) regression), using
   //                     the default fraction of good points
   //               "ROB=0.x" - compute the LTS regression coefficients, using
   //                           0.x as a fraction of good points
   //             = "S"  The result of the fit is returned in the TFitResultPtr
   //                     (see below Access to the Fit Result)
   //
   //   When the fit is drawn (by default), the parameter goption may be used
   //   to specify a list of graphics options. See TGraphPainter for a complete
   //   list of these options.
   //
   //   In order to use the Range option, one must first create a function
   //   with the expression to be fitted. For example, if your graph
   //   has a defined range between -4 and 4 and you want to fit a gaussian
   //   only in the interval 1 to 3, you can do:
   //        TF1 *f1 = new TF1("f1","gaus",1,3);
   //        graph->Fit("f1","R");
   //
   //
   // Who is calling this function:
   //
   //   Note that this function is called when calling TGraphErrors::Fit
   //   or TGraphAsymmErrors::Fit ot TGraphBentErrors::Fit
   //   See the discussion below on error calulation.
   //
   // Linear fitting:
   // ===============
   //
   //   When the fitting function is linear (contains the "++" sign) or the fitting
   //   function is a polynomial, a linear fitter is initialised.
   //   To create a linear function, use the following syntax: linear parts
   //   separated by "++" sign.
   //   Example: to fit the parameters of "[0]*x + [1]*sin(x)", create a
   //    TF1 *f1=new TF1("f1", "x++sin(x)", xmin, xmax);
   //   For such a TF1 you don't have to set the initial conditions.
   //   Going via the linear fitter for functions, linear in parameters, gives a
   //   considerable advantage in speed.
   //
   // Setting initial conditions:
   // ===========================
   //
   //   Parameters must be initialized before invoking the Fit function.
   //   The setting of the parameter initial values is automatic for the
   //   predefined functions : poln, expo, gaus, landau. One can however disable
   //   this automatic computation by specifying the option "B".
   //   You can specify boundary limits for some or all parameters via
   //        f1->SetParLimits(p_number, parmin, parmax);
   //   If parmin>=parmax, the parameter is fixed
   //   Note that you are not forced to fix the limits for all parameters.
   //   For example, if you fit a function with 6 parameters, you can do:
   //     func->SetParameters(0,3.1,1.e-6,0.1,-8,100);
   //     func->SetParLimits(4,-10,-4);
   //     func->SetParLimits(5, 1,1);
   //   With this setup, parameters 0->3 can vary freely.
   //   Parameter 4 has boundaries [-10,-4] with initial value -8.
   //   Parameter 5 is fixed to 100.
   //
   // Fit range:
   // ==========
   //
   //   The fit range can be specified in two ways:
   //     - specify rxmax > rxmin (default is rxmin=rxmax=0)
   //     - specify the option "R". In this case, the function will be taken
   //       instead of the full graph range.
   //
   // Changing the fitting function:
   // ==============================
   //
   //   By default a chi2 fitting function is used for fitting a TGraph.
   //   The function is implemented in FitUtil::EvaluateChi2.
   //   In case of TGraphErrors an effective chi2 is used (see below TGraphErrors fit)
   //   To specify a User defined fitting function, specify option "U" and
   //   call the following functions:
   //     TVirtualFitter::Fitter(mygraph)->SetFCN(MyFittingFunction)
   //   where MyFittingFunction is of type:
   //   extern void MyFittingFunction(Int_t &npar, Double_t *gin, Double_t &f,
   //                                 Double_t *u, Int_t flag);
   //
   //
   // TGraphErrors fit:
   // =================
   //
   //   In case of a TGraphErrors object, when x errors are present, the error along x,
   //   is projected along the y-direction by calculating the function at the points x-exlow and
   //   x+exhigh. The chisquare is then computed as the sum of the quantity below at each point:
   //
   // Begin_Latex
   // #frac{(y-f(x))^{2}}{ey^{2}+(#frac{1}{2}(exl+exh)f'(x))^{2}}
   // End_Latex
   //
   //   where x and y are the point coordinates, and f'(x) is the derivative of the
   //   function f(x).
   //
   //   In case the function lies below (above) the data point, ey is ey_low (ey_high).
   //
   //   thanks to Andy Haas (haas@yahoo.com) for adding the case with TGraphAsymmErrors
   //             University of Washington
   //
   //   The approach used to approximate the uncertainty in y because of the
   //   errors in x is to make it equal the error in x times the slope of the line.
   //   The improvement, compared to the first method (f(x+ exhigh) - f(x-exlow))/2
   //   is of (error of x)**2 order. This approach is called "effective variance method".
   //   This improvement has been made in version 4.00/08 by Anna Kreshuk.
   //   The implementation is provided in the function FitUtil::EvaluateChi2Effective
   //
   // NOTE:
   //   1) By using the "effective variance" method a simple linear regression
   //      becomes a non-linear case, which takes several iterations
   //      instead of 0 as in the linear case.
   //
   //   2) The effective variance technique assumes that there is no correlation
   //      between the x and y coordinate.
   //
   //   3) The standard chi2 (least square) method without error in the coordinates (x) can
   //       be forced by using option "EX0"
   //
   //   4)  The linear fitter doesn't take into account the errors in x. When fitting a
   //       TGraphErrors with a linear functions the errors in x willnot be considere.
   //        If errors in x are important, go through minuit (use option "F" for polynomial fitting).
   //
   //   5) When fitting a TGraph (i.e. no errors associated with each point),
   //   a correction is applied to the errors on the parameters with the following
   //   formula:
   //      errorp *= sqrt(chisquare/(ndf-1))
   //
   //   Access to the fit result
   //   ========================
   //  The function returns a TFitResultPtr which can hold a  pointer to a TFitResult object.
   //  By default the TFitResultPtr contains only the status of the fit which is return by an
   //  automatic conversion of the TFitResultPtr to an integer. One can write in this case
   //  directly:
   //  Int_t fitStatus =  h->Fit(myFunc)
   //
   //  If the option "S" is instead used, TFitResultPtr contains the TFitResult and behaves
   //  as a smart pointer to it. For example one can do:
   //  TFitResultPtr r = h->Fit(myFunc,"S");
   //  TMatrixDSym cov = r->GetCovarianceMatrix();  //  to access the covariance matrix
   //  Double_t chi2   = r->Chi2(); // to retrieve the fit chi2
   //  Double_t par0   = r->Value(0); // retrieve the value for the parameter 0
   //  Double_t err0   = r->ParError(0); // retrieve the error for the parameter 0
   //  r->Print("V");     // print full information of fit including covariance matrix
   //  r->Write();        // store the result in a file
   //
   //  The fit parameters, error and chi2 (but not covariance matrix) can be retrieved also
   //  from the fitted function.
   //  If the histogram is made persistent, the list of
   //  associated functions is also persistent. Given a pointer (see above)
   //  to an associated function myfunc, one can retrieve the function/fit
   //  parameters with calls such as:
   //    Double_t chi2 = myfunc->GetChisquare();
   //    Double_t par0 = myfunc->GetParameter(0); //value of 1st parameter
   //    Double_t err0 = myfunc->GetParError(0);  //error on first parameter
   //
   //
   //  Access to the fit status
   //  =====================
   //  The status of the fit can be obtained converting the TFitResultPtr to an integer
   //  indipendently if the fit option "S" is used or not:
   //  TFitResultPtr r = h->Fit(myFunc,opt);
   //  Int_t fitStatus = r;
   //
   //  The fitStatus is 0 if the fit is OK (i.e. no error occurred).
   //  The value of the fit status code is negative in case of an error not connected with the
   //  minimization procedure, for example when a wrong function is used.
   //  Otherwise the return value is the one returned from the minimization procedure.
   //  When TMinuit (default case) or Minuit2 are used as minimizer the status returned is :
   //  fitStatus =  migradResult + 10*minosResult + 100*hesseResult + 1000*improveResult.
   //  TMinuit will return 0 (for migrad, minos, hesse or improve) in case of success and 4 in
   //  case of error (see the documentation of TMinuit::mnexcm). So for example, for an error
   //  only in Minos but not in Migrad a fitStatus of 40 will be returned.
   //  Minuit2 will return also 0 in case of success and different values in migrad, minos or
   //  hesse depending on the error.   See in this case the documentation of
   //  Minuit2Minimizer::Minimize for the migradResult, Minuit2Minimizer::GetMinosError for the
   //  minosResult and Minuit2Minimizer::Hesse for the hesseResult.
   //  If other minimizers are used see their specific documentation for the status code
   //  returned. For example in the case of Fumili, for the status returned see TFumili::Minimize.
   //
   // Associated functions:
   // =====================
   //
   //   One or more object (typically a TF1*) can be added to the list
   //   of functions (fFunctions) associated with each graph.
   //   When TGraph::Fit is invoked, the fitted function is added to this list.
   //   Given a graph gr, one can retrieve an associated function
   //   with:  TF1 *myfunc = gr->GetFunction("myfunc");
   //
   //   If the graph is made persistent, the list of associated functions is also
   //   persistent. Given a pointer (see above) to an associated function myfunc,
   //   one can retrieve the function/fit parameters with calls such as:
   //     Double_t chi2 = myfunc->GetChisquare();
   //     Double_t par0 = myfunc->GetParameter(0); //value of 1st parameter
   //     Double_t err0 = myfunc->GetParError(0);  //error on first parameter
   //
   // Fit Statistics
   // ==============
   //
   //   You can change the statistics box to display the fit parameters with
   //   the TStyle::SetOptFit(mode) method. This mode has four digits.
   //   mode = pcev  (default = 0111)
   //     v = 1;  print name/values of parameters
   //     e = 1;  print errors (if e=1, v must be 1)
   //     c = 1;  print Chisquare/Number of degress of freedom
   //     p = 1;  print Probability
   //
   //   For example: gStyle->SetOptFit(1011);
   //   prints the fit probability, parameter names/values, and errors.
   //   You can change the position of the statistics box with these lines
   //   (where g is a pointer to the TGraph):
   //
   //   Root > TPaveStats *st = (TPaveStats*)g->GetListOfFunctions()->FindObject("stats")
   //   Root > st->SetX1NDC(newx1); //new x start position
   //   Root > st->SetX2NDC(newx2); //new x end position
   //

   Foption_t fitOption;
   ROOT::Fit::FitOptionsMake(option, fitOption);
   // create range and minimizer options with default values
   ROOT::Fit::DataRange range(rxmin, rxmax);
   ROOT::Math::MinimizerOptions minOption;
   return ROOT::Fit::FitObject(this, f1 , fitOption , minOption, goption, range);
}


//______________________________________________________________________________
void TGraph::FitPanel()
{
   // Display a GUI panel with all graph fit options.
   //
   //   See class TFitEditor for example

   if (!gPad)
      gROOT->MakeDefCanvas();

   if (!gPad) {
      Error("FitPanel", "Unable to create a default canvas");
      return;
   }

   // use plugin manager to create instance of TFitEditor
   TPluginHandler *handler = gROOT->GetPluginManager()->FindHandler("TFitEditor");
   if (handler && handler->LoadPlugin() != -1) {
      if (handler->ExecPlugin(2, gPad, this) == 0)
         Error("FitPanel", "Unable to crate the FitPanel");
   } else
      Error("FitPanel", "Unable to find the FitPanel plug-in");
}


//______________________________________________________________________________
Double_t TGraph::GetCorrelationFactor() const
{
   // Return graph correlation factor

   Double_t rms1 = GetRMS(1);
   if (rms1 == 0) return 0;
   Double_t rms2 = GetRMS(2);
   if (rms2 == 0) return 0;
   return GetCovariance() / rms1 / rms2;
}


//______________________________________________________________________________
Double_t TGraph::GetCovariance() const
{
   // Return covariance of vectors x,y

   if (fNpoints <= 0) return 0;
   Double_t sum = fNpoints, sumx = 0, sumy = 0, sumxy = 0;

   for (Int_t i = 0; i < fNpoints; i++) {
      sumx  += fX[i];
      sumy  += fY[i];
      sumxy += fX[i] * fY[i];
   }
   return sumxy / sum - sumx / sum * sumy / sum;
}


//______________________________________________________________________________
Double_t TGraph::GetMean(Int_t axis) const
{
   // Return mean value of X (axis=1)  or Y (axis=2)

   if (axis < 1 || axis > 2) return 0;
   if (fNpoints <= 0) return 0;
   Double_t sumx = 0;
   for (Int_t i = 0; i < fNpoints; i++) {
      if (axis == 1) sumx += fX[i];
      else           sumx += fY[i];
   }
   return sumx / fNpoints;
}


//______________________________________________________________________________
Double_t TGraph::GetRMS(Int_t axis) const
{
   // Return RMS of X (axis=1)  or Y (axis=2)

   if (axis < 1 || axis > 2) return 0;
   if (fNpoints <= 0) return 0;
   Double_t sumx = 0, sumx2 = 0;
   for (Int_t i = 0; i < fNpoints; i++) {
      if (axis == 1) {
         sumx += fX[i];
         sumx2 += fX[i] * fX[i];
      } else           {
         sumx += fY[i];
         sumx2 += fY[i] * fY[i];
      }
   }
   Double_t x = sumx / fNpoints;
   Double_t rms2 = TMath::Abs(sumx2 / fNpoints - x * x);
   return TMath::Sqrt(rms2);
}


//______________________________________________________________________________
Double_t TGraph::GetErrorX(Int_t) const
{
   // This function is called by GraphFitChisquare.
   // It always returns a negative value. Real implementation in TGraphErrors

   return -1;
}


//______________________________________________________________________________
Double_t TGraph::GetErrorY(Int_t) const
{
   // This function is called by GraphFitChisquare.
   // It always returns a negative value. Real implementation in TGraphErrors

   return -1;
}


//______________________________________________________________________________
Double_t TGraph::GetErrorXhigh(Int_t) const
{
   // This function is called by GraphFitChisquare.
   // It always returns a negative value. Real implementation in TGraphErrors
   // and TGraphAsymmErrors

   return -1;
}


//______________________________________________________________________________
Double_t TGraph::GetErrorXlow(Int_t) const
{
   // This function is called by GraphFitChisquare.
   // It always returns a negative value. Real implementation in TGraphErrors
   // and TGraphAsymmErrors

   return -1;
}


//______________________________________________________________________________
Double_t TGraph::GetErrorYhigh(Int_t) const
{
   // This function is called by GraphFitChisquare.
   // It always returns a negative value. Real implementation in TGraphErrors
   // and TGraphAsymmErrors

   return -1;
}


//______________________________________________________________________________
Double_t TGraph::GetErrorYlow(Int_t) const
{
   // This function is called by GraphFitChisquare.
   // It always returns a negative value. Real implementation in TGraphErrors
   // and TGraphAsymmErrors

   return -1;
}


//______________________________________________________________________________
TF1 *TGraph::GetFunction(const char *name) const
{
   // Return pointer to function with name.
   //
   // Functions such as TGraph::Fit store the fitted function in the list of
   // functions of this graph.

   if (!fFunctions) return 0;
   return (TF1*)fFunctions->FindObject(name);
}


//______________________________________________________________________________
TH1F *TGraph::GetHistogram() const
{
   // Returns a pointer to the histogram used to draw the axis
   // Takes into account the two following cases.
   //    1- option 'A' was specified in TGraph::Draw. Return fHistogram
   //    2- user had called TPad::DrawFrame. return pointer to hframe histogram

   Double_t rwxmin, rwxmax, rwymin, rwymax, maximum, minimum, dx, dy;
   Double_t uxmin, uxmax;

   ComputeRange(rwxmin, rwymin, rwxmax, rwymax);  //this is redefined in TGraphErrors

   // (if fHistogram exist) && (if the log scale is on) &&
   // (if the computed range minimum is > 0) && (if the fHistogram minimum is zero)
   // then it means fHistogram limits have been computed in linear scale
   // therefore they might be too strict and cut some points. In that case the
   // fHistogram limits should be recomputed ie: the existing fHistogram
   // should not be returned.
   TH1F *historg = 0;
   if (fHistogram) {
      if (gPad && gPad->GetLogx()) {
         if (rwxmin <= 0 || fHistogram->GetXaxis()->GetXmin() != 0) return fHistogram;
      } else if (gPad && gPad->GetLogy()) {
         if (rwymin <= 0 || fHistogram->GetMinimum() != 0) return fHistogram;
      } else {
         return fHistogram;
      }
      historg = fHistogram;
   }

   if (rwxmin == rwxmax) rwxmax += 1.;
   if (rwymin == rwymax) rwymax += 1.;
   dx = 0.1 * (rwxmax - rwxmin);
   dy = 0.1 * (rwymax - rwymin);
   uxmin    = rwxmin - dx;
   uxmax    = rwxmax + dx;
   minimum  = rwymin - dy;
   maximum  = rwymax + dy;
   if (fMinimum != -1111) minimum = fMinimum;
   if (fMaximum != -1111) maximum = fMaximum;

   // the graph is created with at least as many channels as there are points
   // to permit zooming on the full range
   if (uxmin < 0 && rwxmin >= 0) {
      if (gPad && gPad->GetLogx()) uxmin = 0.9 * rwxmin;
      else                 uxmin = 0;
   }
   if (uxmax > 0 && rwxmax <= 0) {
      if (gPad && gPad->GetLogx()) uxmax = 1.1 * rwxmax;
      else                 uxmax = 0;
   }
   if (minimum < 0 && rwymin >= 0) {
      if (gPad && gPad->GetLogy()) minimum = 0.9 * rwymin;
      else                minimum = 0;
   }
   if (minimum <= 0 && gPad && gPad->GetLogy()) minimum = 0.001 * maximum;
   if (uxmin <= 0 && gPad && gPad->GetLogx()) {
      if (uxmax > 1000) uxmin = 1;
      else              uxmin = 0.001 * uxmax;
   }

   rwxmin = uxmin;
   rwxmax = uxmax;
   Int_t npt = 100;
   if (fNpoints > npt) npt = fNpoints;
   const char *gname = GetName();
   if (strlen(gname) == 0) gname = "Graph";
   ((TGraph*)this)->fHistogram = new TH1F(gname, GetTitle(), npt, rwxmin, rwxmax);
   if (!fHistogram) return 0;
   fHistogram->SetMinimum(minimum);
   fHistogram->SetBit(TH1::kNoStats);
   fHistogram->SetMaximum(maximum);
   fHistogram->GetYaxis()->SetLimits(minimum, maximum);
   fHistogram->SetDirectory(0);
   // Restore the axis attributes if needed
   if (historg) {
      fHistogram->GetXaxis()->SetTitle(historg->GetXaxis()->GetTitle());
      fHistogram->GetXaxis()->CenterTitle(historg->GetXaxis()->GetCenterTitle());
      fHistogram->GetXaxis()->RotateTitle(historg->GetXaxis()->GetRotateTitle());
      fHistogram->GetXaxis()->SetNoExponent(historg->GetXaxis()->GetNoExponent());
      fHistogram->GetXaxis()->SetNdivisions(historg->GetXaxis()->GetNdivisions());
      fHistogram->GetXaxis()->SetLabelFont(historg->GetXaxis()->GetLabelFont());
      fHistogram->GetXaxis()->SetLabelOffset(historg->GetXaxis()->GetLabelOffset());
      fHistogram->GetXaxis()->SetLabelSize(historg->GetXaxis()->GetLabelSize());
      fHistogram->GetXaxis()->SetTitleSize(historg->GetXaxis()->GetTitleSize());
      fHistogram->GetXaxis()->SetTitleOffset(historg->GetXaxis()->GetTitleOffset());
      fHistogram->GetXaxis()->SetTitleFont(historg->GetXaxis()->GetTitleFont());

      fHistogram->GetYaxis()->SetTitle(historg->GetYaxis()->GetTitle());
      fHistogram->GetYaxis()->CenterTitle(historg->GetYaxis()->GetCenterTitle());
      fHistogram->GetYaxis()->RotateTitle(historg->GetYaxis()->GetRotateTitle());
      fHistogram->GetYaxis()->SetNoExponent(historg->GetYaxis()->GetNoExponent());
      fHistogram->GetYaxis()->SetNdivisions(historg->GetYaxis()->GetNdivisions());
      fHistogram->GetYaxis()->SetLabelFont(historg->GetYaxis()->GetLabelFont());
      fHistogram->GetYaxis()->SetLabelOffset(historg->GetYaxis()->GetLabelOffset());
      fHistogram->GetYaxis()->SetLabelSize(historg->GetYaxis()->GetLabelSize());
      fHistogram->GetYaxis()->SetTitleSize(historg->GetYaxis()->GetTitleSize());
      fHistogram->GetYaxis()->SetTitleOffset(historg->GetYaxis()->GetTitleOffset());
      fHistogram->GetYaxis()->SetTitleFont(historg->GetYaxis()->GetTitleFont());

      delete historg;
   }
   return fHistogram;
}


//______________________________________________________________________________
Int_t TGraph::GetPoint(Int_t i, Double_t &x, Double_t &y) const
{
   // Get x and y values for point number i.
   // The function returns -1 in case of an invalid request or the point number otherwise

   if (i < 0 || i >= fNpoints) return -1;
   if (!fX || !fY) return -1;
   x = fX[i];
   y = fY[i];
   return i;
}


//______________________________________________________________________________
TAxis *TGraph::GetXaxis() const
{
   // Get x axis of the graph.

   TH1 *h = GetHistogram();
   if (!h) return 0;
   return h->GetXaxis();
}


//______________________________________________________________________________
TAxis *TGraph::GetYaxis() const
{
   // Get y axis of the graph.

   TH1 *h = GetHistogram();
   if (!h) return 0;
   return h->GetYaxis();
}


//______________________________________________________________________________
void TGraph::InitGaus(Double_t xmin, Double_t xmax)
{
   // Compute Initial values of parameters for a gaussian.

   Double_t allcha, sumx, sumx2, x, val, rms, mean;
   Int_t bin;
   const Double_t sqrtpi = 2.506628;

   // Compute mean value and RMS of the graph in the given range
   if (xmax <= xmin) {
      xmin = fX[0];
      xmax = fX[fNpoints-1];
   }
   Int_t np = 0;
   allcha = sumx = sumx2 = 0;
   for (bin = 0; bin < fNpoints; bin++) {
      x       = fX[bin];
      if (x < xmin || x > xmax) continue;
      np++;
      val     = fY[bin];
      sumx   += val * x;
      sumx2  += val * x * x;
      allcha += val;
   }
   if (np == 0 || allcha == 0) return;
   mean = sumx / allcha;
   rms  = TMath::Sqrt(sumx2 / allcha - mean * mean);
   Double_t binwidx = TMath::Abs((xmax - xmin) / np);
   if (rms == 0) rms = 1;
   TVirtualFitter *grFitter = TVirtualFitter::GetFitter();
   TF1 *f1 = (TF1*)grFitter->GetUserFunc();
   f1->SetParameter(0, binwidx * allcha / (sqrtpi * rms));
   f1->SetParameter(1, mean);
   f1->SetParameter(2, rms);
   f1->SetParLimits(2, 0, 10 * rms);
}


//______________________________________________________________________________
void TGraph::InitExpo(Double_t xmin, Double_t xmax)
{
   // Compute Initial values of parameters for an exponential.

   Double_t constant, slope;
   Int_t ifail;
   if (xmax <= xmin) {
      xmin = fX[0];
      xmax = fX[fNpoints-1];
   }
   Int_t nchanx = fNpoints;

   LeastSquareLinearFit(-nchanx, constant, slope, ifail, xmin, xmax);

   TVirtualFitter *grFitter = TVirtualFitter::GetFitter();
   TF1 *f1 = (TF1*)grFitter->GetUserFunc();
   f1->SetParameter(0, constant);
   f1->SetParameter(1, slope);
}


//______________________________________________________________________________
void TGraph::InitPolynom(Double_t xmin, Double_t xmax)
{
   // Compute Initial values of parameters for a polynom.

   Double_t fitpar[25];

   TVirtualFitter *grFitter = TVirtualFitter::GetFitter();
   TF1 *f1 = (TF1*)grFitter->GetUserFunc();
   Int_t npar   = f1->GetNpar();
   if (xmax <= xmin) {
      xmin = fX[0];
      xmax = fX[fNpoints-1];
   }

   LeastSquareFit(npar, fitpar, xmin, xmax);

   for (Int_t i = 0; i < npar; i++) f1->SetParameter(i, fitpar[i]);
}


//______________________________________________________________________________
Int_t TGraph::InsertPoint()
{
   // Insert a new point at the mouse position

   Int_t px = gPad->GetEventX();
   Int_t py = gPad->GetEventY();

   //localize point where to insert
   Int_t ipoint = -2;
   Int_t i, d = 0;
   // start with a small window (in case the mouse is very close to one point)
   for (i = 0; i < fNpoints - 1; i++) {
      d = DistancetoLine(px, py, gPad->XtoPad(fX[i]), gPad->YtoPad(fY[i]), gPad->XtoPad(fX[i+1]), gPad->YtoPad(fY[i+1]));
      if (d < 5) {
         ipoint = i + 1;
         break;
      }
   }
   if (ipoint == -2) {
      //may be we are far from one point, try again with a larger window
      for (i = 0; i < fNpoints - 1; i++) {
         d = DistancetoLine(px, py, gPad->XtoPad(fX[i]), gPad->YtoPad(fY[i]), gPad->XtoPad(fX[i+1]), gPad->YtoPad(fY[i+1]));
         if (d < 10) {
            ipoint = i + 1;
            break;
         }
      }
   }
   if (ipoint == -2) {
      //distinguish between first and last point
      Int_t dpx = px - gPad->XtoAbsPixel(gPad->XtoPad(fX[0]));
      Int_t dpy = py - gPad->YtoAbsPixel(gPad->XtoPad(fY[0]));
      if (dpx * dpx + dpy * dpy < 25) ipoint = 0;
      else                      ipoint = fNpoints;
   }
   Double_t **ps = ExpandAndCopy(fNpoints + 1, ipoint);
   CopyAndRelease(ps, ipoint, fNpoints++, ipoint + 1);

   // To avoid redefenitions in descendant classes
   FillZero(ipoint, ipoint + 1);

   fX[ipoint] = gPad->PadtoX(gPad->AbsPixeltoX(px));
   fY[ipoint] = gPad->PadtoY(gPad->AbsPixeltoY(py));
   ShiftHighlights(ipoint, kTRUE);
   gPad->Modified();
   return ipoint;
}

//______________________________________________________________________________
Double_t TGraph::Integral(Int_t first, Int_t last) const
{
   // Integrate the TGraph data within a given (index) range
   // Note that this function computes the area of the polygon enclosed by the points of the TGraph.
   // The polygon segments, which are defined by the points of the TGraph, do not need to form a closed polygon,
   // since the last polygon segment, which closes the polygon, is taken as the line connecting the last TGraph point
   // with the first one. It is clear that the order of the point is essential in defining the polygon.
   // Also note that the segments should not intersect.
   //
   // NB: if last=-1 (default) last is set to the last point.
   //     if (first <0) the first point (0) is taken.
   //
   //Method:
   // There are many ways to calculate the surface of a polygon. It all depends on what kind of data
   // you have to deal with. The most evident solution would be to divide the polygon in triangles and
   // calculate the surface of them. But this can quickly become complicated as you will have to test
   // every segments of every triangles and check if they are intersecting with a current polygon's
   // segment or if it goes outside the polygon. Many calculations that would lead to many problems...
   //      The solution (implemented by R.Brun)
   // Fortunately for us, there is a simple way to solve this problem, as long as the polygon's
   // segments don't intersect.
   // It takes the x coordinate of the current vertex and multiply it by the y coordinate of the next
   // vertex. Then it subtracts from it the result of the y coordinate of the current vertex multiplied
   // by the x coordinate of the next vertex. Then divide the result by 2 to get the surface/area.
   //      Sources
   //      http://forums.wolfram.com/mathgroup/archive/1998/Mar/msg00462.html
   //      http://stackoverflow.com/questions/451426/how-do-i-calculate-the-surface-area-of-a-2d-polygon

   if (first < 0) first = 0;
   if (last < 0) last = fNpoints - 1;
   if (last >= fNpoints) last = fNpoints - 1;
   if (first >= last) return 0;
   Int_t np = last - first + 1;
   Double_t sum = 0.0;
   //for(Int_t i=first;i<=last;i++) {
   //   Int_t j = first + (i-first+1)%np;
   //   sum += TMath::Abs(fX[i]*fY[j]);
   //   sum -= TMath::Abs(fY[i]*fX[j]);
   //}
   for (Int_t i = first; i <= last; i++) {
      Int_t j = first + (i - first + 1) % np;
      sum += (fY[i] + fY[j]) * (fX[j] - fX[i]);
   }
   return 0.5 * TMath::Abs(sum);
}


//______________________________________________________________________________
Int_t TGraph::IsInside(Double_t x, Double_t y) const
{
   // Return 1 if the point (x,y) is inside the polygon defined by
   // the graph vertices 0 otherwise.
   //
   // Algorithm:
   // The loop is executed with the end-point coordinates of a line segment
   // (X1,Y1)-(X2,Y2) and the Y-coordinate of a horizontal line.
   // The counter inter is incremented if the line (X1,Y1)-(X2,Y2) intersects
   // the horizontal line. In this case XINT is set to the X-coordinate of the
   // intersection point. If inter is an odd number, then the point x,y is within
   // the polygon.

   return (Int_t)TMath::IsInside(x, y, fNpoints, fX, fY);
}


//______________________________________________________________________________
void TGraph::LeastSquareFit(Int_t m, Double_t *a, Double_t xmin, Double_t xmax)
{
   // Least squares polynomial fitting without weights.
   //
   //  m     number of parameters
   //  a     array of parameters
   //  first 1st point number to fit (default =0)
   //  last  last point number to fit (default=fNpoints-1)
   //
   //   based on CERNLIB routine LSQ: Translated to C++ by Rene Brun

   const Double_t zero = 0.;
   const Double_t one = 1.;
   const Int_t idim = 20;

   Double_t  b[400]        /* was [20][20] */;
   Int_t i, k, l, ifail;
   Double_t power;
   Double_t da[20], xk, yk;
   Int_t n = fNpoints;
   if (xmax <= xmin) {
      xmin = fX[0];
      xmax = fX[fNpoints-1];
   }

   if (m <= 2) {
      LeastSquareLinearFit(n, a[0], a[1], ifail, xmin, xmax);
      return;
   }
   if (m > idim || m > n) return;
   da[0] = zero;
   for (l = 2; l <= m; ++l) {
      b[l-1]           = zero;
      b[m + l*20 - 21] = zero;
      da[l-1]          = zero;
   }
   Int_t np = 0;
   for (k = 0; k < fNpoints; ++k) {
      xk     = fX[k];
      if (xk < xmin || xk > xmax) continue;
      np++;
      yk     = fY[k];
      power  = one;
      da[0] += yk;
      for (l = 2; l <= m; ++l) {
         power   *= xk;
         b[l-1]  += power;
         da[l-1] += power * yk;
      }
      for (l = 2; l <= m; ++l) {
         power            *= xk;
         b[m + l*20 - 21] += power;
      }
   }
   b[0]  = Double_t(np);
   for (i = 3; i <= m; ++i) {
      for (k = i; k <= m; ++k) {
         b[k - 1 + (i-1)*20 - 21] = b[k + (i-2)*20 - 21];
      }
   }
   H1LeastSquareSeqnd(m, b, idim, ifail, 1, da);

   if (ifail < 0) {
      a[0] = fY[0];
      for (i = 1; i < m; ++i) a[i] = 0;
      return;
   }
   for (i = 0; i < m; ++i) a[i] = da[i];
}


//______________________________________________________________________________
void TGraph::LeastSquareLinearFit(Int_t ndata, Double_t &a0, Double_t &a1, Int_t &ifail, Double_t xmin, Double_t xmax)
{
   // Least square linear fit without weights.
   //
   //  Fit a straight line (a0 + a1*x) to the data in this graph.
   //  ndata:  if ndata<0, fits the logarithm of the graph (used in InitExpo() to set
   //          the initial parameter values for a fit with exponential function.
   //  a0:     constant
   //  a1:     slope
   //  ifail:  return parameter indicating the status of the fit (ifail=0, fit is OK)
   //  xmin, xmax: fitting range
   //
   //  extracted from CERNLIB LLSQ: Translated to C++ by Rene Brun

   Double_t xbar, ybar, x2bar;
   Int_t i;
   Double_t xybar;
   Double_t fn, xk, yk;
   Double_t det;
   if (xmax <= xmin) {
      xmin = fX[0];
      xmax = fX[fNpoints-1];
   }

   ifail = -2;
   xbar  = ybar = x2bar = xybar = 0;
   Int_t np = 0;
   for (i = 0; i < fNpoints; ++i) {
      xk = fX[i];
      if (xk < xmin || xk > xmax) continue;
      np++;
      yk = fY[i];
      if (ndata < 0) {
         if (yk <= 0) yk = 1e-9;
         yk = TMath::Log(yk);
      }
      xbar  += xk;
      ybar  += yk;
      x2bar += xk * xk;
      xybar += xk * yk;
   }
   fn    = Double_t(np);
   det   = fn * x2bar - xbar * xbar;
   ifail = -1;
   if (det <= 0) {
      if (fn > 0) a0 = ybar / fn;
      else        a0 = 0;
      a1 = 0;
      return;
   }
   ifail = 0;
   a0 = (x2bar * ybar - xbar * xybar) / det;
   a1 = (fn * xybar - xbar * ybar) / det;
}


//______________________________________________________________________________
void TGraph::Paint(Option_t *option)
{
   // Draw this graph with its current attributes.

   TVirtualGraphPainter *painter = TVirtualGraphPainter::GetPainter();
   if (painter) painter->PaintHelper(this, option);
}


//______________________________________________________________________________
void TGraph::PaintGraph(Int_t npoints, const Double_t *x, const Double_t *y, Option_t *chopt)
{
   // Draw the (x,y) as a graph.

   TVirtualGraphPainter *painter = TVirtualGraphPainter::GetPainter();
   if (painter) painter->PaintGraph(this, npoints, x, y, chopt);
}


//______________________________________________________________________________
void TGraph::PaintGrapHist(Int_t npoints, const Double_t *x, const Double_t *y, Option_t *chopt)
{
   // Draw the (x,y) as a histogram.

   TVirtualGraphPainter *painter = TVirtualGraphPainter::GetPainter();
   if (painter) painter->PaintGrapHist(this, npoints, x, y, chopt);
}


//______________________________________________________________________________
void TGraph::PaintStats(TF1 *fit)
{
   // Draw the stats

   TVirtualGraphPainter *painter = TVirtualGraphPainter::GetPainter();
   if (painter) painter->PaintStats(this, fit);
}


//______________________________________________________________________________
void TGraph::Print(Option_t *) const
{
   // Print graph values.

   for (Int_t i = 0; i < fNpoints; i++) {
      printf("x[%d]=%g, y[%d]=%g\n", i, fX[i], i, fY[i]);
   }
}


//______________________________________________________________________________
void TGraph::RecursiveRemove(TObject *obj)
{
   // Recursively remove object from the list of functions

   if (fFunctions) {
      if (!fFunctions->TestBit(kInvalidObject)) fFunctions->RecursiveRemove(obj);
   }
   if (fHistogram == obj) fHistogram = 0;
}


//______________________________________________________________________________
Int_t TGraph::RemovePoint()
{
   // Delete point close to the mouse position

   Int_t px = gPad->GetEventX();
   Int_t py = gPad->GetEventY();

   //localize point to be deleted
   Int_t ipoint = -2;
   Int_t i;
   // start with a small window (in case the mouse is very close to one point)
   for (i = 0; i < fNpoints; i++) {
      Int_t dpx = px - gPad->XtoAbsPixel(gPad->XtoPad(fX[i]));
      Int_t dpy = py - gPad->YtoAbsPixel(gPad->YtoPad(fY[i]));
      if (dpx * dpx + dpy * dpy < 100) {
         ipoint = i;
         break;
      }
   }
   return RemovePoint(ipoint);
}


//______________________________________________________________________________
Int_t TGraph::RemovePoint(Int_t ipoint)
{
   // Delete point number ipoint

   if (ipoint < 0) return -1;
   if (ipoint >= fNpoints) return -1;

   Double_t **ps = ShrinkAndCopy(fNpoints - 1, ipoint);
   CopyAndRelease(ps, ipoint + 1, fNpoints--, ipoint);
   ShiftHighlights(ipoint, kFALSE);
   if (gPad) gPad->Modified();
   return ipoint;
}


//______________________________________________________________________________
void TGraph::SavePrimitive(ostream &out, Option_t *option /*= ""*/)
{
   // Save primitive as a C++ statement(s) on output stream out

   char quote = '"';
   out << "   " << endl;
   if (gROOT->ClassSaved(TGraph::Class())) {
      out << "   ";
   } else {
      out << "   TGraph *";
   }
   out << "graph = new TGraph(" << fNpoints << ");" << endl;
   out << "   graph->SetName(" << quote << GetName() << quote << ");" << endl;
   out << "   graph->SetTitle(" << quote << GetTitle() << quote << ");" << endl;

   SaveFillAttributes(out, "graph", 0, 1001);
   SaveLineAttributes(out, "graph", 1, 1, 1);
   SaveMarkerAttributes(out, "graph", 1, 1, 1);

   if (fNpoints >= 1) {
      streamsize prec = out.precision();
      out.precision(10);
      for (Int_t i = 0; i < fNpoints; i++) {
         out << "   graph->SetPoint(" << i << "," << fX[i] << "," << fY[i] << ");" << endl;
      }
      out.precision(prec);
   }

   static Int_t frameNumber = 0;
   if (fHistogram) {
      frameNumber++;
      TString hname = fHistogram->GetName();
      hname += frameNumber;
      fHistogram->SetName(Form("Graph_%s", hname.Data()));
      fHistogram->SavePrimitive(out, "nodraw");
      out << "   graph->SetHistogram(" << fHistogram->GetName() << ");" << endl;
      out << "   " << endl;
   }

   // save list of functions
   TIter next(fFunctions);
   TObject *obj;
   while ((obj = next())) {
      obj->SavePrimitive(out, "nodraw");
      if (obj->InheritsFrom("TPaveStats")) {
         out << "   graph->GetListOfFunctions()->Add(ptstats);" << endl;
         out << "   ptstats->SetParent(graph->GetListOfFunctions());" << endl;
      } else {
         out << "   graph->GetListOfFunctions()->Add(" << obj->GetName() << ");" << endl;
      }
   }

   const char *l;
   l = strstr(option, "multigraph");
   if (l) {
      out << "   multigraph->Add(graph," << quote << l + 10 << quote << ");" << endl;
      return;
   }
   l = strstr(option, "th2poly");
   if (l) {
      out << "   " << l + 7 << "->AddBin(graph);" << endl;
      return;
   }
   out << "   graph->Draw(" << quote << option << quote << ");" << endl;
}


//______________________________________________________________________________
void TGraph::Set(Int_t n)
{
   // Set number of points in the graph
   // Existing coordinates are preserved
   // New coordinates above fNpoints are preset to 0.

   if (n < 0) n = 0;
   if (n == fNpoints) return;
   Double_t **ps = Allocate(n);
   CopyAndRelease(ps, 0, TMath::Min(fNpoints, n), 0);
   if (n > fNpoints) {
      FillZero(fNpoints, n, kFALSE);
   }
   fNpoints = n;

   if (!fHighlights) return;
   for (Int_t i = n; i < fHighlights->GetSize(); i++) {
      TObject *obj = fHighlights->RemoveAt(i);
      if (obj && fHighlights->IsOwner()) delete obj; // if owner, then deleting associated obj
   }
   fHighlights->Expand(fNpoints);
}


//______________________________________________________________________________
Bool_t TGraph::GetEditable() const
{
   // Return kTRUE if kNotEditable bit is not set, kFALSE otherwise.

   return TestBit(kNotEditable) ? kFALSE : kTRUE;
}


//______________________________________________________________________________
void TGraph::SetEditable(Bool_t editable)
{
   // if editable=kFALSE, the graph cannot be modified with the mouse
   //  by default a TGraph is editable

   if (editable) ResetBit(kNotEditable);
   else          SetBit(kNotEditable);
}


//______________________________________________________________________________
Int_t TGraph::GetHighlightPoint()
{
   // which point is highlighted

   TVirtualGraphPainter *painter = TVirtualGraphPainter::GetPainter();
   if (painter) return painter->GetHighlightPointHelper(this);
   else return -1;
}


//______________________________________________________________________________
void TGraph::SetHighlight(Bool_t highlight)
{
   // Set highlight (enable/disble) mode for this graph
   // by default highlight mode is disable

   SetBit(kIsHighlight, highlight);

   TVirtualGraphPainter *painter = TVirtualGraphPainter::GetPainter();
   if (painter) painter->SetHighlight(this);

   //   //if (!painter) return;
   // musim vsak pridat header TGP;
   //   if (painter) painter->SetHighlight(this);
   //   if (highlight) ak je pole kresli aj pad/canvas;
   //   else           ak je pad close; (ak defcanvas -> close, inak clear pad, abo ani ne)
   // pad/canvas close()
}


//______________________________________________________________________________
void TGraph::SetHighlightPad(TVirtualPad *pad)
{
   // Set pad where will draw associated highlight object for current point of graph
   // if pad = 0 (default) will make a default canvas
   // static function (one common pad for all graphs)

   TVirtualGraphPainter *painter = TVirtualGraphPainter::GetPainter();
   if (painter) painter->SetHighlightPad(pad);
}


//______________________________________________________________________________
void TGraph::SetMaximum(Double_t maximum)
{
   // Set the maximum of the graph.

   fMaximum = maximum;
   GetHistogram()->SetMaximum(maximum);
}


//______________________________________________________________________________
void TGraph::SetMinimum(Double_t minimum)
{
   // Set the minimum of the graph.

   fMinimum = minimum;
   GetHistogram()->SetMinimum(minimum);
}


//______________________________________________________________________________
void TGraph::SetPoint(Int_t i, Double_t x, Double_t y)
{
   // Set x and y values for point number i.

   if (i < 0) return;
   if (fHistogram) {
      delete fHistogram;
      fHistogram = 0;
   }
   if (i >= fMaxSize) {
      Double_t **ps = ExpandAndCopy(i + 1, fNpoints);
      CopyAndRelease(ps, 0, 0, 0);
   }
   if (i >= fNpoints) {
      // points above i can be not initialized
      // set zero up to i-th point to avoid redefenition
      // of this method in descendant classes
      FillZero(fNpoints, i + 1);
      fNpoints = i + 1;
      if (fHighlights) fHighlights->Expand(fNpoints);
   }
   fX[i] = x;
   fY[i] = y;
   if (gPad) gPad->Modified();
}


//______________________________________________________________________________
void TGraph::SetTitle(const char* title)
{
   // Set graph title.

   fTitle = title;
   if (fHistogram) fHistogram->SetTitle(title);
}


//______________________________________________________________________________
Double_t **TGraph::ShrinkAndCopy(Int_t size, Int_t oend)
{
   // if size*2 <= fMaxSize allocate new arrays of size points,
   // copy points [0,oend).
   // Return newarray (passed or new instance if it was zero
   // and allocations are needed)
   if (size * 2 > fMaxSize || !fMaxSize) {
      return 0;
   }
   Double_t **newarrays = Allocate(size);
   CopyPoints(newarrays, 0, oend, 0);
   return newarrays;
}


//______________________________________________________________________________
void TGraph::Sort(Bool_t (*greaterfunc)(const TGraph*, Int_t, Int_t) /*=TGraph::CompareX()*/,
                  Bool_t ascending /*=kTRUE*/, Int_t low /* =0 */, Int_t high /* =-1111 */)
{
   // Sorts the points of this TGraph using in-place quicksort (see e.g. older glibc).
   // To compare two points the function parameter greaterfunc is used (see TGraph::CompareX for an
   // example of such a method, which is also the default comparison function for Sort). After
   // the sort, greaterfunc(this, i, j) will return kTRUE for all i>j if ascending == kTRUE, and
   // kFALSE otherwise.
   //
   // The last two parameters are used for the recursive quick sort, stating the range to be sorted
   //
   // Examples:
   //   // sort points along x axis
   //   graph->Sort();
   //   // sort points along their distance to origin
   //   graph->Sort(&TGraph::CompareRadius);
   //
   //   Bool_t CompareErrors(const TGraph* gr, Int_t i, Int_t j) {
   //     const TGraphErrors* ge=(const TGraphErrors*)gr;
   //     return (ge->GetEY()[i]>ge->GetEY()[j]); }
   //   // sort using the above comparison function, largest errors first
   //   graph->Sort(&CompareErrors, kFALSE);

   if (high == -1111) high = GetN() - 1;
   //  Termination condition
   if (high <= low) return;

   int left, right;
   left = low; // low is the pivot element
   right = high;
   while (left < right) {
      // move left while item < pivot
      while (left <= high && greaterfunc(this, left, low) != ascending)
         left++;
      // move right while item > pivot
      while (right > low && greaterfunc(this, right, low) == ascending)
         right--;
      if (left < right && left < high && right > low)
         SwapPoints(left, right);
   }
   // right is final position for the pivot
   if (right > low)
      SwapPoints(low, right);
   Sort(greaterfunc, ascending, low, right - 1);
   Sort(greaterfunc, ascending, right + 1, high);
}


//______________________________________________________________________________
void TGraph::Streamer(TBuffer &b)
{
   // Stream an object of class TGraph.

   if (b.IsReading()) {
      UInt_t R__s, R__c;
      Version_t R__v = b.ReadVersion(&R__s, &R__c);
      if (R__v > 2) {
         b.ReadClassBuffer(TGraph::Class(), this, R__v, R__s, R__c);
         if (fHistogram) fHistogram->SetDirectory(0);
         TIter next(fFunctions);
         TObject *obj;
         while ((obj = next())) {
            if (obj->InheritsFrom(TF1::Class())) {
               TF1 *f1 = (TF1*)obj;
               f1->SetParent(this);
            }
         }
         fMaxSize = fNpoints;
         return;
      }
      //====process old versions before automatic schema evolution
      TNamed::Streamer(b);
      TAttLine::Streamer(b);
      TAttFill::Streamer(b);
      TAttMarker::Streamer(b);
      b >> fNpoints;
      fMaxSize = fNpoints;
      fX = new Double_t[fNpoints];
      fY = new Double_t[fNpoints];
      if (R__v < 2) {
         Float_t *x = new Float_t[fNpoints];
         Float_t *y = new Float_t[fNpoints];
         b.ReadFastArray(x, fNpoints);
         b.ReadFastArray(y, fNpoints);
         for (Int_t i = 0; i < fNpoints; i++) {
            fX[i] = x[i];
            fY[i] = y[i];
         }
         delete [] y;
         delete [] x;
      } else {
         b.ReadFastArray(fX, fNpoints);
         b.ReadFastArray(fY, fNpoints);
      }
      b >> fFunctions;
      b >> fHistogram;
      if (fHistogram) fHistogram->SetDirectory(0);
      if (R__v < 2) {
         Float_t mi, ma;
         b >> mi;
         b >> ma;
         fMinimum = mi;
         fMaximum = ma;
      } else {
         b >> fMinimum;
         b >> fMaximum;
      }
      b.CheckByteCount(R__s, R__c, TGraph::IsA());
      //====end of old versions

   } else {
      b.WriteClassBuffer(TGraph::Class(), this);
   }
}


//______________________________________________________________________________
void TGraph::SwapPoints(Int_t pos1, Int_t pos2)
{
   // Swap points.

   SwapValues(fX, pos1, pos2);
   SwapValues(fY, pos1, pos2);
}


//______________________________________________________________________________
void TGraph::SwapValues(Double_t* arr, Int_t pos1, Int_t pos2)
{
   // Swap values.

   Double_t tmp = arr[pos1];
   arr[pos1] = arr[pos2];
   arr[pos2] = tmp;
}


//______________________________________________________________________________
void TGraph::UseCurrentStyle()
{
   // Set current style settings in this graph
   // This function is called when either TCanvas::UseCurrentStyle
   // or TROOT::ForceStyle have been invoked.

   if (gStyle->IsReading()) {
      SetFillColor(gStyle->GetHistFillColor());
      SetFillStyle(gStyle->GetHistFillStyle());
      SetLineColor(gStyle->GetHistLineColor());
      SetLineStyle(gStyle->GetHistLineStyle());
      SetLineWidth(gStyle->GetHistLineWidth());
      SetMarkerColor(gStyle->GetMarkerColor());
      SetMarkerStyle(gStyle->GetMarkerStyle());
      SetMarkerSize(gStyle->GetMarkerSize());
   } else {
      gStyle->SetHistFillColor(GetFillColor());
      gStyle->SetHistFillStyle(GetFillStyle());
      gStyle->SetHistLineColor(GetLineColor());
      gStyle->SetHistLineStyle(GetLineStyle());
      gStyle->SetHistLineWidth(GetLineWidth());
      gStyle->SetMarkerColor(GetMarkerColor());
      gStyle->SetMarkerStyle(GetMarkerStyle());
      gStyle->SetMarkerSize(GetMarkerSize());
   }
   if (fHistogram) fHistogram->UseCurrentStyle();

   TIter next(GetListOfFunctions());
   TObject *obj;

   while ((obj = next())) {
      obj->UseCurrentStyle();
   }
}


//______________________________________________________________________________
Int_t TGraph::Merge(TCollection* li)
{
   // Adds all graphs from the collection to this graph.
   // Returns the total number of poins in the result or -1 in case of an error.

   TIter next(li);
   while (TObject* o = next()) {
      TGraph *g = dynamic_cast<TGraph*>(o);
      if (!g) {
         Error("Merge",
               "Cannot merge - an object which doesn't inherit from TGraph found in the list");
         return -1;
      }
      DoMerge(g);
   }
   return GetN();
}
//______________________________________________________________________________
Bool_t TGraph::DoMerge(const TGraph* g)
{
   //  protected function to perform the merge operation of a graph

   Double_t x, y;
   for (Int_t i = 0 ; i < g->GetN(); i++) {
      g->GetPoint(i, x, y);
      SetPoint(GetN(), x, y);
   }
   return kTRUE;
}
//______________________________________________________________________________
void TGraph::Zero(Int_t &k, Double_t AZ, Double_t BZ, Double_t E2, Double_t &X, Double_t &Y
                  , Int_t maxiterations)
{
   // Find zero of a continuous function.
   // This function finds a real zero of the continuous real
   // function Y(X) in a given interval (A,B). See accompanying
   // notes for details of the argument list and calling sequence

   static Double_t a, b, ya, ytest, y1, x1, h;
   static Int_t j1, it, j3, j2;
   Double_t yb, x2;
   yb = 0;

   //       Calculate Y(X) at X=AZ.
   if (k <= 0) {
      a  = AZ;
      b  = BZ;
      X  = a;
      j1 = 1;
      it = 1;
      k  = j1;
      return;
   }

   //       Test whether Y(X) is sufficiently small.

   if (TMath::Abs(Y) <= E2) {
      k = 2;
      return;
   }

   //       Calculate Y(X) at X=BZ.

   if (j1 == 1) {
      ya = Y;
      X  = b;
      j1 = 2;
      return;
   }
   //       Test whether the signs of Y(AZ) and Y(BZ) are different.
   //       if not, begin the binary subdivision.

   if (j1 != 2) goto L100;
   if (ya * Y < 0) goto L120;
   x1 = a;
   y1 = ya;
   j1 = 3;
   h  = b - a;
   j2 = 1;
   x2 = a + 0.5 * h;
   j3 = 1;
   it++;      //*-*-   Check whether (maxiterations) function values have been calculated.
   if (it >= maxiterations) k = j1;
   else                     X = x2;
   return;

   //      Test whether a bracket has been found .
   //      If not,continue the search

L100:
   if (j1 > 3) goto L170;
   if (ya*Y >= 0) {
      if (j3 >= j2) {
         h  = 0.5 * h;
         j2 = 2 * j2;
         a  = x1;
         ya = y1;
         x2 = a + 0.5 * h;
         j3 = 1;
      } else {
         a  = X;
         ya = Y;
         x2 = X + h;
         j3++;
      }
      it++;
      if (it >= maxiterations) k = j1;
      else                     X = x2;
      return;
   }

   //       The first bracket has been found.calculate the next X by the
   //       secant method based on the bracket.

L120:
   b  = X;
   yb = Y;
   j1 = 4;
L130:
   if (TMath::Abs(ya) > TMath::Abs(yb)) {
      x1 = a;
      y1 = ya;
      X  = b;
      Y  = yb;
   } else                                 {
      x1 = b;
      y1 = yb;
      X  = a;
      Y  = ya;
   }

   //       Use the secant method based on the function values y1 and Y.
   //       check that x2 is inside the interval (a,b).

L150:
   x2    = X - Y * (X - x1) / (Y - y1);
   x1    = X;
   y1    = Y;
   ytest = 0.5 * TMath::Min(TMath::Abs(ya), TMath::Abs(yb));
   if ((x2 - a)*(x2 - b) < 0) {
      it++;
      if (it >= maxiterations) k = j1;
      else                     X = x2;
      return;
   }

   //       Calculate the next value of X by bisection . Check whether
   //       the maximum accuracy has been achieved.

L160:
   x2    = 0.5 * (a + b);
   ytest = 0;
   if ((x2 - a)*(x2 - b) >= 0) {
      k = 2;
      return;
   }
   it++;
   if (it >= maxiterations) k = j1;
   else                     X = x2;
   return;


   //       Revise the bracket (a,b).

L170:
   if (j1 != 4) return;
   if (ya * Y < 0) {
      b  = X;
      yb = Y;
   } else          {
      a  = X;
      ya = Y;
   }

   //       Use ytest to decide the method for the next value of X.

   if (ytest <= 0) goto L130;
   if (TMath::Abs(Y) - ytest <= 0) goto L150;
   goto L160;
}
// @(#)root/hist:$Id$
// Author: Rene Brun, Olivier Couet   12/12/94

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#ifndef ROOT_TGraph
#define ROOT_TGraph


//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TGraph                                                               //
//                                                                      //
// Graph graphics class.                                                //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#ifndef ROOT_TNamed
#include "TNamed.h"
#endif
#ifndef ROOT_TAttLine
#include "TAttLine.h"
#endif
#ifndef ROOT_TAttFill
#include "TAttFill.h"
#endif
#ifndef ROOT_TAttMarker
#include "TAttMarker.h"
#endif
#ifndef ROOT_TVectorFfwd
#include "TVectorFfwd.h"
#endif
#ifndef ROOT_TVectorDfwd
#include "TVectorDfwd.h"
#endif

class TBrowser;
class TAxis;
class TH1;
class TH1F;
class TCollection;
class TF1;
class TSpline;
class TVirtualPad;

#include "TFitResultPtr.h"

class TGraph : public TNamed, public TAttLine, public TAttFill, public TAttMarker {

protected:

   Int_t              fMaxSize;   //!Current dimension of arrays fX and fY
   Int_t              fNpoints;   //Number of points <= fMaxSize
   Double_t          *fX;         //[fNpoints] array of X points
   Double_t          *fY;         //[fNpoints] array of Y points
   TList             *fFunctions; //Pointer to list of functions (fits and user)
   TObjArray         *fHighlights;//!Pointer to array of highlight objects (user)
   TH1F              *fHistogram; //Pointer to histogram used for drawing axis
   Double_t           fMinimum;   //Minimum value for plotting along y
   Double_t           fMaximum;   //Maximum value for plotting along y

   static void        SwapValues(Double_t* arr, Int_t pos1, Int_t pos2);
   virtual void       SwapPoints(Int_t pos1, Int_t pos2);

   virtual Double_t **Allocate(Int_t newsize);
   Double_t         **AllocateArrays(Int_t Narrays, Int_t arraySize);
   virtual Bool_t     CopyPoints(Double_t **newarrays, Int_t ibegin, Int_t iend, Int_t obegin);
   virtual void       CopyAndRelease(Double_t **newarrays, Int_t ibegin, Int_t iend, Int_t obegin);
   Bool_t             CtorAllocate();
   Double_t         **ExpandAndCopy(Int_t size, Int_t iend);
   virtual void       FillZero(Int_t begin, Int_t end, Bool_t from_ctor = kTRUE);
   Double_t         **ShrinkAndCopy(Int_t size, Int_t iend);
   virtual void       ShiftHighlights(Int_t pos, Bool_t insert);
   virtual Bool_t     DoMerge(const TGraph * g);

public:
   // TGraph status bits
   enum {
      kClipFrame     = BIT(10),  // clip to the frame boundary
      kNotEditable   = BIT(18),  // bit set if graph is non editable
      kIsHighlight   = BIT(19)   // bit set if graph is highlight
   };

   TGraph();
   TGraph(Int_t n);
   TGraph(Int_t n, const Int_t *x, const Int_t *y);
   TGraph(Int_t n, const Float_t *x, const Float_t *y);
   TGraph(Int_t n, const Double_t *x, const Double_t *y);
   TGraph(const TGraph &gr);
   TGraph& operator=(const TGraph&);
   TGraph(const TVectorF &vx, const TVectorF &vy);
   TGraph(const TVectorD &vx, const TVectorD &vy);
   TGraph(const TH1 *h);
   TGraph(const TF1 *f, Option_t *option="");
   TGraph(const char *filename, const char *format="%lg %lg", Option_t *option="");
   virtual ~TGraph();

   virtual void          AddHighlight(Int_t ipoint, TObject *obj);
   virtual void          Apply(TF1 *f);
   virtual void          Browse(TBrowser *b);
   virtual Double_t      Chisquare(const TF1 *f1, Option_t *option="") const;
   static Bool_t         CompareArg(const TGraph* gr, Int_t left, Int_t right);
   static Bool_t         CompareX(const TGraph* gr, Int_t left, Int_t right);
   static Bool_t         CompareY(const TGraph* gr, Int_t left, Int_t right);
   static Bool_t         CompareRadius(const TGraph* gr, Int_t left, Int_t right);
   virtual void          ComputeRange(Double_t &xmin, Double_t &ymin, Double_t &xmax, Double_t &ymax) const;
   virtual Int_t         DistancetoPrimitive(Int_t px, Int_t py);
   virtual void          Draw(Option_t *chopt="");
   virtual void          DrawGraph(Int_t n, const Int_t *x, const Int_t *y, Option_t *option="");
   virtual void          DrawGraph(Int_t n, const Float_t *x, const Float_t *y, Option_t *option="");
   virtual void          DrawGraph(Int_t n, const Double_t *x=0, const Double_t *y=0, Option_t *option="");
   virtual void          DrawPanel(); // *MENU*
   virtual Double_t      Eval(Double_t x, TSpline *spline=0, Option_t *option="") const;
   virtual void          ExecuteEvent(Int_t event, Int_t px, Int_t py);
   virtual void          Expand(Int_t newsize);
   virtual void          Expand(Int_t newsize, Int_t step);
   virtual TObject      *FindObject(const char *name) const;
   virtual TObject      *FindObject(const TObject *obj) const;
   virtual TFitResultPtr Fit(const char *formula ,Option_t *option="" ,Option_t *goption="", Axis_t xmin=0, Axis_t xmax=0); // *MENU*
   virtual TFitResultPtr Fit(TF1 *f1 ,Option_t *option="" ,Option_t *goption="", Axis_t xmin=0, Axis_t xmax=0);
   virtual void          FitPanel(); // *MENU*
   Bool_t                GetEditable() const;
   TF1                  *GetFunction(const char *name) const;
   virtual Int_t         GetHighlightPoint();
   TH1F                 *GetHistogram() const;
   TObjArray            *GetListOfHighlights() const { return fHighlights; }
   TList                *GetListOfFunctions() const { return fFunctions; }
   virtual Double_t      GetCorrelationFactor() const;
   virtual Double_t      GetCovariance() const;
   virtual Double_t      GetMean(Int_t axis=1) const;
   virtual Double_t      GetRMS(Int_t axis=1) const;
   Int_t                 GetMaxSize() const {return fMaxSize;}
   Int_t                 GetN() const {return fNpoints;}
   virtual Double_t      GetErrorX(Int_t bin) const;
   virtual Double_t      GetErrorY(Int_t bin) const;
   virtual Double_t      GetErrorXhigh(Int_t bin) const;
   virtual Double_t      GetErrorXlow(Int_t bin)  const;
   virtual Double_t      GetErrorYhigh(Int_t bin) const;
   virtual Double_t      GetErrorYlow(Int_t bin)  const;
   Double_t             *GetX()  const {return fX;}
   Double_t             *GetY()  const {return fY;}
   virtual Double_t     *GetEX() const {return 0;}
   virtual Double_t     *GetEY() const {return 0;}
   virtual Double_t     *GetEXhigh() const {return 0;}
   virtual Double_t     *GetEXlow()  const {return 0;}
   virtual Double_t     *GetEYhigh() const {return 0;}
   virtual Double_t     *GetEYlow()  const {return 0;}
   virtual Double_t     *GetEXlowd()  const {return 0;}
   virtual Double_t     *GetEXhighd() const {return 0;}
   virtual Double_t     *GetEYlowd()  const {return 0;}
   virtual Double_t     *GetEYhighd() const {return 0;}
   Double_t              GetMaximum()  const {return fMaximum;}
   Double_t              GetMinimum()  const {return fMinimum;}
   TAxis                *GetXaxis() const ;
   TAxis                *GetYaxis() const ;
   virtual Int_t         GetPoint(Int_t i, Double_t &x, Double_t &y) const;

   virtual void          InitExpo(Double_t xmin=0, Double_t xmax=0);
   virtual void          InitGaus(Double_t xmin=0, Double_t xmax=0);
   virtual void          InitPolynom(Double_t xmin=0, Double_t xmax=0);
   virtual Int_t         InsertPoint(); // *MENU*
   virtual Double_t      Integral(Int_t first=0, Int_t last=-1) const;
   virtual Bool_t        IsEditable() const {return !TestBit(kNotEditable);}
   virtual Bool_t        IsHighlight() const { return TestBit(kIsHighlight); }
   virtual Int_t         IsInside(Double_t x, Double_t y) const;
   virtual void          LeastSquareFit(Int_t m, Double_t *a, Double_t xmin=0, Double_t xmax=0);
   virtual void          LeastSquareLinearFit(Int_t n, Double_t &a0, Double_t &a1, Int_t &ifail, Double_t xmin=0, Double_t xmax=0);
   virtual Int_t         Merge(TCollection* list);
   virtual void          Paint(Option_t *chopt="");
   void                  PaintGraph(Int_t npoints, const Double_t *x, const Double_t *y, Option_t *chopt);
   void                  PaintGrapHist(Int_t npoints, const Double_t *x, const Double_t *y, Option_t *chopt); 
   virtual void          PaintStats(TF1 *fit);
   virtual void          Print(Option_t *chopt="") const;
   virtual void          RecursiveRemove(TObject *obj);
   virtual Int_t         RemovePoint(); // *MENU*
   virtual Int_t         RemovePoint(Int_t ipoint);
   virtual void          SavePrimitive(ostream &out, Option_t *option = "");
   virtual void          SetEditable(Bool_t editable=kTRUE); // *TOGGLE* *GETTER=GetEditable
   virtual void          SetHighlight(Bool_t highlight = kTRUE); // *TOGGLE* *GETTER=IsHighlight
   static void           SetHighlightPad(TVirtualPad *pad = 0);
   virtual void          SetHistogram(TH1F *h) {fHistogram = h;}
   virtual void          SetMaximum(Double_t maximum=-1111); // *MENU*
   virtual void          SetMinimum(Double_t minimum=-1111); // *MENU*
   virtual void          Set(Int_t n);
   virtual void          SetPoint(Int_t i, Double_t x, Double_t y);
   virtual void          SetTitle(const char *title="");    // *MENU*
   virtual void          Sort(Bool_t (*greater)(const TGraph*, Int_t, Int_t)=&TGraph::CompareX,
                              Bool_t ascending=kTRUE, Int_t low=0, Int_t high=-1111);
   virtual void          UseCurrentStyle();
   void                  Zero(Int_t &k,Double_t AZ,Double_t BZ,Double_t E2,Double_t &X,Double_t &Y,Int_t maxiterations);

   ClassDef(TGraph,4)  //Graph graphics class
};

inline Double_t **TGraph::Allocate(Int_t newsize) {
   return AllocateArrays(2, newsize);
}

#endif
// @(#)root/histpainter:$Id: TGraphPainter.cxx,v 1.00
// Author: Olivier Couet

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "TROOT.h"
#include "TGraphPainter.h"
#include "TMath.h"
#include "TGraph.h"
#include "TPolyLine.h"
#include "TPolyMarker.h"
#include "TVirtualPad.h"
#include "TView.h"
#include "TStyle.h"
#include "TH1.h"
#include "TF1.h"
#include "TPaveStats.h"
#include "TGaxis.h"
#include "TGraphAsymmErrors.h"
#include "TGraphBentErrors.h"
#include "TGraphPolargram.h"
#include "TGraphPolar.h"
#include "TGraphQQ.h"
#include "TLatex.h"
#include "TArrow.h"
#include "TFrame.h"
#include "TVirtualPadEditor.h"

Double_t *gxwork, *gywork, *gxworkl, *gyworkl;

ClassImp(TGraphPainter);


//______________________________________________________________________________
/* Begin_Html
<center><h2>The graph painter class</h2></center>

<ul>
<li><a href="#GP00">Introduction</li></a>
<li><a href="#GP01">Graphs' plotting options</li></a>
<li><a href="#GP02">Exclusion graphs</li></a>
<li><a href="#GP03">Graphs with error bars</li></a>
<ul>
<li><a href="#GP03a">TGraphErrors</li></a>
<li><a href="#GP03b">TGraphAsymmErrors</li></a>
<li><a href="#GP03c">TGraphBentErrors</li></a>
</ul>
<li><a href="#GP04">TGraphPolar options</li></a>
</ul>

<a name="GP00"></a><h3>Introduction</h3>

Graphs are drawn via the painter <tt>TGraphPainter</tt> class. This class
implements techniques needed to display the various kind of
graphs i.e.: <tt>TGraph</tt>, <tt>TGraphErrors</tt>,
<tt>TGraphBentErrors</tt> and <tt>TGraphAsymmErrors</tt>.

<p>
To draw a graph "<tt>graph</tt>" it's enough to do:
<pre>
   graph->Draw("AL");
</pre>


<p>The option <tt>"AL"</tt> in the <tt>Draw()</tt> method means:
<ol>
<li>The axis should be drawn (option <tt>"A"</tt>),</li>
<li>The graph should be drawn as a simple line (option <tt>"L"</tt>).</li>
</ol>
By default a graph is drawn in the current pad in the current coordinate system.
To define a suitable coordinate system and draw the axis the option
<tt>"A"</tt> must be specified.
<p>
<tt>TGraphPainter</tt> offers many options to paint the various kind of graphs.
<p>
It is separated from the graph classes so that one can have graphs without the
graphics overhead, for example in a batch program.
<p>
When a displayed graph is modified, there is no need to call
<tt>Draw()</tt> again; the image will be refreshed the next time the
pad will be updated.
<p>A pad is updated after one of these three actions:
<ol>
<li>  a carriage return on the ROOT command line,
<li>  a click inside the pad,
<li>  a call to <tt>TPad::Update</tt>.
</ol>

<a name="GP01"></a><h3>Graphs' plotting options</h3>
Graphs can be drawn with the following options:
<p>
<table border=0>

<tr><th valign=top>"A"</th><td>
Axis are drawn around the graph
</td></tr>

<tr><th valign=top>"L"</th><td>
A simple polyline is drawn
</td></tr>

<tr><th valign=top>"F"</th><td>
A fill area is drawn ('CF' draw a smoothed fill area)
</td></tr>

<tr><th valign=top>"C"</th><td>
A smooth Curve is drawn
</td></tr>

<tr><th valign=top>"*"</th><td>
A Star is plotted at each point
</td></tr>

<tr><th valign=top>"P"</th><td>
The current marker is plotted at each point
</td></tr>

<tr><th valign=top>"B"</th><td>
A Bar chart is drawn
</td></tr>

<tr><th valign=top>"1"</th><td>
When a graph is drawn as a bar chart, this option makes the bars start from
the bottom of the pad. By default they start at 0.
</td></tr>

<tr><th valign=top>"X+"</th><td>
The X-axis is drawn on the top side of the plot.
</td></tr>

<tr><th valign=top>"Y+"</th><td>
The Y-axis is drawn on the right side of the plot.
</td></tr>

</table>
<p>

Drawing options can be combined. In the following example the graph
is drawn as a smooth curve (option "C") with markers (option "P") and
with axes (option "A").

End_Html
Begin_Macro(source)
{
   TCanvas *c1 = new TCanvas("c1","c1",200,10,600,400);

   c1->SetFillColor(42);
   c1->SetGrid();

   const Int_t n = 20;
   Double_t x[n], y[n];
   for (Int_t i=0;i<n;i++) {
      x[i] = i*0.1;
      y[i] = 10*sin(x[i]+0.2);
   }
   gr = new TGraph(n,x,y);
   gr->SetLineColor(2);
   gr->SetLineWidth(4);
   gr->SetMarkerColor(4);
   gr->SetMarkerSize(1.5);
   gr->SetMarkerStyle(21);
   gr->SetTitle("Option ACP example");
   gr->GetXaxis()->SetTitle("X title");
   gr->GetYaxis()->SetTitle("Y title");
   gr->Draw("ACP");

   // TCanvas::Update() draws the frame, after which one can change it
   c1->Update();
   c1->GetFrame()->SetFillColor(21);
   c1->GetFrame()->SetBorderSize(12);
   c1->Modified();
   return c1;
}
End_Macro
Begin_Html

<p>The following macro shows the option "B" usage. It can be combined with the
option "1".

End_Html
Begin_Macro(source)
{
   TCanvas *c47 = new TCanvas("c47","c47",200,10,600,400);
   c47->Divide(1,2);
   const Int_t n = 20;
   Double_t x[n], y[n];
   for (Int_t i=0;i<n;i++) {
      x[i] = i*0.1;
      y[i] = 10*sin(x[i]+0.2)-6;
   }
   gr = new TGraph(n,x,y);
   gr->SetFillColor(38);
   c47->cd(1); gr->Draw("AB");
   c47->cd(2); gr->Draw("AB1");
 return c47;
}
End_Macro
Begin_Html

<a name="GP02"></a><h3>Exclusion graphs</h3>

When a graph is painted with the option <tt>"C"</tt> or <tt>"L"</tt> it is
possible to draw a filled area on one side of the line. This is useful to show
exclusion zones.

<p>This drawing mode is activated when the absolute value of the graph line
width (set by <tt>SetLineWidth()</tt>) is greater than 99. In that
case the line width number is interpreted as:
<pre>
      100*ff+ll = ffll
</pre>
<ul>
<li> The two digits number <tt>"ll"</tt> represent the normal line width
<li> The two digits number  <tt>"ff"</tt> represent the filled area width.
<li> The sign of "ffll" allows to flip the filled area from one side of the line
     to the other.
</ul>
The current fill area attributes are used to draw the hatched zone.

End_Html
Begin_Macro(source)
../../../tutorials/graphs/exclusiongraph.C
End_Macro
Begin_Html

<a name="GP03"></a><h3>Graphs with error bars</h3>
Three classes are available to handle graphs with error bars:
<tt>TGraphErrors</tt>, <tt>TGraphAsymmErrors</tt> and <tt>TGraphBentErrors</tt>.
The following drawing options are specific to graphs with error bars:
<p>
<table border=0>

<tr><th valign=top>"Z"</th><td>
Do not draw small horizontal and vertical lines the end of the error bars.
Without "Z", the default is to draw these.
</td></tr>

<tr><th valign=top>">"</th><td>
An arrow is drawn at the end of the error bars.
The size of the arrow is set to 2/3 of the marker size.
</td></tr>

<tr><th valign=top>"|>"</th><td>
A filled arrow is drawn at the end of the error bars.
The size of the arrow is set to 2/3 of the marker size.
</td></tr>

<tr><th valign=top>"X"</th><td>
Do not draw error bars.  By default, graph classes that have errors
are drawn with the errors (TGraph itself has no errors, and so this option
has no effect.)
</td></tr>

<tr><th valign=top>"||"</th><td>
Draw only the small vertical/horizontal lines at the ends of the
error bars, without drawing the bars themselves. This option is
interesting to superimpose statistical-only errors on top of a graph
with statistical+systematic errors.
</td></tr>

<tr><th valign=top>"[]"</th><td>
Does the same as option "||" except that it draws additional marks at the
ends of the small vertical/horizontal lines. It makes plots less ambiguous
in case several graphs are drawn on the same picture.
</td></tr>

<tr><th valign=top>"0"</th><td>
By default, when a data point is outside the visible range along the Y
axis, the error bars are not drawn. This option forces error bars' drawing for
the data points outside the visible range along the Y axis (see example below).
</td></tr>

<tr><th valign=top>"2"</th><td>
Error rectangles are drawn.
</td></tr>

<tr><th valign=top>"3"</th><td>
A filled area is drawn through the end points of the vertical error bars.
</td></tr>

<tr><th valign=top>"4"</th><td>
A smoothed filled area is drawn through the end points of the vertical error
bars.
</td></tr>

<tr><th valign=top>"5"</th><td>
Error rectangles are drawn like option "2". In addition the contour line
around the boxes is drawn. This can be useful when boxes' fill colors are very
light or in gray scale mode.
</td></tr>
</table>
<p>
<tt>gStyle->SetErrorX(dx)</tt> controls the size of the error along x.
<tt>dx = 0</tt> removes the error along x.
<p>
<tt>gStyle->SetEndErrorSize(np)</tt> controls the size of the lines
at the end of the error bars (when option 1 is used).
By default <tt>np=1</tt>. (np represents the number of pixels).

<a name="GP03a"></a><h4><u>TGraphErrors</u></h4>
A <tt>TGraphErrors</tt> is a <tt>TGraph</tt> with error bars. The errors are
defined along X and Y and are symmetric: The left and right errors are the same
along X and the bottom and up errors are the same along Y.

End_Html
Begin_Macro(source)
{
   TCanvas *c4 = new TCanvas("c4","c4",200,10,600,400);
   double x[] = {0, 1, 2, 3, 4};
   double y[] = {0, 2, 4, 1, 3};
   double ex[] = {0.1, 0.2, 0.3, 0.4, 0.5};
   double ey[] = {1, 0.5, 1, 0.5, 1};
   TGraphErrors* ge = new TGraphErrors(5, x, y, ex, ey);
   ge->Draw("ap");
   return c4;
}
End_Macro
Begin_Html

<p>The option "0" shows the error bars for data points outside range.

End_Html
Begin_Macro(source)
{
   TCanvas *c48 = new TCanvas("c48","c48",200,10,600,400);
   float x[]     = {1,2,3};
   float err_x[] = {0,0,0};
   float err_y[] = {5,5,5};
   float y[]     = {1,4,9};
   TGraphErrors tg(3,x,y,err_x,err_y);
   c48->Divide(2,1);
   c48->cd(1); gPad->DrawFrame(0,0,4,8); tg.Draw("PC");
   c48->cd(2); gPad->DrawFrame(0,0,4,8); tg.Draw("0PC");
   return c48;
}
End_Macro
Begin_Html

<p>The option "3" shows the errors as a band.

End_Html
Begin_Macro(source)
{
   TCanvas *c41 = new TCanvas("c41","c41",200,10,600,400);
   double x[] = {0, 1, 2, 3, 4};
   double y[] = {0, 2, 4, 1, 3};
   double ex[] = {0.1, 0.2, 0.3, 0.4, 0.5};
   double ey[] = {1, 0.5, 1, 0.5, 1};
   TGraphErrors* ge = new TGraphErrors(5, x, y, ex, ey);
   ge->SetFillColor(4);
   ge->SetFillStyle(3010);
   ge->Draw("a3");
   return c41;
}
End_Macro
Begin_Html

<p>The option "4" is similar to the option "3" except that the band
is smoothed. As the following picture shows, this option should be
used carefully because the smoothing algorithm may show some (huge)
"bouncing" effects. In some cases it looks nicer than option "3"
(because it is smooth) but it can be misleading.

End_Html
Begin_Macro(source)
{
   TCanvas *c42 = new TCanvas("c42","c42",200,10,600,400);
   double x[] = {0, 1, 2, 3, 4};
   double y[] = {0, 2, 4, 1, 3};
   double ex[] = {0.1, 0.2, 0.3, 0.4, 0.5};
   double ey[] = {1, 0.5, 1, 0.5, 1};
   TGraphErrors* ge = new TGraphErrors(5, x, y, ex, ey);
   ge->SetFillColor(6);
   ge->SetFillStyle(3005);
   ge->Draw("a4");
   return c42;
}
End_Macro
Begin_Html

<p>The following example shows how the option "[]" can be used to superimpose
systematic errors on top of a graph with statistical errors.

End_Html
Begin_Macro(source)
{
   TCanvas *c43 = new TCanvas("c43","c43",200,10,600,400);
   c43->DrawFrame(0., -0.5, 6., 2);

   double x[5]    = {1, 2, 3, 4, 5};
   double zero[5] = {0, 0, 0, 0, 0};

   // data set (1) with stat and sys errors
   double py1[5]      = {1.2, 1.15, 1.19, 0.9, 1.4};
   double ey_stat1[5] = {0.2, 0.18, 0.17, 0.2, 0.4};
   double ey_sys1[5]  = {0.5, 0.71, 0.76, 0.5, 0.45};

   // data set (2) with stat and sys errors
   double y2[5]       = {0.25, 0.18, 0.29, 0.2, 0.21};
   double ey_stat2[5] = {0.2, 0.18, 0.17, 0.2, 0.4};
   double ey_sys2[5]  = {0.63, 0.19, 0.7, 0.2, 0.7};

   // Now draw data set (1)

   // We first have to draw it only with the stat errors
   TGraphErrors *graph1 = new TGraphErrors(5, x, py1, zero, ey_stat1);
   graph1->SetMarkerStyle(20);
   graph1->Draw("P");

   // Now we have to somehow depict the sys errors

   TGraphErrors *graph1_sys = new TGraphErrors(5, x, py1, zero, ey_sys1);
   graph1_sys->Draw("[]");

   // Now draw data set (2)

   // We first have to draw it only with the stat errors
   TGraphErrors *graph2 = new TGraphErrors(5, x, y2, zero, ey_stat2);
   graph2->SetMarkerStyle(24);
   graph2->Draw("P");

   // Now we have to somehow depict the sys errors

   TGraphErrors *graph2_sys = new TGraphErrors(5, x, y2, zero, ey_sys2);
   graph2_sys->Draw("[]");
   return c43;
}
End_Macro
Begin_Html

<a name="GP03b"></a><h4><u>TGraphAsymmErrors</u></h4>
A <tt>TGraphAsymmErrors</tt> is like a <tt>TGraphErrors</tt> but the errors
defined along X and Y are not symmetric: The left and right errors are
different along X and the bottom and up errors are different along Y.

End_Html
Begin_Macro(source)
{
   TCanvas *c44 = new TCanvas("c44","c44",200,10,600,400);
   double ax[] = {0, 1, 2, 3, 4};
   double ay[] = {0, 2, 4, 1, 3};
   double aexl[] = {0.1, 0.2, 0.3, 0.4, 0.5};
   double aexh[] = {0.5, 0.4, 0.3, 0.2, 0.1};
   double aeyl[] = {1, 0.5, 1, 0.5, 1};
   double aeyh[] = {0.5, 1, 0.5, 1, 0.5};
   TGraphAsymmErrors* gae = new TGraphAsymmErrors(5, ax, ay, aexl, aexh, aeyl, aeyh);
   gae->SetFillColor(2);
   gae->SetFillStyle(3001);
   gae->Draw("a2");
   gae->Draw("p");
   return c44;
}
End_Macro
Begin_Html


<a name="GP03c"></a><h4><u>TGraphBentErrors</u></h4>
A <tt>TGraphBentErrors</tt> is like a <tt>TGraphAsymmErrors</tt>.
An extra parameter allows to bend the error bars to better see them
when several graphs are drawn on the same plot.

End_Html
Begin_Macro(source)
{
   TCanvas *c45 = new TCanvas("c45","c45",200,10,600,400);
   const Int_t n = 10;
   Double_t x[n]  = {-0.22, 0.05, 0.25, 0.35, 0.5, 0.61,0.7,0.85,0.89,0.95};
   Double_t y[n]  = {1,2.9,5.6,7.4,9,9.6,8.7,6.3,4.5,1};
   Double_t exl[n] = {.05,.1,.07,.07,.04,.05,.06,.07,.08,.05};
   Double_t eyl[n] = {.8,.7,.6,.5,.4,.4,.5,.6,.7,.8};
   Double_t exh[n] = {.02,.08,.05,.05,.03,.03,.04,.05,.06,.03};
   Double_t eyh[n] = {.6,.5,.4,.3,.2,.2,.3,.4,.5,.6};
   Double_t exld[n] = {.0,.0,.0,.0,.0,.0,.0,.0,.0,.0};
   Double_t eyld[n] = {.0,.0,.05,.0,.0,.0,.0,.0,.0,.0};
   Double_t exhd[n] = {.0,.0,.0,.0,.0,.0,.0,.0,.0,.0};
   Double_t eyhd[n] = {.0,.0,.0,.0,.0,.0,.0,.0,.05,.0};
   TGraphBentErrors *gr = new TGraphBentErrors(n,x,y,exl,exh,eyl,eyh,exld,exhd,eyld,eyhd);
   gr->SetTitle("TGraphBentErrors Example");
   gr->SetMarkerColor(4);
   gr->SetMarkerStyle(21);
   gr->Draw("ALP");
   return c45;
}
End_Macro
Begin_Html


<a name="GP04"></a><h3>TGraphPolar options</h3>

The drawing options for the polar graphs are the following:

<table border=0>

<tr><th valign=top>"O"</th><td>
Polar labels are drawn orthogonally to the polargram radius.
</td></tr>

<tr><th valign=top>"P"</th><td>
Polymarker are drawn at each point position.
</td></tr>

<tr><th valign=top>"E"</th><td>
Draw error bars.
</td></tr>

<tr><th valign=top>"F"</th><td>
Draw fill area (closed polygon).
</td></tr>

<tr><th valign=top>"A"</th><td>
Force axis redrawing even if a polargram already exists.
</td></tr>

<tr><th valign=top>"N"</th><td>
Disable the display of the polar labels.
</td></tr>

</table>

End_Html
Begin_Macro(source)
{
   TCanvas *c46 = new TCanvas("c46","c46",500,500);
   TGraphPolar * grP1 = new TGraphPolar();
   grP1->SetTitle("TGraphPolar example");

   grP1->SetPoint(0, (1*TMath::Pi())/4., 0.05);
   grP1->SetPoint(1, (2*TMath::Pi())/4., 0.10);
   grP1->SetPoint(2, (3*TMath::Pi())/4., 0.15);
   grP1->SetPoint(3, (4*TMath::Pi())/4., 0.20);
   grP1->SetPoint(4, (5*TMath::Pi())/4., 0.25);
   grP1->SetPoint(5, (6*TMath::Pi())/4., 0.30);
   grP1->SetPoint(6, (7*TMath::Pi())/4., 0.35);
   grP1->SetPoint(7, (8*TMath::Pi())/4., 0.40);

   grP1->SetMarkerStyle(20);
   grP1->SetMarkerSize(1.);
   grP1->SetMarkerColor(4);
   grP1->SetLineColor(4);
   grP1->Draw("ALP");

   // Update, otherwise GetPolargram returns 0
   c46->Update();
   grP1->GetPolargram()->SetToRadian();

   return c46;
}
End_Macro
Begin_Html

End_Html */


//______________________________________________________________________________
TGraphPainter::TGraphPainter()
{
   /* Begin_Html
   Default constructor
   End_Html */
}


//______________________________________________________________________________
TGraphPainter::~TGraphPainter()
{
   /* Begin_Html
   Destructor.
   End_Html */
}


//______________________________________________________________________________
void TGraphPainter::ComputeLogs(Int_t npoints, Int_t opt)
{
   /* Begin_Html
   Compute the logarithm of global variables <tt>gxwork</tt> and <tt>gywork</tt>
   according to the value of Options and put the results in the global
   variables <tt>gxworkl</tt> and <tt>gyworkl</tt>.
   <p>
   npoints : Number of points in gxwork and in gywork.
   <ul>
   <li> opt = 1 ComputeLogs is called from PaintGrapHist
   <li> opt = 0 ComputeLogs is called from PaintGraph
   </ul>
   End_Html */

   Int_t i;
   memcpy(gxworkl,gxwork,npoints*8);
   memcpy(gyworkl,gywork,npoints*8);
   if (gPad->GetLogx()) {
      for (i=0;i<npoints;i++) {
         if (gxworkl[i] > 0) gxworkl[i] = TMath::Log10(gxworkl[i]);
         else                gxworkl[i] = gPad->GetX1();
      }
   }
   if (!opt && gPad->GetLogy()) {
      for (i=0;i<npoints;i++) {
         if (gyworkl[i] > 0) gyworkl[i] = TMath::Log10(gyworkl[i]);
         else                gyworkl[i] = gPad->GetY1();
      }
   }
}


//______________________________________________________________________________
Int_t TGraphPainter::DistancetoPrimitiveHelper(TGraph *theGraph, Int_t px, Int_t py)
{
   /* Begin_Html
   Compute distance from point px,py to a graph.
   <p>
   Compute the closest distance of approach from point px,py to this line.
   The distance is computed in pixels units.
   End_Html */

   // Are we on the axis?
   Int_t distance;
   if (theGraph->GetHistogram()) {
      distance = theGraph->GetHistogram()->DistancetoPrimitive(px,py);
      if (distance <= 5) return distance;
   }

   // Somewhere on the graph points?
   const Int_t big = 9999;
   const Int_t kMaxDiff = 10;
   Int_t puxmin = gPad->XtoAbsPixel(gPad->GetUxmin());
   Int_t puymin = gPad->YtoAbsPixel(gPad->GetUymin());
   Int_t puxmax = gPad->XtoAbsPixel(gPad->GetUxmax());
   Int_t puymax = gPad->YtoAbsPixel(gPad->GetUymax());

   // return if point is not in the graph area
   if (px <= puxmin) return big;
   if (py >= puymin) return big;
   if (px >= puxmax) return big;
   if (py <= puymax) return big;

   // check if point is near one of the graph points
   Int_t i, pxp, pyp, d;
   distance = big;

   Int_t theNpoints = theGraph->GetN();
   Double_t *theX, *theY;
   if (theGraph->InheritsFrom(TGraphPolar::Class())) {
      TGraphPolar *theGraphPolar = (TGraphPolar*) theGraph;
      theX   = theGraphPolar->GetXpol();
      theY   = theGraphPolar->GetYpol();
   } else {
      theX   = theGraph->GetX();
      theY   = theGraph->GetY();
   }

   for (i=0;i<theNpoints;i++) {
      pxp = gPad->XtoAbsPixel(gPad->XtoPad(theX[i]));
      pyp = gPad->YtoAbsPixel(gPad->YtoPad(theY[i]));
      d   = TMath::Abs(pxp-px) + TMath::Abs(pyp-py);
      if (d < distance) distance = d;
   }
   if (distance < kMaxDiff) return distance;

   for (i=0;i<theNpoints-1;i++) {
      TAttLine l;
      d = l.DistancetoLine(px, py, gPad->XtoPad(theX[i]), gPad->YtoPad(theY[i]), gPad->XtoPad(theX[i+1]), gPad->YtoPad(theY[i+1]));
      if (d < distance) distance = d;
   }

   // If graph has been drawn with the fill area option, check if we are inside
   TString drawOption = theGraph->GetDrawOption();
   drawOption.ToLower();
   if (drawOption.Contains("f")) {
      Double_t xp = gPad->AbsPixeltoX(px); xp = gPad->PadtoX(xp);
      Double_t yp = gPad->AbsPixeltoY(py); yp = gPad->PadtoY(yp);
      if (TMath::IsInside(xp,yp,theNpoints,theX,theY) != 0) distance = 1;
   }

   // Loop on the list of associated functions and user objects
   TObject *f;
   TList *functions = theGraph->GetListOfFunctions();
   TIter   next(functions);
   while ((f = (TObject*) next())) {
      Int_t dist;
      if (f->InheritsFrom(TF1::Class())) dist = f->DistancetoPrimitive(-px,py);
      else                               dist = f->DistancetoPrimitive(px,py);
      if (dist < kMaxDiff) {
         gPad->SetSelected(f);
         return 0; //must be o and not dist in case of TMultiGraph
      }
   }

   return distance;
}


//______________________________________________________________________________
void TGraphPainter::DrawPanelHelper(TGraph *theGraph)
{
   /* Begin_html
   Display a panel with all histogram drawing options.
   End_html */

   if (!gPad) {
      Error("DrawPanel", "need to draw graph first");
      return;
   }
   TVirtualPadEditor *editor = TVirtualPadEditor::GetPadEditor();
   editor->Show();
   gROOT->ProcessLine(Form("((TCanvas*)0x%lx)->Selected((TVirtualPad*)0x%lx,(TObject*)0x%lx,1)",
                           (ULong_t)gPad->GetCanvas(), (ULong_t)gPad, (ULong_t)theGraph));
}


//______________________________________________________________________________
void TGraphPainter::ExecuteEventHelper(TGraph *theGraph, Int_t event, Int_t px, Int_t py)
{
   /* Begin_Html
   Execute action corresponding to one event.
   <p>
   This member function is called when a graph is clicked with the locator.
   <p>
   If the left mouse button is clicked on one of the line end points, this point
   follows the cursor until button is released.
   <p>
   If the middle mouse button clicked, the line is moved parallel to itself
   until the button is released.
   End_Html */

   Int_t i, d;
   Double_t xmin, xmax, ymin, ymax, dx, dy, dxr, dyr;
   const Int_t kMaxDiff =  10;//3;
   static Bool_t middle, badcase;
   static Int_t ipoint, pxp, pyp;
   static Int_t px1,px2,py1,py2;
   static Int_t pxold, pyold, px1old, py1old, px2old, py2old;
   static Int_t dpx, dpy;
   static Int_t *x=0, *y=0;
   Bool_t opaque  = gPad->OpaqueMoving();

   if (!theGraph->IsEditable() || theGraph->InheritsFrom(TGraphPolar::Class())) {
      gPad->SetCursor(kHand);
      return;
   }
   if (!gPad->IsEditable()) return;
   Int_t theNpoints = theGraph->GetN();
   Double_t *theX  = theGraph->GetX();
   Double_t *theY  = theGraph->GetY();

   switch (event) {

   case kButton1Down:
      badcase = kFALSE;
      gVirtualX->SetLineColor(-1);
      theGraph->TAttLine::Modify();  //Change line attributes only if necessary
      px1 = gPad->XtoAbsPixel(gPad->GetX1());
      py1 = gPad->YtoAbsPixel(gPad->GetY1());
      px2 = gPad->XtoAbsPixel(gPad->GetX2());
      py2 = gPad->YtoAbsPixel(gPad->GetY2());
      ipoint = -1;


      if (x || y) break;
      x = new Int_t[theNpoints+1];
      y = new Int_t[theNpoints+1];
      for (i=0;i<theNpoints;i++) {
         pxp = gPad->XtoAbsPixel(gPad->XtoPad(theX[i]));
         pyp = gPad->YtoAbsPixel(gPad->YtoPad(theY[i]));
         if (pxp < -kMaxPixel || pxp >= kMaxPixel ||
             pyp < -kMaxPixel || pyp >= kMaxPixel) {
            badcase = kTRUE;
            continue;
         }
         if (!opaque) {
            gVirtualX->DrawLine(pxp-4, pyp-4, pxp+4,  pyp-4);
            gVirtualX->DrawLine(pxp+4, pyp-4, pxp+4,  pyp+4);
            gVirtualX->DrawLine(pxp+4, pyp+4, pxp-4,  pyp+4);
            gVirtualX->DrawLine(pxp-4, pyp+4, pxp-4,  pyp-4);
         }
         x[i] = pxp;
         y[i] = pyp;
         d   = TMath::Abs(pxp-px) + TMath::Abs(pyp-py);
         if (d < kMaxDiff) ipoint =i;
      }
      dpx = 0;
      dpy = 0;
      pxold = px;
      pyold = py;
      if (ipoint < 0) return;
      if (ipoint == 0) {
         px1old = 0;
         py1old = 0;
         px2old = gPad->XtoAbsPixel(theX[1]);
         py2old = gPad->YtoAbsPixel(theY[1]);
      } else if (ipoint == theNpoints-1) {
         px1old = gPad->XtoAbsPixel(gPad->XtoPad(theX[theNpoints-2]));
         py1old = gPad->YtoAbsPixel(gPad->YtoPad(theY[theNpoints-2]));
         px2old = 0;
         py2old = 0;
      } else {
         px1old = gPad->XtoAbsPixel(gPad->XtoPad(theX[ipoint-1]));
         py1old = gPad->YtoAbsPixel(gPad->YtoPad(theY[ipoint-1]));
         px2old = gPad->XtoAbsPixel(gPad->XtoPad(theX[ipoint+1]));
         py2old = gPad->YtoAbsPixel(gPad->YtoPad(theY[ipoint+1]));
      }
      pxold = gPad->XtoAbsPixel(gPad->XtoPad(theX[ipoint]));
      pyold = gPad->YtoAbsPixel(gPad->YtoPad(theY[ipoint]));

      break;


   case kMouseMotion:

      middle = kTRUE;
      for (i=0;i<theNpoints;i++) {
         pxp = gPad->XtoAbsPixel(gPad->XtoPad(theX[i]));
         pyp = gPad->YtoAbsPixel(gPad->YtoPad(theY[i]));
         d   = TMath::Abs(pxp-px) + TMath::Abs(pyp-py);
         if (d < kMaxDiff) middle = kFALSE;
      }


   // check if point is close to an axis
      if (middle) gPad->SetCursor(kMove);
      else gPad->SetCursor(kHand);
      break;

   case kButton1Motion:
      if (!opaque) {
         if (middle) {
            for(i=0;i<theNpoints-1;i++) {
               gVirtualX->DrawLine(x[i]+dpx, y[i]+dpy, x[i+1]+dpx, y[i+1]+dpy);
               pxp = x[i]+dpx;
               pyp = y[i]+dpy;
               if (pxp < -kMaxPixel || pxp >= kMaxPixel ||
                   pyp < -kMaxPixel || pyp >= kMaxPixel) continue;
               gVirtualX->DrawLine(pxp-4, pyp-4, pxp+4,  pyp-4);
               gVirtualX->DrawLine(pxp+4, pyp-4, pxp+4,  pyp+4);
               gVirtualX->DrawLine(pxp+4, pyp+4, pxp-4,  pyp+4);
               gVirtualX->DrawLine(pxp-4, pyp+4, pxp-4,  pyp-4);
            }
            pxp = x[theNpoints-1]+dpx;
            pyp = y[theNpoints-1]+dpy;
            gVirtualX->DrawLine(pxp-4, pyp-4, pxp+4,  pyp-4);
            gVirtualX->DrawLine(pxp+4, pyp-4, pxp+4,  pyp+4);
            gVirtualX->DrawLine(pxp+4, pyp+4, pxp-4,  pyp+4);
            gVirtualX->DrawLine(pxp-4, pyp+4, pxp-4,  pyp-4);
            dpx += px - pxold;
            dpy += py - pyold;
            pxold = px;
            pyold = py;
            for(i=0;i<theNpoints-1;i++) {
               gVirtualX->DrawLine(x[i]+dpx, y[i]+dpy, x[i+1]+dpx, y[i+1]+dpy);
               pxp = x[i]+dpx;
               pyp = y[i]+dpy;
               if (pxp < -kMaxPixel || pxp >= kMaxPixel ||
                   pyp < -kMaxPixel || pyp >= kMaxPixel) continue;
               gVirtualX->DrawLine(pxp-4, pyp-4, pxp+4,  pyp-4);
               gVirtualX->DrawLine(pxp+4, pyp-4, pxp+4,  pyp+4);
               gVirtualX->DrawLine(pxp+4, pyp+4, pxp-4,  pyp+4);
               gVirtualX->DrawLine(pxp-4, pyp+4, pxp-4,  pyp-4);
            }
            pxp = x[theNpoints-1]+dpx;
            pyp = y[theNpoints-1]+dpy;
            gVirtualX->DrawLine(pxp-4, pyp-4, pxp+4,  pyp-4);
            gVirtualX->DrawLine(pxp+4, pyp-4, pxp+4,  pyp+4);
            gVirtualX->DrawLine(pxp+4, pyp+4, pxp-4,  pyp+4);
            gVirtualX->DrawLine(pxp-4, pyp+4, pxp-4,  pyp-4);
         } else {
            if (px1old) gVirtualX->DrawLine(px1old, py1old, pxold,  pyold);
            if (px2old) gVirtualX->DrawLine(pxold,  pyold,  px2old, py2old);
            gVirtualX->DrawLine(pxold-4, pyold-4, pxold+4,  pyold-4);
            gVirtualX->DrawLine(pxold+4, pyold-4, pxold+4,  pyold+4);
            gVirtualX->DrawLine(pxold+4, pyold+4, pxold-4,  pyold+4);
            gVirtualX->DrawLine(pxold-4, pyold+4, pxold-4,  pyold-4);
            pxold = px;
            pxold = TMath::Max(pxold, px1);
            pxold = TMath::Min(pxold, px2);
            pyold = py;
            pyold = TMath::Max(pyold, py2);
            pyold = TMath::Min(pyold, py1);
            if (px1old) gVirtualX->DrawLine(px1old, py1old, pxold,  pyold);
            if (px2old) gVirtualX->DrawLine(pxold,  pyold,  px2old, py2old);
            gVirtualX->DrawLine(pxold-4, pyold-4, pxold+4,  pyold-4);
            gVirtualX->DrawLine(pxold+4, pyold-4, pxold+4,  pyold+4);
            gVirtualX->DrawLine(pxold+4, pyold+4, pxold-4,  pyold+4);
            gVirtualX->DrawLine(pxold-4, pyold+4, pxold-4,  pyold-4);
         }
      } else {
         xmin = gPad->GetUxmin();
         xmax = gPad->GetUxmax();
         ymin = gPad->GetUymin();
         ymax = gPad->GetUymax();
         dx   = xmax-xmin;
         dy   = ymax-ymin;
         dxr  = dx/(1 - gPad->GetLeftMargin() - gPad->GetRightMargin());
         dyr  = dy/(1 - gPad->GetBottomMargin() - gPad->GetTopMargin());

         if (theGraph->GetHistogram()) {
            // Range() could change the size of the pad pixmap and therefore should
            // be called before the other paint routines
            gPad->Range(xmin - dxr*gPad->GetLeftMargin(),
                         ymin - dyr*gPad->GetBottomMargin(),
                         xmax + dxr*gPad->GetRightMargin(),
                         ymax + dyr*gPad->GetTopMargin());
            gPad->RangeAxis(xmin, ymin, xmax, ymax);
         }
         if (middle) {
            dpx += px - pxold;
            dpy += py - pyold;
            pxold = px;
            pyold = py;
            for(i=0;i<theNpoints;i++) {
               if (badcase) continue;  //do not update if big zoom and points moved
               if (x) theX[i] = gPad->PadtoX(gPad->AbsPixeltoX(x[i]+dpx));
               if (y) theY[i] = gPad->PadtoY(gPad->AbsPixeltoY(y[i]+dpy));
            }
         } else {
            pxold = px;
            pxold = TMath::Max(pxold, px1);
            pxold = TMath::Min(pxold, px2);
            pyold = py;
            pyold = TMath::Max(pyold, py2);
            pyold = TMath::Min(pyold, py1);
            theX[ipoint] = gPad->PadtoX(gPad->AbsPixeltoX(pxold));
            theY[ipoint] = gPad->PadtoY(gPad->AbsPixeltoY(pyold));
            if (theGraph->InheritsFrom("TCutG")) {
               //make sure first and last point are the same
               if (ipoint == 0) {
                  theX[theNpoints-1] = theX[0];
                  theY[theNpoints-1] = theY[0];
               }
               if (ipoint == theNpoints-1) {
                  theX[0] = theX[theNpoints-1];
                  theY[0] = theY[theNpoints-1];
               }
            }
         }
         badcase = kFALSE;
         gPad->Modified(kTRUE);
         //gPad->Update();
      }
      break;

   case kButton1Up:

      if (gROOT->IsEscaped()) {
         gROOT->SetEscape(kFALSE);
         delete [] x; x = 0;
         delete [] y; y = 0;
         break;
      }

   // Compute x,y range
      xmin = gPad->GetUxmin();
      xmax = gPad->GetUxmax();
      ymin = gPad->GetUymin();
      ymax = gPad->GetUymax();
      dx   = xmax-xmin;
      dy   = ymax-ymin;
      dxr  = dx/(1 - gPad->GetLeftMargin() - gPad->GetRightMargin());
      dyr  = dy/(1 - gPad->GetBottomMargin() - gPad->GetTopMargin());

      if (theGraph->GetHistogram()) {
         // Range() could change the size of the pad pixmap and therefore should
         // be called before the other paint routines
         gPad->Range(xmin - dxr*gPad->GetLeftMargin(),
                      ymin - dyr*gPad->GetBottomMargin(),
                      xmax + dxr*gPad->GetRightMargin(),
                      ymax + dyr*gPad->GetTopMargin());
         gPad->RangeAxis(xmin, ymin, xmax, ymax);
      }
      if (middle) {
         for(i=0;i<theNpoints;i++) {
            if (badcase) continue;  //do not update if big zoom and points moved
            if (x) theX[i] = gPad->PadtoX(gPad->AbsPixeltoX(x[i]+dpx));
            if (y) theY[i] = gPad->PadtoY(gPad->AbsPixeltoY(y[i]+dpy));
         }
      } else {
         theX[ipoint] = gPad->PadtoX(gPad->AbsPixeltoX(pxold));
         theY[ipoint] = gPad->PadtoY(gPad->AbsPixeltoY(pyold));
         if (theGraph->InheritsFrom("TCutG")) {
            //make sure first and last point are the same
            if (ipoint == 0) {
               theX[theNpoints-1] = theX[0];
               theY[theNpoints-1] = theY[0];
            }
            if (ipoint == theNpoints-1) {
               theX[0] = theX[theNpoints-1];
               theY[0] = theY[theNpoints-1];
            }
         }
      }
      badcase = kFALSE;
      delete [] x; x = 0;
      delete [] y; y = 0;
      gPad->Modified(kTRUE);
      gVirtualX->SetLineColor(-1);
   }
}


//______________________________________________________________________________
char *TGraphPainter::GetObjectInfoHelper(TGraph * /*theGraph*/, Int_t /*px*/, Int_t /*py*/) const
{
   return (char*)"";
}


//______________________________________________________________________________
void TGraphPainter::PaintHelper(TGraph *theGraph, Option_t *option)
{
   /* Begin_Html
   Paint a any kind of TGraph
   End_Html */

   if (theGraph) {
      SetBit(TGraph::kClipFrame, theGraph->TestBit(TGraph::kClipFrame));
      if (theGraph->InheritsFrom(TGraphBentErrors::Class())) {
         PaintGraphBentErrors(theGraph,option);
      } else if (theGraph->InheritsFrom(TGraphQQ::Class())) {
         PaintGraphQQ(theGraph,option);
      } else if (theGraph->InheritsFrom(TGraphAsymmErrors::Class())) {
         PaintGraphAsymmErrors(theGraph,option);
      } else if (theGraph->InheritsFrom(TGraphErrors::Class())) {
         if (theGraph->InheritsFrom(TGraphPolar::Class())) {
            PaintGraphPolar(theGraph,option);
         } else {
            PaintGraphErrors(theGraph,option);
         }
      } else {
         PaintGraphSimple(theGraph,option);
      }
   }
}


//______________________________________________________________________________
void TGraphPainter::PaintGraph(TGraph *theGraph, Int_t npoints, const Double_t *x, const Double_t *y, Option_t *chopt)
{
   /* Begin_Html
   <a href="#GP01">Control function to draw a graph.</a>
   End_Html */
   if (theGraph->InheritsFrom("TGraphPolar"))
      gPad->PushSelectableObject(theGraph);

   Int_t optionLine , optionAxis , optionCurve, optionStar , optionMark;
   Int_t optionBar  , optionR    , optionOne  , optionE;
   Int_t optionFill , optionZ    , optionCurveFill;
   Int_t i, npt, nloop;
   Int_t drawtype=0;
   Double_t xlow, xhigh, ylow, yhigh;
   Double_t barxmin, barxmax, barymin, barymax;
   Double_t uxmin, uxmax;
   Double_t x1, xn, y1, yn;
   Double_t dbar, bdelta;
   Int_t theNpoints = theGraph->GetN();

   if (npoints <= 0) {
      Error("PaintGraph", "illegal number of points (%d)", npoints);
      return;
   }
   TString opt = chopt;
   opt.ToUpper();
   opt.ReplaceAll("SAME","");

   if (opt.Contains("L")) optionLine = 1;  else optionLine = 0;
   if (opt.Contains("A")) optionAxis = 1;  else optionAxis = 0;
   if (opt.Contains("C")) optionCurve= 1;  else optionCurve= 0;
   if (opt.Contains("*")) optionStar = 1;  else optionStar = 0;
   if (opt.Contains("P")) optionMark = 1;  else optionMark = 0;
   if (opt.Contains("B")) optionBar  = 1;  else optionBar  = 0;
   if (opt.Contains("R")) optionR    = 1;  else optionR    = 0;
   if (opt.Contains("1")) optionOne  = 1;  else optionOne  = 0;
   if (opt.Contains("F")) optionFill = 1;  else optionFill = 0;
   if (opt.Contains("2") || opt.Contains("3") ||
      opt.Contains("4") || opt.Contains("5")) optionE = 1;  else optionE = 0;
   optionZ    = 0;

   // If no "drawing" option is selected and if chopt<>' ' nothing is done.
   if (optionLine+optionFill+optionCurve+optionStar+optionMark+optionBar+optionE == 0) {
      if (!chopt[0])  optionLine=1;
      else   return;
   }

   if (optionStar) theGraph->SetMarkerStyle(3);

   optionCurveFill = 0;
   if (optionCurve && optionFill) {
      optionCurveFill = 1;
      optionFill      = 0;
   }

   // Draw the Axis.
   Double_t rwxmin,rwxmax, rwymin, rwymax, maximum, minimum, dx, dy;
   if (optionAxis) {
      if (theGraph->GetHistogram()) {
         rwxmin    = gPad->GetUxmin();
         rwxmax    = gPad->GetUxmax();
         rwymin    = gPad->GetUymin();
         rwymax    = gPad->GetUymax();
         minimum   = theGraph->GetHistogram()->GetMinimumStored();
         maximum   = theGraph->GetHistogram()->GetMaximumStored();
         if (minimum == -1111) { //this can happen after unzooming
            minimum = theGraph->GetHistogram()->GetYaxis()->GetXmin();
            theGraph->GetHistogram()->SetMinimum(minimum);
         }
         if (maximum == -1111) {
            maximum = theGraph->GetHistogram()->GetYaxis()->GetXmax();
            theGraph->GetHistogram()->SetMaximum(maximum);
         }
         uxmin     = gPad->PadtoX(rwxmin);
         uxmax     = gPad->PadtoX(rwxmax);
      } else {

         theGraph->ComputeRange(rwxmin, rwymin, rwxmax, rwymax);  //this is redefined in TGraphErrors

         if (rwxmin == rwxmax) rwxmax += 1.;
         if (rwymin == rwymax) rwymax += 1.;
         dx = 0.1*(rwxmax-rwxmin);
         dy = 0.1*(rwymax-rwymin);
         uxmin    = rwxmin - dx;
         uxmax    = rwxmax + dx;
         minimum  = rwymin - dy;
         maximum  = rwymax + dy;
      }
      if (theGraph->GetMinimum() != -1111) rwymin = minimum = theGraph->GetMinimum();
      if (theGraph->GetMaximum() != -1111) rwymax = maximum = theGraph->GetMaximum();
      if (uxmin < 0 && rwxmin >= 0) uxmin = 0.9*rwxmin;
      if (uxmax > 0 && rwxmax <= 0) {
         if (gPad->GetLogx()) uxmax = 1.1*rwxmax;
         else                 uxmax = 0;
      }
      if (minimum < 0 && rwymin >= 0) minimum = 0.9*rwymin;
      if (maximum > 0 && rwymax <= 0) {
         //if(gPad->GetLogy()) maximum = 1.1*rwymax;
         //else                maximum = 0;
      }
      if (minimum <= 0 && gPad->GetLogy()) minimum = 0.001*maximum;
      if (uxmin <= 0 && gPad->GetLogx()) {
         if (uxmax > 1000) uxmin = 1;
         else              uxmin = 0.001*uxmax;
      }
      rwymin = minimum;
      rwymax = maximum;

      // Create a temporary histogram and fill each bin with the
      // function value.
      char chopth[8] = " ";
      if (strstr(chopt,"x+")) strncat(chopth, "x+",2);
      if (strstr(chopt,"y+")) strncat(chopth, "y+",2);
      if (!theGraph->GetHistogram()) {
         // the graph is created with at least as many bins as there are
         // points to permit zooming on the full range.
         rwxmin = uxmin;
         rwxmax = uxmax;
         npt = 100;
         if (theNpoints > npt) npt = theNpoints;
         TH1F *h = new TH1F(Form("%s_h",GetName()),GetTitle(),npt,rwxmin,rwxmax);
         theGraph->SetHistogram(h);
         if (!theGraph->GetHistogram()) return;
         theGraph->GetHistogram()->SetMinimum(rwymin);
         theGraph->GetHistogram()->SetMaximum(rwymax);
         theGraph->GetHistogram()->GetYaxis()->SetLimits(rwymin,rwymax);
         theGraph->GetHistogram()->SetBit(TH1::kNoStats);
         theGraph->GetHistogram()->SetDirectory(0);
         theGraph->GetHistogram()->Paint(chopth); // Draw histogram axis, title and grid
      } else {
         if (gPad->GetLogy()) {
            theGraph->GetHistogram()->SetMinimum(rwymin);
            theGraph->GetHistogram()->SetMaximum(rwymax);
            theGraph->GetHistogram()->GetYaxis()->SetLimits(rwymin,rwymax);
         }
         theGraph->GetHistogram()->Paint(chopth); // Draw histogram axis, title and grid
      }
   }

   // Set Clipping option
   gPad->SetBit(TGraph::kClipFrame, theGraph->TestBit(TGraph::kClipFrame));

   TF1 *fit = 0;
   TList *functions = theGraph->GetListOfFunctions();
   TObject *f;
   if (functions) {
      f = (TF1*)functions->First();
      if (f) {
         if (f->InheritsFrom(TF1::Class())) fit = (TF1*)f;
      }
      TIter   next(functions);
      while ((f = (TObject*) next())) {
         if (f->InheritsFrom(TF1::Class())) {
            fit = (TF1*)f;
            break;
         }
      }
   }
   if (fit) PaintStats(theGraph, fit);

   rwxmin   = gPad->GetUxmin();
   rwxmax   = gPad->GetUxmax();
   rwymin   = gPad->GetUymin();
   rwymax   = gPad->GetUymax();
   uxmin    = gPad->PadtoX(rwxmin);
   uxmax    = gPad->PadtoX(rwxmax);
   if (theGraph->GetHistogram() && !theGraph->InheritsFrom("TGraphPolar")) {
      maximum = theGraph->GetHistogram()->GetMaximum();
      minimum = theGraph->GetHistogram()->GetMinimum();
   } else {
      maximum = gPad->PadtoY(rwymax);
      minimum = gPad->PadtoY(rwymin);
   }

   // Set attributes
   theGraph->TAttLine::Modify();
   theGraph->TAttFill::Modify();
   theGraph->TAttMarker::Modify();

   // Draw the graph with a polyline or a fill area
   gxwork  = new Double_t[2*npoints+10];
   gywork  = new Double_t[2*npoints+10];
   gxworkl = new Double_t[2*npoints+10];
   gyworkl = new Double_t[2*npoints+10];

   if (optionLine || optionFill) {
      x1    = x[0];
      xn    = x[npoints-1];
      y1    = y[0];
      yn    = y[npoints-1];
      nloop = npoints;
      if (optionFill && (xn != x1 || yn != y1)) nloop++;
      npt = 0;
      for (i=1;i<=nloop;i++) {
         if (i > npoints) {
            gxwork[npt] = gxwork[0];  gywork[npt] = gywork[0];
         } else {
            gxwork[npt] = x[i-1];      gywork[npt] = y[i-1];
            npt++;
         }
         if (i == nloop) {
            ComputeLogs(npt, optionZ);
            Int_t bord = gStyle->GetDrawBorder();
            if (optionR) {
               if (optionFill) {
                  gPad->PaintFillArea(npt,gyworkl,gxworkl);
                  if (bord) gPad->PaintPolyLine(npt,gyworkl,gxworkl);
               } else {
                  if (TMath::Abs(theGraph->GetLineWidth())>99) PaintPolyLineHatches(theGraph, npt, gyworkl, gxworkl);
                  gPad->PaintPolyLine(npt,gyworkl,gxworkl);
               }
            } else {
               if (optionFill) {
                  gPad->PaintFillArea(npt,gxworkl,gyworkl);
                  if (bord) gPad->PaintPolyLine(npt,gxworkl,gyworkl);
               } else {
                  if (TMath::Abs(theGraph->GetLineWidth())>99) PaintPolyLineHatches(theGraph, npt, gxworkl, gyworkl);
                  gPad->PaintPolyLine(npt,gxworkl,gyworkl);
               }
            }
            gxwork[0] = gxwork[npt-1];  gywork[0] = gywork[npt-1];
            npt      = 1;
         }
      }
   }

   // Draw the graph with a smooth Curve. Smoothing via Smooth
   if (optionCurve) {
      x1 = x[0];
      xn = x[npoints-1];
      y1 = y[0];
      yn = y[npoints-1];
      drawtype = 1;
      nloop = npoints;
      if (optionCurveFill) {
         drawtype += 1000;
         if (xn != x1 || yn != y1) nloop++;
      }
      if (!optionR) {
         npt = 0;
         for (i=1;i<=nloop;i++) {
            if (i > npoints) {
               gxwork[npt] = gxwork[0];  gywork[npt] = gywork[0];
            } else {
               gxwork[npt] = x[i-1];      gywork[npt] = y[i-1];
               npt++;
            }
            ComputeLogs(npt, optionZ);
            if (gyworkl[npt-1] < rwymin || gyworkl[npt-1] > rwymax) {
               if (npt > 2) {
                  ComputeLogs(npt, optionZ);
                  Smooth(theGraph, npt,gxworkl,gyworkl,drawtype);
               }
               gxwork[0] = gxwork[npt-1]; gywork[0] = gywork[npt-1];
               npt=1;
               continue;
            }
         }
         if (npt > 1) {
            ComputeLogs(npt, optionZ);
            Smooth(theGraph, npt,gxworkl,gyworkl,drawtype);
         }
      } else {
         drawtype += 10;
         npt    = 0;
         for (i=1;i<=nloop;i++) {
            if (i > npoints) {
               gxwork[npt] = gxwork[0];  gywork[npt] = gywork[0];
            } else {
               if (y[i-1] < minimum || y[i-1] > maximum) continue;
               if (x[i-1] < uxmin    || x[i-1] > uxmax)  continue;
               gxwork[npt] = x[i-1];      gywork[npt] = y[i-1];
               npt++;
            }
            ComputeLogs(npt, optionZ);
            if (gxworkl[npt-1] < rwxmin || gxworkl[npt-1] > rwxmax) {
               if (npt > 2) {
                  ComputeLogs(npt, optionZ);
                  Smooth(theGraph, npt,gxworkl,gyworkl,drawtype);
               }
               gxwork[0] = gxwork[npt-1]; gywork[0] = gywork[npt-1];
               npt=1;
               continue;
            }
         }
         if (npt > 1) {
            ComputeLogs(npt, optionZ);
            Smooth(theGraph, npt,gxworkl,gyworkl,drawtype);
         }
      }
   }

   // Draw the graph with a '*' on every points
   if (optionStar) {
      theGraph->SetMarkerStyle(3);
      npt = 0;
      for (i=1;i<=npoints;i++) {
         gxwork[npt] = x[i-1];      gywork[npt] = y[i-1];
         npt++;
         if (i == npoints) {
            ComputeLogs(npt, optionZ);
            if (optionR)  gPad->PaintPolyMarker(npt,gyworkl,gxworkl);
            else          gPad->PaintPolyMarker(npt,gxworkl,gyworkl);
            npt = 0;
         }
      }
   }

   // Draw the graph with the current polymarker on every points
   if (optionMark) {
      npt = 0;
      for (i=1;i<=npoints;i++) {
         gxwork[npt] = x[i-1];      gywork[npt] = y[i-1];
         npt++;
         if (i == npoints) {
            ComputeLogs(npt, optionZ);
            if (optionR) gPad->PaintPolyMarker(npt,gyworkl,gxworkl);
            else         gPad->PaintPolyMarker(npt,gxworkl,gyworkl);
            npt = 0;
         }
      }
   }

   // Draw the graph as a bar chart
   if (optionBar) {
      if (!optionR) {
         barxmin = x[0];
         barxmax = x[0];
         for (i=1;i<npoints;i++) {
            if (x[i] < barxmin) barxmin = x[i];
            if (x[i] > barxmax) barxmax = x[i];
         }
         bdelta = (barxmax-barxmin)/Double_t(npoints);
      } else {
         barymin = y[0];
         barymax = y[0];
         for (i=1;i<npoints;i++) {
            if (y[i] < barymin) barymin = y[i];
            if (y[i] > barymax) barymax = y[i];
         }
         bdelta = (barymax-barymin)/Double_t(npoints);
      }
      dbar  = 0.5*bdelta*gStyle->GetBarWidth();
      if (!optionR) {
         for (i=1;i<=npoints;i++) {
            xlow  = x[i-1] - dbar;
            xhigh = x[i-1] + dbar;
            yhigh = y[i-1];
            if (xlow  < uxmin) xlow = uxmin;
            if (xhigh > uxmax) xhigh = uxmax;
            if (!optionOne) ylow = TMath::Max((Double_t)0,gPad->GetUymin());
            else            ylow = gPad->GetUymin();
            gxwork[0] = xlow;
            gywork[0] = ylow;
            gxwork[1] = xhigh;
            gywork[1] = yhigh;
            ComputeLogs(2, optionZ);
            if (gyworkl[0] < gPad->GetUymin()) gyworkl[0] = gPad->GetUymin();
            if (gyworkl[1] < gPad->GetUymin()) continue;
            if (gyworkl[1] > gPad->GetUymax()) gyworkl[1] = gPad->GetUymax();
            if (gyworkl[0] > gPad->GetUymax()) continue;

            gPad->PaintBox(gxworkl[0],gyworkl[0],gxworkl[1],gyworkl[1]);
         }
      } else {
         for (i=1;i<=npoints;i++) {
            xhigh = x[i-1];
            ylow  = y[i-1] - dbar;
            yhigh = y[i-1] + dbar;
            xlow     = TMath::Max((Double_t)0, gPad->GetUxmin());
            gxwork[0] = xlow;
            gywork[0] = ylow;
            gxwork[1] = xhigh;
            gywork[1] = yhigh;
            ComputeLogs(2, optionZ);
            gPad->PaintBox(gxworkl[0],gyworkl[0],gxworkl[1],gyworkl[1]);
         }
      }
   }
   gPad->ResetBit(TGraph::kClipFrame);

   delete [] gxwork;
   delete [] gywork;
   delete [] gxworkl;
   delete [] gyworkl;
}


//______________________________________________________________________________
void TGraphPainter::PaintGrapHist(TGraph *theGraph, Int_t npoints, const Double_t *x,
                                  const Double_t *y, Option_t *chopt)
{
   /* Begin_Html
    This is a service method used by
    <a href="http://root.cern.ch/root/html/THistPainter.html"><tt>THistPainter</tt></a>
    to paint 1D histograms. <b>It is not used to paint TGraph</b>.
    <p>
    Input parameters:
    <ul>
    <li> npoints : Number of points in X or in Y.
    <li> x[npoints] or x[0] : x coordinates or (xmin,xmax).
    <li> y[npoints] or y[0] : y coordinates or (ymin,ymax).
    <li> chopt : Option.
    </ul>
    <p>
    The aspect of the histogram is done according to the value of the chopt.
    <p>
    <table border=0>
    <tr><th valign=top>"R"</th><td>
    Graph is drawn horizontaly, parallel to X axis. (default is vertically,
    parallel to Y axis)
    <br>
    If option R is selected the user must give:
    <ul>
    <li> 2 values for Y (y[0]=YMIN and y[1]=YMAX)
    <li> N values for X, one for each channel.
    </ul>
    Otherwise the user must give:
    <ul>
    <li> N values for Y, one for each channel.
    <li> 2 values for X (x[0]=XMIN and x[1]=XMAX)
    </ul>
    </td></tr>

    <tr><th valign=top>"L"</th><td>
    A simple polyline beetwen every points is drawn.
    </td></tr>

    <tr><th valign=top>"H"</th><td>
    An Histogram with equidistant bins is drawn as a polyline.
    </td></tr>

    <tr><th valign=top>"F"</th><td>
    An histogram with equidistant bins is drawn as a fill area. Contour is not
    drawn unless chopt='H' is also selected..
    </td></tr>

    <tr><th valign=top>"N"</th><td>
    Non equidistant bins (default is equidistant). If N is the number of channels
    array X and Y must be dimensionned as follow:
    <ul>
    <li>>If option R is not selected (default) then the user must give:</li>
      <ul>
      <li>(N+1) values for X (limits of channels).</li>
      <li>N values for Y, one for each channel.</li>
      <ul>
    <li>Otherwise the user must give:</li>
      <ul>
      <li>(N+1) values for Y (limits of channels).</li>
      <li>N values for X, one for each channel.</li>
      </ul>
    </ul>
    </td></tr>

    <tr><th valign=top>"F1"</th><td>
    Idem as 'F' except that fill area base line is the minimum of the pad instead
    of Y=0.
    </td></tr>

    <tr><th valign=top>"F2"</th><td>
    Draw a Fill area polyline connecting the center of bins
    </td></tr>

    <tr><th valign=top>"C"</th><td>
    A smooth Curve is drawn.
    </td></tr>

    <tr><th valign=top>"*"</th><td>
    A Star is plotted at the center of each bin.
    </td></tr>

    <tr><th valign=top>"P"</th><td>
    Idem with the current marker.
    </td></tr>

    <tr><th valign=top>"P0"</th><td>
    Idem with the current marker. Empty bins also drawn.
    </td></tr>

    <tr><th valign=top>"B"</th><td>
    A Bar chart with equidistant bins is drawn as fill areas (Contours are drawn).
    </td></tr>

    <tr><th valign=top>"]["</th><td>
    "Cutoff" style. When this option is selected together with H option, the
    first and last vertical lines of the histogram are not drawn.
    </td></tr>

    </table>
    End_Html */

   const char *where = "PaintGraphHist";

   Int_t optionLine , optionAxis , optionCurve, optionStar, optionMark;
   Int_t optionBar  , optionRot  , optionOne  , optionOff ;
   Int_t optionFill , optionZ;
   Int_t optionHist , optionBins , optionMarker;
   Int_t i, j, npt;
   Int_t drawtype=0, drawborder, drawbordersav;
   Double_t xlow, xhigh, ylow, yhigh;
   Double_t wmin, wmax;
   Double_t dbar, offset, wminstep;
   Double_t delta = 0;
   Double_t ylast = 0;
   Double_t xi, xi1, xj, xj1, yi1, yi, yj, yj1, xwmin, ywmin;
   Int_t first, last, nbins;
   Int_t fillarea;

   char choptaxis[10] = " ";

   if (npoints <= 0) {
      Error(where, "illegal number of points (%d)", npoints);
      return;
   }
   TString opt = chopt;
   opt.ToUpper();
   if (opt.Contains("H"))  optionHist = 1;  else optionHist = 0;
   if (opt.Contains("F"))  optionFill = 1;  else optionFill = 0;
   if (opt.Contains("C"))  optionCurve= 1;  else optionCurve= 0;
   if (opt.Contains("*"))  optionStar = 1;  else optionStar = 0;
   if (opt.Contains("R"))  optionRot  = 1;  else optionRot  = 0;
   if (opt.Contains("1"))  optionOne  = 1;  else optionOne  = 0;
   if (opt.Contains("B"))  optionBar  = 1;  else optionBar  = 0;
   if (opt.Contains("N"))  optionBins = 1;  else optionBins = 0;
   if (opt.Contains("L"))  optionLine = 1;  else optionLine = 0;
   if (opt.Contains("P"))  optionMark = 1;  else optionMark = 0;
   if (opt.Contains("A"))  optionAxis = 1;  else optionAxis = 0;
   if (opt.Contains("][")) optionOff  = 1;  else optionOff  = 0;
   if (opt.Contains("P0")) optionMark = 10;

   Int_t optionFill2 = 0;
   if (opt.Contains("F") && opt.Contains("2")) {
      optionFill = 0; optionFill2 = 1;
   }

   // Set Clipping option
   Option_t *noClip;
   if (theGraph->TestBit(TGraph::kClipFrame)) noClip = "";
   else noClip = "C";
   gPad->SetBit(TGraph::kClipFrame, theGraph->TestBit(TGraph::kClipFrame));

   optionZ = 1;

   if (optionStar) theGraph->SetMarkerStyle(3);

   first = 1;
   last  = npoints;
   nbins = last - first + 1;

   //           Draw the Axis with a fixed number of division: 510

   Double_t baroffset = gStyle->GetBarOffset();
   Double_t barwidth  = gStyle->GetBarWidth();
   Double_t rwxmin    = gPad->GetUxmin();
   Double_t rwxmax    = gPad->GetUxmax();
   Double_t rwymin    = gPad->GetUymin();
   Double_t rwymax    = gPad->GetUymax();
   Double_t uxmin     = gPad->PadtoX(rwxmin);
   Double_t uxmax     = gPad->PadtoX(rwxmax);
   Double_t rounding  = (uxmax-uxmin)*1.e-5;
   drawborder         = gStyle->GetDrawBorder();
   if (optionAxis) {
      Int_t nx1, nx2, ndivx, ndivy, ndiv;
      choptaxis[0]  = 0;
      Double_t rwmin  = rwxmin;
      Double_t rwmax  = rwxmax;
      ndivx = gStyle->GetNdivisions("X");
      ndivy = gStyle->GetNdivisions("Y");
      if (ndivx > 1000) {
         nx2   = ndivx/100;
         nx1   = TMath::Max(1, ndivx%100);
         ndivx = 100*nx2 + Int_t(Double_t(nx1)*gPad->GetAbsWNDC());
      }
      ndiv  =TMath::Abs(ndivx);
      // coverity [Calling risky function]
      if (ndivx < 0) strlcat(choptaxis, "N",10);
      if (gPad->GetGridx()) {
         // coverity [Calling risky function]
         strlcat(choptaxis, "W",10);
      }
      if (gPad->GetLogx()) {
         rwmin = TMath::Power(10,rwxmin);
         rwmax = TMath::Power(10,rwxmax);
         // coverity [Calling risky function]
         strlcat(choptaxis, "G",10);
      }
      TGaxis *axis = new TGaxis();
      axis->SetLineColor(gStyle->GetAxisColor("X"));
      axis->SetTextColor(gStyle->GetLabelColor("X"));
      axis->SetTextFont(gStyle->GetLabelFont("X"));
      axis->SetLabelSize(gStyle->GetLabelSize("X"));
      axis->SetLabelOffset(gStyle->GetLabelOffset("X"));
      axis->SetTickSize(gStyle->GetTickLength("X"));

      axis->PaintAxis(rwxmin,rwymin,rwxmax,rwymin,rwmin,rwmax,ndiv,choptaxis);

      choptaxis[0]  = 0;
      rwmin  = rwymin;
      rwmax  = rwymax;
      if (ndivy < 0) {
         nx2   = ndivy/100;
         nx1   = TMath::Max(1, ndivy%100);
         ndivy = 100*nx2 + Int_t(Double_t(nx1)*gPad->GetAbsHNDC());
         // coverity [Calling risky function]
         strlcat(choptaxis, "N",10);
      }
      ndiv  =TMath::Abs(ndivy);
      if (gPad->GetGridy()) {
         // coverity [Calling risky function]
         strlcat(choptaxis, "W",10);
      }
      if (gPad->GetLogy()) {
         rwmin = TMath::Power(10,rwymin);
         rwmax = TMath::Power(10,rwymax);
         // coverity [Calling risky function]
         strlcat(choptaxis,"G",10);
      }
      axis->SetLineColor(gStyle->GetAxisColor("Y"));
      axis->SetTextColor(gStyle->GetLabelColor("Y"));
      axis->SetTextFont(gStyle->GetLabelFont("Y"));
      axis->SetLabelSize(gStyle->GetLabelSize("Y"));
      axis->SetLabelOffset(gStyle->GetLabelOffset("Y"));
      axis->SetTickSize(gStyle->GetTickLength("Y"));

      axis->PaintAxis(rwxmin,rwymin,rwxmin,rwymax,rwmin,rwmax,ndiv,choptaxis);
      delete axis;
   }


   //           Set attributes
   theGraph->TAttLine::Modify();
   theGraph->TAttFill::Modify();
   theGraph->TAttMarker::Modify();

   //       Min-Max scope

   if (!optionRot) {wmin = x[0];   wmax = x[1];}
   else            {wmin = y[0];   wmax = y[1];}

   if (!optionBins) delta = (wmax - wmin)/ Double_t(nbins);

   Int_t fwidth = gPad->GetFrameLineWidth();
   TFrame *frame = gPad->GetFrame();
   if (frame) fwidth = frame->GetLineWidth();
   if (optionOff) fwidth = 1;
   Double_t dxframe = gPad->AbsPixeltoX(fwidth/2) - gPad->AbsPixeltoX(0);
   Double_t vxmin = gPad->PadtoX(gPad->GetUxmin() + dxframe);
   Double_t vxmax = gPad->PadtoX(gPad->GetUxmax() - dxframe);
   Double_t dyframe = -gPad->AbsPixeltoY(fwidth/2) + gPad->AbsPixeltoY(0);
   Double_t vymin = gPad->GetUymin() + dyframe; //y already in log scale
   vxmin = TMath::Max(vxmin,wmin);
   vxmax = TMath::Min(vxmax,wmax);

   //           Draw the histogram with a fill area

   gxwork  = new Double_t[2*npoints+10];
   gywork  = new Double_t[2*npoints+10];
   gxworkl = new Double_t[2*npoints+10];
   gyworkl = new Double_t[2*npoints+10];

   if (optionFill && !optionCurve) {
      fillarea = kTRUE;
      if (!optionRot) {
         gxwork[0] = vxmin;
         if (!optionOne) gywork[0] = TMath::Min(TMath::Max((Double_t)0,gPad->GetUymin())
                                               ,gPad->GetUymax());
         else            gywork[0] = gPad->GetUymin();
         npt = 2;
         for (j=first; j<=last;j++) {
            if (!optionBins) {
               gxwork[npt-1]   = gxwork[npt-2];
               gxwork[npt]     = wmin+((j-first+1)*delta);
               if (gxwork[npt] < gxwork[0]) gxwork[npt] = gxwork[0];

            } else {
               xj1 = x[j];      xj  = x[j-1];
               if (xj1 < xj) {
                  if (j != last) Error(where, "X must be in increasing order");
                  else           Error(where, "X must have N+1 values with option N");
                  return;
               }
               gxwork[npt-1] = x[j-1];       gxwork[npt] = x[j];
            }
            gywork[npt-1] = y[j-1];
            gywork[npt]   = y[j-1];
            if (gywork[npt] < vymin) {gywork[npt] = vymin; gywork[npt-1] = vymin;}
            if ((gxwork[npt-1] >= uxmin-rounding && gxwork[npt-1] <= uxmax+rounding) ||
                (gxwork[npt]   >= uxmin-rounding && gxwork[npt]   <= uxmax+rounding)) npt += 2;
            if (j == last) {
               gxwork[npt-1] = gxwork[npt-2];
               gywork[npt-1] = gywork[0];
               //make sure that the fill area does not overwrite the frame
               //take into account the frame linewidth
               if (gxwork[0    ] < vxmin) {gxwork[0    ] = vxmin; gxwork[1    ] = vxmin;}
               if (gywork[0] < vymin) {gywork[0] = vymin; gywork[npt-1] = vymin;}

               //transform to log ?
               ComputeLogs(npt, optionZ);
               gPad->PaintFillArea(npt,gxworkl,gyworkl);
               if (drawborder) {
                  if (!fillarea) gyworkl[0] = ylast;
                  gPad->PaintPolyLine(npt-1,gxworkl,gyworkl,noClip);
               }
               continue;
            }
         }  //endfor (j=first; j<=last;j++) {
      } else {
         gywork[0] = wmin;
         if (!optionOne) gxwork[0] = TMath::Max((Double_t)0,gPad->GetUxmin());
         else            gxwork[0] = gPad->GetUxmin();
         npt = 2;
         for (j=first; j<=last;j++) {
            if (!optionBins) {
               gywork[npt-1] = gywork[npt-2];
               gywork[npt]   = wmin+((j-first+1)*delta);
            } else {
               yj1 = y[j];      yj  = y[j-1];
               if (yj1 < yj) {
                  if (j != last) Error(where, "Y must be in increasing order");
                  else           Error(where, "Y must have N+1 values with option N");
                  return;
               }
               gywork[npt-1] = y[j-1];       gywork[npt] = y[j];
            }
            gxwork[npt-1] = x[j-1];      gxwork[npt] = x[j-1];
            if ((gxwork[npt-1] >= uxmin-rounding && gxwork[npt-1] <= uxmax+rounding) ||
                (gxwork[npt]   >= uxmin-rounding && gxwork[npt]   <= uxmax+rounding)) npt += 2;
            if (j == last) {
               gywork[npt-1] = gywork[npt-2];
               gxwork[npt-1] = gxwork[0];
               ComputeLogs(npt, optionZ);
               gPad->PaintFillArea(npt,gxworkl,gyworkl);
               if (drawborder) {
                  if (!fillarea) gyworkl[0] = ylast;
                  gPad->PaintPolyLine(npt-1,gxworkl,gyworkl,noClip);
               }
               continue;
            }
         }  //endfor (j=first; j<=last;j++)
      }
      theGraph->TAttLine::Modify();
      theGraph->TAttFill::Modify();
   }

   //      Draw a standard Histogram (default)

   if ((optionHist) || !chopt[0]) {
      if (!optionRot) {
         gxwork[0] = wmin;
         gywork[0] = gPad->GetUymin();
         ywmin    = gywork[0];
         npt      = 2;
         for (i=first; i<=last;i++) {
            if (!optionBins) {
               gxwork[npt-1] = gxwork[npt-2];
               gxwork[npt]   = wmin+((i-first+1)*delta);
            } else {
               xi1 = x[i];      xi  = x[i-1];
               if (xi1 < xi) {
                  if (i != last) Error(where, "X must be in increasing order");
                  else           Error(where, "X must have N+1 values with option N");
                  return;
               }
               gxwork[npt-1] = x[i-1];      gxwork[npt] = x[i];
            }
            gywork[npt-1] = y[i-1];
            gywork[npt]   = y[i-1];
            if (gywork[npt] < vymin) {gywork[npt] = vymin; gywork[npt-1] = vymin;}
            if ((gxwork[npt-1] >= uxmin-rounding && gxwork[npt-1] <= uxmax+rounding) ||
                (gxwork[npt]   >= uxmin-rounding && gxwork[npt]   <= uxmax+rounding)) npt += 2;
            if (i == last) {
               gxwork[npt-1] = gxwork[npt-2];
               gywork[npt-1] = gywork[0];
               //make sure that the fill area does not overwrite the frame
               //take into account the frame linewidth
               if (gxwork[0] < vxmin) {gxwork[0] = vxmin; gxwork[1    ] = vxmin;}
               if (gywork[0] < vymin) {gywork[0] = vymin; gywork[npt-1] = vymin;}

               ComputeLogs(npt, optionZ);

               // do not draw the two vertical lines on the edges
               Int_t nbpoints = npt-2;
               Int_t point1  = 1;

               if (optionOff) {
                  // remove points before the low cutoff
                  Int_t ip;
                  for (ip=point1; ip<=nbpoints; ip++) {
                     if (gyworkl[ip] != ywmin) {
                        point1 = ip;
                        break;
                     }
                  }
                  // remove points after the high cutoff
                  Int_t point2 = nbpoints;
                  for (ip=point2; ip>=point1; ip--) {
                     if (gyworkl[ip] != ywmin) {
                        point2 = ip;
                        break;
                     }
                  }
                  nbpoints = point2-point1+1;
               } else {
                  // if the 1st or last bin are not on the pad limits the
                  // the two vertical lines on the edges are added.
                  if (gxwork[0] > gPad->GetUxmin()) { nbpoints++; point1 = 0; }
                  if (gxwork[nbpoints] < gPad->GetUxmax()) nbpoints++;
               }

               gPad->PaintPolyLine(nbpoints,&gxworkl[point1],&gyworkl[point1],noClip);
               continue;
            }
         }  //endfor (i=first; i<=last;i++)
      } else {
         gywork[0] = wmin;
         gxwork[0] = TMath::Max((Double_t)0,gPad->GetUxmin());
         xwmin    = gxwork[0];
         npt      = 2;
         for (i=first; i<=last;i++) {
            if (!optionBins) {
               gywork[npt-1]   = gywork[npt-2];
               gywork[npt] = wmin+((i-first+1)*delta);
            } else {
               yi1 = y[i];      yi  = y[i-1];
               if (yi1 < yi) {
                  if (i != last) Error(where, "Y must be in increasing order");
                  else           Error(where, "Y must have N+1 values with option N");
                  return;
               }
               gywork[npt-1] = y[i-1];      gywork[npt] = y[i];
            }
            gxwork[npt-1] = x[i-1];      gxwork[npt] = x[i-1];
            if ((gxwork[npt-1] >= uxmin-rounding && gxwork[npt-1] <= uxmax+rounding) ||
                (gxwork[npt]   >= uxmin-rounding && gxwork[npt]   <= uxmax+rounding)) npt += 2;
            if (i == last) {
               gywork[npt-1] = gywork[npt-2];
               gxwork[npt-1] = xwmin;
               ComputeLogs(npt, optionZ);
               gPad->PaintPolyLine(npt,gxworkl,gyworkl,noClip);
               continue;
            }
         }  //endfor (i=first; i<=last;i++)
      }
   }

   //              Draw the histogram with a smooth Curve.
   //              The smoothing is done by the method Smooth()

   if (optionCurve) {
      if (!optionFill) {
         drawtype = 1;
      } else {
         if (!optionOne) drawtype = 2;
         else            drawtype = 3;
      }
      if (!optionRot) {
         npt = 0;
         for (i=first; i<=last;i++) {
            npt++;
            if (!optionBins) {
               gxwork[npt-1] = wmin+(i-first)*delta+0.5*delta;
            } else {
               xi1 = x[i];      xi  = x[i-1];
               if (xi1 < xi) {
                  if (i != last) Error(where, "X must be in increasing order");
                  else           Error(where, "X must have N+1 values with option N");
                  return;
               }
               gxwork[npt-1] = x[i-1] + 0.5*(x[i]-x[i-1]);
            }
            if (gxwork[npt-1] < uxmin || gxwork[npt-1] > uxmax) {
               npt--;
               continue;
            }
            gywork[npt-1] = y[i-1];
            ComputeLogs(npt, optionZ);
            if ((gyworkl[npt-1] < rwymin) || (gyworkl[npt-1] > rwymax)) {
               if (npt > 2) {
                  ComputeLogs(npt, optionZ);
                  Smooth(theGraph, npt,gxworkl,gyworkl,drawtype);
               }
               gxwork[0] = gxwork[npt-1];
               gywork[0] = gywork[npt-1];
               npt      = 1;
               continue;
            }
            if (npt >= 50) {
               ComputeLogs(50, optionZ);
               Smooth(theGraph, 50,gxworkl,gyworkl,drawtype);
               gxwork[0] = gxwork[npt-1];
               gywork[0] = gywork[npt-1];
               npt      = 1;
            }
         }  //endfor (i=first; i<=last;i++)
         if (npt > 1) {
            ComputeLogs(npt, optionZ);
            Smooth(theGraph, npt,gxworkl,gyworkl,drawtype);
         }
      } else {
         drawtype = drawtype+10;
         npt   = 0;
         for (i=first; i<=last;i++) {
            npt++;
            if (!optionBins) {
               gywork[npt-1] = wmin+(i-first)*delta+0.5*delta;
            } else {
               yi1 = y[i];      yi = y[i-1];
               if (yi1 < yi) {
                  if (i != last) Error(where, "Y must be in increasing order");
                  else           Error(where, "Y must have N+1 values with option N");
                  return;
               }
               gywork[npt-1] = y[i-1] + 0.5*(y[i]-y[i-1]);
            }
            gxwork[npt-1] = x[i-1];
            ComputeLogs(npt, optionZ);
            if ((gxworkl[npt] < uxmin) || (gxworkl[npt] > uxmax)) {
               if (npt > 2) {
                  ComputeLogs(npt, optionZ);
                  Smooth(theGraph, npt,gxworkl,gyworkl,drawtype);
               }
               gxwork[0] = gxwork[npt-1];
               gywork[0] = gywork[npt-1];
               npt      = 1;
               continue;
            }
            if (npt >= 50) {
               ComputeLogs(50, optionZ);
               Smooth(theGraph, 50,gxworkl,gyworkl,drawtype);
               gxwork[0] = gxwork[npt-1];
               gywork[0] = gywork[npt-1];
               npt      = 1;
            }
         }  //endfor (i=first; i<=last;i++)
         if (npt > 1) {
            ComputeLogs(npt, optionZ);
            Smooth(theGraph, npt,gxworkl,gyworkl,drawtype);
         }
      }
   }

   //    Draw the histogram with a simple line or/and a marker

   optionMarker = 0;
   if ((optionStar) || (optionMark))optionMarker=1;
   if ((optionMarker) || (optionLine)) {
      wminstep = wmin + 0.5*delta;
      Axis_t ax1,ax2,ay1,ay2;
      gPad->GetRangeAxis(ax1,ay1,ax2,ay2);

      if (!optionRot) {
         npt = 0;
         for (i=first; i<=last;i++) {
            npt++;
            if (!optionBins) {
               gxwork[npt-1] = wmin+(i-first)*delta+0.5*delta;
            } else {
               xi1 = x[i];      xi = x[i-1];
               if (xi1 < xi) {
                  if (i != last) Error(where, "X must be in increasing order");
                  else           Error(where, "X must have N+1 values with option N");
                  return;
               }
               gxwork[npt-1] = x[i-1] + 0.5*(x[i]-x[i-1]);
            }
            if (gxwork[npt-1] < uxmin || gxwork[npt-1] > uxmax) { npt--; continue;}
            if ((optionMark != 10) && (optionLine == 0)) {
               if (y[i-1] <= rwymin)  {npt--; continue;}
            }
            gywork[npt-1] = y[i-1];
            gywork[npt]   = y[i-1]; //new
            if ((gywork[npt-1] < rwymin) || ((gywork[npt-1] > rwymax) && !optionFill2)) {
               if ((gywork[npt-1] < rwymin)) gywork[npt-1] = rwymin;
               if ((gywork[npt-1] > rwymax)) gywork[npt-1] = rwymax;
               if (npt > 2) {
                  if (optionMarker) {
                     ComputeLogs(npt, optionZ);
                     gPad->PaintPolyMarker(npt,gxworkl,gyworkl);
                  }
                  if (optionLine) {
                     if (!optionMarker) ComputeLogs(npt, optionZ);
                     gPad->PaintPolyLine(npt,gxworkl,gyworkl,noClip);
                  }
               }
               gxwork[0] = gxwork[npt-1];
               gywork[0] = gywork[npt-1];
               npt       = 1;
               continue;
            }

            if (npt >= 50) {
               if (optionMarker) {
                  ComputeLogs(50, optionZ);
                  gPad->PaintPolyMarker(50,gxworkl,gyworkl);
               }
               if (optionLine) {
                  if (!optionMarker) ComputeLogs(50, optionZ);
                  if (optionFill2) {
                     gxworkl[npt]   = gxworkl[npt-1]; gyworkl[npt]   = rwymin;
                     gxworkl[npt+1] = gxworkl[0];     gyworkl[npt+1] = rwymin;
                     gPad->PaintFillArea(52,gxworkl,gyworkl);
                  }
                  gPad->PaintPolyLine(50,gxworkl,gyworkl);
               }
               gxwork[0] = gxwork[npt-1];
               gywork[0] = gywork[npt-1];
               npt      = 1;
            }
         }  //endfor (i=first; i<=last;i++)
         if (optionMarker && npt > 0) {
            ComputeLogs(npt, optionZ);
            gPad->PaintPolyMarker(npt,gxworkl,gyworkl);
         }
         if (optionLine && npt > 1) {
            if (!optionMarker) ComputeLogs(npt, optionZ);
            if (optionFill2) {
               gxworkl[npt]   = gxworkl[npt-1]; gyworkl[npt]   = rwymin;
               gxworkl[npt+1] = gxworkl[0];     gyworkl[npt+1] = rwymin;
               gPad->PaintFillArea(npt+2,gxworkl,gyworkl);
            }
            gPad->PaintPolyLine(npt,gxworkl,gyworkl);
         }
      } else {
         npt = 0;
         for (i=first; i<=last;i++) {
            npt++;
            if (!optionBins) {
               gywork[npt-1] = wminstep+(i-first)*delta+0.5*delta;
            } else {
               yi1 = y[i];      yi = y[i-1];
               if (yi1 < yi) {
                  if (i != last) Error(where, "Y must be in increasing order");
                  else           Error(where, "Y must have N+1 values with option N");
                  return;
               }
               gywork[npt-1] = y[i-1] + 0.5*(y[i]-y[i-1]);
            }
            gxwork[npt-1] = x[i-1];
            if ((gxwork[npt-1] < uxmin) || (gxwork[npt-1] > uxmax)) {
               if (npt > 2) {
                  if (optionMarker) {
                     ComputeLogs(npt, optionZ);
                     gPad->PaintPolyMarker(npt,gxworkl,gyworkl);
                  }
                  if (optionLine) {
                     if (!optionMarker) ComputeLogs(npt, optionZ);
                     gPad->PaintPolyLine(npt,gxworkl,gyworkl,noClip);
                  }
               }
               gxwork[0] = gxwork[npt-1];
               gywork[0] = gywork[npt-1];
               npt      = 1;
               continue;
            }
            if (npt >= 50) {
               if (optionMarker) {
                  ComputeLogs(50, optionZ);
                  gPad->PaintPolyMarker(50,gxworkl,gyworkl);
               }
               if (optionLine) {
                  if (!optionMarker) ComputeLogs(50, optionZ);
                  gPad->PaintPolyLine(50,gxworkl,gyworkl);
               }
               gxwork[0] = gxwork[npt-1];
               gywork[0] = gywork[npt-1];
               npt      = 1;
            }
         }  //endfor (i=first; i<=last;i++)
         if (optionMarker && npt > 0) {
            ComputeLogs(npt, optionZ);
            gPad->PaintPolyMarker(npt,gxworkl,gyworkl);
         }
         if (optionLine != 0 && npt > 1) {
            if (!optionMarker) ComputeLogs(npt, optionZ);
            gPad->PaintPolyLine(npt,gxworkl,gyworkl,noClip);
         }
      }
   }

   //              Draw the histogram as a bar chart

   if (optionBar) {
      if (!optionBins) {
         offset = delta*baroffset; dbar = delta*barwidth;
      } else {
         if (!optionRot) {
            offset = (x[1]-x[0])*baroffset;
            dbar   = (x[1]-x[0])*barwidth;
         } else {
            offset = (y[1]-y[0])*baroffset;
            dbar   = (y[1]-y[0])*barwidth;
         }
      }
      drawbordersav = drawborder;
      gStyle->SetDrawBorder(1);
      if (!optionRot) {
         xlow  = wmin+offset;
         xhigh = wmin+offset+dbar;
         if (!optionOne) ylow = TMath::Min(TMath::Max((Double_t)0,gPad->GetUymin())
                                ,gPad->GetUymax());
         else            ylow = gPad->GetUymin();

         for (i=first; i<=last;i++) {
            yhigh    = y[i-1];
            gxwork[0] = xlow;
            gywork[0] = ylow;
            gxwork[1] = xhigh;
            gywork[1] = yhigh;
            ComputeLogs(2, optionZ);
            gPad->PaintBox(gxworkl[0],gyworkl[0],gxworkl[1],gyworkl[1]);
            if (!optionBins) {
               xlow  = xlow+delta;
               xhigh = xhigh+delta;
            } else {
               if (i < last) {
                  xi1 = x[i];      xi = x[i-1];
                  if (xi1 < xi) {
                     Error(where, "X must be in increasing order");
                     return;
                  }
                  offset  = (x[i+1]-x[i])*baroffset;
                  dbar    = (x[i+1]-x[i])*barwidth;
                  xlow    = x[i] + offset;
                  xhigh   = x[i] + offset + dbar;
               }
            }
         }  //endfor (i=first; i<=last;i++)
      } else {
         ylow  = wmin + offset;
         yhigh = wmin + offset + dbar;
         if (!optionOne) xlow = TMath::Max((Double_t)0,gPad->GetUxmin());
         else            xlow = gPad->GetUxmin();

         for (i=first; i<=last;i++) {
            xhigh    = x[i-1];
            gxwork[0] = xlow;
            gywork[0] = ylow;
            gxwork[1] = xhigh;
            gywork[1] = yhigh;
            ComputeLogs(2, optionZ);
            gPad->PaintBox(gxworkl[0],gyworkl[0],gxworkl[1],gyworkl[1]);
            gPad->PaintBox(xlow,ylow,xhigh,yhigh);
            if (!optionBins) {
               ylow  = ylow  + delta;
               yhigh = yhigh + delta;
            } else {
               if (i < last) {
                  yi1 = y[i];      yi = y[i-1];
                  if (yi1 < yi) {
                     Error(where, "Y must be in increasing order");
                     return;
                  }
                  offset  = (y[i+1]-y[i])*baroffset;
                  dbar    = (y[i+1]-y[i])*barwidth;
                  ylow    = y[i] + offset;
                  yhigh   = y[i] + offset + dbar;
               }
            }
         }  //endfor (i=first; i<=last;i++)
      }
      gStyle->SetDrawBorder(drawbordersav);
   }
   gPad->ResetBit(TGraph::kClipFrame);

   delete [] gxwork;
   delete [] gywork;
   delete [] gxworkl;
   delete [] gyworkl;
}


//______________________________________________________________________________
void TGraphPainter::PaintGraphAsymmErrors(TGraph *theGraph, Option_t *option)
{
   /* Begin_Html
   <a href="#GP03">Paint this TGraphAsymmErrors with its current attributes.</a>
   End_Html */

   Double_t *xline = 0;
   Double_t *yline = 0;
   Int_t if1 = 0;
   Int_t if2 = 0;
   Double_t xb[4], yb[4];

   const Int_t kBASEMARKER=8;
   Double_t s2x, s2y, symbolsize, sbase;
   Double_t x, y, xl1, xl2, xr1, xr2, yup1, yup2, ylow1, ylow2, tx, ty;
   static Float_t cxx[15] = {1,1,0.6,0.6,1,1,0.6,0.5,1,0.6,0.6,1,0.6,1,1};
   static Float_t cyy[15] = {1,1,1,1,1,1,1,1,1,0.5,0.6,1,1,1,1};
   Int_t theNpoints = theGraph->GetN();
   Double_t *theX  = theGraph->GetX();
   Double_t *theY  = theGraph->GetY();
   Double_t *theEXlow  = theGraph->GetEXlow();  if (!theEXlow) return;
   Double_t *theEYlow  = theGraph->GetEYlow();  if (!theEYlow) return;
   Double_t *theEXhigh = theGraph->GetEXhigh(); if (!theEXhigh) return;
   Double_t *theEYhigh = theGraph->GetEYhigh(); if (!theEYhigh) return;

   if (strchr(option,'X') || strchr(option,'x')) {PaintGraphSimple(theGraph, option); return;}
   Bool_t brackets = kFALSE;
   Bool_t braticks = kFALSE;
   if (strstr(option,"||") || strstr(option,"[]")) {
      brackets = kTRUE;
      if (strstr(option,"[]")) braticks = kTRUE;
   }
   Bool_t endLines = kTRUE;
   if (strchr(option,'z')) endLines = kFALSE;
   if (strchr(option,'Z')) endLines = kFALSE;
   const char *arrowOpt = 0;
   if (strchr(option,'>'))  arrowOpt = ">";
   if (strstr(option,"|>")) arrowOpt = "|>";

   Bool_t axis = kFALSE;
   if (strchr(option,'a')) axis = kTRUE;
   if (strchr(option,'A')) axis = kTRUE;
   if (axis) PaintGraphSimple(theGraph, option);

   Bool_t option0 = kFALSE;
   Bool_t option2 = kFALSE;
   Bool_t option3 = kFALSE;
   Bool_t option4 = kFALSE;
   Bool_t option5 = kFALSE;
   if (strchr(option,'0')) option0 = kTRUE;
   if (strchr(option,'2')) option2 = kTRUE;
   if (strchr(option,'3')) option3 = kTRUE;
   if (strchr(option,'4')) {option3 = kTRUE; option4 = kTRUE;}
   if (strchr(option,'5')) {option2 = kTRUE; option5 = kTRUE;}

   if (option3) {
      xline = new Double_t[2*theNpoints];
      yline = new Double_t[2*theNpoints];
      if (!xline || !yline) {
         Error("Paint", "too many points, out of memory");
         return;
      }
      if1 = 1;
      if2 = 2*theNpoints;
   }

   theGraph->TAttLine::Modify();

   TArrow arrow;
   arrow.SetLineWidth(theGraph->GetLineWidth());
   arrow.SetLineColor(theGraph->GetLineColor());
   arrow.SetFillColor(theGraph->GetFillColor());

   TBox box;
   Double_t x1b,y1b,x2b,y2b;
   box.SetLineWidth(theGraph->GetLineWidth());
   box.SetLineColor(theGraph->GetLineColor());
   box.SetFillColor(theGraph->GetFillColor());
   box.SetFillStyle(theGraph->GetFillStyle());

   symbolsize  = theGraph->GetMarkerSize();
   sbase       = symbolsize*kBASEMARKER;
   Int_t mark  = theGraph->GetMarkerStyle();
   Double_t cx  = 0;
   Double_t cy  = 0;
   if (mark >= 20 && mark <= 34) {
      cx = cxx[mark-20];
      cy = cyy[mark-20];
   }

   // Define the offset of the error bars due to the symbol size
   s2x  = gPad->PixeltoX(Int_t(0.5*sbase)) - gPad->PixeltoX(0);
   s2y  =-gPad->PixeltoY(Int_t(0.5*sbase)) + gPad->PixeltoY(0);
   Int_t dxend = Int_t(gStyle->GetEndErrorSize());
   tx    = gPad->PixeltoX(dxend) - gPad->PixeltoX(0);
   ty    =-gPad->PixeltoY(dxend) + gPad->PixeltoY(0);
   Float_t asize = 0.6*symbolsize*kBASEMARKER/gPad->GetWh();

   gPad->SetBit(TGraph::kClipFrame, theGraph->TestBit(TGraph::kClipFrame));
   for (Int_t i=0;i<theNpoints;i++) {
      x  = gPad->XtoPad(theX[i]);
      y  = gPad->YtoPad(theY[i]);
      if (!option0) {
         if (option3) {
            if (x < gPad->GetUxmin()) x = gPad->GetUxmin();
            if (x > gPad->GetUxmax()) x = gPad->GetUxmax();
            if (y < gPad->GetUymin()) y = gPad->GetUymin();
            if (y > gPad->GetUymax()) y = gPad->GetUymax();
         } else {
            if (x < gPad->GetUxmin()) continue;
            if (x > gPad->GetUxmax()) continue;
            if (y < gPad->GetUymin()) continue;
            if (y > gPad->GetUymax()) continue;
         }
      }
      xl1 = x - s2x*cx;
      xl2 = gPad->XtoPad(theX[i] - theEXlow[i]);

      //  draw the error rectangles
      if (option2) {
         x1b = gPad->XtoPad(theX[i] - theEXlow[i]);
         y1b = gPad->YtoPad(theY[i] - theEYlow[i]);
         x2b = gPad->XtoPad(theX[i] + theEXhigh[i]);
         y2b = gPad->YtoPad(theY[i] + theEYhigh[i]);
         if (x1b < gPad->GetUxmin()) x1b = gPad->GetUxmin();
         if (x1b > gPad->GetUxmax()) x1b = gPad->GetUxmax();
         if (y1b < gPad->GetUymin()) y1b = gPad->GetUymin();
         if (y1b > gPad->GetUymax()) y1b = gPad->GetUymax();
         if (x2b < gPad->GetUxmin()) x2b = gPad->GetUxmin();
         if (x2b > gPad->GetUxmax()) x2b = gPad->GetUxmax();
         if (y2b < gPad->GetUymin()) y2b = gPad->GetUymin();
         if (y2b > gPad->GetUymax()) y2b = gPad->GetUymax();
         if (option5) box.PaintBox(x1b, y1b, x2b, y2b, "l");
         else         box.PaintBox(x1b, y1b, x2b, y2b);
         continue;
      }

      //  keep points for fill area drawing
      if (option3) {
         xline[if1-1] = x;
         xline[if2-1] = x;
         yline[if1-1] = gPad->YtoPad(theY[i] + theEYhigh[i]);
         yline[if2-1] = gPad->YtoPad(theY[i] - theEYlow[i]);
         if1++;
         if2--;
         continue;
      }

      if (xl1 > xl2) {
         if (arrowOpt) {
            arrow.PaintArrow(xl1,y,xl2,y,asize,arrowOpt);
         } else {
            if (!brackets) gPad->PaintLine(xl1,y,xl2,y);
            if (endLines) {
               if (braticks) {
                  xb[0] = xl2+tx; yb[0] = y-ty;
                  xb[1] = xl2;    yb[1] = y-ty;
                  xb[2] = xl2;    yb[2] = y+ty;
                  xb[3] = xl2+tx; yb[3] = y+ty;
                  gPad->PaintPolyLine(4, xb, yb);
               } else {
                  gPad->PaintLine(xl2,y-ty,xl2,y+ty);
               }
            }
         }
      }
      xr1 = x + s2x*cx;
      xr2 = gPad->XtoPad(theX[i] + theEXhigh[i]);
      if (xr1 < xr2) {
         if (arrowOpt) {
            arrow.PaintArrow(xr1,y,xr2,y,asize,arrowOpt);
         } else {
            if (!brackets) gPad->PaintLine(xr1,y,xr2,y);
            if (endLines) {
               if (braticks) {
                  xb[0] = xr2-tx; yb[0] = y-ty;
                  xb[1] = xr2;    yb[1] = y-ty;
                  xb[2] = xr2;    yb[2] = y+ty;
                  xb[3] = xr2-tx; yb[3] = y+ty;
                  gPad->PaintPolyLine(4, xb, yb);
               } else {
                  gPad->PaintLine(xr2,y-ty,xr2,y+ty);
               }
            }
         }
      }
      yup1 = y + s2y*cy;
      yup2 = gPad->YtoPad(theY[i] + theEYhigh[i]);
      if (yup2 > gPad->GetUymax()) yup2 =  gPad->GetUymax();
      if (yup2 > yup1) {
         if (arrowOpt) {
            arrow.PaintArrow(x,yup1,x,yup2,asize,arrowOpt);
         } else {
            if (!brackets) gPad->PaintLine(x,yup1,x,yup2);
            if (endLines) {
               if (braticks) {
                  xb[0] = x-tx; yb[0] = yup2-ty;
                  xb[1] = x-tx; yb[1] = yup2;
                  xb[2] = x+tx; yb[2] = yup2;
                  xb[3] = x+tx; yb[3] = yup2-ty;
                  gPad->PaintPolyLine(4, xb, yb);
               } else {
                  gPad->PaintLine(x-tx,yup2,x+tx,yup2);
               }
            }
         }
      }
      ylow1 = y - s2y*cy;
      ylow2 = gPad->YtoPad(theY[i] - theEYlow[i]);
      if (ylow2 < gPad->GetUymin()) ylow2 =  gPad->GetUymin();
      if (ylow2 < ylow1) {
         if (arrowOpt) {
            arrow.PaintArrow(x,ylow1,x,ylow2,asize,arrowOpt);
         } else {
            if (!brackets) gPad->PaintLine(x,ylow1,x,ylow2);
            if (endLines) {
               if (braticks) {
                  xb[0] = x-tx; yb[0] = ylow2+ty;
                  xb[1] = x-tx; yb[1] = ylow2;
                  xb[2] = x+tx; yb[2] = ylow2;
                  xb[3] = x+tx; yb[3] = ylow2+ty;
                  gPad->PaintPolyLine(4, xb, yb);
               } else {
                  gPad->PaintLine(x-tx,ylow2,x+tx,ylow2);
               }
            }
         }
      }
   }
   if (!brackets && !axis) PaintGraphSimple(theGraph, option);
   gPad->ResetBit(TGraph::kClipFrame);

   if (option3) {
      Int_t logx = gPad->GetLogx();
      Int_t logy = gPad->GetLogy();
      gPad->SetLogx(0);
      gPad->SetLogy(0);
      if (option4) PaintGraph(theGraph, 2*theNpoints, xline, yline,"FC");
      else         PaintGraph(theGraph, 2*theNpoints, xline, yline,"F");
      gPad->SetLogx(logx);
      gPad->SetLogy(logy);
      delete [] xline;
      delete [] yline;
   }
}


//_____________________________________________________________________________
void TGraphPainter::PaintGraphBentErrors(TGraph *theGraph, Option_t *option)
{
   /* Begin_Html
   <a href="#GP03">Paint this TGraphBentErrors with its current attributes.</a>
   End_Html */

   Double_t *xline = 0;
   Double_t *yline = 0;
   Int_t if1 = 0;
   Int_t if2 = 0;
   Double_t xb[4], yb[4];

   const Int_t kBASEMARKER=8;
   Double_t s2x, s2y, symbolsize, sbase;
   Double_t x, y, xl1, xl2, xr1, xr2, yup1, yup2, ylow1, ylow2, tx, ty;
   Double_t bxl, bxh, byl, byh;
   static Float_t cxx[15] = {1,1,0.6,0.6,1,1,0.6,0.5,1,0.6,0.6,1,0.6,1,1};
   static Float_t cyy[15] = {1,1,1,1,1,1,1,1,1,0.5,0.6,1,1,1,1};
   Int_t theNpoints = theGraph->GetN();
   Double_t *theX  = theGraph->GetX();
   Double_t *theY  = theGraph->GetY();
   Double_t *theEXlow   = theGraph->GetEXlow();   if (!theEXlow) return;
   Double_t *theEYlow   = theGraph->GetEYlow();   if (!theEYlow) return;
   Double_t *theEXhigh  = theGraph->GetEXhigh();  if (!theEXhigh) return;
   Double_t *theEYhigh  = theGraph->GetEYhigh();  if (!theEYhigh) return;
   Double_t *theEXlowd  = theGraph->GetEXlowd();  if (!theEXlowd) return;
   Double_t *theEXhighd = theGraph->GetEXhighd(); if (!theEXhighd) return;
   Double_t *theEYlowd  = theGraph->GetEYlowd();  if (!theEYlowd) return;
   Double_t *theEYhighd = theGraph->GetEYhighd(); if (!theEYhighd) return;

   if (strchr(option,'X') || strchr(option,'x')) {PaintGraphSimple(theGraph, option); return;}
   Bool_t brackets = kFALSE;
   Bool_t braticks = kFALSE;
   if (strstr(option,"||") || strstr(option,"[]")) {
      brackets = kTRUE;
      if (strstr(option,"[]")) braticks = kTRUE;
   }
   Bool_t endLines = kTRUE;
   if (strchr(option,'z')) endLines = kFALSE;
   if (strchr(option,'Z')) endLines = kFALSE;
   const char *arrowOpt = 0;
   if (strchr(option,'>'))  arrowOpt = ">";
   if (strstr(option,"|>")) arrowOpt = "|>";

   Bool_t axis = kFALSE;
   if (strchr(option,'a')) axis = kTRUE;
   if (strchr(option,'A')) axis = kTRUE;
   if (axis) PaintGraphSimple(theGraph,option);

   Bool_t option0 = kFALSE;
   Bool_t option2 = kFALSE;
   Bool_t option3 = kFALSE;
   Bool_t option4 = kFALSE;
   Bool_t option5 = kFALSE;
   if (strchr(option,'0')) option0 = kTRUE;
   if (strchr(option,'2')) option2 = kTRUE;
   if (strchr(option,'3')) option3 = kTRUE;
   if (strchr(option,'4')) {option3 = kTRUE; option4 = kTRUE;}
   if (strchr(option,'5')) {option2 = kTRUE; option5 = kTRUE;}

   if (option3) {
      xline = new Double_t[2*theNpoints];
      yline = new Double_t[2*theNpoints];
      if (!xline || !yline) {
         Error("Paint", "too many points, out of memory");
         return;
      }
      if1 = 1;
      if2 = 2*theNpoints;
   }

   theGraph->TAttLine::Modify();

   TArrow arrow;
   arrow.SetLineWidth(theGraph->GetLineWidth());
   arrow.SetLineColor(theGraph->GetLineColor());
   arrow.SetFillColor(theGraph->GetFillColor());

   TBox box;
   Double_t x1b,y1b,x2b,y2b;
   box.SetLineWidth(theGraph->GetLineWidth());
   box.SetLineColor(theGraph->GetLineColor());
   box.SetFillColor(theGraph->GetFillColor());
   box.SetFillStyle(theGraph->GetFillStyle());

   symbolsize  = theGraph->GetMarkerSize();
   sbase       = symbolsize*kBASEMARKER;
   Int_t mark  = theGraph->GetMarkerStyle();
   Double_t cx  = 0;
   Double_t cy  = 0;
   if (mark >= 20 && mark <= 34) {
      cx = cxx[mark-20];
      cy = cyy[mark-20];
   }

   // define the offset of the error bars due to the symbol size
   s2x  = gPad->PixeltoX(Int_t(0.5*sbase)) - gPad->PixeltoX(0);
   s2y  =-gPad->PixeltoY(Int_t(0.5*sbase)) + gPad->PixeltoY(0);
   Int_t dxend = Int_t(gStyle->GetEndErrorSize());
   tx   = gPad->PixeltoX(dxend) - gPad->PixeltoX(0);
   ty   =-gPad->PixeltoY(dxend) + gPad->PixeltoY(0);
   Float_t asize = 0.6*symbolsize*kBASEMARKER/gPad->GetWh();

   gPad->SetBit(TGraph::kClipFrame, theGraph->TestBit(TGraph::kClipFrame));
   for (Int_t i=0;i<theNpoints;i++) {
      x  = gPad->XtoPad(theX[i]);
      y  = gPad->YtoPad(theY[i]);
      bxl = gPad->YtoPad(theY[i]+theEXlowd[i]);
      bxh = gPad->YtoPad(theY[i]+theEXhighd[i]);
      byl = gPad->XtoPad(theX[i]+theEYlowd[i]);
      byh = gPad->XtoPad(theX[i]+theEYhighd[i]);
      if (!option0) {
         if (option3) {
            if (x < gPad->GetUxmin()) x = gPad->GetUxmin();
            if (x > gPad->GetUxmax()) x = gPad->GetUxmax();
            if (y < gPad->GetUymin()) y = gPad->GetUymin();
            if (y > gPad->GetUymax()) y = gPad->GetUymax();
         } else {
            if (x < gPad->GetUxmin()) continue;
            if (x > gPad->GetUxmax()) continue;
            if (y < gPad->GetUymin()) continue;
            if (y > gPad->GetUymax()) continue;
         }
      }

      //  draw the error rectangles
      if (option2) {
         x1b = gPad->XtoPad(theX[i] - theEXlow[i]);
         y1b = gPad->YtoPad(theY[i] - theEYlow[i]);
         x2b = gPad->XtoPad(theX[i] + theEXhigh[i]);
         y2b = gPad->YtoPad(theY[i] + theEYhigh[i]);
         if (x1b < gPad->GetUxmin()) x1b = gPad->GetUxmin();
         if (x1b > gPad->GetUxmax()) x1b = gPad->GetUxmax();
         if (y1b < gPad->GetUymin()) y1b = gPad->GetUymin();
         if (y1b > gPad->GetUymax()) y1b = gPad->GetUymax();
         if (x2b < gPad->GetUxmin()) x2b = gPad->GetUxmin();
         if (x2b > gPad->GetUxmax()) x2b = gPad->GetUxmax();
         if (y2b < gPad->GetUymin()) y2b = gPad->GetUymin();
         if (y2b > gPad->GetUymax()) y2b = gPad->GetUymax();
         if (option5) box.PaintBox(x1b, y1b, x2b, y2b, "l");
         else         box.PaintBox(x1b, y1b, x2b, y2b);
         continue;
      }

      //  keep points for fill area drawing
      if (option3) {
         xline[if1-1] = byh;
         xline[if2-1] = byl;
         yline[if1-1] = gPad->YtoPad(theY[i] + theEYhigh[i]);
         yline[if2-1] = gPad->YtoPad(theY[i] - theEYlow[i]);
         if1++;
         if2--;
         continue;
      }

      xl1 = x - s2x*cx;
      xl2 = gPad->XtoPad(theX[i] - theEXlow[i]);
      if (xl1 > xl2) {
         if (arrowOpt) {
            arrow.PaintArrow(xl1,y,xl2,bxl,asize,arrowOpt);
         } else {
            if (!brackets) gPad->PaintLine(xl1,y,xl2,bxl);
            if (endLines) {
               if (braticks) {
                  xb[0] = xl2+tx; yb[0] = bxl-ty;
                  xb[1] = xl2;    yb[1] = bxl-ty;
                  xb[2] = xl2;    yb[2] = bxl+ty;
                  xb[3] = xl2+tx; yb[3] = bxl+ty;
                  gPad->PaintPolyLine(4, xb, yb);
               } else {
                  gPad->PaintLine(xl2,bxl-ty,xl2,bxl+ty);
               }
            }
         }
      }
      xr1 = x + s2x*cx;
      xr2 = gPad->XtoPad(theX[i] + theEXhigh[i]);
      if (xr1 < xr2) {
         if (arrowOpt) {
            arrow.PaintArrow(xr1,y,xr2,bxh,asize,arrowOpt);
         } else {
            if (!brackets) gPad->PaintLine(xr1,y,xr2,bxh);
            if (endLines) {
               if (braticks) {
                  xb[0] = xr2-tx; yb[0] = bxh-ty;
                  xb[1] = xr2;    yb[1] = bxh-ty;
                  xb[2] = xr2;    yb[2] = bxh+ty;
                  xb[3] = xr2-tx; yb[3] = bxh+ty;
                  gPad->PaintPolyLine(4, xb, yb);
               } else {
                  gPad->PaintLine(xr2,bxh-ty,xr2,bxh+ty);
               }
            }
         }
      }
      yup1 = y + s2y*cy;
      yup2 = gPad->YtoPad(theY[i] + theEYhigh[i]);
      if (yup2 > gPad->GetUymax()) yup2 =  gPad->GetUymax();
      if (yup2 > yup1) {
         if (arrowOpt) {
            arrow.PaintArrow(x,yup1,byh,yup2,asize,arrowOpt);
         } else {
            if (!brackets) gPad->PaintLine(x,yup1,byh,yup2);
            if (endLines) {
               if (braticks) {
                  xb[0] = byh-tx; yb[0] = yup2-ty;
                  xb[1] = byh-tx; yb[1] = yup2;
                  xb[2] = byh+tx; yb[2] = yup2;
                  xb[3] = byh+tx; yb[3] = yup2-ty;
                  gPad->PaintPolyLine(4, xb, yb);
               } else {
                  gPad->PaintLine(byh-tx,yup2,byh+tx,yup2);
               }
            }
         }
      }
      ylow1 = y - s2y*cy;
      ylow2 = gPad->YtoPad(theY[i] - theEYlow[i]);
      if (ylow2 < gPad->GetUymin()) ylow2 =  gPad->GetUymin();
      if (ylow2 < ylow1) {
         if (arrowOpt) {
            arrow.PaintArrow(x,ylow1,byl,ylow2,asize,arrowOpt);
         } else {
            if (!brackets) gPad->PaintLine(x,ylow1,byl,ylow2);
            if (endLines) {
               if (braticks) {
                  xb[0] = byl-tx; yb[0] = ylow2+ty;
                  xb[1] = byl-tx; yb[1] = ylow2;
                  xb[2] = byl+tx; yb[2] = ylow2;
                  xb[3] = byl+tx; yb[3] = ylow2+ty;
                  gPad->PaintPolyLine(4, xb, yb);
               } else {
                  gPad->PaintLine(byl-tx,ylow2,byl+tx,ylow2);
               }
            }
         }
      }
   }
   if (!brackets && !axis) PaintGraphSimple(theGraph, option);
   gPad->ResetBit(TGraph::kClipFrame);

   if (option3) {
      Int_t logx = gPad->GetLogx();
      Int_t logy = gPad->GetLogy();
      gPad->SetLogx(0);
      gPad->SetLogy(0);
      if (option4) PaintGraph(theGraph, 2*theNpoints, xline, yline,"FC");
      else         PaintGraph(theGraph, 2*theNpoints, xline, yline,"F");
      gPad->SetLogx(logx);
      gPad->SetLogy(logy);
      delete [] xline;
      delete [] yline;
   }
}


//______________________________________________________________________________
void TGraphPainter::PaintGraphErrors(TGraph *theGraph, Option_t *option)
{
   /* Begin_Html
   <a href="#GP03">Paint this TGraphErrors with its current attributes.</a>
   End_Html */

   Double_t *xline = 0;
   Double_t *yline = 0;
   Int_t if1 = 0;
   Int_t if2 = 0;
   Double_t xb[4], yb[4];

   const Int_t kBASEMARKER=8;
   Double_t s2x, s2y, symbolsize, sbase;
   Double_t x, y, ex, ey, xl1, xl2, xr1, xr2, yup1, yup2, ylow1, ylow2, tx, ty;
   static Float_t cxx[15] = {1,1,0.6,0.6,1,1,0.6,0.5,1,0.6,0.6,1,0.6,1,1};
   static Float_t cyy[15] = {1,1,1,1,1,1,1,1,1,0.5,0.6,1,1,1,1};
   Int_t theNpoints = theGraph->GetN();
   Double_t *theX  = theGraph->GetX();
   Double_t *theY  = theGraph->GetY();
   Double_t *theEX = theGraph->GetEX(); if (!theEX) return;
   Double_t *theEY = theGraph->GetEY(); if (!theEY) return;

   if (strchr(option,'X') || strchr(option,'x')) {PaintGraphSimple(theGraph, option); return;}
   Bool_t brackets = kFALSE;
   Bool_t braticks = kFALSE;
   if (strstr(option,"||") || strstr(option,"[]")) {
      brackets = kTRUE;
      if (strstr(option,"[]")) braticks = kTRUE;
   }
   Bool_t endLines = kTRUE;
   if (strchr(option,'z')) endLines = kFALSE;
   if (strchr(option,'Z')) endLines = kFALSE;
   const char *arrowOpt = 0;
   if (strchr(option,'>'))  arrowOpt = ">";
   if (strstr(option,"|>")) arrowOpt = "|>";

   Bool_t axis = kFALSE;
   if (strchr(option,'a')) axis = kTRUE;
   if (strchr(option,'A')) axis = kTRUE;
   if (axis) PaintGraphSimple(theGraph, option);

   Bool_t option0 = kFALSE;
   Bool_t option2 = kFALSE;
   Bool_t option3 = kFALSE;
   Bool_t option4 = kFALSE;
   Bool_t option5 = kFALSE;
   if (strchr(option,'0')) option0 = kTRUE;
   if (strchr(option,'2')) option2 = kTRUE;
   if (strchr(option,'3')) option3 = kTRUE;
   if (strchr(option,'4')) {option3 = kTRUE; option4 = kTRUE;}
   if (strchr(option,'5')) {option2 = kTRUE; option5 = kTRUE;}

   if (option3) {
      xline = new Double_t[2*theNpoints];
      yline = new Double_t[2*theNpoints];
      if (!xline || !yline) {
         Error("Paint", "too many points, out of memory");
         return;
      }
      if1 = 1;
      if2 = 2*theNpoints;
   }

   theGraph->TAttLine::Modify();

   TArrow arrow;
   arrow.SetLineWidth(theGraph->GetLineWidth());
   arrow.SetLineColor(theGraph->GetLineColor());
   arrow.SetFillColor(theGraph->GetFillColor());

   TBox box;
   Double_t x1b,y1b,x2b,y2b;
   box.SetLineWidth(theGraph->GetLineWidth());
   box.SetLineColor(theGraph->GetLineColor());
   box.SetFillColor(theGraph->GetFillColor());
   box.SetFillStyle(theGraph->GetFillStyle());

   symbolsize  = theGraph->GetMarkerSize();
   sbase       = symbolsize*kBASEMARKER;
   Int_t mark  = theGraph->GetMarkerStyle();
   Double_t cx  = 0;
   Double_t cy  = 0;
   if (mark >= 20 && mark <= 34) {
      cx = cxx[mark-20];
      cy = cyy[mark-20];
   }

   //      define the offset of the error bars due to the symbol size
   s2x  = gPad->PixeltoX(Int_t(0.5*sbase)) - gPad->PixeltoX(0);
   s2y  =-gPad->PixeltoY(Int_t(0.5*sbase)) + gPad->PixeltoY(0);
   Int_t dxend = Int_t(gStyle->GetEndErrorSize());
   tx    = gPad->PixeltoX(dxend) - gPad->PixeltoX(0);
   ty    =-gPad->PixeltoY(dxend) + gPad->PixeltoY(0);
   Float_t asize = 0.6*symbolsize*kBASEMARKER/gPad->GetWh();

   gPad->SetBit(TGraph::kClipFrame, theGraph->TestBit(TGraph::kClipFrame));
   for (Int_t i=0;i<theNpoints;i++) {
      x  = gPad->XtoPad(theX[i]);
      y  = gPad->YtoPad(theY[i]);
      if (!option0) {
         if (option3) {
            if (x < gPad->GetUxmin()) x = gPad->GetUxmin();
            if (x > gPad->GetUxmax()) x = gPad->GetUxmax();
            if (y < gPad->GetUymin()) y = gPad->GetUymin();
            if (y > gPad->GetUymax()) y = gPad->GetUymax();
         } else {
            if (x < gPad->GetUxmin()) continue;
            if (x > gPad->GetUxmax()) continue;
            if (y < gPad->GetUymin()) continue;
            if (y > gPad->GetUymax()) continue;
         }
      }
      ex = theEX[i];
      ey = theEY[i];

      //  draw the error rectangles
      if (option2) {
         x1b = gPad->XtoPad(theX[i] - ex);
         y1b = gPad->YtoPad(theY[i] - ey);
         x2b = gPad->XtoPad(theX[i] + ex);
         y2b = gPad->YtoPad(theY[i] + ey);
         if (x1b < gPad->GetUxmin()) x1b = gPad->GetUxmin();
         if (x1b > gPad->GetUxmax()) x1b = gPad->GetUxmax();
         if (y1b < gPad->GetUymin()) y1b = gPad->GetUymin();
         if (y1b > gPad->GetUymax()) y1b = gPad->GetUymax();
         if (x2b < gPad->GetUxmin()) x2b = gPad->GetUxmin();
         if (x2b > gPad->GetUxmax()) x2b = gPad->GetUxmax();
         if (y2b < gPad->GetUymin()) y2b = gPad->GetUymin();
         if (y2b > gPad->GetUymax()) y2b = gPad->GetUymax();
         if (option5) box.PaintBox(x1b, y1b, x2b, y2b, "l");
         else         box.PaintBox(x1b, y1b, x2b, y2b);
         continue;
      }

      //  keep points for fill area drawing
      if (option3) {
         xline[if1-1] = x;
         xline[if2-1] = x;
         yline[if1-1] = gPad->YtoPad(theY[i] + ey);
         yline[if2-1] = gPad->YtoPad(theY[i] - ey);
         if1++;
         if2--;
         continue;
      }

      xl1 = x - s2x*cx;
      xl2 = gPad->XtoPad(theX[i] - ex);
      if (xl1 > xl2) {
         if (arrowOpt) {
            arrow.PaintArrow(xl1,y,xl2,y,asize,arrowOpt);
         } else {
            if (!brackets) gPad->PaintLine(xl1,y,xl2,y);
            if (endLines) {
               if (braticks) {
                  xb[0] = xl2+tx; yb[0] = y-ty;
                  xb[1] = xl2;    yb[1] = y-ty;
                  xb[2] = xl2;    yb[2] = y+ty;
                  xb[3] = xl2+tx; yb[3] = y+ty;
                  gPad->PaintPolyLine(4, xb, yb);
               } else {
                  gPad->PaintLine(xl2,y-ty,xl2,y+ty);
               }
            }
         }
      }
      xr1 = x + s2x*cx;
      xr2 = gPad->XtoPad(theX[i] + ex);
      if (xr1 < xr2) {
         if (arrowOpt) {
            arrow.PaintArrow(xr1,y,xr2,y,asize,arrowOpt);
         } else {
            if (!brackets) gPad->PaintLine(xr1,y,xr2,y);
            if (endLines) {
               if (braticks) {
                  xb[0] = xr2-tx; yb[0] = y-ty;
                  xb[1] = xr2;    yb[1] = y-ty;
                  xb[2] = xr2;    yb[2] = y+ty;
                  xb[3] = xr2-tx; yb[3] = y+ty;
                  gPad->PaintPolyLine(4, xb, yb);
               } else {
                  gPad->PaintLine(xr2,y-ty,xr2,y+ty);
               }
            }
         }
      }
      yup1 = y + s2y*cy;
      yup2 = gPad->YtoPad(theY[i] + ey);
      if (yup2 > gPad->GetUymax()) yup2 =  gPad->GetUymax();
      if (yup2 > yup1) {
         if (arrowOpt) {
            arrow.PaintArrow(x,yup1,x,yup2,asize,arrowOpt);
         } else {
            if (!brackets) gPad->PaintLine(x,yup1,x,yup2);
            if (endLines) {
               if (braticks) {
                  xb[0] = x-tx; yb[0] = yup2-ty;
                  xb[1] = x-tx; yb[1] = yup2;
                  xb[2] = x+tx; yb[2] = yup2;
                  xb[3] = x+tx; yb[3] = yup2-ty;
                  gPad->PaintPolyLine(4, xb, yb);
               } else {
                  gPad->PaintLine(x-tx,yup2,x+tx,yup2);
               }
            }
         }
      }
      ylow1 = y - s2y*cy;
      ylow2 = gPad->YtoPad(theY[i] - ey);
      if (ylow2 < gPad->GetUymin()) ylow2 =  gPad->GetUymin();
      if (ylow2 < ylow1) {
         if (arrowOpt) {
            arrow.PaintArrow(x,ylow1,x,ylow2,asize,arrowOpt);
         } else {
            if (!brackets) gPad->PaintLine(x,ylow1,x,ylow2);
            if (endLines) {
               if (braticks) {
                  xb[0] = x-tx; yb[0] = ylow2+ty;
                  xb[1] = x-tx; yb[1] = ylow2;
                  xb[2] = x+tx; yb[2] = ylow2;
                  xb[3] = x+tx; yb[3] = ylow2+ty;
                  gPad->PaintPolyLine(4, xb, yb);
               } else {
                  gPad->PaintLine(x-tx,ylow2,x+tx,ylow2);
               }
            }
         }
      }
   }
   if (!brackets && !axis) PaintGraphSimple(theGraph, option);
   gPad->ResetBit(TGraph::kClipFrame);

   if (option3) {
      Int_t logx = gPad->GetLogx();
      Int_t logy = gPad->GetLogy();
      gPad->SetLogx(0);
      gPad->SetLogy(0);
      if (option4) PaintGraph(theGraph, 2*theNpoints, xline, yline,"FC");
      else         PaintGraph(theGraph, 2*theNpoints, xline, yline,"F");
      gPad->SetLogx(logx);
      gPad->SetLogy(logy);
      delete [] xline;
      delete [] yline;
   }
}


//______________________________________________________________________________
void TGraphPainter::PaintGraphPolar(TGraph *theGraph, Option_t* options)
{
   /* Begin_Html
   <a href="#GP04">Paint this TGraphPolar with its current attributes.</a>
   End_Html */

   Int_t ipt, i;
   Double_t rwrmin, rwrmax, rwtmin, rwtmax;

   TGraphPolar *theGraphPolar = (TGraphPolar*) theGraph;

   Int_t theNpoints  = theGraphPolar->GetN();
   Double_t *theX    = theGraphPolar->GetX();
   Double_t *theY    = theGraphPolar->GetY();
   Double_t *theEX   = theGraphPolar->GetEX();
   Double_t *theEY   = theGraphPolar->GetEY();

   if (theNpoints<1) return;
   TString opt = options;
   opt.ToUpper();

   Bool_t nolabel = kFALSE;
   if (opt.Contains("N")){
      nolabel = kTRUE;
      opt.ReplaceAll("N","");
   }

   TGraphPolargram *thePolargram = theGraphPolar->GetPolargram();

   // Check for existing TGraphPolargram in the Pad
   if (gPad) {
      // Existing polargram
      if (thePolargram) if (!gPad->FindObject(thePolargram->GetName())) thePolargram=0;
      if (!thePolargram) {
         // Find any other Polargram in the Pad
         TListIter padObjIter(gPad->GetListOfPrimitives());
         while (TObject* AnyObj = padObjIter.Next()) {
            if (TString(AnyObj->ClassName()).CompareTo("TGraphPolargram",
                                                      TString::kExact)==0)
            thePolargram = (TGraphPolargram*)AnyObj;
            theGraphPolar->SetPolargram(thePolargram);
         }
      }
   }

   // Get new polargram range if necessary.
   if (!thePolargram) {
      // Get range, initialize with first/last value
      rwrmin = theY[0]; rwrmax = theY[theNpoints-1];
      rwtmin = theX[0]; rwtmax = theX[theNpoints-1];

      for (ipt = 0; ipt < theNpoints; ipt++) {
         // Check for errors if available
         if (theEX) {
            if (theX[ipt] -theEX[ipt] < rwtmin) rwtmin = theX[ipt]-theEX[ipt];
            if (theX[ipt] +theEX[ipt] > rwtmax) rwtmax = theX[ipt]+theEX[ipt];
         } else {
            if (theX[ipt] < rwtmin) rwtmin=theX[ipt];
            if (theX[ipt] > rwtmax) rwtmax=theX[ipt];
         }
         if (theEY) {
            if (theY[ipt] -theEY[ipt] < rwrmin) rwrmin = theY[ipt]-theEY[ipt];
            if (theY[ipt] +theEY[ipt] > rwrmax) rwrmax = theY[ipt]+theEY[ipt];
         } else {
            if (theY[ipt] < rwrmin) rwrmin=theY[ipt];
            if (theY[ipt] > rwrmax) rwrmax=theY[ipt];
         }
      }
      // Add radial and Polar margins.
      if (rwrmin == rwrmax) rwrmax += 1.;
      if (rwtmin == rwtmax) rwtmax += 1.;
      Double_t dr = (rwrmax-rwrmin);
      Double_t dt = (rwtmax-rwtmin);
      rwrmax += 0.1*dr;
      rwrmin -= 0.1*dr;

      // Assume equaly spaced points for full 2*Pi.
      rwtmax += dt/theNpoints;
   } else {
      rwrmin = thePolargram->GetRMin();
      rwrmax = thePolargram->GetRMax();
      rwtmin = thePolargram->GetTMin();
      rwtmax = thePolargram->GetTMax();
   }

   if ((!thePolargram) || theGraphPolar->GetOptionAxis()) {
      // Draw Polar coord system
      thePolargram = new TGraphPolargram("Polargram",rwrmin,rwrmax,rwtmin,rwtmax);
      theGraphPolar->SetPolargram(thePolargram);
      if (opt.Contains("O")) thePolargram->SetBit(TGraphPolargram::kLabelOrtho);
      else thePolargram->ResetBit(TGraphPolargram::kLabelOrtho);
      if (nolabel) thePolargram->Draw("N");
      else         thePolargram->Draw("");
      theGraphPolar->SetOptionAxis(kFALSE);   //Prevent redrawing
   }

   // Convert points to polar.
   Double_t *theXpol = theGraphPolar->GetXpol();
   Double_t *theYpol = theGraphPolar->GetYpol();

   // Project theta in [0,2*Pi] and radius in [0,1].
   Double_t radiusNDC = rwrmax-rwrmin;
   Double_t thetaNDC  = (rwtmax-rwtmin)/(2*TMath::Pi());

   // Draw the error bars.
   // Y errors are lines, but X errors are pieces of circles.
   if (opt.Contains("E")) {
      if (theEY) {
         for (i=0; i<theNpoints; i++) {
            Double_t eymin, eymax, exmin,exmax;
            exmin = (theY[i]-theEY[i]-rwrmin)/radiusNDC*
                     TMath::Cos((theX[i]-rwtmin)/thetaNDC);
            eymin = (theY[i]-theEY[i]-rwrmin)/radiusNDC*
                     TMath::Sin((theX[i]-rwtmin)/thetaNDC);
            exmax = (theY[i]+theEY[i]-rwrmin)/radiusNDC*
                     TMath::Cos((theX[i]-rwtmin)/thetaNDC);
            eymax = (theY[i]+theEY[i]-rwrmin)/radiusNDC*
                     TMath::Sin((theX[i]-rwtmin)/thetaNDC);
            theGraphPolar->TAttLine::Modify();
            if (exmin != exmax || eymin != eymax) gPad->PaintLine(exmin,eymin,exmax,eymax);
         }
      }
      if (theEX) {
         for (i=0; i<theNpoints; i++) {
            Double_t rad = (theY[i]-rwrmin)/radiusNDC;
            Double_t phimin = (theX[i]-theEX[i]-rwtmin)/thetaNDC*180/TMath::Pi();
            Double_t phimax = (theX[i]+theEX[i]-rwtmin)/thetaNDC*180/TMath::Pi();
            theGraphPolar->TAttLine::Modify();
            if (phimin != phimax) thePolargram->PaintCircle(0,0,rad,phimin,phimax,0);
         }
      }
   }

   // Draw the graph itself.
   if (!(gPad->GetLogx()) && !(gPad->GetLogy())) {
      Double_t a, b, c=1, x1, x2, y1, y2, discr, norm1, norm2, xts, yts;
      Bool_t previouspointin = kFALSE;
      Double_t norm = 0;
      Double_t xt   = 0;
      Double_t yt   = 0 ;
      Int_t j       = -1;
      for (i=0; i<theNpoints; i++) {
         if (thePolargram->IsRadian()) {c=1;}
         if (thePolargram->IsDegree()) {c=180/TMath::Pi();}
         if (thePolargram->IsGrad())   {c=100/TMath::Pi();}
         xts  = xt;
         yts  = yt;
         xt   = (theY[i]-rwrmin)/radiusNDC*TMath::Cos(c*(theX[i]-rwtmin)/thetaNDC);
         yt   = (theY[i]-rwrmin)/radiusNDC*TMath::Sin(c*(theX[i]-rwtmin)/thetaNDC);
         norm = sqrt(xt*xt+yt*yt);
         // Check if points are in the main circle.
         if ( norm <= 1) {
            // We check that the previous point was in the circle too.
            // We record new point position.
            if (!previouspointin) {
               j++;
               theXpol[j] = xt;
               theYpol[j] = yt;
            } else {
               a = (yt-yts)/(xt-xts);
               b = yts-a*xts;
               discr = 4*(a*a-b*b+1);
               x1 = (-2*a*b+sqrt(discr))/(2*(a*a+1));
               x2 = (-2*a*b-sqrt(discr))/(2*(a*a+1));
               y1 = a*x1+b;
               y2 = a*x2+b;
               norm1 = sqrt((x1-xt)*(x1-xt)+(y1-yt)*(y1-yt));
               norm2 = sqrt((x2-xt)*(x2-xt)+(y2-yt)*(y2-yt));
               previouspointin = kFALSE;
               j = 0;
               if (norm1 < norm2) {
                  theXpol[j] = x1;
                  theYpol[j] = y1;
               } else {
                  theXpol[j] = x2;
                  theYpol[j] = y2;
               }
               j++;
               theXpol[j] = xt;
               theYpol[j] = yt;
               PaintGraph(theGraphPolar, j+1, theXpol, theYpol, opt);
            }
         } else {
            // We check that the previous point was in the circle.
            // We record new point position
            if (j>=1 && !previouspointin) {
               a = (yt-theYpol[j])/(xt-theXpol[j]);
               b = theYpol[j]-a*theXpol[j];
               previouspointin = kTRUE;
               discr = 4*(a*a-b*b+1);
               x1 = (-2*a*b+sqrt(discr))/(2*(a*a+1));
               x2 = (-2*a*b-sqrt(discr))/(2*(a*a+1));
               y1 = a*x1+b;
               y2 = a*x2+b;
               norm1 = sqrt((x1-xt)*(x1-xt)+(y1-yt)*(y1-yt));
               norm2 = sqrt((x2-xt)*(x2-xt)+(y2-yt)*(y2-yt));
               j++;
               if (norm1 < norm2) {
                  theXpol[j] = x1;
                  theYpol[j] = y1;
               } else {
                  theXpol[j] = x2;
                  theYpol[j] = y2;
               }
               PaintGraph(theGraphPolar, j+1, theXpol, theYpol, opt);
            }
            j=-1;
         }
      }
      if (j>=1) {
         // If the last point is in the circle, we draw the last serie of point.
         PaintGraph(theGraphPolar, j+1, theXpol, theYpol, opt);
      }
   } else {
      for (i=0; i<theNpoints; i++) {
         theXpol[i] = TMath::Abs((theY[i]-rwrmin)/radiusNDC*TMath::Cos((theX[i]-rwtmin)/thetaNDC)+1);
         theYpol[i] = TMath::Abs((theY[i]-rwrmin)/radiusNDC*TMath::Sin((theX[i]-rwtmin)/thetaNDC)+1);
      }
      PaintGraph(theGraphPolar, theNpoints, theXpol, theYpol,opt);
   }

   // Paint the title.

   if (TestBit(TH1::kNoTitle)) return;
   Int_t nt = strlen(theGraph->GetTitle());
   TPaveText *title = 0;
   TObject *obj;
   TIter next(gPad->GetListOfPrimitives());
   while ((obj = next())) {
      if (!obj->InheritsFrom(TPaveText::Class())) continue;
      title = (TPaveText*)obj;
      if (title->GetName())
         if (strcmp(title->GetName(),"title")) {title = 0; continue;}
      break;
   }
   if (nt == 0 || gStyle->GetOptTitle() <= 0) {
      if (title) delete title;
      return;
   }
   Double_t ht = gStyle->GetTitleH();
   Double_t wt = gStyle->GetTitleW();
   if (ht <= 0) ht = 1.1*gStyle->GetTitleFontSize();
   if (ht <= 0) ht = 0.05;
   if (wt <= 0) {
      TLatex l;
      l.SetTextSize(ht);
      l.SetTitle(theGraph->GetTitle());
      // Adjustment in case the title has several lines (#splitline)
      ht = TMath::Max(ht, 1.2*l.GetYsize()/(gPad->GetY2() - gPad->GetY1()));
      Double_t wndc = l.GetXsize()/(gPad->GetX2() - gPad->GetX1());
      wt = TMath::Min(0.7, 0.02+wndc);
   }
   if (title) {
      TText *t0 = (TText*)title->GetLine(0);
      if (t0) {
         if (!strcmp(t0->GetTitle(),theGraph->GetTitle())) return;
         t0->SetTitle(theGraph->GetTitle());
         if (wt > 0) title->SetX2NDC(title->GetX1NDC()+wt);
      }
      return;
   }

   Int_t talh = gStyle->GetTitleAlign()/10;
   if (talh < 1) talh = 1; if (talh > 3) talh = 3;
   Int_t talv = gStyle->GetTitleAlign()%10;
   if (talv < 1) talv = 1; if (talv > 3) talv = 3;

   Double_t xpos, ypos;
   xpos = gStyle->GetTitleX();
   ypos = gStyle->GetTitleY();

   if (talh == 2) xpos = xpos-wt/2.;
   if (talh == 3) xpos = xpos-wt;
   if (talv == 2) ypos = ypos+ht/2.;
   if (talv == 1) ypos = ypos+ht;

   TPaveText *ptitle = new TPaveText(xpos, ypos-ht, xpos+wt, ypos,"blNDC");

   // Box with the histogram title.
   ptitle->SetFillColor(gStyle->GetTitleFillColor());
   ptitle->SetFillStyle(gStyle->GetTitleStyle());
   ptitle->SetName("title");
   ptitle->SetBorderSize(gStyle->GetTitleBorderSize());
   ptitle->SetTextColor(gStyle->GetTitleTextColor());
   ptitle->SetTextFont(gStyle->GetTitleFont(""));
   if (gStyle->GetTitleFont("")%10 > 2)
   ptitle->SetTextSize(gStyle->GetTitleFontSize());
   ptitle->AddText(theGraph->GetTitle());
   ptitle->SetBit(kCanDelete);
   ptitle->Draw();
   ptitle->Paint();
}


//______________________________________________________________________________
void TGraphPainter::PaintGraphQQ(TGraph *theGraph, Option_t *option)
{
   /* Begin_Html
   Paint this graphQQ. No options for the time being.
   End_Html */

   TGraphQQ *theGraphQQ = (TGraphQQ*) theGraph;

   Double_t *theX    = theGraphQQ->GetX();
   Double_t  theXq1  = theGraphQQ->GetXq1();
   Double_t  theXq2  = theGraphQQ->GetXq2();
   Double_t  theYq1  = theGraphQQ->GetYq1();
   Double_t  theYq2  = theGraphQQ->GetYq2();
   TF1      *theF    = theGraphQQ->GetF();

   if (!theX){
      Error("TGraphQQ::Paint", "2nd dataset or theoretical function not specified");
      return;
   }

   if (theF){
      theGraphQQ->GetXaxis()->SetTitle("theoretical quantiles");
      theGraphQQ->GetYaxis()->SetTitle("data quantiles");
   }

   PaintGraphSimple(theGraph,option);

   Double_t xmin = gPad->GetUxmin();
   Double_t xmax = gPad->GetUxmax();
   Double_t ymin = gPad->GetUymin();
   Double_t ymax = gPad->GetUymax();
   Double_t yxmin, xymin, yxmax, xymax;
   Double_t xqmin = TMath::Max(xmin, theXq1);
   Double_t xqmax = TMath::Min(xmax, theXq2);
   Double_t yqmin = TMath::Max(ymin, theYq1);
   Double_t yqmax = TMath::Min(ymax, theYq2);

   TLine line1, line2, line3;
   line1.SetLineStyle(2);
   line3.SetLineStyle(2);
   yxmin = (theYq2-theYq1)*(xmin-theXq1)/(theXq2-theXq1) + theYq1;
   if (yxmin < ymin){
      xymin = (theXq2-theXq1)*(ymin-theYq1)/(theYq2-theYq1) + theXq1;
      line1.PaintLine(xymin, ymin, xqmin, yqmin);
   }
   else
      line1.PaintLine(xmin, yxmin, xqmin, yqmin);

   line2.PaintLine(xqmin, yqmin, xqmax, yqmax);

   yxmax = (theYq2-theYq1)*(xmax-theXq1)/(theXq2-theXq1) + theYq1;
   if (yxmax > ymax){
      xymax = (theXq2-theXq1)*(ymax-theYq1)/(theYq2-theYq1) + theXq1;
      line3.PaintLine(xqmax, yqmax, xymax, ymax);
   }
   else
      line3.PaintLine(xqmax, yqmax, xmax, yxmax);
}


//______________________________________________________________________________
void TGraphPainter::PaintGraphSimple(TGraph *theGraph, Option_t *option)
{
   /* Begin_Html
   Paint a simple graph, without errors bars.
   End_Html */

   if (strstr(option,"H") || strstr(option,"h")) {
      PaintGrapHist(theGraph, theGraph->GetN(), theGraph->GetX(), theGraph->GetY(), option);
   } else {
      PaintGraph(theGraph, theGraph->GetN(), theGraph->GetX(), theGraph->GetY(), option);
   }

   // Paint associated objects in the list of functions (for instance
   // the fit function).
   TList *functions = theGraph->GetListOfFunctions();
   if (!functions) return;
   TObjOptLink *lnk = (TObjOptLink*)functions->FirstLink();
   TObject *obj;

   while (lnk) {
      obj = lnk->GetObject();
      TVirtualPad *padsave = gPad;
      if (obj->InheritsFrom(TF1::Class())) {
         if (obj->TestBit(TF1::kNotDraw) == 0) obj->Paint("lsame");
      } else  {
         obj->Paint(lnk->GetOption());
      }
      lnk = (TObjOptLink*)lnk->Next();
      padsave->cd();
   }
   return;
}


//______________________________________________________________________________
void TGraphPainter::PaintPolyLineHatches(TGraph *theGraph, Int_t n, const Double_t *x, const Double_t *y)
{
   /* Begin_Html
   Paint a polyline with hatches on one side showing an exclusion zone. x and y
   are the the vectors holding the polyline and n the number of points in the
   polyline and <tt>w</tt> the width of the hatches. <tt>w</tt> can be negative.
   This method is not meant to be used directly. It is called automatically
   according to the line style convention.
   End_Html */

   Int_t i,j,nf;
   Double_t w = (theGraph->GetLineWidth()/100)*0.005;

   Double_t *xf = new Double_t[2*n];
   Double_t *yf = new Double_t[2*n];
   Double_t *xt = new Double_t[n];
   Double_t *yt = new Double_t[n];
   Double_t x1, x2, y1, y2, x3, y3, xm, ym, a, a1, a2, a3;

   // Compute the gPad coordinates in TRUE normalized space (NDC)
   Int_t ix1,iy1,ix2,iy2;
   Int_t iw = gPad->GetWw();
   Int_t ih = gPad->GetWh();
   Double_t x1p,y1p,x2p,y2p;
   gPad->GetPadPar(x1p,y1p,x2p,y2p);
   ix1 = (Int_t)(iw*x1p);
   iy1 = (Int_t)(ih*y1p);
   ix2 = (Int_t)(iw*x2p);
   iy2 = (Int_t)(ih*y2p);
   Double_t wndc  = TMath::Min(1.,(Double_t)iw/(Double_t)ih);
   Double_t hndc  = TMath::Min(1.,(Double_t)ih/(Double_t)iw);
   Double_t rh    = hndc/(Double_t)ih;
   Double_t rw    = wndc/(Double_t)iw;
   Double_t x1ndc = (Double_t)ix1*rw;
   Double_t y1ndc = (Double_t)iy1*rh;
   Double_t x2ndc = (Double_t)ix2*rw;
   Double_t y2ndc = (Double_t)iy2*rh;

   // Ratios to convert user space in TRUE normalized space (NDC)
   Double_t rx1,ry1,rx2,ry2;
   gPad->GetRange(rx1,ry1,rx2,ry2);
   Double_t rx = (x2ndc-x1ndc)/(rx2-rx1);
   Double_t ry = (y2ndc-y1ndc)/(ry2-ry1);

   // The first part of the filled area is made of the graph points.
   // Make sure that two adjacent points are different.
   xf[0] = rx*(x[0]-rx1)+x1ndc;
   yf[0] = ry*(y[0]-ry1)+y1ndc;
   nf = 0;
   for (i=1; i<n; i++) {
      if (x[i]==x[i-1] && y[i]==y[i-1]) continue;
      nf++;
      xf[nf] = rx*(x[i]-rx1)+x1ndc;
      if (xf[i]==xf[i-1]) xf[i] += 0.000001; // add an epsilon to avoid exact vertical lines.
      yf[nf] = ry*(y[i]-ry1)+y1ndc;
   }

   // For each graph points a shifted points is computed to build up
   // the second part of the filled area. First and last points are
   // treated as special cases, outside of the loop.
   if (xf[1]==xf[0]) {
      a = TMath::PiOver2();
   } else {
      a = TMath::ATan((yf[1]-yf[0])/(xf[1]-xf[0]));
   }
   if (xf[0]<=xf[1]) {
      xt[0] = xf[0]-w*TMath::Sin(a);
      yt[0] = yf[0]+w*TMath::Cos(a);
   } else {
      xt[0] = xf[0]+w*TMath::Sin(a);
      yt[0] = yf[0]-w*TMath::Cos(a);
   }

   if (xf[nf]==xf[nf-1]) {
      a = TMath::PiOver2();
   } else {
      a = TMath::ATan((yf[nf]-yf[nf-1])/(xf[nf]-xf[nf-1]));
   }
   if (xf[nf]>=xf[nf-1]) {
      xt[nf] = xf[nf]-w*TMath::Sin(a);
      yt[nf] = yf[nf]+w*TMath::Cos(a);
   } else {
      xt[nf] = xf[nf]+w*TMath::Sin(a);
      yt[nf] = yf[nf]-w*TMath::Cos(a);
   }

   Double_t xi0,yi0,xi1,yi1,xi2,yi2;
   for (i=1; i<nf; i++) {
      xi0 = xf[i];
      yi0 = yf[i];
      xi1 = xf[i+1];
      yi1 = yf[i+1];
      xi2 = xf[i-1];
      yi2 = yf[i-1];
      if (xi1==xi0) {
         a1 = TMath::PiOver2();
      } else {
         a1  = TMath::ATan((yi1-yi0)/(xi1-xi0));
      }
      if (xi1<xi0) a1 = a1+3.14159;
      if (xi2==xi0) {
         a2 = TMath::PiOver2();
      } else {
         a2  = TMath::ATan((yi0-yi2)/(xi0-xi2));
      }
      if (xi0<xi2) a2 = a2+3.14159;
      x1 = xi0-w*TMath::Sin(a1);
      y1 = yi0+w*TMath::Cos(a1);
      x2 = xi0-w*TMath::Sin(a2);
      y2 = yi0+w*TMath::Cos(a2);
      xm = (x1+x2)*0.5;
      ym = (y1+y2)*0.5;
      if (xm==xi0) {
         a3 = TMath::PiOver2();
      } else {
         a3 = TMath::ATan((ym-yi0)/(xm-xi0));
      }
      x3 = xi0-w*TMath::Sin(a3+1.57079);
      y3 = yi0+w*TMath::Cos(a3+1.57079);
      // Rotate (x3,y3) by PI around (xi0,yi0) if it is not on the (xm,ym) side.
      if ((xm-xi0)*(x3-xi0)<0 && (ym-yi0)*(y3-yi0)<0) {
         x3 = 2*xi0-x3;
         y3 = 2*yi0-y3;
      }
      if ((xm==x1) && (ym==y1)) {
         x3 = xm;
         y3 = ym;
      }
      xt[i] = x3;
      yt[i] = y3;
   }

   // Close the polygon if the first and last points are the same
   if (xf[nf]==xf[0] && yf[nf]==yf[0]) {
      xm = (xt[nf]+xt[0])*0.5;
      ym = (yt[nf]+yt[0])*0.5;
      if (xm==xf[0]) {
         a3 = TMath::PiOver2();
      } else {
         a3 = TMath::ATan((ym-yf[0])/(xm-xf[0]));
      }
      x3 = xf[0]+w*TMath::Sin(a3+1.57079);
      y3 = yf[0]-w*TMath::Cos(a3+1.57079);
      if ((xm-xf[0])*(x3-xf[0])<0 && (ym-yf[0])*(y3-yf[0])<0) {
         x3 = 2*xf[0]-x3;
         y3 = 2*yf[0]-y3;
      }
      xt[nf] = x3;
      xt[0]  = x3;
      yt[nf] = y3;
      yt[0]  = y3;
   }

   // Find the crossing segments and remove the useless ones
   Double_t xc, yc, c1, b1, c2, b2;
   Bool_t cross = kFALSE;
   Int_t nf2 = nf;
   for (i=nf2; i>0; i--) {
      for (j=i-1; j>0; j--) {
         if (xt[i-1]==xt[i] || xt[j-1]==xt[j]) continue;
         c1  = (yt[i-1]-yt[i])/(xt[i-1]-xt[i]);
         b1  = yt[i]-c1*xt[i];
         c2  = (yt[j-1]-yt[j])/(xt[j-1]-xt[j]);
         b2  = yt[j]-c2*xt[j];
         if (c1 != c2) {
            xc = (b2-b1)/(c1-c2);
            yc = c1*xc+b1;
            if (xc>TMath::Min(xt[i],xt[i-1]) && xc<TMath::Max(xt[i],xt[i-1]) &&
                xc>TMath::Min(xt[j],xt[j-1]) && xc<TMath::Max(xt[j],xt[j-1]) &&
                yc>TMath::Min(yt[i],yt[i-1]) && yc<TMath::Max(yt[i],yt[i-1]) &&
                yc>TMath::Min(yt[j],yt[j-1]) && yc<TMath::Max(yt[j],yt[j-1])) {
               nf++; xf[nf] = xt[i]; yf[nf] = yt[i];
               nf++; xf[nf] = xc   ; yf[nf] = yc;
               i = j;
               cross = kTRUE;
               break;
            } else {
               continue;
            }
         } else {
            continue;
         }
      }
      if (!cross) {
         nf++;
         xf[nf] = xt[i];
         yf[nf] = yt[i];
      }
      cross = kFALSE;
   }
   nf++; xf[nf] = xt[0]; yf[nf] = yt[0];

   // NDC to user coordinates
   for (i=0; i<nf+1; i++) {
      xf[i] = (1/rx)*(xf[i]-x1ndc)+rx1;
      yf[i] = (1/ry)*(yf[i]-y1ndc)+ry1;
   }

   // Draw filled area
   gPad->PaintFillArea(nf+1,xf,yf);
   theGraph->TAttLine::Modify(); // In case of PaintFillAreaHatches

   delete [] xf;
   delete [] yf;
   delete [] xt;
   delete [] yt;
}


//______________________________________________________________________________
void TGraphPainter::PaintStats(TGraph *theGraph, TF1 *fit)
{
   /* Begin_Html
   Paint the statistics box with the fit info.
   End_Html */

   Int_t dofit;
   TPaveStats *stats  = 0;
   TList *functions = theGraph->GetListOfFunctions();
   TIter next(functions);
   TObject *obj;
   while ((obj = next())) {
      if (obj->InheritsFrom(TPaveStats::Class())) {
         stats = (TPaveStats*)obj;
         break;
      }
   }

   if (stats) dofit  = stats->GetOptFit();
   else       dofit  = gStyle->GetOptFit();

   if (!dofit) fit = 0;
   if (!fit) return;
   if (dofit  == 1) dofit  =  111;
   Int_t nlines = 0;
   Int_t print_fval    = dofit%10;
   Int_t print_ferrors = (dofit/10)%10;
   Int_t print_fchi2   = (dofit/100)%10;
   Int_t print_fprob   = (dofit/1000)%10;
   Int_t nlinesf = print_fval + print_fchi2 + print_fprob;
   if (fit) nlinesf += fit->GetNpar();
   Bool_t done = kFALSE;
   Double_t  statw  = 1.8*gStyle->GetStatW();
   Double_t  stath  = 0.25*(nlines+nlinesf)*gStyle->GetStatH();
   if (stats) {
      stats->Clear();
      done = kTRUE;
   } else {
      stats  = new TPaveStats(
               gStyle->GetStatX()-statw,
               gStyle->GetStatY()-stath,
               gStyle->GetStatX(),
               gStyle->GetStatY(),"brNDC");

      stats->SetParent(functions);
      stats->SetOptFit(dofit);
      stats->SetOptStat(0);
      stats->SetFillColor(gStyle->GetStatColor());
      stats->SetFillStyle(gStyle->GetStatStyle());
      stats->SetBorderSize(gStyle->GetStatBorderSize());
      stats->SetTextFont(gStyle->GetStatFont());
      if (gStyle->GetStatFont()%10 > 2)
         stats->SetTextSize(gStyle->GetStatFontSize());
      stats->SetFitFormat(gStyle->GetFitFormat());
      stats->SetStatFormat(gStyle->GetStatFormat());
      stats->SetName("stats");

      stats->SetTextColor(gStyle->GetStatTextColor());
      stats->SetTextAlign(12);
      stats->SetBit(kCanDelete);
      stats->SetBit(kMustCleanup);
   }

   char t[64];
   char textstats[50];
   Int_t ndf = fit->GetNDF();
   snprintf(textstats,50,"#chi^{2} / ndf = %s%s / %d","%",stats->GetFitFormat(),ndf);
   snprintf(t,64,textstats,(Float_t)fit->GetChisquare());
   if (print_fchi2) stats->AddText(t);
   if (print_fprob) {
      snprintf(textstats,50,"Prob  = %s%s","%",stats->GetFitFormat());
      snprintf(t,64,textstats,(Float_t)TMath::Prob(fit->GetChisquare(),ndf));
      stats->AddText(t);
   }
   if (print_fval || print_ferrors) {
      for (Int_t ipar=0;ipar<fit->GetNpar();ipar++) {
         if (print_ferrors) {
            snprintf(textstats,50,"%-8s = %s%s #pm %s%s ",fit->GetParName(ipar),"%",stats->GetFitFormat(),"%",stats->GetFitFormat());
            snprintf(t,64,textstats,(Float_t)fit->GetParameter(ipar)
                            ,(Float_t)fit->GetParError(ipar));
         } else {
            snprintf(textstats,50,"%-8s = %s%s ",fit->GetParName(ipar),"%",stats->GetFitFormat());
            snprintf(t,64,textstats,(Float_t)fit->GetParameter(ipar));
         }
         t[63] = 0;
         stats->AddText(t);
      }
   }

   if (!done) functions->Add(stats);
   stats->Paint();
}


//______________________________________________________________________________
void TGraphPainter::Smooth(TGraph *theGraph, Int_t npoints, Double_t *x, Double_t *y, Int_t drawtype)
{
   /* Begin_Html
   Smooth a curve given by N points.
   <p>
   The original code is from an underlaying routine for Draw based on the
   CERN GD3 routine TVIPTE:
   <pre>
        Author - Marlow etc.   Modified by - P. Ward     Date -  3.10.1973
   </pre>
   This method draws a smooth tangentially continuous curve through
   the sequence of data points P(I) I=1,N where P(I)=(X(I),Y(I)).
   The curve is approximated by a polygonal arc of short vectors.
   The data points can represent open curves, P(1) != P(N) or closed
   curves P(2) == P(N). If a tangential discontinuity at P(I) is
   required, then set P(I)=P(I+1). Loops are also allowed.
   <p>
   Reference Marlow and Powell, Harwell report No.R.7092.1972
   MCCONALOGUE, Computer Journal VOL.13, NO4, NOV1970P p392 6
   <p>
   <ul>
   <li>  npoints   : Number of data points.
   <li>  x         : Abscissa
   <li>  y         : Ordinate
   </ul>
   End_Html */

   Int_t i, k, kp, km, npointsMax, banksize, n2, npt;
   Int_t maxiterations, finished;
   Int_t jtype, ktype, closed;
   Double_t sxmin, sxmax, symin, symax;
   Double_t delta;
   Double_t xorg, yorg;
   Double_t ratio_signs, xratio, yratio;
   Int_t flgic, flgis;
   Int_t iw, loptx;
   Double_t p1, p2, p3, p4, p5, p6;
   Double_t w1, w2, w3;
   Double_t a, b, c, r, s, t, z;
   Double_t co, so, ct, st, ctu, stu, xnt;
   Double_t dx1, dy1, dx2, dy2, dk1, dk2;
   Double_t xo, yo, dx, dy, xt, yt;
   Double_t xa, xb, ya, yb;
   Double_t u1, u2, u3, tj;
   Double_t cc, err;
   Double_t sb, sth;
   Double_t wsign, tsquare, tcube;
   c = t = co = so = ct = st = ctu = stu = dx1 = dy1 = dx2 = dy2 = 0;
   xt = yt = xa = xb = ya = yb = u1 = u2 = u3 = tj = sb = 0;

   npointsMax  = npoints*10;
   n2          = npointsMax-2;
   banksize    = n2;

   Double_t *qlx = new Double_t[npointsMax];
   Double_t *qly = new Double_t[npointsMax];
   if (!qlx || !qly) {
      Error("Smooth", "not enough space in memory");
      return;
   }

   //  Decode the type of curve (drawtype).

   loptx = kFALSE;
   jtype  = (drawtype%1000)-10;
   if (jtype > 0) { ktype = jtype; loptx = kTRUE; }
   else             ktype = drawtype%1000;

   Double_t ruxmin = gPad->GetUxmin();
   Double_t ruymin = gPad->GetUymin();
   if (ktype == 3) {
      xorg = ruxmin;
      yorg = ruymin;
   } else {
      xorg = TMath::Max((Double_t)0,ruxmin);
      yorg = TMath::Min(TMath::Max((Double_t)0,ruymin),gPad->GetUymax());
   }

   // delta is the accuracy required in constructing the curve.
   // If it is zero then the routine calculates a value otherwise
   // it uses this value. (default is 0.0)

   delta         = 0.00055;
   maxiterations = 20;

   //       Scale data to the range 0-ratio_signs in X, 0-1 in Y
   //       where ratio_signs is the ratio between the number of changes
   //       of sign in Y divided by the number of changes of sign in X

   sxmin = x[0];
   sxmax = x[0];
   symin = y[0];
   symax = y[0];
   Double_t six   = 1;
   Double_t siy   = 1;
   for (i=1;i<npoints;i++) {
      if (i > 1) {
         if ((x[i]-x[i-1])*(x[i-1]-x[i-2]) < 0) six++;
         if ((y[i]-y[i-1])*(y[i-1]-y[i-2]) < 0) siy++;
      }
      if (x[i] < sxmin) sxmin = x[i];
      if (x[i] > sxmax) sxmax = x[i];
      if (y[i] < symin) symin = y[i];
      if (y[i] > symax) symax = y[i];
   }
   closed = 0;
   Double_t dx1n   = TMath::Abs(x[npoints-1]-x[0]);
   Double_t dy1n   = TMath::Abs(y[npoints-1]-y[0]);
   if (dx1n < 0.01*(sxmax-sxmin) && dy1n < 0.01*(symax-symin))  closed = 1;
   if (sxmin == sxmax) {
      xratio = 1;
   } else {
      if (six > 1) ratio_signs = siy/six;
      else         ratio_signs = 20;
      xratio = ratio_signs/(sxmax-sxmin);
   }
   if (symin == symax) yratio = 1;
   else                yratio = 1/(symax-symin);

   qlx[0] = x[0];
   qly[0] = y[0];
   for (i=0;i<npoints;i++) {
      x[i] = (x[i]-sxmin)*xratio;
      y[i] = (y[i]-symin)*yratio;
   }

   //          "finished" is minus one if we must draw a straight line from P(k-1)
   //          to P(k). "finished" is one if the last call to PaintPolyLine has < n2
   //          points. "finished" is zero otherwise. npt counts the X and Y
   //          coordinates in work . When npt=n2 a call to IPL is made.

   finished = 0;
   npt      = 1;
   k        = 1;

   //           Convert coordinates back to original system

   //           Separate the set of data points into arcs P(k-1),P(k).
   //           Calculate the direction cosines. first consider whether
   //           there is a continuous tangent at the endpoints.

   if (!closed) {
      if (x[0] != x[npoints-1] || y[0] != y[npoints-1]) goto L40;
      if (x[npoints-2] == x[npoints-1] && y[npoints-2] == y[npoints-1]) goto L40;
      if (x[0] == x[1] && y[0] == y[1]) goto L40;
   }
   flgic = kFALSE;
   flgis = kTRUE;

   //           flgic is true if the curve is open and false if it is closed.
   //           flgis is true in the main loop, but is false if there is
   //           a deviation from the main loop.

   km = npoints - 1;

   //           Calculate direction cosines at P(1) using P(N-1),P(1),P(2).

   goto L100;
L40:
   flgic = kTRUE;
   flgis = kFALSE;

   //           Skip excessive consecutive equal points.

L50:
   if (k >= npoints) {
      finished = 1;  // Prepare to clear out remaining short vectors before returning
      if (npt > 1) goto L310;
      goto L390;
   }
   k++;
   if (x[k-1] == x[k-2] && y[k-1] == y[k-2])  goto L50;
L60:
   km = k-1;
   if (k > npoints) {
      finished = 1;  // Prepare to clear out remaining short vectors before returning
      if (npt > 1) goto L310;
      goto L390;
   }
   if (k < npoints) goto L90;
   if (!flgic) { kp = 2; goto L130;}

L80:
   if (flgis) goto L150;

   //           Draw a straight line from P(k-1) to P(k).

   finished = -1;
   goto L170;

   //           Test whether P(k) is a cusp.

L90:
   if (x[k-1] == x[k] && y[k-1] == y[k]) goto L80;
L100:
   kp = k+1;
   goto L130;

   //           Branch if the next section of the curve begins at a cusp.

L110:
   if (!flgis) goto L50;

   //           Carry forward the direction cosines from the previous arc.

L120:
   co = ct;
   so = st;
   k++;
   goto L60;

   //           Calculate the direction cosines at P(k).  If k=1 then
   //           N-1 is used for k-1. If k=N then 2 is used for k+1.
   //           direction cosines at P(k) obtained from P(k-1),P(k),P(k+1).

L130:
   dx1 = x[k-1]  - x[km-1];
   dy1 = y[k-1]  - y[km-1];
   dk1 = dx1*dx1 + dy1*dy1;
   dx2 = x[kp-1] - x[k-1];
   dy2 = y[kp-1] - y[k-1];
   dk2 = dx2*dx2 + dy2*dy2;
   ctu = dx1*dk2 + dx2*dk1;
   stu = dy1*dk2 + dy2*dk1;
   xnt = ctu*ctu + stu*stu;

   //           If both ctu and stu are zero,then default.This can
   //           occur when P(k)=P(k+1). I.E. A loop.

   if (xnt < 1.E-25) {
      ctu = dy1;
      stu =-dx1;
      xnt = dk1;
   }
   //           Normalise direction cosines.

   ct = ctu/TMath::Sqrt(xnt);
   st = stu/TMath::Sqrt(xnt);
   if (flgis) goto L160;

   //           Direction cosines at P(k-1) obtained from P(k-1),P(k),P(k+1).

   w3    = 2*(dx1*dy2-dx2*dy1);
   co    = ctu+w3*dy1;
   so    = stu-w3*dx1;
   xnt   = 1/TMath::Sqrt(co*co+so*so);
   co    = co*xnt;
   so    = so*xnt;
   flgis = kTRUE;
   goto L170;

   //           Direction cosines at P(k) obtained from P(k-2),P(k-1),P(k).

L150:
   w3    = 2*(dx1*dy2-dx2*dy1);
   ct    = ctu-w3*dy2;
   st    = stu+w3*dx2;
   xnt   = 1/TMath::Sqrt(ct*ct+st*st);
   ct    = ct*xnt;
   st    = st*xnt;
   flgis = kFALSE;
   goto L170;
L160:
   if (k <= 1) goto L120;

   //           For the arc between P(k-1) and P(k) with direction cosines co,
   //           so and ct,st respectively, calculate the coefficients of the
   //           parametric cubic represented by X(t) and Y(t) where
   //           X(t)=xa*t**3 + xb*t**2 + co*t + xo
   //           Y(t)=ya*t**3 + yb*t**2 + so*t + yo

L170:
   xo = x[k-2];
   yo = y[k-2];
   dx = x[k-1] - xo;
   dy = y[k-1] - yo;

   //           Initialise the values of X(TI),Y(TI) in xt and yt respectively.

   xt = xo;
   yt = yo;
   if (finished < 0) {  // Draw a straight line between (xo,yo) and (xt,yt)
      xt += dx;
      yt += dy;
      goto L300;
   }
   c  = dx*dx+dy*dy;
   a  = co+ct;
   b  = so+st;
   r  = dx*a+dy*b;
   t  = c*6/(TMath::Sqrt(r*r+2*(7-co*ct-so*st)*c)+r);
   tsquare = t*t;
   tcube   = t*tsquare;
   xa = (a*t-2*dx)/tcube;
   xb = (3*dx-(co+a)*t)/tsquare;
   ya = (b*t-2*dy)/tcube;
   yb = (3*dy-(so+b)*t)/tsquare;

   //           If the curve is close to a straight line then use a straight
   //           line between (xo,yo) and (xt,yt).

   if (.75*TMath::Max(TMath::Abs(dx*so-dy*co),TMath::Abs(dx*st-dy*ct)) <= delta) {
      finished = -1;
      xt += dx;
      yt += dy;
      goto L300;
   }

   //           Calculate a set of values 0 == t(0).LTCT(1) <  ...  < t(M)=TC
   //           such that polygonal arc joining X(t(J)),Y(t(J)) (J=0,1,..M)
   //           is within the required accuracy of the curve

   tj = 0;
   u1 = ya*xb-yb*xa;
   u2 = yb*co-xb*so;
   u3 = so*xa-ya*co;

   //           Given t(J), calculate t(J+1). The values of X(t(J)),
   //           Y(t(J)) t(J) are contained in xt,yt and tj respectively.

L180:
   s  = t - tj;
   iw = -2;

   //           Define iw here later.

   p1 = (2*u1)*tj-u3;
   p2 = (u1*tj-u3)*3*tj+u2;
   p3 = 3*tj*ya+yb;
   p4 = (p3+yb)*tj+so;
   p5 = 3*tj*xa+xb;
   p6 = (p5+xb)*tj+co;

   //           Test D(tj,THETA). A is set to (Y(tj+s)-Y(tj))/s.b is
   //           set to (X(tj+s)-X(tj))/s.

   cc  = 0.8209285;
   err = 0.1209835;
L190:
   iw -= 2;
L200:
   a   = (s*ya+p3)*s+p4;
   b   = (s*xa+p5)*s+p6;

   //           Set z to PSI(D/delta)-cc.

   w1 = -s*(s*u1+p1);
   w2 = s*s*u1-p2;
   w3 = 1.5*w1+w2;

   //           Set the estimate of (THETA-tj)/s.Then set the numerator
   //           of the expression (EQUATION 4.4)/s. Then set the square
   //           of D(tj,tj+s)/delta. Then replace z by PSI(D/delta)-cc.

   if (w3 > 0) wsign = TMath::Abs(w1);
   else        wsign = -TMath::Abs(w1);
   sth = 0.5+wsign/(3.4*TMath::Abs(w1)+5.2*TMath::Abs(w3));
   z   = s*sth*(s-s*sth)*(w1*sth+w1+w2);
   z   = z*z/((a*a+b*b)*(delta*delta));
   z   = (z+2.642937)*z/((.3715652*z+3.063444)*z+.2441889)-cc;

   //           Branch if z has been calculated

   if (iw > 0) goto L250;
   if (z > err) goto L240;
   goto L220;
L210:
   iw -= 2;
L220:
   if (iw+2 == 0) goto L190;
   if (iw+2 >  0) goto L290;

   //           Last part of arc.

L230:
   xt = x[k-1];
   yt = y[k-1];
   s  = 0;
   goto L300;

   //           z(s). find a value of s where 0 <= s <= sb such that
   //           TMath::Abs(z(s)) < err

L240:
   kp = 0;
   c  = z;
   sb = s;
L250:
   theGraph->Zero(kp,0,sb,err,s,z,maxiterations);
   if (kp == 2) goto L210;
   if (kp > 2) {
      Error("Smooth", "Attempt to plot outside plot limits");
      goto L230;
   }
   if (iw > 0) goto L200;

   //           Set z=z(s) for s=0.

   if (iw < 0) {
      z  = -cc;
      iw = 0;
      goto L250;
   }

   //           Set z=z(s) for s=sb.

   z  = c;
   iw = 1;
   goto L250;

   //           Update tj,xt and yt.

L290:
   xt = xt + s*b;
   yt = yt + s*a;
   tj = s  + tj;

   //           Convert coordinates to original system

L300:
   qlx[npt] = sxmin + xt/xratio;
   qly[npt] = symin + yt/yratio;
   npt++;

   //           If a fill area must be drawn and if the banks LX and
   //           LY are too small they are enlarged in order to draw
   //           the filled area in one go.

   if (npt < banksize)  goto L320;
   if (drawtype >= 1000 || ktype > 1) {
      Int_t newsize = banksize + n2;
      Double_t *qtemp = new Double_t[banksize];
      for (i=0;i<banksize;i++) qtemp[i] = qlx[i];
      delete [] qlx;
      qlx = new Double_t[newsize];
      for (i=0;i<banksize;i++) qlx[i]   = qtemp[i];
      for (i=0;i<banksize;i++) qtemp[i] = qly[i];
      delete [] qly;
      qly = new Double_t[newsize];
      for (i=0;i<banksize;i++) qly[i] = qtemp[i];
      delete [] qtemp;
      banksize = newsize;
      goto L320;
   }

   //           Draw the graph

L310:
   if (drawtype >= 1000) {
      gPad->PaintFillArea(npt,qlx,qly, "B");
   } else {
      if (ktype > 1) {
         if (!loptx) {
            qlx[npt]   = qlx[npt-1];
            qlx[npt+1] = qlx[0];
            qly[npt]   = yorg;
            qly[npt+1] = yorg;
         } else {
            qlx[npt]   = xorg;
            qlx[npt+1] = xorg;
            qly[npt]   = qly[npt-1];
            qly[npt+1] = qly[0];
         }
         gPad->PaintFillArea(npt+2,qlx,qly);
      }
      if (TMath::Abs(theGraph->GetLineWidth())>99) PaintPolyLineHatches(theGraph, npt, qlx, qly);
      gPad->PaintPolyLine(npt,qlx,qly);
   }
   npt = 1;
   qlx[0] = sxmin + xt/xratio;
   qly[0] = symin + yt/yratio;
L320:
   if (finished > 0) goto L390;
   if (finished < 0) { finished = 0; goto L110;}
   if (s > 0) goto L180;
   goto L110;

   //           Convert coordinates back to original system

L390:
   for (i=0;i<npoints;i++) {
      x[i] = sxmin + x[i]/xratio;
      y[i] = symin + y[i]/yratio;
   }

   delete [] qlx;
   delete [] qly;
}
// @(#)root/histpainter:$Id: TGraphPainter.h,v 1.00
// Author: Olivier Couet

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#ifndef ROOT_TGraphPainter
#define ROOT_TGraphPainter


//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TGraphPainter                                                        //
//                                                                      //
// helper class to draw graphs                                          //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#ifndef ROOT_Object
#include "TVirtualGraphPainter.h"
#endif

class TGraph;
class TF1;

class TGraphPainter : public TVirtualGraphPainter {

public:

   TGraphPainter();

   virtual ~TGraphPainter();

   void           ComputeLogs(Int_t npoints, Int_t opt);
   virtual Int_t  DistancetoPrimitiveHelper(TGraph *theGraph, Int_t px, Int_t py);
   virtual void   DrawPanelHelper(TGraph *theGraph);
   virtual void   ExecuteEventHelper(TGraph *theGraph, Int_t event, Int_t px, Int_t py);
   virtual char  *GetObjectInfoHelper(TGraph *theGraph, Int_t px, Int_t py) const;
   void           PaintHelper(TGraph *theGraph, Option_t *option);
   virtual void   PaintGraph(TGraph *theGraph, Int_t npoints, const Double_t *x, const Double_t *y, Option_t *chopt);
   virtual void   PaintGrapHist(TGraph *theGraph, Int_t npoints, const Double_t *x, const Double_t *y, Option_t *chopt);
   void           PaintGraphAsymmErrors(TGraph *theGraph, Option_t *option);
   void           PaintGraphBentErrors(TGraph *theGraph, Option_t *option);
   void           PaintGraphErrors(TGraph *theGraph, Option_t *option);
   void           PaintGraphPolar(TGraph *theGraph, Option_t *option);
   void           PaintGraphQQ(TGraph *theGraph, Option_t *option);
   void           PaintGraphSimple(TGraph *theGraph, Option_t *option);
   void           PaintPolyLineHatches(TGraph *theGraph, Int_t n, const Double_t *x, const Double_t *y);
   void           PaintStats(TGraph *theGraph, TF1 *fit);
   void           Smooth(TGraph *theGraph, Int_t npoints, Double_t *x, Double_t *y, Int_t drawtype);

   ClassDef(TGraphPainter,0)  // TGraph painter
};

#endif
// @(#)root/histpainter:$Id: TGraphPainter.cxx,v 1.00
// Author: Olivier Couet

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "TROOT.h"
#include "TGraphPainter.h"
#include "TMath.h"
#include "TGraph.h"
#include "TPolyLine.h"
#include "TPolyMarker.h"
#include "TVirtualPad.h"
#include "TView.h"
#include "TStyle.h"
#include "TH1.h"
#include "TF1.h"
#include "TPaveStats.h"
#include "TGaxis.h"
#include "TGraphAsymmErrors.h"
#include "TGraphBentErrors.h"
#include "TGraphPolargram.h"
#include "TGraphPolar.h"
#include "TGraphQQ.h"
#include "TLatex.h"
#include "TArrow.h"
#include "TFrame.h"
#include "TMarker.h"
#include "TCanvas.h"
#include "TVirtualPadEditor.h"

Double_t *gxwork, *gywork, *gxworkl, *gyworkl;

static Int_t   gHighlightPoint = -1;   // highlight point of graph
static TGraph *gHighlightGraph = 0;    // pointer to graph with highlight point

ClassImp(TGraphPainter);


//______________________________________________________________________________
/* Begin_Html
<center><h2>The graph painter class</h2></center>

<ul>
<li><a href="#GP00">Introduction</li></a>
<li><a href="#GP01">Graphs' plotting options</li></a>
<li><a href="#GP02">Exclusion graphs</li></a>
<li><a href="#GP03">Graphs with error bars</li></a>
<ul>
<li><a href="#GP03a">TGraphErrors</li></a>
<li><a href="#GP03b">TGraphAsymmErrors</li></a>
<li><a href="#GP03c">TGraphBentErrors</li></a>
</ul>
<li><a href="#GP04">TGraphPolar options</li></a>
</ul>

<a name="GP00"></a><h3>Introduction</h3>

Graphs are drawn via the painter <tt>TGraphPainter</tt> class. This class
implements techniques needed to display the various kind of
graphs i.e.: <tt>TGraph</tt>, <tt>TGraphErrors</tt>,
<tt>TGraphBentErrors</tt> and <tt>TGraphAsymmErrors</tt>.

<p>
To draw a graph "<tt>graph</tt>" it's enough to do:
<pre>
   graph->Draw("AL");
</pre>


<p>The option <tt>"AL"</tt> in the <tt>Draw()</tt> method means:
<ol>
<li>The axis should be drawn (option <tt>"A"</tt>),</li>
<li>The graph should be drawn as a simple line (option <tt>"L"</tt>).</li>
</ol>
By default a graph is drawn in the current pad in the current coordinate system.
To define a suitable coordinate system and draw the axis the option
<tt>"A"</tt> must be specified.
<p>
<tt>TGraphPainter</tt> offers many options to paint the various kind of graphs.
<p>
It is separated from the graph classes so that one can have graphs without the
graphics overhead, for example in a batch program.
<p>
When a displayed graph is modified, there is no need to call
<tt>Draw()</tt> again; the image will be refreshed the next time the
pad will be updated.
<p>A pad is updated after one of these three actions:
<ol>
<li>  a carriage return on the ROOT command line,
<li>  a click inside the pad,
<li>  a call to <tt>TPad::Update</tt>.
</ol>

<a name="GP01"></a><h3>Graphs' plotting options</h3>
Graphs can be drawn with the following options:
<p>
<table border=0>

<tr><th valign=top>"A"</th><td>
Axis are drawn around the graph
</td></tr>

<tr><th valign=top>"L"</th><td>
A simple polyline is drawn
</td></tr>

<tr><th valign=top>"F"</th><td>
A fill area is drawn ('CF' draw a smoothed fill area)
</td></tr>

<tr><th valign=top>"C"</th><td>
A smooth Curve is drawn
</td></tr>

<tr><th valign=top>"*"</th><td>
A Star is plotted at each point
</td></tr>

<tr><th valign=top>"P"</th><td>
The current marker is plotted at each point
</td></tr>

<tr><th valign=top>"B"</th><td>
A Bar chart is drawn
</td></tr>

<tr><th valign=top>"1"</th><td>
When a graph is drawn as a bar chart, this option makes the bars start from
the bottom of the pad. By default they start at 0.
</td></tr>

<tr><th valign=top>"X+"</th><td>
The X-axis is drawn on the top side of the plot.
</td></tr>

<tr><th valign=top>"Y+"</th><td>
The Y-axis is drawn on the right side of the plot.
</td></tr>

</table>
<p>

Drawing options can be combined. In the following example the graph
is drawn as a smooth curve (option "C") with markers (option "P") and
with axes (option "A").

End_Html
Begin_Macro(source)
{
   TCanvas *c1 = new TCanvas("c1","c1",200,10,600,400);

   c1->SetFillColor(42);
   c1->SetGrid();

   const Int_t n = 20;
   Double_t x[n], y[n];
   for (Int_t i=0;i<n;i++) {
      x[i] = i*0.1;
      y[i] = 10*sin(x[i]+0.2);
   }
   gr = new TGraph(n,x,y);
   gr->SetLineColor(2);
   gr->SetLineWidth(4);
   gr->SetMarkerColor(4);
   gr->SetMarkerSize(1.5);
   gr->SetMarkerStyle(21);
   gr->SetTitle("Option ACP example");
   gr->GetXaxis()->SetTitle("X title");
   gr->GetYaxis()->SetTitle("Y title");
   gr->Draw("ACP");

   // TCanvas::Update() draws the frame, after which one can change it
   c1->Update();
   c1->GetFrame()->SetFillColor(21);
   c1->GetFrame()->SetBorderSize(12);
   c1->Modified();
   return c1;
}
End_Macro
Begin_Html

<p>The following macro shows the option "B" usage. It can be combined with the
option "1".

End_Html
Begin_Macro(source)
{
   TCanvas *c47 = new TCanvas("c47","c47",200,10,600,400);
   c47->Divide(1,2);
   const Int_t n = 20;
   Double_t x[n], y[n];
   for (Int_t i=0;i<n;i++) {
      x[i] = i*0.1;
      y[i] = 10*sin(x[i]+0.2)-6;
   }
   gr = new TGraph(n,x,y);
   gr->SetFillColor(38);
   c47->cd(1); gr->Draw("AB");
   c47->cd(2); gr->Draw("AB1");
 return c47;
}
End_Macro
Begin_Html

<a name="GP02"></a><h3>Exclusion graphs</h3>

When a graph is painted with the option <tt>"C"</tt> or <tt>"L"</tt> it is
possible to draw a filled area on one side of the line. This is useful to show
exclusion zones.

<p>This drawing mode is activated when the absolute value of the graph line
width (set by <tt>SetLineWidth()</tt>) is greater than 99. In that
case the line width number is interpreted as:
<pre>
      100*ff+ll = ffll
</pre>
<ul>
<li> The two digits number <tt>"ll"</tt> represent the normal line width
<li> The two digits number  <tt>"ff"</tt> represent the filled area width.
<li> The sign of "ffll" allows to flip the filled area from one side of the line
     to the other.
</ul>
The current fill area attributes are used to draw the hatched zone.

End_Html
Begin_Macro(source)
../../../tutorials/graphs/exclusiongraph.C
End_Macro
Begin_Html

<a name="GP03"></a><h3>Graphs with error bars</h3>
Three classes are available to handle graphs with error bars:
<tt>TGraphErrors</tt>, <tt>TGraphAsymmErrors</tt> and <tt>TGraphBentErrors</tt>.
The following drawing options are specific to graphs with error bars:
<p>
<table border=0>

<tr><th valign=top>"Z"</th><td>
Do not draw small horizontal and vertical lines the end of the error bars.
Without "Z", the default is to draw these.
</td></tr>

<tr><th valign=top>">"</th><td>
An arrow is drawn at the end of the error bars.
The size of the arrow is set to 2/3 of the marker size.
</td></tr>

<tr><th valign=top>"|>"</th><td>
A filled arrow is drawn at the end of the error bars.
The size of the arrow is set to 2/3 of the marker size.
</td></tr>

<tr><th valign=top>"X"</th><td>
Do not draw error bars.  By default, graph classes that have errors
are drawn with the errors (TGraph itself has no errors, and so this option
has no effect.)
</td></tr>

<tr><th valign=top>"||"</th><td>
Draw only the small vertical/horizontal lines at the ends of the
error bars, without drawing the bars themselves. This option is
interesting to superimpose statistical-only errors on top of a graph
with statistical+systematic errors.
</td></tr>

<tr><th valign=top>"[]"</th><td>
Does the same as option "||" except that it draws additional marks at the
ends of the small vertical/horizontal lines. It makes plots less ambiguous
in case several graphs are drawn on the same picture.
</td></tr>

<tr><th valign=top>"0"</th><td>
By default, when a data point is outside the visible range along the Y
axis, the error bars are not drawn. This option forces error bars' drawing for
the data points outside the visible range along the Y axis (see example below).
</td></tr>

<tr><th valign=top>"2"</th><td>
Error rectangles are drawn.
</td></tr>

<tr><th valign=top>"3"</th><td>
A filled area is drawn through the end points of the vertical error bars.
</td></tr>

<tr><th valign=top>"4"</th><td>
A smoothed filled area is drawn through the end points of the vertical error
bars.
</td></tr>

<tr><th valign=top>"5"</th><td>
Error rectangles are drawn like option "2". In addition the contour line
around the boxes is drawn. This can be useful when boxes' fill colors are very
light or in gray scale mode.
</td></tr>
</table>
<p>
<tt>gStyle->SetErrorX(dx)</tt> controls the size of the error along x.
<tt>dx = 0</tt> removes the error along x.
<p>
<tt>gStyle->SetEndErrorSize(np)</tt> controls the size of the lines
at the end of the error bars (when option 1 is used).
By default <tt>np=1</tt>. (np represents the number of pixels).

<a name="GP03a"></a><h4><u>TGraphErrors</u></h4>
A <tt>TGraphErrors</tt> is a <tt>TGraph</tt> with error bars. The errors are
defined along X and Y and are symmetric: The left and right errors are the same
along X and the bottom and up errors are the same along Y.

End_Html
Begin_Macro(source)
{
   TCanvas *c4 = new TCanvas("c4","c4",200,10,600,400);
   double x[] = {0, 1, 2, 3, 4};
   double y[] = {0, 2, 4, 1, 3};
   double ex[] = {0.1, 0.2, 0.3, 0.4, 0.5};
   double ey[] = {1, 0.5, 1, 0.5, 1};
   TGraphErrors* ge = new TGraphErrors(5, x, y, ex, ey);
   ge->Draw("ap");
   return c4;
}
End_Macro
Begin_Html

<p>The option "0" shows the error bars for data points outside range.

End_Html
Begin_Macro(source)
{
   TCanvas *c48 = new TCanvas("c48","c48",200,10,600,400);
   float x[]     = {1,2,3};
   float err_x[] = {0,0,0};
   float err_y[] = {5,5,5};
   float y[]     = {1,4,9};
   TGraphErrors tg(3,x,y,err_x,err_y);
   c48->Divide(2,1);
   c48->cd(1); gPad->DrawFrame(0,0,4,8); tg.Draw("PC");
   c48->cd(2); gPad->DrawFrame(0,0,4,8); tg.Draw("0PC");
   return c48;
}
End_Macro
Begin_Html

<p>The option "3" shows the errors as a band.

End_Html
Begin_Macro(source)
{
   TCanvas *c41 = new TCanvas("c41","c41",200,10,600,400);
   double x[] = {0, 1, 2, 3, 4};
   double y[] = {0, 2, 4, 1, 3};
   double ex[] = {0.1, 0.2, 0.3, 0.4, 0.5};
   double ey[] = {1, 0.5, 1, 0.5, 1};
   TGraphErrors* ge = new TGraphErrors(5, x, y, ex, ey);
   ge->SetFillColor(4);
   ge->SetFillStyle(3010);
   ge->Draw("a3");
   return c41;
}
End_Macro
Begin_Html

<p>The option "4" is similar to the option "3" except that the band
is smoothed. As the following picture shows, this option should be
used carefully because the smoothing algorithm may show some (huge)
"bouncing" effects. In some cases it looks nicer than option "3"
(because it is smooth) but it can be misleading.

End_Html
Begin_Macro(source)
{
   TCanvas *c42 = new TCanvas("c42","c42",200,10,600,400);
   double x[] = {0, 1, 2, 3, 4};
   double y[] = {0, 2, 4, 1, 3};
   double ex[] = {0.1, 0.2, 0.3, 0.4, 0.5};
   double ey[] = {1, 0.5, 1, 0.5, 1};
   TGraphErrors* ge = new TGraphErrors(5, x, y, ex, ey);
   ge->SetFillColor(6);
   ge->SetFillStyle(3005);
   ge->Draw("a4");
   return c42;
}
End_Macro
Begin_Html

<p>The following example shows how the option "[]" can be used to superimpose
systematic errors on top of a graph with statistical errors.

End_Html
Begin_Macro(source)
{
   TCanvas *c43 = new TCanvas("c43","c43",200,10,600,400);
   c43->DrawFrame(0., -0.5, 6., 2);

   double x[5]    = {1, 2, 3, 4, 5};
   double zero[5] = {0, 0, 0, 0, 0};

   // data set (1) with stat and sys errors
   double py1[5]      = {1.2, 1.15, 1.19, 0.9, 1.4};
   double ey_stat1[5] = {0.2, 0.18, 0.17, 0.2, 0.4};
   double ey_sys1[5]  = {0.5, 0.71, 0.76, 0.5, 0.45};

   // data set (2) with stat and sys errors
   double y2[5]       = {0.25, 0.18, 0.29, 0.2, 0.21};
   double ey_stat2[5] = {0.2, 0.18, 0.17, 0.2, 0.4};
   double ey_sys2[5]  = {0.63, 0.19, 0.7, 0.2, 0.7};

   // Now draw data set (1)

   // We first have to draw it only with the stat errors
   TGraphErrors *graph1 = new TGraphErrors(5, x, py1, zero, ey_stat1);
   graph1->SetMarkerStyle(20);
   graph1->Draw("P");

   // Now we have to somehow depict the sys errors

   TGraphErrors *graph1_sys = new TGraphErrors(5, x, py1, zero, ey_sys1);
   graph1_sys->Draw("[]");

   // Now draw data set (2)

   // We first have to draw it only with the stat errors
   TGraphErrors *graph2 = new TGraphErrors(5, x, y2, zero, ey_stat2);
   graph2->SetMarkerStyle(24);
   graph2->Draw("P");

   // Now we have to somehow depict the sys errors

   TGraphErrors *graph2_sys = new TGraphErrors(5, x, y2, zero, ey_sys2);
   graph2_sys->Draw("[]");
   return c43;
}
End_Macro
Begin_Html

<a name="GP03b"></a><h4><u>TGraphAsymmErrors</u></h4>
A <tt>TGraphAsymmErrors</tt> is like a <tt>TGraphErrors</tt> but the errors
defined along X and Y are not symmetric: The left and right errors are
different along X and the bottom and up errors are different along Y.

End_Html
Begin_Macro(source)
{
   TCanvas *c44 = new TCanvas("c44","c44",200,10,600,400);
   double ax[] = {0, 1, 2, 3, 4};
   double ay[] = {0, 2, 4, 1, 3};
   double aexl[] = {0.1, 0.2, 0.3, 0.4, 0.5};
   double aexh[] = {0.5, 0.4, 0.3, 0.2, 0.1};
   double aeyl[] = {1, 0.5, 1, 0.5, 1};
   double aeyh[] = {0.5, 1, 0.5, 1, 0.5};
   TGraphAsymmErrors* gae = new TGraphAsymmErrors(5, ax, ay, aexl, aexh, aeyl, aeyh);
   gae->SetFillColor(2);
   gae->SetFillStyle(3001);
   gae->Draw("a2");
   gae->Draw("p");
   return c44;
}
End_Macro
Begin_Html


<a name="GP03c"></a><h4><u>TGraphBentErrors</u></h4>
A <tt>TGraphBentErrors</tt> is like a <tt>TGraphAsymmErrors</tt>.
An extra parameter allows to bend the error bars to better see them
when several graphs are drawn on the same plot.

End_Html
Begin_Macro(source)
{
   TCanvas *c45 = new TCanvas("c45","c45",200,10,600,400);
   const Int_t n = 10;
   Double_t x[n]  = {-0.22, 0.05, 0.25, 0.35, 0.5, 0.61,0.7,0.85,0.89,0.95};
   Double_t y[n]  = {1,2.9,5.6,7.4,9,9.6,8.7,6.3,4.5,1};
   Double_t exl[n] = {.05,.1,.07,.07,.04,.05,.06,.07,.08,.05};
   Double_t eyl[n] = {.8,.7,.6,.5,.4,.4,.5,.6,.7,.8};
   Double_t exh[n] = {.02,.08,.05,.05,.03,.03,.04,.05,.06,.03};
   Double_t eyh[n] = {.6,.5,.4,.3,.2,.2,.3,.4,.5,.6};
   Double_t exld[n] = {.0,.0,.0,.0,.0,.0,.0,.0,.0,.0};
   Double_t eyld[n] = {.0,.0,.05,.0,.0,.0,.0,.0,.0,.0};
   Double_t exhd[n] = {.0,.0,.0,.0,.0,.0,.0,.0,.0,.0};
   Double_t eyhd[n] = {.0,.0,.0,.0,.0,.0,.0,.0,.05,.0};
   TGraphBentErrors *gr = new TGraphBentErrors(n,x,y,exl,exh,eyl,eyh,exld,exhd,eyld,eyhd);
   gr->SetTitle("TGraphBentErrors Example");
   gr->SetMarkerColor(4);
   gr->SetMarkerStyle(21);
   gr->Draw("ALP");
   return c45;
}
End_Macro
Begin_Html


<a name="GP04"></a><h3>TGraphPolar options</h3>

The drawing options for the polar graphs are the following:

<table border=0>

<tr><th valign=top>"O"</th><td>
Polar labels are drawn orthogonally to the polargram radius.
</td></tr>

<tr><th valign=top>"P"</th><td>
Polymarker are drawn at each point position.
</td></tr>

<tr><th valign=top>"E"</th><td>
Draw error bars.
</td></tr>

<tr><th valign=top>"F"</th><td>
Draw fill area (closed polygon).
</td></tr>

<tr><th valign=top>"A"</th><td>
Force axis redrawing even if a polargram already exists.
</td></tr>

<tr><th valign=top>"N"</th><td>
Disable the display of the polar labels.
</td></tr>

</table>

End_Html
Begin_Macro(source)
{
   TCanvas *c46 = new TCanvas("c46","c46",500,500);
   TGraphPolar * grP1 = new TGraphPolar();
   grP1->SetTitle("TGraphPolar example");

   grP1->SetPoint(0, (1*TMath::Pi())/4., 0.05);
   grP1->SetPoint(1, (2*TMath::Pi())/4., 0.10);
   grP1->SetPoint(2, (3*TMath::Pi())/4., 0.15);
   grP1->SetPoint(3, (4*TMath::Pi())/4., 0.20);
   grP1->SetPoint(4, (5*TMath::Pi())/4., 0.25);
   grP1->SetPoint(5, (6*TMath::Pi())/4., 0.30);
   grP1->SetPoint(6, (7*TMath::Pi())/4., 0.35);
   grP1->SetPoint(7, (8*TMath::Pi())/4., 0.40);

   grP1->SetMarkerStyle(20);
   grP1->SetMarkerSize(1.);
   grP1->SetMarkerColor(4);
   grP1->SetLineColor(4);
   grP1->Draw("ALP");

   // Update, otherwise GetPolargram returns 0
   c46->Update();
   grP1->GetPolargram()->SetToRadian();

   return c46;
}
End_Macro
Begin_Html

End_Html */


//______________________________________________________________________________
TGraphPainter::TGraphPainter()
: fHighlightPad(0)
{
   /* Begin_Html
   Default constructor
   End_Html */
}


//______________________________________________________________________________
TGraphPainter::~TGraphPainter()
{
   /* Begin_Html
   Destructor.
   End_Html */
}


//______________________________________________________________________________
void TGraphPainter::ComputeLogs(Int_t npoints, Int_t opt)
{
   /* Begin_Html
   Compute the logarithm of global variables <tt>gxwork</tt> and <tt>gywork</tt>
   according to the value of Options and put the results in the global
   variables <tt>gxworkl</tt> and <tt>gyworkl</tt>.
   <p>
   npoints : Number of points in gxwork and in gywork.
   <ul>
   <li> opt = 1 ComputeLogs is called from PaintGrapHist
   <li> opt = 0 ComputeLogs is called from PaintGraph
   </ul>
   End_Html */

   Int_t i;
   memcpy(gxworkl,gxwork,npoints*8);
   memcpy(gyworkl,gywork,npoints*8);
   if (gPad->GetLogx()) {
      for (i=0;i<npoints;i++) {
         if (gxworkl[i] > 0) gxworkl[i] = TMath::Log10(gxworkl[i]);
         else                gxworkl[i] = gPad->GetX1();
      }
   }
   if (!opt && gPad->GetLogy()) {
      for (i=0;i<npoints;i++) {
         if (gyworkl[i] > 0) gyworkl[i] = TMath::Log10(gyworkl[i]);
         else                gyworkl[i] = gPad->GetY1();
      }
   }
}


//______________________________________________________________________________
Int_t TGraphPainter::DistancetoPrimitiveHelper(TGraph *theGraph, Int_t px, Int_t py)
{
   /* Begin_Html
   Compute distance from point px,py to a graph.
   <p>
   Compute the closest distance of approach from point px,py to this line.
   The distance is computed in pixels units.
   End_Html */

   // Are we on the axis?
   Int_t distance;
   if (theGraph->GetHistogram()) {
      distance = theGraph->GetHistogram()->DistancetoPrimitive(px,py);
      if (distance <= 5) return distance;
   }

   // Somewhere on the graph points?
   const Int_t big = 9999;
   const Int_t kMaxDiff = 10;
   Int_t puxmin = gPad->XtoAbsPixel(gPad->GetUxmin());
   Int_t puymin = gPad->YtoAbsPixel(gPad->GetUymin());
   Int_t puxmax = gPad->XtoAbsPixel(gPad->GetUxmax());
   Int_t puymax = gPad->YtoAbsPixel(gPad->GetUymax());

   // return if point is not in the graph area
   if (px <= puxmin) return big;
   if (py >= puymin) return big;
   if (px >= puxmax) return big;
   if (py <= puymax) return big;

   // check if point is near one of the graph points
   Int_t i, pxp, pyp, d;
   distance = big;

   Int_t theNpoints = theGraph->GetN();
   Double_t *theX, *theY;
   if (theGraph->InheritsFrom(TGraphPolar::Class())) {
      TGraphPolar *theGraphPolar = (TGraphPolar*) theGraph;
      theX   = theGraphPolar->GetXpol();
      theY   = theGraphPolar->GetYpol();
   } else {
      theX   = theGraph->GetX();
      theY   = theGraph->GetY();
   }

   Int_t hpoint = -1;
   const Int_t kHighlightRange = 50; // maybe as fgHighlightRange and Set/Get
   static Int_t distanceOld = kHighlightRange;
   if (gHighlightPoint == -1) distanceOld = kHighlightRange; // reset

   for (i=0;i<theNpoints;i++) {
      pxp = gPad->XtoAbsPixel(gPad->XtoPad(theX[i]));
      pyp = gPad->YtoAbsPixel(gPad->YtoPad(theY[i]));
      d   = TMath::Abs(pxp-px) + TMath::Abs(pyp-py);
      if (d < distance) {
         distance = d;
         hpoint = i;
      }
   }

   // check for highlight point, only if highlight is enable
   // better choice is highlighting in DistancetoPrimitive than in ExecuteEvent
   if (theGraph->IsHighlight()) {
      if ((distance < kHighlightRange) && (distance < distanceOld)) { // closest point
         if ((gHighlightPoint != hpoint) || (gHighlightGraph != theGraph)) { // was changed
            //Info("DistancetoPrimitiveHelper", "graph: %p\tpoint: %d", (void *)theGraph, hpoint);
            gHighlightPoint = hpoint;
            gHighlightGraph = theGraph;
            gPad->Modified(kTRUE);
            gPad->Update();           // paint highlight point as marker
            HighlightPoint(theGraph); // draw highlight object for this point of graph (if exist)
         }
      }
      if (gHighlightGraph == theGraph) distanceOld = distance;
   }
   if (distance < kMaxDiff) return distance;

   for (i=0;i<theNpoints-1;i++) {
      TAttLine l;
      d = l.DistancetoLine(px, py, gPad->XtoPad(theX[i]), gPad->YtoPad(theY[i]), gPad->XtoPad(theX[i+1]), gPad->YtoPad(theY[i+1]));
      if (d < distance) distance = d;
   }

   // If graph has been drawn with the fill area option, check if we are inside
   TString drawOption = theGraph->GetDrawOption();
   drawOption.ToLower();
   if (drawOption.Contains("f")) {
      Double_t xp = gPad->AbsPixeltoX(px); xp = gPad->PadtoX(xp);
      Double_t yp = gPad->AbsPixeltoY(py); yp = gPad->PadtoY(yp);
      if (TMath::IsInside(xp,yp,theNpoints,theX,theY) != 0) distance = 1;
   }

   // Loop on the list of associated functions and user objects
   TObject *f;
   TList *functions = theGraph->GetListOfFunctions();
   TIter   next(functions);
   while ((f = (TObject*) next())) {
      Int_t dist;
      if (f->InheritsFrom(TF1::Class())) dist = f->DistancetoPrimitive(-px,py);
      else                               dist = f->DistancetoPrimitive(px,py);
      if (dist < kMaxDiff) {
         gPad->SetSelected(f);
         return 0; //must be o and not dist in case of TMultiGraph
      }
   }

   return distance;
}


//______________________________________________________________________________
void TGraphPainter::DrawPanelHelper(TGraph *theGraph)
{
   /* Begin_html
   Display a panel with all histogram drawing options.
   End_html */

   if (!gPad) {
      Error("DrawPanel", "need to draw graph first");
      return;
   }
   TVirtualPadEditor *editor = TVirtualPadEditor::GetPadEditor();
   editor->Show();
   gROOT->ProcessLine(Form("((TCanvas*)0x%lx)->Selected((TVirtualPad*)0x%lx,(TObject*)0x%lx,1)",
                           (ULong_t)gPad->GetCanvas(), (ULong_t)gPad, (ULong_t)theGraph));
}


//______________________________________________________________________________
void TGraphPainter::ExecuteEventHelper(TGraph *theGraph, Int_t event, Int_t px, Int_t py)
{
   /* Begin_Html
   Execute action corresponding to one event.
   <p>
   This member function is called when a graph is clicked with the locator.
   <p>
   If the left mouse button is clicked on one of the line end points, this point
   follows the cursor until button is released.
   <p>
   If the middle mouse button clicked, the line is moved parallel to itself
   until the button is released.
   End_Html */

   Int_t i, d;
   Double_t xmin, xmax, ymin, ymax, dx, dy, dxr, dyr;
   const Int_t kMaxDiff =  10;//3;
   static Bool_t middle, badcase;
   static Int_t ipoint, pxp, pyp;
   static Int_t px1,px2,py1,py2;
   static Int_t pxold, pyold, px1old, py1old, px2old, py2old;
   static Int_t dpx, dpy;
   static Int_t *x=0, *y=0;
   Bool_t opaque  = gPad->OpaqueMoving();

   if (!theGraph->IsEditable() || theGraph->InheritsFrom(TGraphPolar::Class())) {
      gPad->SetCursor(kHand);
      return;
   }
   if (!gPad->IsEditable()) return;
   Int_t theNpoints = theGraph->GetN();
   Double_t *theX  = theGraph->GetX();
   Double_t *theY  = theGraph->GetY();

   switch (event) {

   case kButton1Down:
      badcase = kFALSE;
      gVirtualX->SetLineColor(-1);
      theGraph->TAttLine::Modify();  //Change line attributes only if necessary
      px1 = gPad->XtoAbsPixel(gPad->GetX1());
      py1 = gPad->YtoAbsPixel(gPad->GetY1());
      px2 = gPad->XtoAbsPixel(gPad->GetX2());
      py2 = gPad->YtoAbsPixel(gPad->GetY2());
      ipoint = -1;


      if (x || y) break;
      x = new Int_t[theNpoints+1];
      y = new Int_t[theNpoints+1];
      for (i=0;i<theNpoints;i++) {
         pxp = gPad->XtoAbsPixel(gPad->XtoPad(theX[i]));
         pyp = gPad->YtoAbsPixel(gPad->YtoPad(theY[i]));
         if (pxp < -kMaxPixel || pxp >= kMaxPixel ||
             pyp < -kMaxPixel || pyp >= kMaxPixel) {
            badcase = kTRUE;
            continue;
         }
         if (!opaque) {
            gVirtualX->DrawLine(pxp-4, pyp-4, pxp+4,  pyp-4);
            gVirtualX->DrawLine(pxp+4, pyp-4, pxp+4,  pyp+4);
            gVirtualX->DrawLine(pxp+4, pyp+4, pxp-4,  pyp+4);
            gVirtualX->DrawLine(pxp-4, pyp+4, pxp-4,  pyp-4);
         }
         x[i] = pxp;
         y[i] = pyp;
         d   = TMath::Abs(pxp-px) + TMath::Abs(pyp-py);
         if (d < kMaxDiff) ipoint =i;
      }
      dpx = 0;
      dpy = 0;
      pxold = px;
      pyold = py;
      if (ipoint < 0) return;
      if (ipoint == 0) {
         px1old = 0;
         py1old = 0;
         px2old = gPad->XtoAbsPixel(theX[1]);
         py2old = gPad->YtoAbsPixel(theY[1]);
      } else if (ipoint == theNpoints-1) {
         px1old = gPad->XtoAbsPixel(gPad->XtoPad(theX[theNpoints-2]));
         py1old = gPad->YtoAbsPixel(gPad->YtoPad(theY[theNpoints-2]));
         px2old = 0;
         py2old = 0;
      } else {
         px1old = gPad->XtoAbsPixel(gPad->XtoPad(theX[ipoint-1]));
         py1old = gPad->YtoAbsPixel(gPad->YtoPad(theY[ipoint-1]));
         px2old = gPad->XtoAbsPixel(gPad->XtoPad(theX[ipoint+1]));
         py2old = gPad->YtoAbsPixel(gPad->YtoPad(theY[ipoint+1]));
      }
      pxold = gPad->XtoAbsPixel(gPad->XtoPad(theX[ipoint]));
      pyold = gPad->YtoAbsPixel(gPad->YtoPad(theY[ipoint]));

      break;


   case kMouseMotion:

      middle = kTRUE;
      for (i=0;i<theNpoints;i++) {
         pxp = gPad->XtoAbsPixel(gPad->XtoPad(theX[i]));
         pyp = gPad->YtoAbsPixel(gPad->YtoPad(theY[i]));
         d   = TMath::Abs(pxp-px) + TMath::Abs(pyp-py);
         if (d < kMaxDiff) middle = kFALSE;
      }


   // check if point is close to an axis
      if (middle) gPad->SetCursor(kMove);
      else gPad->SetCursor(kHand);
      break;

   case kButton1Motion:
      if (!opaque) {
         if (middle) {
            for(i=0;i<theNpoints-1;i++) {
               gVirtualX->DrawLine(x[i]+dpx, y[i]+dpy, x[i+1]+dpx, y[i+1]+dpy);
               pxp = x[i]+dpx;
               pyp = y[i]+dpy;
               if (pxp < -kMaxPixel || pxp >= kMaxPixel ||
                   pyp < -kMaxPixel || pyp >= kMaxPixel) continue;
               gVirtualX->DrawLine(pxp-4, pyp-4, pxp+4,  pyp-4);
               gVirtualX->DrawLine(pxp+4, pyp-4, pxp+4,  pyp+4);
               gVirtualX->DrawLine(pxp+4, pyp+4, pxp-4,  pyp+4);
               gVirtualX->DrawLine(pxp-4, pyp+4, pxp-4,  pyp-4);
            }
            pxp = x[theNpoints-1]+dpx;
            pyp = y[theNpoints-1]+dpy;
            gVirtualX->DrawLine(pxp-4, pyp-4, pxp+4,  pyp-4);
            gVirtualX->DrawLine(pxp+4, pyp-4, pxp+4,  pyp+4);
            gVirtualX->DrawLine(pxp+4, pyp+4, pxp-4,  pyp+4);
            gVirtualX->DrawLine(pxp-4, pyp+4, pxp-4,  pyp-4);
            dpx += px - pxold;
            dpy += py - pyold;
            pxold = px;
            pyold = py;
            for(i=0;i<theNpoints-1;i++) {
               gVirtualX->DrawLine(x[i]+dpx, y[i]+dpy, x[i+1]+dpx, y[i+1]+dpy);
               pxp = x[i]+dpx;
               pyp = y[i]+dpy;
               if (pxp < -kMaxPixel || pxp >= kMaxPixel ||
                   pyp < -kMaxPixel || pyp >= kMaxPixel) continue;
               gVirtualX->DrawLine(pxp-4, pyp-4, pxp+4,  pyp-4);
               gVirtualX->DrawLine(pxp+4, pyp-4, pxp+4,  pyp+4);
               gVirtualX->DrawLine(pxp+4, pyp+4, pxp-4,  pyp+4);
               gVirtualX->DrawLine(pxp-4, pyp+4, pxp-4,  pyp-4);
            }
            pxp = x[theNpoints-1]+dpx;
            pyp = y[theNpoints-1]+dpy;
            gVirtualX->DrawLine(pxp-4, pyp-4, pxp+4,  pyp-4);
            gVirtualX->DrawLine(pxp+4, pyp-4, pxp+4,  pyp+4);
            gVirtualX->DrawLine(pxp+4, pyp+4, pxp-4,  pyp+4);
            gVirtualX->DrawLine(pxp-4, pyp+4, pxp-4,  pyp-4);
         } else {
            if (px1old) gVirtualX->DrawLine(px1old, py1old, pxold,  pyold);
            if (px2old) gVirtualX->DrawLine(pxold,  pyold,  px2old, py2old);
            gVirtualX->DrawLine(pxold-4, pyold-4, pxold+4,  pyold-4);
            gVirtualX->DrawLine(pxold+4, pyold-4, pxold+4,  pyold+4);
            gVirtualX->DrawLine(pxold+4, pyold+4, pxold-4,  pyold+4);
            gVirtualX->DrawLine(pxold-4, pyold+4, pxold-4,  pyold-4);
            pxold = px;
            pxold = TMath::Max(pxold, px1);
            pxold = TMath::Min(pxold, px2);
            pyold = py;
            pyold = TMath::Max(pyold, py2);
            pyold = TMath::Min(pyold, py1);
            if (px1old) gVirtualX->DrawLine(px1old, py1old, pxold,  pyold);
            if (px2old) gVirtualX->DrawLine(pxold,  pyold,  px2old, py2old);
            gVirtualX->DrawLine(pxold-4, pyold-4, pxold+4,  pyold-4);
            gVirtualX->DrawLine(pxold+4, pyold-4, pxold+4,  pyold+4);
            gVirtualX->DrawLine(pxold+4, pyold+4, pxold-4,  pyold+4);
            gVirtualX->DrawLine(pxold-4, pyold+4, pxold-4,  pyold-4);
         }
      } else {
         xmin = gPad->GetUxmin();
         xmax = gPad->GetUxmax();
         ymin = gPad->GetUymin();
         ymax = gPad->GetUymax();
         dx   = xmax-xmin;
         dy   = ymax-ymin;
         dxr  = dx/(1 - gPad->GetLeftMargin() - gPad->GetRightMargin());
         dyr  = dy/(1 - gPad->GetBottomMargin() - gPad->GetTopMargin());

         if (theGraph->GetHistogram()) {
            // Range() could change the size of the pad pixmap and therefore should
            // be called before the other paint routines
            gPad->Range(xmin - dxr*gPad->GetLeftMargin(),
                         ymin - dyr*gPad->GetBottomMargin(),
                         xmax + dxr*gPad->GetRightMargin(),
                         ymax + dyr*gPad->GetTopMargin());
            gPad->RangeAxis(xmin, ymin, xmax, ymax);
         }
         if (middle) {
            dpx += px - pxold;
            dpy += py - pyold;
            pxold = px;
            pyold = py;
            for(i=0;i<theNpoints;i++) {
               if (badcase) continue;  //do not update if big zoom and points moved
               if (x) theX[i] = gPad->PadtoX(gPad->AbsPixeltoX(x[i]+dpx));
               if (y) theY[i] = gPad->PadtoY(gPad->AbsPixeltoY(y[i]+dpy));
            }
         } else {
            pxold = px;
            pxold = TMath::Max(pxold, px1);
            pxold = TMath::Min(pxold, px2);
            pyold = py;
            pyold = TMath::Max(pyold, py2);
            pyold = TMath::Min(pyold, py1);
            theX[ipoint] = gPad->PadtoX(gPad->AbsPixeltoX(pxold));
            theY[ipoint] = gPad->PadtoY(gPad->AbsPixeltoY(pyold));
            if (theGraph->InheritsFrom("TCutG")) {
               //make sure first and last point are the same
               if (ipoint == 0) {
                  theX[theNpoints-1] = theX[0];
                  theY[theNpoints-1] = theY[0];
               }
               if (ipoint == theNpoints-1) {
                  theX[0] = theX[theNpoints-1];
                  theY[0] = theY[theNpoints-1];
               }
            }
         }
         badcase = kFALSE;
         gPad->Modified(kTRUE);
         //gPad->Update();
      }
      break;

   case kButton1Up:

      if (gROOT->IsEscaped()) {
         gROOT->SetEscape(kFALSE);
         delete [] x; x = 0;
         delete [] y; y = 0;
         break;
      }

   // Compute x,y range
      xmin = gPad->GetUxmin();
      xmax = gPad->GetUxmax();
      ymin = gPad->GetUymin();
      ymax = gPad->GetUymax();
      dx   = xmax-xmin;
      dy   = ymax-ymin;
      dxr  = dx/(1 - gPad->GetLeftMargin() - gPad->GetRightMargin());
      dyr  = dy/(1 - gPad->GetBottomMargin() - gPad->GetTopMargin());

      if (theGraph->GetHistogram()) {
         // Range() could change the size of the pad pixmap and therefore should
         // be called before the other paint routines
         gPad->Range(xmin - dxr*gPad->GetLeftMargin(),
                      ymin - dyr*gPad->GetBottomMargin(),
                      xmax + dxr*gPad->GetRightMargin(),
                      ymax + dyr*gPad->GetTopMargin());
         gPad->RangeAxis(xmin, ymin, xmax, ymax);
      }
      if (middle) {
         for(i=0;i<theNpoints;i++) {
            if (badcase) continue;  //do not update if big zoom and points moved
            if (x) theX[i] = gPad->PadtoX(gPad->AbsPixeltoX(x[i]+dpx));
            if (y) theY[i] = gPad->PadtoY(gPad->AbsPixeltoY(y[i]+dpy));
         }
      } else {
         theX[ipoint] = gPad->PadtoX(gPad->AbsPixeltoX(pxold));
         theY[ipoint] = gPad->PadtoY(gPad->AbsPixeltoY(pyold));
         if (theGraph->InheritsFrom("TCutG")) {
            //make sure first and last point are the same
            if (ipoint == 0) {
               theX[theNpoints-1] = theX[0];
               theY[theNpoints-1] = theY[0];
            }
            if (ipoint == theNpoints-1) {
               theX[0] = theX[theNpoints-1];
               theY[0] = theY[theNpoints-1];
            }
         }
      }
      badcase = kFALSE;
      delete [] x; x = 0;
      delete [] y; y = 0;
      gPad->Modified(kTRUE);
      gVirtualX->SetLineColor(-1);
   }
}


//______________________________________________________________________________
char *TGraphPainter::GetObjectInfoHelper(TGraph * /*theGraph*/, Int_t /*px*/, Int_t /*py*/) const
{
   return (char*)"";
}


//______________________________________________________________________________
void TGraphPainter::PaintHighlightPoint(TGraph *theGraph, Option_t * /*option*/)
{
   // Paint highlight point as TMarker object (open circle), only if highlight is enable

   static TMarker *hmarker = 0;
   Double_t hx, hy;
   if (theGraph->IsHighlight() && (gHighlightGraph == theGraph)) {
      if (theGraph->GetPoint(gHighlightPoint, hx, hy) == -1) {
         // special case, e.g. after interactive remove last point
         if (hmarker) { hmarker->Delete(); hmarker = 0; }
      } else {
         if (!hmarker) {
            hmarker = new TMarker(hx, hy, 24);
            hmarker->SetBit(kCannotPick);
         }
         hmarker->SetX(hx);
         hmarker->SetY(hy);
         hmarker->SetMarkerSize(theGraph->GetMarkerSize()*2.0);
         if (hmarker->GetMarkerSize() < 1.0) hmarker->SetMarkerSize(1.0); // always visible
         hmarker->SetMarkerColor(theGraph->GetMarkerColor());
         hmarker->Paint();
         //Info("PaintHighlightPoint", "graph: %p\tpoint: %d", (void *)gHighlightGraph, gHighlightPoint);
      }
   } else if (gHighlightPoint == -1)
      if (hmarker) { hmarker->Delete(); hmarker = 0; }
}


//______________________________________________________________________________
void TGraphPainter::PaintHelper(TGraph *theGraph, Option_t *option)
{
   /* Begin_Html
   Paint a any kind of TGraph
   End_Html */

   if (theGraph) {
      SetBit(TGraph::kClipFrame, theGraph->TestBit(TGraph::kClipFrame));
      if (theGraph->InheritsFrom(TGraphBentErrors::Class())) {
         PaintGraphBentErrors(theGraph,option);
      } else if (theGraph->InheritsFrom(TGraphQQ::Class())) {
         PaintGraphQQ(theGraph,option);
      } else if (theGraph->InheritsFrom(TGraphAsymmErrors::Class())) {
         PaintGraphAsymmErrors(theGraph,option);
      } else if (theGraph->InheritsFrom(TGraphErrors::Class())) {
         if (theGraph->InheritsFrom(TGraphPolar::Class())) {
            PaintGraphPolar(theGraph,option);
         } else {
            PaintGraphErrors(theGraph,option);
         }
      } else {
         PaintGraphSimple(theGraph,option);
      }
   }
}


//______________________________________________________________________________
void TGraphPainter::PaintGraph(TGraph *theGraph, Int_t npoints, const Double_t *x, const Double_t *y, Option_t *chopt)
{
   /* Begin_Html
   <a href="#GP01">Control function to draw a graph.</a>
   End_Html */
   if (theGraph->InheritsFrom("TGraphPolar"))
      gPad->PushSelectableObject(theGraph);

   Int_t optionLine , optionAxis , optionCurve, optionStar , optionMark;
   Int_t optionBar  , optionR    , optionOne  , optionE;
   Int_t optionFill , optionZ    , optionCurveFill;
   Int_t i, npt, nloop;
   Int_t drawtype=0;
   Double_t xlow, xhigh, ylow, yhigh;
   Double_t barxmin, barxmax, barymin, barymax;
   Double_t uxmin, uxmax;
   Double_t x1, xn, y1, yn;
   Double_t dbar, bdelta;
   Int_t theNpoints = theGraph->GetN();

   if (npoints <= 0) {
      Error("PaintGraph", "illegal number of points (%d)", npoints);
      return;
   }
   TString opt = chopt;
   opt.ToUpper();
   opt.ReplaceAll("SAME","");

   if (opt.Contains("L")) optionLine = 1;  else optionLine = 0;
   if (opt.Contains("A")) optionAxis = 1;  else optionAxis = 0;
   if (opt.Contains("C")) optionCurve= 1;  else optionCurve= 0;
   if (opt.Contains("*")) optionStar = 1;  else optionStar = 0;
   if (opt.Contains("P")) optionMark = 1;  else optionMark = 0;
   if (opt.Contains("B")) optionBar  = 1;  else optionBar  = 0;
   if (opt.Contains("R")) optionR    = 1;  else optionR    = 0;
   if (opt.Contains("1")) optionOne  = 1;  else optionOne  = 0;
   if (opt.Contains("F")) optionFill = 1;  else optionFill = 0;
   if (opt.Contains("2") || opt.Contains("3") ||
      opt.Contains("4") || opt.Contains("5")) optionE = 1;  else optionE = 0;
   optionZ    = 0;

   // If no "drawing" option is selected and if chopt<>' ' nothing is done.
   if (optionLine+optionFill+optionCurve+optionStar+optionMark+optionBar+optionE == 0) {
      if (!chopt[0])  optionLine=1;
      else   return;
   }

   if (optionStar) theGraph->SetMarkerStyle(3);

   optionCurveFill = 0;
   if (optionCurve && optionFill) {
      optionCurveFill = 1;
      optionFill      = 0;
   }

   // Draw the Axis.
   Double_t rwxmin,rwxmax, rwymin, rwymax, maximum, minimum, dx, dy;
   if (optionAxis) {
      if (theGraph->GetHistogram()) {
         rwxmin    = gPad->GetUxmin();
         rwxmax    = gPad->GetUxmax();
         rwymin    = gPad->GetUymin();
         rwymax    = gPad->GetUymax();
         minimum   = theGraph->GetHistogram()->GetMinimumStored();
         maximum   = theGraph->GetHistogram()->GetMaximumStored();
         if (minimum == -1111) { //this can happen after unzooming
            minimum = theGraph->GetHistogram()->GetYaxis()->GetXmin();
            theGraph->GetHistogram()->SetMinimum(minimum);
         }
         if (maximum == -1111) {
            maximum = theGraph->GetHistogram()->GetYaxis()->GetXmax();
            theGraph->GetHistogram()->SetMaximum(maximum);
         }
         uxmin     = gPad->PadtoX(rwxmin);
         uxmax     = gPad->PadtoX(rwxmax);
      } else {

         theGraph->ComputeRange(rwxmin, rwymin, rwxmax, rwymax);  //this is redefined in TGraphErrors

         if (rwxmin == rwxmax) rwxmax += 1.;
         if (rwymin == rwymax) rwymax += 1.;
         dx = 0.1*(rwxmax-rwxmin);
         dy = 0.1*(rwymax-rwymin);
         uxmin    = rwxmin - dx;
         uxmax    = rwxmax + dx;
         minimum  = rwymin - dy;
         maximum  = rwymax + dy;
      }
      if (theGraph->GetMinimum() != -1111) rwymin = minimum = theGraph->GetMinimum();
      if (theGraph->GetMaximum() != -1111) rwymax = maximum = theGraph->GetMaximum();
      if (uxmin < 0 && rwxmin >= 0) uxmin = 0.9*rwxmin;
      if (uxmax > 0 && rwxmax <= 0) {
         if (gPad->GetLogx()) uxmax = 1.1*rwxmax;
         else                 uxmax = 0;
      }
      if (minimum < 0 && rwymin >= 0) minimum = 0.9*rwymin;
      if (maximum > 0 && rwymax <= 0) {
         //if(gPad->GetLogy()) maximum = 1.1*rwymax;
         //else                maximum = 0;
      }
      if (minimum <= 0 && gPad->GetLogy()) minimum = 0.001*maximum;
      if (uxmin <= 0 && gPad->GetLogx()) {
         if (uxmax > 1000) uxmin = 1;
         else              uxmin = 0.001*uxmax;
      }
      rwymin = minimum;
      rwymax = maximum;

      // Create a temporary histogram and fill each bin with the
      // function value.
      char chopth[8] = " ";
      if (strstr(chopt,"x+")) strncat(chopth, "x+",2);
      if (strstr(chopt,"y+")) strncat(chopth, "y+",2);
      if (!theGraph->GetHistogram()) {
         // the graph is created with at least as many bins as there are
         // points to permit zooming on the full range.
         rwxmin = uxmin;
         rwxmax = uxmax;
         npt = 100;
         if (theNpoints > npt) npt = theNpoints;
         TH1F *h = new TH1F(Form("%s_h",GetName()),GetTitle(),npt,rwxmin,rwxmax);
         theGraph->SetHistogram(h);
         if (!theGraph->GetHistogram()) return;
         theGraph->GetHistogram()->SetMinimum(rwymin);
         theGraph->GetHistogram()->SetMaximum(rwymax);
         theGraph->GetHistogram()->GetYaxis()->SetLimits(rwymin,rwymax);
         theGraph->GetHistogram()->SetBit(TH1::kNoStats);
         theGraph->GetHistogram()->SetDirectory(0);
         theGraph->GetHistogram()->Paint(chopth); // Draw histogram axis, title and grid
      } else {
         if (gPad->GetLogy()) {
            theGraph->GetHistogram()->SetMinimum(rwymin);
            theGraph->GetHistogram()->SetMaximum(rwymax);
            theGraph->GetHistogram()->GetYaxis()->SetLimits(rwymin,rwymax);
         }
         theGraph->GetHistogram()->Paint(chopth); // Draw histogram axis, title and grid
      }
   }

   // Set Clipping option
   gPad->SetBit(TGraph::kClipFrame, theGraph->TestBit(TGraph::kClipFrame));

   TF1 *fit = 0;
   TList *functions = theGraph->GetListOfFunctions();
   TObject *f;
   if (functions) {
      f = (TF1*)functions->First();
      if (f) {
         if (f->InheritsFrom(TF1::Class())) fit = (TF1*)f;
      }
      TIter   next(functions);
      while ((f = (TObject*) next())) {
         if (f->InheritsFrom(TF1::Class())) {
            fit = (TF1*)f;
            break;
         }
      }
   }
   if (fit) PaintStats(theGraph, fit);

   rwxmin   = gPad->GetUxmin();
   rwxmax   = gPad->GetUxmax();
   rwymin   = gPad->GetUymin();
   rwymax   = gPad->GetUymax();
   uxmin    = gPad->PadtoX(rwxmin);
   uxmax    = gPad->PadtoX(rwxmax);
   if (theGraph->GetHistogram() && !theGraph->InheritsFrom("TGraphPolar")) {
      maximum = theGraph->GetHistogram()->GetMaximum();
      minimum = theGraph->GetHistogram()->GetMinimum();
   } else {
      maximum = gPad->PadtoY(rwymax);
      minimum = gPad->PadtoY(rwymin);
   }

   // Set attributes
   theGraph->TAttLine::Modify();
   theGraph->TAttFill::Modify();
   theGraph->TAttMarker::Modify();

   // Draw the graph with a polyline or a fill area
   gxwork  = new Double_t[2*npoints+10];
   gywork  = new Double_t[2*npoints+10];
   gxworkl = new Double_t[2*npoints+10];
   gyworkl = new Double_t[2*npoints+10];

   if (optionLine || optionFill) {
      x1    = x[0];
      xn    = x[npoints-1];
      y1    = y[0];
      yn    = y[npoints-1];
      nloop = npoints;
      if (optionFill && (xn != x1 || yn != y1)) nloop++;
      npt = 0;
      for (i=1;i<=nloop;i++) {
         if (i > npoints) {
            gxwork[npt] = gxwork[0];  gywork[npt] = gywork[0];
         } else {
            gxwork[npt] = x[i-1];      gywork[npt] = y[i-1];
            npt++;
         }
         if (i == nloop) {
            ComputeLogs(npt, optionZ);
            Int_t bord = gStyle->GetDrawBorder();
            if (optionR) {
               if (optionFill) {
                  gPad->PaintFillArea(npt,gyworkl,gxworkl);
                  if (bord) gPad->PaintPolyLine(npt,gyworkl,gxworkl);
               } else {
                  if (TMath::Abs(theGraph->GetLineWidth())>99) PaintPolyLineHatches(theGraph, npt, gyworkl, gxworkl);
                  gPad->PaintPolyLine(npt,gyworkl,gxworkl);
               }
            } else {
               if (optionFill) {
                  gPad->PaintFillArea(npt,gxworkl,gyworkl);
                  if (bord) gPad->PaintPolyLine(npt,gxworkl,gyworkl);
               } else {
                  if (TMath::Abs(theGraph->GetLineWidth())>99) PaintPolyLineHatches(theGraph, npt, gxworkl, gyworkl);
                  gPad->PaintPolyLine(npt,gxworkl,gyworkl);
               }
            }
            gxwork[0] = gxwork[npt-1];  gywork[0] = gywork[npt-1];
            npt      = 1;
         }
      }
   }

   // Draw the graph with a smooth Curve. Smoothing via Smooth
   if (optionCurve) {
      x1 = x[0];
      xn = x[npoints-1];
      y1 = y[0];
      yn = y[npoints-1];
      drawtype = 1;
      nloop = npoints;
      if (optionCurveFill) {
         drawtype += 1000;
         if (xn != x1 || yn != y1) nloop++;
      }
      if (!optionR) {
         npt = 0;
         for (i=1;i<=nloop;i++) {
            if (i > npoints) {
               gxwork[npt] = gxwork[0];  gywork[npt] = gywork[0];
            } else {
               gxwork[npt] = x[i-1];      gywork[npt] = y[i-1];
               npt++;
            }
            ComputeLogs(npt, optionZ);
            if (gyworkl[npt-1] < rwymin || gyworkl[npt-1] > rwymax) {
               if (npt > 2) {
                  ComputeLogs(npt, optionZ);
                  Smooth(theGraph, npt,gxworkl,gyworkl,drawtype);
               }
               gxwork[0] = gxwork[npt-1]; gywork[0] = gywork[npt-1];
               npt=1;
               continue;
            }
         }
         if (npt > 1) {
            ComputeLogs(npt, optionZ);
            Smooth(theGraph, npt,gxworkl,gyworkl,drawtype);
         }
      } else {
         drawtype += 10;
         npt    = 0;
         for (i=1;i<=nloop;i++) {
            if (i > npoints) {
               gxwork[npt] = gxwork[0];  gywork[npt] = gywork[0];
            } else {
               if (y[i-1] < minimum || y[i-1] > maximum) continue;
               if (x[i-1] < uxmin    || x[i-1] > uxmax)  continue;
               gxwork[npt] = x[i-1];      gywork[npt] = y[i-1];
               npt++;
            }
            ComputeLogs(npt, optionZ);
            if (gxworkl[npt-1] < rwxmin || gxworkl[npt-1] > rwxmax) {
               if (npt > 2) {
                  ComputeLogs(npt, optionZ);
                  Smooth(theGraph, npt,gxworkl,gyworkl,drawtype);
               }
               gxwork[0] = gxwork[npt-1]; gywork[0] = gywork[npt-1];
               npt=1;
               continue;
            }
         }
         if (npt > 1) {
            ComputeLogs(npt, optionZ);
            Smooth(theGraph, npt,gxworkl,gyworkl,drawtype);
         }
      }
   }

   // Draw the graph with a '*' on every points
   if (optionStar) {
      theGraph->SetMarkerStyle(3);
      npt = 0;
      for (i=1;i<=npoints;i++) {
         gxwork[npt] = x[i-1];      gywork[npt] = y[i-1];
         npt++;
         if (i == npoints) {
            ComputeLogs(npt, optionZ);
            if (optionR)  gPad->PaintPolyMarker(npt,gyworkl,gxworkl);
            else          gPad->PaintPolyMarker(npt,gxworkl,gyworkl);
            npt = 0;
         }
      }
   }

   // Draw the graph with the current polymarker on every points
   if (optionMark) {
      npt = 0;
      for (i=1;i<=npoints;i++) {
         gxwork[npt] = x[i-1];      gywork[npt] = y[i-1];
         npt++;
         if (i == npoints) {
            ComputeLogs(npt, optionZ);
            if (optionR) gPad->PaintPolyMarker(npt,gyworkl,gxworkl);
            else         gPad->PaintPolyMarker(npt,gxworkl,gyworkl);
            npt = 0;
         }
      }
   }

   // Draw the graph as a bar chart
   if (optionBar) {
      if (!optionR) {
         barxmin = x[0];
         barxmax = x[0];
         for (i=1;i<npoints;i++) {
            if (x[i] < barxmin) barxmin = x[i];
            if (x[i] > barxmax) barxmax = x[i];
         }
         bdelta = (barxmax-barxmin)/Double_t(npoints);
      } else {
         barymin = y[0];
         barymax = y[0];
         for (i=1;i<npoints;i++) {
            if (y[i] < barymin) barymin = y[i];
            if (y[i] > barymax) barymax = y[i];
         }
         bdelta = (barymax-barymin)/Double_t(npoints);
      }
      dbar  = 0.5*bdelta*gStyle->GetBarWidth();
      if (!optionR) {
         for (i=1;i<=npoints;i++) {
            xlow  = x[i-1] - dbar;
            xhigh = x[i-1] + dbar;
            yhigh = y[i-1];
            if (xlow  < uxmin) xlow = uxmin;
            if (xhigh > uxmax) xhigh = uxmax;
            if (!optionOne) ylow = TMath::Max((Double_t)0,gPad->GetUymin());
            else            ylow = gPad->GetUymin();
            gxwork[0] = xlow;
            gywork[0] = ylow;
            gxwork[1] = xhigh;
            gywork[1] = yhigh;
            ComputeLogs(2, optionZ);
            if (gyworkl[0] < gPad->GetUymin()) gyworkl[0] = gPad->GetUymin();
            if (gyworkl[1] < gPad->GetUymin()) continue;
            if (gyworkl[1] > gPad->GetUymax()) gyworkl[1] = gPad->GetUymax();
            if (gyworkl[0] > gPad->GetUymax()) continue;

            gPad->PaintBox(gxworkl[0],gyworkl[0],gxworkl[1],gyworkl[1]);
         }
      } else {
         for (i=1;i<=npoints;i++) {
            xhigh = x[i-1];
            ylow  = y[i-1] - dbar;
            yhigh = y[i-1] + dbar;
            xlow     = TMath::Max((Double_t)0, gPad->GetUxmin());
            gxwork[0] = xlow;
            gywork[0] = ylow;
            gxwork[1] = xhigh;
            gywork[1] = yhigh;
            ComputeLogs(2, optionZ);
            gPad->PaintBox(gxworkl[0],gyworkl[0],gxworkl[1],gyworkl[1]);
         }
      }
   }
   gPad->ResetBit(TGraph::kClipFrame);

   delete [] gxwork;
   delete [] gywork;
   delete [] gxworkl;
   delete [] gyworkl;
}


//______________________________________________________________________________
void TGraphPainter::PaintGrapHist(TGraph *theGraph, Int_t npoints, const Double_t *x,
                                  const Double_t *y, Option_t *chopt)
{
   /* Begin_Html
    This is a service method used by
    <a href="http://root.cern.ch/root/html/THistPainter.html"><tt>THistPainter</tt></a>
    to paint 1D histograms. <b>It is not used to paint TGraph</b>.
    <p>
    Input parameters:
    <ul>
    <li> npoints : Number of points in X or in Y.
    <li> x[npoints] or x[0] : x coordinates or (xmin,xmax).
    <li> y[npoints] or y[0] : y coordinates or (ymin,ymax).
    <li> chopt : Option.
    </ul>
    <p>
    The aspect of the histogram is done according to the value of the chopt.
    <p>
    <table border=0>
    <tr><th valign=top>"R"</th><td>
    Graph is drawn horizontaly, parallel to X axis. (default is vertically,
    parallel to Y axis)
    <br>
    If option R is selected the user must give:
    <ul>
    <li> 2 values for Y (y[0]=YMIN and y[1]=YMAX)
    <li> N values for X, one for each channel.
    </ul>
    Otherwise the user must give:
    <ul>
    <li> N values for Y, one for each channel.
    <li> 2 values for X (x[0]=XMIN and x[1]=XMAX)
    </ul>
    </td></tr>

    <tr><th valign=top>"L"</th><td>
    A simple polyline beetwen every points is drawn.
    </td></tr>

    <tr><th valign=top>"H"</th><td>
    An Histogram with equidistant bins is drawn as a polyline.
    </td></tr>

    <tr><th valign=top>"F"</th><td>
    An histogram with equidistant bins is drawn as a fill area. Contour is not
    drawn unless chopt='H' is also selected..
    </td></tr>

    <tr><th valign=top>"N"</th><td>
    Non equidistant bins (default is equidistant). If N is the number of channels
    array X and Y must be dimensionned as follow:
    <ul>
    <li>>If option R is not selected (default) then the user must give:</li>
      <ul>
      <li>(N+1) values for X (limits of channels).</li>
      <li>N values for Y, one for each channel.</li>
      <ul>
    <li>Otherwise the user must give:</li>
      <ul>
      <li>(N+1) values for Y (limits of channels).</li>
      <li>N values for X, one for each channel.</li>
      </ul>
    </ul>
    </td></tr>

    <tr><th valign=top>"F1"</th><td>
    Idem as 'F' except that fill area base line is the minimum of the pad instead
    of Y=0.
    </td></tr>

    <tr><th valign=top>"F2"</th><td>
    Draw a Fill area polyline connecting the center of bins
    </td></tr>

    <tr><th valign=top>"C"</th><td>
    A smooth Curve is drawn.
    </td></tr>

    <tr><th valign=top>"*"</th><td>
    A Star is plotted at the center of each bin.
    </td></tr>

    <tr><th valign=top>"P"</th><td>
    Idem with the current marker.
    </td></tr>

    <tr><th valign=top>"P0"</th><td>
    Idem with the current marker. Empty bins also drawn.
    </td></tr>

    <tr><th valign=top>"B"</th><td>
    A Bar chart with equidistant bins is drawn as fill areas (Contours are drawn).
    </td></tr>

    <tr><th valign=top>"]["</th><td>
    "Cutoff" style. When this option is selected together with H option, the
    first and last vertical lines of the histogram are not drawn.
    </td></tr>

    </table>
    End_Html */

   const char *where = "PaintGraphHist";

   Int_t optionLine , optionAxis , optionCurve, optionStar, optionMark;
   Int_t optionBar  , optionRot  , optionOne  , optionOff ;
   Int_t optionFill , optionZ;
   Int_t optionHist , optionBins , optionMarker;
   Int_t i, j, npt;
   Int_t drawtype=0, drawborder, drawbordersav;
   Double_t xlow, xhigh, ylow, yhigh;
   Double_t wmin, wmax;
   Double_t dbar, offset, wminstep;
   Double_t delta = 0;
   Double_t ylast = 0;
   Double_t xi, xi1, xj, xj1, yi1, yi, yj, yj1, xwmin, ywmin;
   Int_t first, last, nbins;
   Int_t fillarea;

   char choptaxis[10] = " ";

   if (npoints <= 0) {
      Error(where, "illegal number of points (%d)", npoints);
      return;
   }
   TString opt = chopt;
   opt.ToUpper();
   if (opt.Contains("H"))  optionHist = 1;  else optionHist = 0;
   if (opt.Contains("F"))  optionFill = 1;  else optionFill = 0;
   if (opt.Contains("C"))  optionCurve= 1;  else optionCurve= 0;
   if (opt.Contains("*"))  optionStar = 1;  else optionStar = 0;
   if (opt.Contains("R"))  optionRot  = 1;  else optionRot  = 0;
   if (opt.Contains("1"))  optionOne  = 1;  else optionOne  = 0;
   if (opt.Contains("B"))  optionBar  = 1;  else optionBar  = 0;
   if (opt.Contains("N"))  optionBins = 1;  else optionBins = 0;
   if (opt.Contains("L"))  optionLine = 1;  else optionLine = 0;
   if (opt.Contains("P"))  optionMark = 1;  else optionMark = 0;
   if (opt.Contains("A"))  optionAxis = 1;  else optionAxis = 0;
   if (opt.Contains("][")) optionOff  = 1;  else optionOff  = 0;
   if (opt.Contains("P0")) optionMark = 10;

   Int_t optionFill2 = 0;
   if (opt.Contains("F") && opt.Contains("2")) {
      optionFill = 0; optionFill2 = 1;
   }

   // Set Clipping option
   Option_t *noClip;
   if (theGraph->TestBit(TGraph::kClipFrame)) noClip = "";
   else noClip = "C";
   gPad->SetBit(TGraph::kClipFrame, theGraph->TestBit(TGraph::kClipFrame));

   optionZ = 1;

   if (optionStar) theGraph->SetMarkerStyle(3);

   first = 1;
   last  = npoints;
   nbins = last - first + 1;

   //           Draw the Axis with a fixed number of division: 510

   Double_t baroffset = gStyle->GetBarOffset();
   Double_t barwidth  = gStyle->GetBarWidth();
   Double_t rwxmin    = gPad->GetUxmin();
   Double_t rwxmax    = gPad->GetUxmax();
   Double_t rwymin    = gPad->GetUymin();
   Double_t rwymax    = gPad->GetUymax();
   Double_t uxmin     = gPad->PadtoX(rwxmin);
   Double_t uxmax     = gPad->PadtoX(rwxmax);
   Double_t rounding  = (uxmax-uxmin)*1.e-5;
   drawborder         = gStyle->GetDrawBorder();
   if (optionAxis) {
      Int_t nx1, nx2, ndivx, ndivy, ndiv;
      choptaxis[0]  = 0;
      Double_t rwmin  = rwxmin;
      Double_t rwmax  = rwxmax;
      ndivx = gStyle->GetNdivisions("X");
      ndivy = gStyle->GetNdivisions("Y");
      if (ndivx > 1000) {
         nx2   = ndivx/100;
         nx1   = TMath::Max(1, ndivx%100);
         ndivx = 100*nx2 + Int_t(Double_t(nx1)*gPad->GetAbsWNDC());
      }
      ndiv  =TMath::Abs(ndivx);
      // coverity [Calling risky function]
      if (ndivx < 0) strlcat(choptaxis, "N",10);
      if (gPad->GetGridx()) {
         // coverity [Calling risky function]
         strlcat(choptaxis, "W",10);
      }
      if (gPad->GetLogx()) {
         rwmin = TMath::Power(10,rwxmin);
         rwmax = TMath::Power(10,rwxmax);
         // coverity [Calling risky function]
         strlcat(choptaxis, "G",10);
      }
      TGaxis *axis = new TGaxis();
      axis->SetLineColor(gStyle->GetAxisColor("X"));
      axis->SetTextColor(gStyle->GetLabelColor("X"));
      axis->SetTextFont(gStyle->GetLabelFont("X"));
      axis->SetLabelSize(gStyle->GetLabelSize("X"));
      axis->SetLabelOffset(gStyle->GetLabelOffset("X"));
      axis->SetTickSize(gStyle->GetTickLength("X"));

      axis->PaintAxis(rwxmin,rwymin,rwxmax,rwymin,rwmin,rwmax,ndiv,choptaxis);

      choptaxis[0]  = 0;
      rwmin  = rwymin;
      rwmax  = rwymax;
      if (ndivy < 0) {
         nx2   = ndivy/100;
         nx1   = TMath::Max(1, ndivy%100);
         ndivy = 100*nx2 + Int_t(Double_t(nx1)*gPad->GetAbsHNDC());
         // coverity [Calling risky function]
         strlcat(choptaxis, "N",10);
      }
      ndiv  =TMath::Abs(ndivy);
      if (gPad->GetGridy()) {
         // coverity [Calling risky function]
         strlcat(choptaxis, "W",10);
      }
      if (gPad->GetLogy()) {
         rwmin = TMath::Power(10,rwymin);
         rwmax = TMath::Power(10,rwymax);
         // coverity [Calling risky function]
         strlcat(choptaxis,"G",10);
      }
      axis->SetLineColor(gStyle->GetAxisColor("Y"));
      axis->SetTextColor(gStyle->GetLabelColor("Y"));
      axis->SetTextFont(gStyle->GetLabelFont("Y"));
      axis->SetLabelSize(gStyle->GetLabelSize("Y"));
      axis->SetLabelOffset(gStyle->GetLabelOffset("Y"));
      axis->SetTickSize(gStyle->GetTickLength("Y"));

      axis->PaintAxis(rwxmin,rwymin,rwxmin,rwymax,rwmin,rwmax,ndiv,choptaxis);
      delete axis;
   }


   //           Set attributes
   theGraph->TAttLine::Modify();
   theGraph->TAttFill::Modify();
   theGraph->TAttMarker::Modify();

   //       Min-Max scope

   if (!optionRot) {wmin = x[0];   wmax = x[1];}
   else            {wmin = y[0];   wmax = y[1];}

   if (!optionBins) delta = (wmax - wmin)/ Double_t(nbins);

   Int_t fwidth = gPad->GetFrameLineWidth();
   TFrame *frame = gPad->GetFrame();
   if (frame) fwidth = frame->GetLineWidth();
   if (optionOff) fwidth = 1;
   Double_t dxframe = gPad->AbsPixeltoX(fwidth/2) - gPad->AbsPixeltoX(0);
   Double_t vxmin = gPad->PadtoX(gPad->GetUxmin() + dxframe);
   Double_t vxmax = gPad->PadtoX(gPad->GetUxmax() - dxframe);
   Double_t dyframe = -gPad->AbsPixeltoY(fwidth/2) + gPad->AbsPixeltoY(0);
   Double_t vymin = gPad->GetUymin() + dyframe; //y already in log scale
   vxmin = TMath::Max(vxmin,wmin);
   vxmax = TMath::Min(vxmax,wmax);

   //           Draw the histogram with a fill area

   gxwork  = new Double_t[2*npoints+10];
   gywork  = new Double_t[2*npoints+10];
   gxworkl = new Double_t[2*npoints+10];
   gyworkl = new Double_t[2*npoints+10];

   if (optionFill && !optionCurve) {
      fillarea = kTRUE;
      if (!optionRot) {
         gxwork[0] = vxmin;
         if (!optionOne) gywork[0] = TMath::Min(TMath::Max((Double_t)0,gPad->GetUymin())
                                               ,gPad->GetUymax());
         else            gywork[0] = gPad->GetUymin();
         npt = 2;
         for (j=first; j<=last;j++) {
            if (!optionBins) {
               gxwork[npt-1]   = gxwork[npt-2];
               gxwork[npt]     = wmin+((j-first+1)*delta);
               if (gxwork[npt] < gxwork[0]) gxwork[npt] = gxwork[0];

            } else {
               xj1 = x[j];      xj  = x[j-1];
               if (xj1 < xj) {
                  if (j != last) Error(where, "X must be in increasing order");
                  else           Error(where, "X must have N+1 values with option N");
                  return;
               }
               gxwork[npt-1] = x[j-1];       gxwork[npt] = x[j];
            }
            gywork[npt-1] = y[j-1];
            gywork[npt]   = y[j-1];
            if (gywork[npt] < vymin) {gywork[npt] = vymin; gywork[npt-1] = vymin;}
            if ((gxwork[npt-1] >= uxmin-rounding && gxwork[npt-1] <= uxmax+rounding) ||
                (gxwork[npt]   >= uxmin-rounding && gxwork[npt]   <= uxmax+rounding)) npt += 2;
            if (j == last) {
               gxwork[npt-1] = gxwork[npt-2];
               gywork[npt-1] = gywork[0];
               //make sure that the fill area does not overwrite the frame
               //take into account the frame linewidth
               if (gxwork[0    ] < vxmin) {gxwork[0    ] = vxmin; gxwork[1    ] = vxmin;}
               if (gywork[0] < vymin) {gywork[0] = vymin; gywork[npt-1] = vymin;}

               //transform to log ?
               ComputeLogs(npt, optionZ);
               gPad->PaintFillArea(npt,gxworkl,gyworkl);
               if (drawborder) {
                  if (!fillarea) gyworkl[0] = ylast;
                  gPad->PaintPolyLine(npt-1,gxworkl,gyworkl,noClip);
               }
               continue;
            }
         }  //endfor (j=first; j<=last;j++) {
      } else {
         gywork[0] = wmin;
         if (!optionOne) gxwork[0] = TMath::Max((Double_t)0,gPad->GetUxmin());
         else            gxwork[0] = gPad->GetUxmin();
         npt = 2;
         for (j=first; j<=last;j++) {
            if (!optionBins) {
               gywork[npt-1] = gywork[npt-2];
               gywork[npt]   = wmin+((j-first+1)*delta);
            } else {
               yj1 = y[j];      yj  = y[j-1];
               if (yj1 < yj) {
                  if (j != last) Error(where, "Y must be in increasing order");
                  else           Error(where, "Y must have N+1 values with option N");
                  return;
               }
               gywork[npt-1] = y[j-1];       gywork[npt] = y[j];
            }
            gxwork[npt-1] = x[j-1];      gxwork[npt] = x[j-1];
            if ((gxwork[npt-1] >= uxmin-rounding && gxwork[npt-1] <= uxmax+rounding) ||
                (gxwork[npt]   >= uxmin-rounding && gxwork[npt]   <= uxmax+rounding)) npt += 2;
            if (j == last) {
               gywork[npt-1] = gywork[npt-2];
               gxwork[npt-1] = gxwork[0];
               ComputeLogs(npt, optionZ);
               gPad->PaintFillArea(npt,gxworkl,gyworkl);
               if (drawborder) {
                  if (!fillarea) gyworkl[0] = ylast;
                  gPad->PaintPolyLine(npt-1,gxworkl,gyworkl,noClip);
               }
               continue;
            }
         }  //endfor (j=first; j<=last;j++)
      }
      theGraph->TAttLine::Modify();
      theGraph->TAttFill::Modify();
   }

   //      Draw a standard Histogram (default)

   if ((optionHist) || !chopt[0]) {
      if (!optionRot) {
         gxwork[0] = wmin;
         gywork[0] = gPad->GetUymin();
         ywmin    = gywork[0];
         npt      = 2;
         for (i=first; i<=last;i++) {
            if (!optionBins) {
               gxwork[npt-1] = gxwork[npt-2];
               gxwork[npt]   = wmin+((i-first+1)*delta);
            } else {
               xi1 = x[i];      xi  = x[i-1];
               if (xi1 < xi) {
                  if (i != last) Error(where, "X must be in increasing order");
                  else           Error(where, "X must have N+1 values with option N");
                  return;
               }
               gxwork[npt-1] = x[i-1];      gxwork[npt] = x[i];
            }
            gywork[npt-1] = y[i-1];
            gywork[npt]   = y[i-1];
            if (gywork[npt] < vymin) {gywork[npt] = vymin; gywork[npt-1] = vymin;}
            if ((gxwork[npt-1] >= uxmin-rounding && gxwork[npt-1] <= uxmax+rounding) ||
                (gxwork[npt]   >= uxmin-rounding && gxwork[npt]   <= uxmax+rounding)) npt += 2;
            if (i == last) {
               gxwork[npt-1] = gxwork[npt-2];
               gywork[npt-1] = gywork[0];
               //make sure that the fill area does not overwrite the frame
               //take into account the frame linewidth
               if (gxwork[0] < vxmin) {gxwork[0] = vxmin; gxwork[1    ] = vxmin;}
               if (gywork[0] < vymin) {gywork[0] = vymin; gywork[npt-1] = vymin;}

               ComputeLogs(npt, optionZ);

               // do not draw the two vertical lines on the edges
               Int_t nbpoints = npt-2;
               Int_t point1  = 1;

               if (optionOff) {
                  // remove points before the low cutoff
                  Int_t ip;
                  for (ip=point1; ip<=nbpoints; ip++) {
                     if (gyworkl[ip] != ywmin) {
                        point1 = ip;
                        break;
                     }
                  }
                  // remove points after the high cutoff
                  Int_t point2 = nbpoints;
                  for (ip=point2; ip>=point1; ip--) {
                     if (gyworkl[ip] != ywmin) {
                        point2 = ip;
                        break;
                     }
                  }
                  nbpoints = point2-point1+1;
               } else {
                  // if the 1st or last bin are not on the pad limits the
                  // the two vertical lines on the edges are added.
                  if (gxwork[0] > gPad->GetUxmin()) { nbpoints++; point1 = 0; }
                  if (gxwork[nbpoints] < gPad->GetUxmax()) nbpoints++;
               }

               gPad->PaintPolyLine(nbpoints,&gxworkl[point1],&gyworkl[point1],noClip);
               continue;
            }
         }  //endfor (i=first; i<=last;i++)
      } else {
         gywork[0] = wmin;
         gxwork[0] = TMath::Max((Double_t)0,gPad->GetUxmin());
         xwmin    = gxwork[0];
         npt      = 2;
         for (i=first; i<=last;i++) {
            if (!optionBins) {
               gywork[npt-1]   = gywork[npt-2];
               gywork[npt] = wmin+((i-first+1)*delta);
            } else {
               yi1 = y[i];      yi  = y[i-1];
               if (yi1 < yi) {
                  if (i != last) Error(where, "Y must be in increasing order");
                  else           Error(where, "Y must have N+1 values with option N");
                  return;
               }
               gywork[npt-1] = y[i-1];      gywork[npt] = y[i];
            }
            gxwork[npt-1] = x[i-1];      gxwork[npt] = x[i-1];
            if ((gxwork[npt-1] >= uxmin-rounding && gxwork[npt-1] <= uxmax+rounding) ||
                (gxwork[npt]   >= uxmin-rounding && gxwork[npt]   <= uxmax+rounding)) npt += 2;
            if (i == last) {
               gywork[npt-1] = gywork[npt-2];
               gxwork[npt-1] = xwmin;
               ComputeLogs(npt, optionZ);
               gPad->PaintPolyLine(npt,gxworkl,gyworkl,noClip);
               continue;
            }
         }  //endfor (i=first; i<=last;i++)
      }
   }

   //              Draw the histogram with a smooth Curve.
   //              The smoothing is done by the method Smooth()

   if (optionCurve) {
      if (!optionFill) {
         drawtype = 1;
      } else {
         if (!optionOne) drawtype = 2;
         else            drawtype = 3;
      }
      if (!optionRot) {
         npt = 0;
         for (i=first; i<=last;i++) {
            npt++;
            if (!optionBins) {
               gxwork[npt-1] = wmin+(i-first)*delta+0.5*delta;
            } else {
               xi1 = x[i];      xi  = x[i-1];
               if (xi1 < xi) {
                  if (i != last) Error(where, "X must be in increasing order");
                  else           Error(where, "X must have N+1 values with option N");
                  return;
               }
               gxwork[npt-1] = x[i-1] + 0.5*(x[i]-x[i-1]);
            }
            if (gxwork[npt-1] < uxmin || gxwork[npt-1] > uxmax) {
               npt--;
               continue;
            }
            gywork[npt-1] = y[i-1];
            ComputeLogs(npt, optionZ);
            if ((gyworkl[npt-1] < rwymin) || (gyworkl[npt-1] > rwymax)) {
               if (npt > 2) {
                  ComputeLogs(npt, optionZ);
                  Smooth(theGraph, npt,gxworkl,gyworkl,drawtype);
               }
               gxwork[0] = gxwork[npt-1];
               gywork[0] = gywork[npt-1];
               npt      = 1;
               continue;
            }
            if (npt >= 50) {
               ComputeLogs(50, optionZ);
               Smooth(theGraph, 50,gxworkl,gyworkl,drawtype);
               gxwork[0] = gxwork[npt-1];
               gywork[0] = gywork[npt-1];
               npt      = 1;
            }
         }  //endfor (i=first; i<=last;i++)
         if (npt > 1) {
            ComputeLogs(npt, optionZ);
            Smooth(theGraph, npt,gxworkl,gyworkl,drawtype);
         }
      } else {
         drawtype = drawtype+10;
         npt   = 0;
         for (i=first; i<=last;i++) {
            npt++;
            if (!optionBins) {
               gywork[npt-1] = wmin+(i-first)*delta+0.5*delta;
            } else {
               yi1 = y[i];      yi = y[i-1];
               if (yi1 < yi) {
                  if (i != last) Error(where, "Y must be in increasing order");
                  else           Error(where, "Y must have N+1 values with option N");
                  return;
               }
               gywork[npt-1] = y[i-1] + 0.5*(y[i]-y[i-1]);
            }
            gxwork[npt-1] = x[i-1];
            ComputeLogs(npt, optionZ);
            if ((gxworkl[npt] < uxmin) || (gxworkl[npt] > uxmax)) {
               if (npt > 2) {
                  ComputeLogs(npt, optionZ);
                  Smooth(theGraph, npt,gxworkl,gyworkl,drawtype);
               }
               gxwork[0] = gxwork[npt-1];
               gywork[0] = gywork[npt-1];
               npt      = 1;
               continue;
            }
            if (npt >= 50) {
               ComputeLogs(50, optionZ);
               Smooth(theGraph, 50,gxworkl,gyworkl,drawtype);
               gxwork[0] = gxwork[npt-1];
               gywork[0] = gywork[npt-1];
               npt      = 1;
            }
         }  //endfor (i=first; i<=last;i++)
         if (npt > 1) {
            ComputeLogs(npt, optionZ);
            Smooth(theGraph, npt,gxworkl,gyworkl,drawtype);
         }
      }
   }

   //    Draw the histogram with a simple line or/and a marker

   optionMarker = 0;
   if ((optionStar) || (optionMark))optionMarker=1;
   if ((optionMarker) || (optionLine)) {
      wminstep = wmin + 0.5*delta;
      Axis_t ax1,ax2,ay1,ay2;
      gPad->GetRangeAxis(ax1,ay1,ax2,ay2);

      if (!optionRot) {
         npt = 0;
         for (i=first; i<=last;i++) {
            npt++;
            if (!optionBins) {
               gxwork[npt-1] = wmin+(i-first)*delta+0.5*delta;
            } else {
               xi1 = x[i];      xi = x[i-1];
               if (xi1 < xi) {
                  if (i != last) Error(where, "X must be in increasing order");
                  else           Error(where, "X must have N+1 values with option N");
                  return;
               }
               gxwork[npt-1] = x[i-1] + 0.5*(x[i]-x[i-1]);
            }
            if (gxwork[npt-1] < uxmin || gxwork[npt-1] > uxmax) { npt--; continue;}
            if ((optionMark != 10) && (optionLine == 0)) {
               if (y[i-1] <= rwymin)  {npt--; continue;}
            }
            gywork[npt-1] = y[i-1];
            gywork[npt]   = y[i-1]; //new
            if ((gywork[npt-1] < rwymin) || ((gywork[npt-1] > rwymax) && !optionFill2)) {
               if ((gywork[npt-1] < rwymin)) gywork[npt-1] = rwymin;
               if ((gywork[npt-1] > rwymax)) gywork[npt-1] = rwymax;
               if (npt > 2) {
                  if (optionMarker) {
                     ComputeLogs(npt, optionZ);
                     gPad->PaintPolyMarker(npt,gxworkl,gyworkl);
                  }
                  if (optionLine) {
                     if (!optionMarker) ComputeLogs(npt, optionZ);
                     gPad->PaintPolyLine(npt,gxworkl,gyworkl,noClip);
                  }
               }
               gxwork[0] = gxwork[npt-1];
               gywork[0] = gywork[npt-1];
               npt       = 1;
               continue;
            }

            if (npt >= 50) {
               if (optionMarker) {
                  ComputeLogs(50, optionZ);
                  gPad->PaintPolyMarker(50,gxworkl,gyworkl);
               }
               if (optionLine) {
                  if (!optionMarker) ComputeLogs(50, optionZ);
                  if (optionFill2) {
                     gxworkl[npt]   = gxworkl[npt-1]; gyworkl[npt]   = rwymin;
                     gxworkl[npt+1] = gxworkl[0];     gyworkl[npt+1] = rwymin;
                     gPad->PaintFillArea(52,gxworkl,gyworkl);
                  }
                  gPad->PaintPolyLine(50,gxworkl,gyworkl);
               }
               gxwork[0] = gxwork[npt-1];
               gywork[0] = gywork[npt-1];
               npt      = 1;
            }
         }  //endfor (i=first; i<=last;i++)
         if (optionMarker && npt > 0) {
            ComputeLogs(npt, optionZ);
            gPad->PaintPolyMarker(npt,gxworkl,gyworkl);
         }
         if (optionLine && npt > 1) {
            if (!optionMarker) ComputeLogs(npt, optionZ);
            if (optionFill2) {
               gxworkl[npt]   = gxworkl[npt-1]; gyworkl[npt]   = rwymin;
               gxworkl[npt+1] = gxworkl[0];     gyworkl[npt+1] = rwymin;
               gPad->PaintFillArea(npt+2,gxworkl,gyworkl);
            }
            gPad->PaintPolyLine(npt,gxworkl,gyworkl);
         }
      } else {
         npt = 0;
         for (i=first; i<=last;i++) {
            npt++;
            if (!optionBins) {
               gywork[npt-1] = wminstep+(i-first)*delta+0.5*delta;
            } else {
               yi1 = y[i];      yi = y[i-1];
               if (yi1 < yi) {
                  if (i != last) Error(where, "Y must be in increasing order");
                  else           Error(where, "Y must have N+1 values with option N");
                  return;
               }
               gywork[npt-1] = y[i-1] + 0.5*(y[i]-y[i-1]);
            }
            gxwork[npt-1] = x[i-1];
            if ((gxwork[npt-1] < uxmin) || (gxwork[npt-1] > uxmax)) {
               if (npt > 2) {
                  if (optionMarker) {
                     ComputeLogs(npt, optionZ);
                     gPad->PaintPolyMarker(npt,gxworkl,gyworkl);
                  }
                  if (optionLine) {
                     if (!optionMarker) ComputeLogs(npt, optionZ);
                     gPad->PaintPolyLine(npt,gxworkl,gyworkl,noClip);
                  }
               }
               gxwork[0] = gxwork[npt-1];
               gywork[0] = gywork[npt-1];
               npt      = 1;
               continue;
            }
            if (npt >= 50) {
               if (optionMarker) {
                  ComputeLogs(50, optionZ);
                  gPad->PaintPolyMarker(50,gxworkl,gyworkl);
               }
               if (optionLine) {
                  if (!optionMarker) ComputeLogs(50, optionZ);
                  gPad->PaintPolyLine(50,gxworkl,gyworkl);
               }
               gxwork[0] = gxwork[npt-1];
               gywork[0] = gywork[npt-1];
               npt      = 1;
            }
         }  //endfor (i=first; i<=last;i++)
         if (optionMarker && npt > 0) {
            ComputeLogs(npt, optionZ);
            gPad->PaintPolyMarker(npt,gxworkl,gyworkl);
         }
         if (optionLine != 0 && npt > 1) {
            if (!optionMarker) ComputeLogs(npt, optionZ);
            gPad->PaintPolyLine(npt,gxworkl,gyworkl,noClip);
         }
      }
   }

   //              Draw the histogram as a bar chart

   if (optionBar) {
      if (!optionBins) {
         offset = delta*baroffset; dbar = delta*barwidth;
      } else {
         if (!optionRot) {
            offset = (x[1]-x[0])*baroffset;
            dbar   = (x[1]-x[0])*barwidth;
         } else {
            offset = (y[1]-y[0])*baroffset;
            dbar   = (y[1]-y[0])*barwidth;
         }
      }
      drawbordersav = drawborder;
      gStyle->SetDrawBorder(1);
      if (!optionRot) {
         xlow  = wmin+offset;
         xhigh = wmin+offset+dbar;
         if (!optionOne) ylow = TMath::Min(TMath::Max((Double_t)0,gPad->GetUymin())
                                ,gPad->GetUymax());
         else            ylow = gPad->GetUymin();

         for (i=first; i<=last;i++) {
            yhigh    = y[i-1];
            gxwork[0] = xlow;
            gywork[0] = ylow;
            gxwork[1] = xhigh;
            gywork[1] = yhigh;
            ComputeLogs(2, optionZ);
            gPad->PaintBox(gxworkl[0],gyworkl[0],gxworkl[1],gyworkl[1]);
            if (!optionBins) {
               xlow  = xlow+delta;
               xhigh = xhigh+delta;
            } else {
               if (i < last) {
                  xi1 = x[i];      xi = x[i-1];
                  if (xi1 < xi) {
                     Error(where, "X must be in increasing order");
                     return;
                  }
                  offset  = (x[i+1]-x[i])*baroffset;
                  dbar    = (x[i+1]-x[i])*barwidth;
                  xlow    = x[i] + offset;
                  xhigh   = x[i] + offset + dbar;
               }
            }
         }  //endfor (i=first; i<=last;i++)
      } else {
         ylow  = wmin + offset;
         yhigh = wmin + offset + dbar;
         if (!optionOne) xlow = TMath::Max((Double_t)0,gPad->GetUxmin());
         else            xlow = gPad->GetUxmin();

         for (i=first; i<=last;i++) {
            xhigh    = x[i-1];
            gxwork[0] = xlow;
            gywork[0] = ylow;
            gxwork[1] = xhigh;
            gywork[1] = yhigh;
            ComputeLogs(2, optionZ);
            gPad->PaintBox(gxworkl[0],gyworkl[0],gxworkl[1],gyworkl[1]);
            gPad->PaintBox(xlow,ylow,xhigh,yhigh);
            if (!optionBins) {
               ylow  = ylow  + delta;
               yhigh = yhigh + delta;
            } else {
               if (i < last) {
                  yi1 = y[i];      yi = y[i-1];
                  if (yi1 < yi) {
                     Error(where, "Y must be in increasing order");
                     return;
                  }
                  offset  = (y[i+1]-y[i])*baroffset;
                  dbar    = (y[i+1]-y[i])*barwidth;
                  ylow    = y[i] + offset;
                  yhigh   = y[i] + offset + dbar;
               }
            }
         }  //endfor (i=first; i<=last;i++)
      }
      gStyle->SetDrawBorder(drawbordersav);
   }
   gPad->ResetBit(TGraph::kClipFrame);

   delete [] gxwork;
   delete [] gywork;
   delete [] gxworkl;
   delete [] gyworkl;
}


//______________________________________________________________________________
void TGraphPainter::PaintGraphAsymmErrors(TGraph *theGraph, Option_t *option)
{
   /* Begin_Html
   <a href="#GP03">Paint this TGraphAsymmErrors with its current attributes.</a>
   End_Html */

   Double_t *xline = 0;
   Double_t *yline = 0;
   Int_t if1 = 0;
   Int_t if2 = 0;
   Double_t xb[4], yb[4];

   const Int_t kBASEMARKER=8;
   Double_t s2x, s2y, symbolsize, sbase;
   Double_t x, y, xl1, xl2, xr1, xr2, yup1, yup2, ylow1, ylow2, tx, ty;
   static Float_t cxx[15] = {1,1,0.6,0.6,1,1,0.6,0.5,1,0.6,0.6,1,0.6,1,1};
   static Float_t cyy[15] = {1,1,1,1,1,1,1,1,1,0.5,0.6,1,1,1,1};
   Int_t theNpoints = theGraph->GetN();
   Double_t *theX  = theGraph->GetX();
   Double_t *theY  = theGraph->GetY();
   Double_t *theEXlow  = theGraph->GetEXlow();  if (!theEXlow) return;
   Double_t *theEYlow  = theGraph->GetEYlow();  if (!theEYlow) return;
   Double_t *theEXhigh = theGraph->GetEXhigh(); if (!theEXhigh) return;
   Double_t *theEYhigh = theGraph->GetEYhigh(); if (!theEYhigh) return;

   if (strchr(option,'X') || strchr(option,'x')) {PaintGraphSimple(theGraph, option); return;}
   Bool_t brackets = kFALSE;
   Bool_t braticks = kFALSE;
   if (strstr(option,"||") || strstr(option,"[]")) {
      brackets = kTRUE;
      if (strstr(option,"[]")) braticks = kTRUE;
   }
   Bool_t endLines = kTRUE;
   if (strchr(option,'z')) endLines = kFALSE;
   if (strchr(option,'Z')) endLines = kFALSE;
   const char *arrowOpt = 0;
   if (strchr(option,'>'))  arrowOpt = ">";
   if (strstr(option,"|>")) arrowOpt = "|>";

   Bool_t axis = kFALSE;
   if (strchr(option,'a')) axis = kTRUE;
   if (strchr(option,'A')) axis = kTRUE;
   if (axis) PaintGraphSimple(theGraph, option);

   Bool_t option0 = kFALSE;
   Bool_t option2 = kFALSE;
   Bool_t option3 = kFALSE;
   Bool_t option4 = kFALSE;
   Bool_t option5 = kFALSE;
   if (strchr(option,'0')) option0 = kTRUE;
   if (strchr(option,'2')) option2 = kTRUE;
   if (strchr(option,'3')) option3 = kTRUE;
   if (strchr(option,'4')) {option3 = kTRUE; option4 = kTRUE;}
   if (strchr(option,'5')) {option2 = kTRUE; option5 = kTRUE;}

   if (option3) {
      xline = new Double_t[2*theNpoints];
      yline = new Double_t[2*theNpoints];
      if (!xline || !yline) {
         Error("Paint", "too many points, out of memory");
         return;
      }
      if1 = 1;
      if2 = 2*theNpoints;
   }

   theGraph->TAttLine::Modify();

   TArrow arrow;
   arrow.SetLineWidth(theGraph->GetLineWidth());
   arrow.SetLineColor(theGraph->GetLineColor());
   arrow.SetFillColor(theGraph->GetFillColor());

   TBox box;
   Double_t x1b,y1b,x2b,y2b;
   box.SetLineWidth(theGraph->GetLineWidth());
   box.SetLineColor(theGraph->GetLineColor());
   box.SetFillColor(theGraph->GetFillColor());
   box.SetFillStyle(theGraph->GetFillStyle());

   symbolsize  = theGraph->GetMarkerSize();
   sbase       = symbolsize*kBASEMARKER;
   Int_t mark  = theGraph->GetMarkerStyle();
   Double_t cx  = 0;
   Double_t cy  = 0;
   if (mark >= 20 && mark <= 34) {
      cx = cxx[mark-20];
      cy = cyy[mark-20];
   }

   // Define the offset of the error bars due to the symbol size
   s2x  = gPad->PixeltoX(Int_t(0.5*sbase)) - gPad->PixeltoX(0);
   s2y  =-gPad->PixeltoY(Int_t(0.5*sbase)) + gPad->PixeltoY(0);
   Int_t dxend = Int_t(gStyle->GetEndErrorSize());
   tx    = gPad->PixeltoX(dxend) - gPad->PixeltoX(0);
   ty    =-gPad->PixeltoY(dxend) + gPad->PixeltoY(0);
   Float_t asize = 0.6*symbolsize*kBASEMARKER/gPad->GetWh();

   gPad->SetBit(TGraph::kClipFrame, theGraph->TestBit(TGraph::kClipFrame));
   for (Int_t i=0;i<theNpoints;i++) {
      x  = gPad->XtoPad(theX[i]);
      y  = gPad->YtoPad(theY[i]);
      if (!option0) {
         if (option3) {
            if (x < gPad->GetUxmin()) x = gPad->GetUxmin();
            if (x > gPad->GetUxmax()) x = gPad->GetUxmax();
            if (y < gPad->GetUymin()) y = gPad->GetUymin();
            if (y > gPad->GetUymax()) y = gPad->GetUymax();
         } else {
            if (x < gPad->GetUxmin()) continue;
            if (x > gPad->GetUxmax()) continue;
            if (y < gPad->GetUymin()) continue;
            if (y > gPad->GetUymax()) continue;
         }
      }
      xl1 = x - s2x*cx;
      xl2 = gPad->XtoPad(theX[i] - theEXlow[i]);

      //  draw the error rectangles
      if (option2) {
         x1b = gPad->XtoPad(theX[i] - theEXlow[i]);
         y1b = gPad->YtoPad(theY[i] - theEYlow[i]);
         x2b = gPad->XtoPad(theX[i] + theEXhigh[i]);
         y2b = gPad->YtoPad(theY[i] + theEYhigh[i]);
         if (x1b < gPad->GetUxmin()) x1b = gPad->GetUxmin();
         if (x1b > gPad->GetUxmax()) x1b = gPad->GetUxmax();
         if (y1b < gPad->GetUymin()) y1b = gPad->GetUymin();
         if (y1b > gPad->GetUymax()) y1b = gPad->GetUymax();
         if (x2b < gPad->GetUxmin()) x2b = gPad->GetUxmin();
         if (x2b > gPad->GetUxmax()) x2b = gPad->GetUxmax();
         if (y2b < gPad->GetUymin()) y2b = gPad->GetUymin();
         if (y2b > gPad->GetUymax()) y2b = gPad->GetUymax();
         if (option5) box.PaintBox(x1b, y1b, x2b, y2b, "l");
         else         box.PaintBox(x1b, y1b, x2b, y2b);
         continue;
      }

      //  keep points for fill area drawing
      if (option3) {
         xline[if1-1] = x;
         xline[if2-1] = x;
         yline[if1-1] = gPad->YtoPad(theY[i] + theEYhigh[i]);
         yline[if2-1] = gPad->YtoPad(theY[i] - theEYlow[i]);
         if1++;
         if2--;
         continue;
      }

      if (xl1 > xl2) {
         if (arrowOpt) {
            arrow.PaintArrow(xl1,y,xl2,y,asize,arrowOpt);
         } else {
            if (!brackets) gPad->PaintLine(xl1,y,xl2,y);
            if (endLines) {
               if (braticks) {
                  xb[0] = xl2+tx; yb[0] = y-ty;
                  xb[1] = xl2;    yb[1] = y-ty;
                  xb[2] = xl2;    yb[2] = y+ty;
                  xb[3] = xl2+tx; yb[3] = y+ty;
                  gPad->PaintPolyLine(4, xb, yb);
               } else {
                  gPad->PaintLine(xl2,y-ty,xl2,y+ty);
               }
            }
         }
      }
      xr1 = x + s2x*cx;
      xr2 = gPad->XtoPad(theX[i] + theEXhigh[i]);
      if (xr1 < xr2) {
         if (arrowOpt) {
            arrow.PaintArrow(xr1,y,xr2,y,asize,arrowOpt);
         } else {
            if (!brackets) gPad->PaintLine(xr1,y,xr2,y);
            if (endLines) {
               if (braticks) {
                  xb[0] = xr2-tx; yb[0] = y-ty;
                  xb[1] = xr2;    yb[1] = y-ty;
                  xb[2] = xr2;    yb[2] = y+ty;
                  xb[3] = xr2-tx; yb[3] = y+ty;
                  gPad->PaintPolyLine(4, xb, yb);
               } else {
                  gPad->PaintLine(xr2,y-ty,xr2,y+ty);
               }
            }
         }
      }
      yup1 = y + s2y*cy;
      yup2 = gPad->YtoPad(theY[i] + theEYhigh[i]);
      if (yup2 > gPad->GetUymax()) yup2 =  gPad->GetUymax();
      if (yup2 > yup1) {
         if (arrowOpt) {
            arrow.PaintArrow(x,yup1,x,yup2,asize,arrowOpt);
         } else {
            if (!brackets) gPad->PaintLine(x,yup1,x,yup2);
            if (endLines) {
               if (braticks) {
                  xb[0] = x-tx; yb[0] = yup2-ty;
                  xb[1] = x-tx; yb[1] = yup2;
                  xb[2] = x+tx; yb[2] = yup2;
                  xb[3] = x+tx; yb[3] = yup2-ty;
                  gPad->PaintPolyLine(4, xb, yb);
               } else {
                  gPad->PaintLine(x-tx,yup2,x+tx,yup2);
               }
            }
         }
      }
      ylow1 = y - s2y*cy;
      ylow2 = gPad->YtoPad(theY[i] - theEYlow[i]);
      if (ylow2 < gPad->GetUymin()) ylow2 =  gPad->GetUymin();
      if (ylow2 < ylow1) {
         if (arrowOpt) {
            arrow.PaintArrow(x,ylow1,x,ylow2,asize,arrowOpt);
         } else {
            if (!brackets) gPad->PaintLine(x,ylow1,x,ylow2);
            if (endLines) {
               if (braticks) {
                  xb[0] = x-tx; yb[0] = ylow2+ty;
                  xb[1] = x-tx; yb[1] = ylow2;
                  xb[2] = x+tx; yb[2] = ylow2;
                  xb[3] = x+tx; yb[3] = ylow2+ty;
                  gPad->PaintPolyLine(4, xb, yb);
               } else {
                  gPad->PaintLine(x-tx,ylow2,x+tx,ylow2);
               }
            }
         }
      }
   }
   if (!brackets && !axis) PaintGraphSimple(theGraph, option);
   gPad->ResetBit(TGraph::kClipFrame);

   if (option3) {
      Int_t logx = gPad->GetLogx();
      Int_t logy = gPad->GetLogy();
      gPad->SetLogx(0);
      gPad->SetLogy(0);
      if (option4) PaintGraph(theGraph, 2*theNpoints, xline, yline,"FC");
      else         PaintGraph(theGraph, 2*theNpoints, xline, yline,"F");
      gPad->SetLogx(logx);
      gPad->SetLogy(logy);
      delete [] xline;
      delete [] yline;
   }
}


//_____________________________________________________________________________
void TGraphPainter::PaintGraphBentErrors(TGraph *theGraph, Option_t *option)
{
   /* Begin_Html
   <a href="#GP03">Paint this TGraphBentErrors with its current attributes.</a>
   End_Html */

   Double_t *xline = 0;
   Double_t *yline = 0;
   Int_t if1 = 0;
   Int_t if2 = 0;
   Double_t xb[4], yb[4];

   const Int_t kBASEMARKER=8;
   Double_t s2x, s2y, symbolsize, sbase;
   Double_t x, y, xl1, xl2, xr1, xr2, yup1, yup2, ylow1, ylow2, tx, ty;
   Double_t bxl, bxh, byl, byh;
   static Float_t cxx[15] = {1,1,0.6,0.6,1,1,0.6,0.5,1,0.6,0.6,1,0.6,1,1};
   static Float_t cyy[15] = {1,1,1,1,1,1,1,1,1,0.5,0.6,1,1,1,1};
   Int_t theNpoints = theGraph->GetN();
   Double_t *theX  = theGraph->GetX();
   Double_t *theY  = theGraph->GetY();
   Double_t *theEXlow   = theGraph->GetEXlow();   if (!theEXlow) return;
   Double_t *theEYlow   = theGraph->GetEYlow();   if (!theEYlow) return;
   Double_t *theEXhigh  = theGraph->GetEXhigh();  if (!theEXhigh) return;
   Double_t *theEYhigh  = theGraph->GetEYhigh();  if (!theEYhigh) return;
   Double_t *theEXlowd  = theGraph->GetEXlowd();  if (!theEXlowd) return;
   Double_t *theEXhighd = theGraph->GetEXhighd(); if (!theEXhighd) return;
   Double_t *theEYlowd  = theGraph->GetEYlowd();  if (!theEYlowd) return;
   Double_t *theEYhighd = theGraph->GetEYhighd(); if (!theEYhighd) return;

   if (strchr(option,'X') || strchr(option,'x')) {PaintGraphSimple(theGraph, option); return;}
   Bool_t brackets = kFALSE;
   Bool_t braticks = kFALSE;
   if (strstr(option,"||") || strstr(option,"[]")) {
      brackets = kTRUE;
      if (strstr(option,"[]")) braticks = kTRUE;
   }
   Bool_t endLines = kTRUE;
   if (strchr(option,'z')) endLines = kFALSE;
   if (strchr(option,'Z')) endLines = kFALSE;
   const char *arrowOpt = 0;
   if (strchr(option,'>'))  arrowOpt = ">";
   if (strstr(option,"|>")) arrowOpt = "|>";

   Bool_t axis = kFALSE;
   if (strchr(option,'a')) axis = kTRUE;
   if (strchr(option,'A')) axis = kTRUE;
   if (axis) PaintGraphSimple(theGraph,option);

   Bool_t option0 = kFALSE;
   Bool_t option2 = kFALSE;
   Bool_t option3 = kFALSE;
   Bool_t option4 = kFALSE;
   Bool_t option5 = kFALSE;
   if (strchr(option,'0')) option0 = kTRUE;
   if (strchr(option,'2')) option2 = kTRUE;
   if (strchr(option,'3')) option3 = kTRUE;
   if (strchr(option,'4')) {option3 = kTRUE; option4 = kTRUE;}
   if (strchr(option,'5')) {option2 = kTRUE; option5 = kTRUE;}

   if (option3) {
      xline = new Double_t[2*theNpoints];
      yline = new Double_t[2*theNpoints];
      if (!xline || !yline) {
         Error("Paint", "too many points, out of memory");
         return;
      }
      if1 = 1;
      if2 = 2*theNpoints;
   }

   theGraph->TAttLine::Modify();

   TArrow arrow;
   arrow.SetLineWidth(theGraph->GetLineWidth());
   arrow.SetLineColor(theGraph->GetLineColor());
   arrow.SetFillColor(theGraph->GetFillColor());

   TBox box;
   Double_t x1b,y1b,x2b,y2b;
   box.SetLineWidth(theGraph->GetLineWidth());
   box.SetLineColor(theGraph->GetLineColor());
   box.SetFillColor(theGraph->GetFillColor());
   box.SetFillStyle(theGraph->GetFillStyle());

   symbolsize  = theGraph->GetMarkerSize();
   sbase       = symbolsize*kBASEMARKER;
   Int_t mark  = theGraph->GetMarkerStyle();
   Double_t cx  = 0;
   Double_t cy  = 0;
   if (mark >= 20 && mark <= 34) {
      cx = cxx[mark-20];
      cy = cyy[mark-20];
   }

   // define the offset of the error bars due to the symbol size
   s2x  = gPad->PixeltoX(Int_t(0.5*sbase)) - gPad->PixeltoX(0);
   s2y  =-gPad->PixeltoY(Int_t(0.5*sbase)) + gPad->PixeltoY(0);
   Int_t dxend = Int_t(gStyle->GetEndErrorSize());
   tx   = gPad->PixeltoX(dxend) - gPad->PixeltoX(0);
   ty   =-gPad->PixeltoY(dxend) + gPad->PixeltoY(0);
   Float_t asize = 0.6*symbolsize*kBASEMARKER/gPad->GetWh();

   gPad->SetBit(TGraph::kClipFrame, theGraph->TestBit(TGraph::kClipFrame));
   for (Int_t i=0;i<theNpoints;i++) {
      x  = gPad->XtoPad(theX[i]);
      y  = gPad->YtoPad(theY[i]);
      bxl = gPad->YtoPad(theY[i]+theEXlowd[i]);
      bxh = gPad->YtoPad(theY[i]+theEXhighd[i]);
      byl = gPad->XtoPad(theX[i]+theEYlowd[i]);
      byh = gPad->XtoPad(theX[i]+theEYhighd[i]);
      if (!option0) {
         if (option3) {
            if (x < gPad->GetUxmin()) x = gPad->GetUxmin();
            if (x > gPad->GetUxmax()) x = gPad->GetUxmax();
            if (y < gPad->GetUymin()) y = gPad->GetUymin();
            if (y > gPad->GetUymax()) y = gPad->GetUymax();
         } else {
            if (x < gPad->GetUxmin()) continue;
            if (x > gPad->GetUxmax()) continue;
            if (y < gPad->GetUymin()) continue;
            if (y > gPad->GetUymax()) continue;
         }
      }

      //  draw the error rectangles
      if (option2) {
         x1b = gPad->XtoPad(theX[i] - theEXlow[i]);
         y1b = gPad->YtoPad(theY[i] - theEYlow[i]);
         x2b = gPad->XtoPad(theX[i] + theEXhigh[i]);
         y2b = gPad->YtoPad(theY[i] + theEYhigh[i]);
         if (x1b < gPad->GetUxmin()) x1b = gPad->GetUxmin();
         if (x1b > gPad->GetUxmax()) x1b = gPad->GetUxmax();
         if (y1b < gPad->GetUymin()) y1b = gPad->GetUymin();
         if (y1b > gPad->GetUymax()) y1b = gPad->GetUymax();
         if (x2b < gPad->GetUxmin()) x2b = gPad->GetUxmin();
         if (x2b > gPad->GetUxmax()) x2b = gPad->GetUxmax();
         if (y2b < gPad->GetUymin()) y2b = gPad->GetUymin();
         if (y2b > gPad->GetUymax()) y2b = gPad->GetUymax();
         if (option5) box.PaintBox(x1b, y1b, x2b, y2b, "l");
         else         box.PaintBox(x1b, y1b, x2b, y2b);
         continue;
      }

      //  keep points for fill area drawing
      if (option3) {
         xline[if1-1] = byh;
         xline[if2-1] = byl;
         yline[if1-1] = gPad->YtoPad(theY[i] + theEYhigh[i]);
         yline[if2-1] = gPad->YtoPad(theY[i] - theEYlow[i]);
         if1++;
         if2--;
         continue;
      }

      xl1 = x - s2x*cx;
      xl2 = gPad->XtoPad(theX[i] - theEXlow[i]);
      if (xl1 > xl2) {
         if (arrowOpt) {
            arrow.PaintArrow(xl1,y,xl2,bxl,asize,arrowOpt);
         } else {
            if (!brackets) gPad->PaintLine(xl1,y,xl2,bxl);
            if (endLines) {
               if (braticks) {
                  xb[0] = xl2+tx; yb[0] = bxl-ty;
                  xb[1] = xl2;    yb[1] = bxl-ty;
                  xb[2] = xl2;    yb[2] = bxl+ty;
                  xb[3] = xl2+tx; yb[3] = bxl+ty;
                  gPad->PaintPolyLine(4, xb, yb);
               } else {
                  gPad->PaintLine(xl2,bxl-ty,xl2,bxl+ty);
               }
            }
         }
      }
      xr1 = x + s2x*cx;
      xr2 = gPad->XtoPad(theX[i] + theEXhigh[i]);
      if (xr1 < xr2) {
         if (arrowOpt) {
            arrow.PaintArrow(xr1,y,xr2,bxh,asize,arrowOpt);
         } else {
            if (!brackets) gPad->PaintLine(xr1,y,xr2,bxh);
            if (endLines) {
               if (braticks) {
                  xb[0] = xr2-tx; yb[0] = bxh-ty;
                  xb[1] = xr2;    yb[1] = bxh-ty;
                  xb[2] = xr2;    yb[2] = bxh+ty;
                  xb[3] = xr2-tx; yb[3] = bxh+ty;
                  gPad->PaintPolyLine(4, xb, yb);
               } else {
                  gPad->PaintLine(xr2,bxh-ty,xr2,bxh+ty);
               }
            }
         }
      }
      yup1 = y + s2y*cy;
      yup2 = gPad->YtoPad(theY[i] + theEYhigh[i]);
      if (yup2 > gPad->GetUymax()) yup2 =  gPad->GetUymax();
      if (yup2 > yup1) {
         if (arrowOpt) {
            arrow.PaintArrow(x,yup1,byh,yup2,asize,arrowOpt);
         } else {
            if (!brackets) gPad->PaintLine(x,yup1,byh,yup2);
            if (endLines) {
               if (braticks) {
                  xb[0] = byh-tx; yb[0] = yup2-ty;
                  xb[1] = byh-tx; yb[1] = yup2;
                  xb[2] = byh+tx; yb[2] = yup2;
                  xb[3] = byh+tx; yb[3] = yup2-ty;
                  gPad->PaintPolyLine(4, xb, yb);
               } else {
                  gPad->PaintLine(byh-tx,yup2,byh+tx,yup2);
               }
            }
         }
      }
      ylow1 = y - s2y*cy;
      ylow2 = gPad->YtoPad(theY[i] - theEYlow[i]);
      if (ylow2 < gPad->GetUymin()) ylow2 =  gPad->GetUymin();
      if (ylow2 < ylow1) {
         if (arrowOpt) {
            arrow.PaintArrow(x,ylow1,byl,ylow2,asize,arrowOpt);
         } else {
            if (!brackets) gPad->PaintLine(x,ylow1,byl,ylow2);
            if (endLines) {
               if (braticks) {
                  xb[0] = byl-tx; yb[0] = ylow2+ty;
                  xb[1] = byl-tx; yb[1] = ylow2;
                  xb[2] = byl+tx; yb[2] = ylow2;
                  xb[3] = byl+tx; yb[3] = ylow2+ty;
                  gPad->PaintPolyLine(4, xb, yb);
               } else {
                  gPad->PaintLine(byl-tx,ylow2,byl+tx,ylow2);
               }
            }
         }
      }
   }
   if (!brackets && !axis) PaintGraphSimple(theGraph, option);
   gPad->ResetBit(TGraph::kClipFrame);

   if (option3) {
      Int_t logx = gPad->GetLogx();
      Int_t logy = gPad->GetLogy();
      gPad->SetLogx(0);
      gPad->SetLogy(0);
      if (option4) PaintGraph(theGraph, 2*theNpoints, xline, yline,"FC");
      else         PaintGraph(theGraph, 2*theNpoints, xline, yline,"F");
      gPad->SetLogx(logx);
      gPad->SetLogy(logy);
      delete [] xline;
      delete [] yline;
   }
}


//______________________________________________________________________________
void TGraphPainter::PaintGraphErrors(TGraph *theGraph, Option_t *option)
{
   /* Begin_Html
   <a href="#GP03">Paint this TGraphErrors with its current attributes.</a>
   End_Html */

   Double_t *xline = 0;
   Double_t *yline = 0;
   Int_t if1 = 0;
   Int_t if2 = 0;
   Double_t xb[4], yb[4];

   const Int_t kBASEMARKER=8;
   Double_t s2x, s2y, symbolsize, sbase;
   Double_t x, y, ex, ey, xl1, xl2, xr1, xr2, yup1, yup2, ylow1, ylow2, tx, ty;
   static Float_t cxx[15] = {1,1,0.6,0.6,1,1,0.6,0.5,1,0.6,0.6,1,0.6,1,1};
   static Float_t cyy[15] = {1,1,1,1,1,1,1,1,1,0.5,0.6,1,1,1,1};
   Int_t theNpoints = theGraph->GetN();
   Double_t *theX  = theGraph->GetX();
   Double_t *theY  = theGraph->GetY();
   Double_t *theEX = theGraph->GetEX(); if (!theEX) return;
   Double_t *theEY = theGraph->GetEY(); if (!theEY) return;

   if (strchr(option,'X') || strchr(option,'x')) {PaintGraphSimple(theGraph, option); return;}
   Bool_t brackets = kFALSE;
   Bool_t braticks = kFALSE;
   if (strstr(option,"||") || strstr(option,"[]")) {
      brackets = kTRUE;
      if (strstr(option,"[]")) braticks = kTRUE;
   }
   Bool_t endLines = kTRUE;
   if (strchr(option,'z')) endLines = kFALSE;
   if (strchr(option,'Z')) endLines = kFALSE;
   const char *arrowOpt = 0;
   if (strchr(option,'>'))  arrowOpt = ">";
   if (strstr(option,"|>")) arrowOpt = "|>";

   Bool_t axis = kFALSE;
   if (strchr(option,'a')) axis = kTRUE;
   if (strchr(option,'A')) axis = kTRUE;
   if (axis) PaintGraphSimple(theGraph, option);

   Bool_t option0 = kFALSE;
   Bool_t option2 = kFALSE;
   Bool_t option3 = kFALSE;
   Bool_t option4 = kFALSE;
   Bool_t option5 = kFALSE;
   if (strchr(option,'0')) option0 = kTRUE;
   if (strchr(option,'2')) option2 = kTRUE;
   if (strchr(option,'3')) option3 = kTRUE;
   if (strchr(option,'4')) {option3 = kTRUE; option4 = kTRUE;}
   if (strchr(option,'5')) {option2 = kTRUE; option5 = kTRUE;}

   if (option3) {
      xline = new Double_t[2*theNpoints];
      yline = new Double_t[2*theNpoints];
      if (!xline || !yline) {
         Error("Paint", "too many points, out of memory");
         return;
      }
      if1 = 1;
      if2 = 2*theNpoints;
   }

   theGraph->TAttLine::Modify();

   TArrow arrow;
   arrow.SetLineWidth(theGraph->GetLineWidth());
   arrow.SetLineColor(theGraph->GetLineColor());
   arrow.SetFillColor(theGraph->GetFillColor());

   TBox box;
   Double_t x1b,y1b,x2b,y2b;
   box.SetLineWidth(theGraph->GetLineWidth());
   box.SetLineColor(theGraph->GetLineColor());
   box.SetFillColor(theGraph->GetFillColor());
   box.SetFillStyle(theGraph->GetFillStyle());

   symbolsize  = theGraph->GetMarkerSize();
   sbase       = symbolsize*kBASEMARKER;
   Int_t mark  = theGraph->GetMarkerStyle();
   Double_t cx  = 0;
   Double_t cy  = 0;
   if (mark >= 20 && mark <= 34) {
      cx = cxx[mark-20];
      cy = cyy[mark-20];
   }

   //      define the offset of the error bars due to the symbol size
   s2x  = gPad->PixeltoX(Int_t(0.5*sbase)) - gPad->PixeltoX(0);
   s2y  =-gPad->PixeltoY(Int_t(0.5*sbase)) + gPad->PixeltoY(0);
   Int_t dxend = Int_t(gStyle->GetEndErrorSize());
   tx    = gPad->PixeltoX(dxend) - gPad->PixeltoX(0);
   ty    =-gPad->PixeltoY(dxend) + gPad->PixeltoY(0);
   Float_t asize = 0.6*symbolsize*kBASEMARKER/gPad->GetWh();

   gPad->SetBit(TGraph::kClipFrame, theGraph->TestBit(TGraph::kClipFrame));
   for (Int_t i=0;i<theNpoints;i++) {
      x  = gPad->XtoPad(theX[i]);
      y  = gPad->YtoPad(theY[i]);
      if (!option0) {
         if (option3) {
            if (x < gPad->GetUxmin()) x = gPad->GetUxmin();
            if (x > gPad->GetUxmax()) x = gPad->GetUxmax();
            if (y < gPad->GetUymin()) y = gPad->GetUymin();
            if (y > gPad->GetUymax()) y = gPad->GetUymax();
         } else {
            if (x < gPad->GetUxmin()) continue;
            if (x > gPad->GetUxmax()) continue;
            if (y < gPad->GetUymin()) continue;
            if (y > gPad->GetUymax()) continue;
         }
      }
      ex = theEX[i];
      ey = theEY[i];

      //  draw the error rectangles
      if (option2) {
         x1b = gPad->XtoPad(theX[i] - ex);
         y1b = gPad->YtoPad(theY[i] - ey);
         x2b = gPad->XtoPad(theX[i] + ex);
         y2b = gPad->YtoPad(theY[i] + ey);
         if (x1b < gPad->GetUxmin()) x1b = gPad->GetUxmin();
         if (x1b > gPad->GetUxmax()) x1b = gPad->GetUxmax();
         if (y1b < gPad->GetUymin()) y1b = gPad->GetUymin();
         if (y1b > gPad->GetUymax()) y1b = gPad->GetUymax();
         if (x2b < gPad->GetUxmin()) x2b = gPad->GetUxmin();
         if (x2b > gPad->GetUxmax()) x2b = gPad->GetUxmax();
         if (y2b < gPad->GetUymin()) y2b = gPad->GetUymin();
         if (y2b > gPad->GetUymax()) y2b = gPad->GetUymax();
         if (option5) box.PaintBox(x1b, y1b, x2b, y2b, "l");
         else         box.PaintBox(x1b, y1b, x2b, y2b);
         continue;
      }

      //  keep points for fill area drawing
      if (option3) {
         xline[if1-1] = x;
         xline[if2-1] = x;
         yline[if1-1] = gPad->YtoPad(theY[i] + ey);
         yline[if2-1] = gPad->YtoPad(theY[i] - ey);
         if1++;
         if2--;
         continue;
      }

      xl1 = x - s2x*cx;
      xl2 = gPad->XtoPad(theX[i] - ex);
      if (xl1 > xl2) {
         if (arrowOpt) {
            arrow.PaintArrow(xl1,y,xl2,y,asize,arrowOpt);
         } else {
            if (!brackets) gPad->PaintLine(xl1,y,xl2,y);
            if (endLines) {
               if (braticks) {
                  xb[0] = xl2+tx; yb[0] = y-ty;
                  xb[1] = xl2;    yb[1] = y-ty;
                  xb[2] = xl2;    yb[2] = y+ty;
                  xb[3] = xl2+tx; yb[3] = y+ty;
                  gPad->PaintPolyLine(4, xb, yb);
               } else {
                  gPad->PaintLine(xl2,y-ty,xl2,y+ty);
               }
            }
         }
      }
      xr1 = x + s2x*cx;
      xr2 = gPad->XtoPad(theX[i] + ex);
      if (xr1 < xr2) {
         if (arrowOpt) {
            arrow.PaintArrow(xr1,y,xr2,y,asize,arrowOpt);
         } else {
            if (!brackets) gPad->PaintLine(xr1,y,xr2,y);
            if (endLines) {
               if (braticks) {
                  xb[0] = xr2-tx; yb[0] = y-ty;
                  xb[1] = xr2;    yb[1] = y-ty;
                  xb[2] = xr2;    yb[2] = y+ty;
                  xb[3] = xr2-tx; yb[3] = y+ty;
                  gPad->PaintPolyLine(4, xb, yb);
               } else {
                  gPad->PaintLine(xr2,y-ty,xr2,y+ty);
               }
            }
         }
      }
      yup1 = y + s2y*cy;
      yup2 = gPad->YtoPad(theY[i] + ey);
      if (yup2 > gPad->GetUymax()) yup2 =  gPad->GetUymax();
      if (yup2 > yup1) {
         if (arrowOpt) {
            arrow.PaintArrow(x,yup1,x,yup2,asize,arrowOpt);
         } else {
            if (!brackets) gPad->PaintLine(x,yup1,x,yup2);
            if (endLines) {
               if (braticks) {
                  xb[0] = x-tx; yb[0] = yup2-ty;
                  xb[1] = x-tx; yb[1] = yup2;
                  xb[2] = x+tx; yb[2] = yup2;
                  xb[3] = x+tx; yb[3] = yup2-ty;
                  gPad->PaintPolyLine(4, xb, yb);
               } else {
                  gPad->PaintLine(x-tx,yup2,x+tx,yup2);
               }
            }
         }
      }
      ylow1 = y - s2y*cy;
      ylow2 = gPad->YtoPad(theY[i] - ey);
      if (ylow2 < gPad->GetUymin()) ylow2 =  gPad->GetUymin();
      if (ylow2 < ylow1) {
         if (arrowOpt) {
            arrow.PaintArrow(x,ylow1,x,ylow2,asize,arrowOpt);
         } else {
            if (!brackets) gPad->PaintLine(x,ylow1,x,ylow2);
            if (endLines) {
               if (braticks) {
                  xb[0] = x-tx; yb[0] = ylow2+ty;
                  xb[1] = x-tx; yb[1] = ylow2;
                  xb[2] = x+tx; yb[2] = ylow2;
                  xb[3] = x+tx; yb[3] = ylow2+ty;
                  gPad->PaintPolyLine(4, xb, yb);
               } else {
                  gPad->PaintLine(x-tx,ylow2,x+tx,ylow2);
               }
            }
         }
      }
   }
   if (!brackets && !axis) PaintGraphSimple(theGraph, option);
   gPad->ResetBit(TGraph::kClipFrame);

   if (option3) {
      Int_t logx = gPad->GetLogx();
      Int_t logy = gPad->GetLogy();
      gPad->SetLogx(0);
      gPad->SetLogy(0);
      if (option4) PaintGraph(theGraph, 2*theNpoints, xline, yline,"FC");
      else         PaintGraph(theGraph, 2*theNpoints, xline, yline,"F");
      gPad->SetLogx(logx);
      gPad->SetLogy(logy);
      delete [] xline;
      delete [] yline;
   }
}


//______________________________________________________________________________
void TGraphPainter::PaintGraphPolar(TGraph *theGraph, Option_t* options)
{
   /* Begin_Html
   <a href="#GP04">Paint this TGraphPolar with its current attributes.</a>
   End_Html */

   Int_t ipt, i;
   Double_t rwrmin, rwrmax, rwtmin, rwtmax;

   TGraphPolar *theGraphPolar = (TGraphPolar*) theGraph;

   Int_t theNpoints  = theGraphPolar->GetN();
   Double_t *theX    = theGraphPolar->GetX();
   Double_t *theY    = theGraphPolar->GetY();
   Double_t *theEX   = theGraphPolar->GetEX();
   Double_t *theEY   = theGraphPolar->GetEY();

   if (theNpoints<1) return;
   TString opt = options;
   opt.ToUpper();

   Bool_t nolabel = kFALSE;
   if (opt.Contains("N")){
      nolabel = kTRUE;
      opt.ReplaceAll("N","");
   }

   TGraphPolargram *thePolargram = theGraphPolar->GetPolargram();

   // Check for existing TGraphPolargram in the Pad
   if (gPad) {
      // Existing polargram
      if (thePolargram) if (!gPad->FindObject(thePolargram->GetName())) thePolargram=0;
      if (!thePolargram) {
         // Find any other Polargram in the Pad
         TListIter padObjIter(gPad->GetListOfPrimitives());
         while (TObject* AnyObj = padObjIter.Next()) {
            if (TString(AnyObj->ClassName()).CompareTo("TGraphPolargram",
                                                      TString::kExact)==0)
            thePolargram = (TGraphPolargram*)AnyObj;
            theGraphPolar->SetPolargram(thePolargram);
         }
      }
   }

   // Get new polargram range if necessary.
   if (!thePolargram) {
      // Get range, initialize with first/last value
      rwrmin = theY[0]; rwrmax = theY[theNpoints-1];
      rwtmin = theX[0]; rwtmax = theX[theNpoints-1];

      for (ipt = 0; ipt < theNpoints; ipt++) {
         // Check for errors if available
         if (theEX) {
            if (theX[ipt] -theEX[ipt] < rwtmin) rwtmin = theX[ipt]-theEX[ipt];
            if (theX[ipt] +theEX[ipt] > rwtmax) rwtmax = theX[ipt]+theEX[ipt];
         } else {
            if (theX[ipt] < rwtmin) rwtmin=theX[ipt];
            if (theX[ipt] > rwtmax) rwtmax=theX[ipt];
         }
         if (theEY) {
            if (theY[ipt] -theEY[ipt] < rwrmin) rwrmin = theY[ipt]-theEY[ipt];
            if (theY[ipt] +theEY[ipt] > rwrmax) rwrmax = theY[ipt]+theEY[ipt];
         } else {
            if (theY[ipt] < rwrmin) rwrmin=theY[ipt];
            if (theY[ipt] > rwrmax) rwrmax=theY[ipt];
         }
      }
      // Add radial and Polar margins.
      if (rwrmin == rwrmax) rwrmax += 1.;
      if (rwtmin == rwtmax) rwtmax += 1.;
      Double_t dr = (rwrmax-rwrmin);
      Double_t dt = (rwtmax-rwtmin);
      rwrmax += 0.1*dr;
      rwrmin -= 0.1*dr;

      // Assume equaly spaced points for full 2*Pi.
      rwtmax += dt/theNpoints;
   } else {
      rwrmin = thePolargram->GetRMin();
      rwrmax = thePolargram->GetRMax();
      rwtmin = thePolargram->GetTMin();
      rwtmax = thePolargram->GetTMax();
   }

   if ((!thePolargram) || theGraphPolar->GetOptionAxis()) {
      // Draw Polar coord system
      thePolargram = new TGraphPolargram("Polargram",rwrmin,rwrmax,rwtmin,rwtmax);
      theGraphPolar->SetPolargram(thePolargram);
      if (opt.Contains("O")) thePolargram->SetBit(TGraphPolargram::kLabelOrtho);
      else thePolargram->ResetBit(TGraphPolargram::kLabelOrtho);
      if (nolabel) thePolargram->Draw("N");
      else         thePolargram->Draw("");
      theGraphPolar->SetOptionAxis(kFALSE);   //Prevent redrawing
   }

   // Convert points to polar.
   Double_t *theXpol = theGraphPolar->GetXpol();
   Double_t *theYpol = theGraphPolar->GetYpol();

   // Project theta in [0,2*Pi] and radius in [0,1].
   Double_t radiusNDC = rwrmax-rwrmin;
   Double_t thetaNDC  = (rwtmax-rwtmin)/(2*TMath::Pi());

   // Draw the error bars.
   // Y errors are lines, but X errors are pieces of circles.
   if (opt.Contains("E")) {
      if (theEY) {
         for (i=0; i<theNpoints; i++) {
            Double_t eymin, eymax, exmin,exmax;
            exmin = (theY[i]-theEY[i]-rwrmin)/radiusNDC*
                     TMath::Cos((theX[i]-rwtmin)/thetaNDC);
            eymin = (theY[i]-theEY[i]-rwrmin)/radiusNDC*
                     TMath::Sin((theX[i]-rwtmin)/thetaNDC);
            exmax = (theY[i]+theEY[i]-rwrmin)/radiusNDC*
                     TMath::Cos((theX[i]-rwtmin)/thetaNDC);
            eymax = (theY[i]+theEY[i]-rwrmin)/radiusNDC*
                     TMath::Sin((theX[i]-rwtmin)/thetaNDC);
            theGraphPolar->TAttLine::Modify();
            if (exmin != exmax || eymin != eymax) gPad->PaintLine(exmin,eymin,exmax,eymax);
         }
      }
      if (theEX) {
         for (i=0; i<theNpoints; i++) {
            Double_t rad = (theY[i]-rwrmin)/radiusNDC;
            Double_t phimin = (theX[i]-theEX[i]-rwtmin)/thetaNDC*180/TMath::Pi();
            Double_t phimax = (theX[i]+theEX[i]-rwtmin)/thetaNDC*180/TMath::Pi();
            theGraphPolar->TAttLine::Modify();
            if (phimin != phimax) thePolargram->PaintCircle(0,0,rad,phimin,phimax,0);
         }
      }
   }

   // Draw the graph itself.
   if (!(gPad->GetLogx()) && !(gPad->GetLogy())) {
      Double_t a, b, c=1, x1, x2, y1, y2, discr, norm1, norm2, xts, yts;
      Bool_t previouspointin = kFALSE;
      Double_t norm = 0;
      Double_t xt   = 0;
      Double_t yt   = 0 ;
      Int_t j       = -1;
      for (i=0; i<theNpoints; i++) {
         if (thePolargram->IsRadian()) {c=1;}
         if (thePolargram->IsDegree()) {c=180/TMath::Pi();}
         if (thePolargram->IsGrad())   {c=100/TMath::Pi();}
         xts  = xt;
         yts  = yt;
         xt   = (theY[i]-rwrmin)/radiusNDC*TMath::Cos(c*(theX[i]-rwtmin)/thetaNDC);
         yt   = (theY[i]-rwrmin)/radiusNDC*TMath::Sin(c*(theX[i]-rwtmin)/thetaNDC);
         norm = sqrt(xt*xt+yt*yt);
         // Check if points are in the main circle.
         if ( norm <= 1) {
            // We check that the previous point was in the circle too.
            // We record new point position.
            if (!previouspointin) {
               j++;
               theXpol[j] = xt;
               theYpol[j] = yt;
            } else {
               a = (yt-yts)/(xt-xts);
               b = yts-a*xts;
               discr = 4*(a*a-b*b+1);
               x1 = (-2*a*b+sqrt(discr))/(2*(a*a+1));
               x2 = (-2*a*b-sqrt(discr))/(2*(a*a+1));
               y1 = a*x1+b;
               y2 = a*x2+b;
               norm1 = sqrt((x1-xt)*(x1-xt)+(y1-yt)*(y1-yt));
               norm2 = sqrt((x2-xt)*(x2-xt)+(y2-yt)*(y2-yt));
               previouspointin = kFALSE;
               j = 0;
               if (norm1 < norm2) {
                  theXpol[j] = x1;
                  theYpol[j] = y1;
               } else {
                  theXpol[j] = x2;
                  theYpol[j] = y2;
               }
               j++;
               theXpol[j] = xt;
               theYpol[j] = yt;
               PaintGraph(theGraphPolar, j+1, theXpol, theYpol, opt);
            }
         } else {
            // We check that the previous point was in the circle.
            // We record new point position
            if (j>=1 && !previouspointin) {
               a = (yt-theYpol[j])/(xt-theXpol[j]);
               b = theYpol[j]-a*theXpol[j];
               previouspointin = kTRUE;
               discr = 4*(a*a-b*b+1);
               x1 = (-2*a*b+sqrt(discr))/(2*(a*a+1));
               x2 = (-2*a*b-sqrt(discr))/(2*(a*a+1));
               y1 = a*x1+b;
               y2 = a*x2+b;
               norm1 = sqrt((x1-xt)*(x1-xt)+(y1-yt)*(y1-yt));
               norm2 = sqrt((x2-xt)*(x2-xt)+(y2-yt)*(y2-yt));
               j++;
               if (norm1 < norm2) {
                  theXpol[j] = x1;
                  theYpol[j] = y1;
               } else {
                  theXpol[j] = x2;
                  theYpol[j] = y2;
               }
               PaintGraph(theGraphPolar, j+1, theXpol, theYpol, opt);
            }
            j=-1;
         }
      }
      if (j>=1) {
         // If the last point is in the circle, we draw the last serie of point.
         PaintGraph(theGraphPolar, j+1, theXpol, theYpol, opt);
      }
   } else {
      for (i=0; i<theNpoints; i++) {
         theXpol[i] = TMath::Abs((theY[i]-rwrmin)/radiusNDC*TMath::Cos((theX[i]-rwtmin)/thetaNDC)+1);
         theYpol[i] = TMath::Abs((theY[i]-rwrmin)/radiusNDC*TMath::Sin((theX[i]-rwtmin)/thetaNDC)+1);
      }
      PaintGraph(theGraphPolar, theNpoints, theXpol, theYpol,opt);
   }

   // Paint the title.

   if (TestBit(TH1::kNoTitle)) return;
   Int_t nt = strlen(theGraph->GetTitle());
   TPaveText *title = 0;
   TObject *obj;
   TIter next(gPad->GetListOfPrimitives());
   while ((obj = next())) {
      if (!obj->InheritsFrom(TPaveText::Class())) continue;
      title = (TPaveText*)obj;
      if (title->GetName())
         if (strcmp(title->GetName(),"title")) {title = 0; continue;}
      break;
   }
   if (nt == 0 || gStyle->GetOptTitle() <= 0) {
      if (title) delete title;
      return;
   }
   Double_t ht = gStyle->GetTitleH();
   Double_t wt = gStyle->GetTitleW();
   if (ht <= 0) ht = 1.1*gStyle->GetTitleFontSize();
   if (ht <= 0) ht = 0.05;
   if (wt <= 0) {
      TLatex l;
      l.SetTextSize(ht);
      l.SetTitle(theGraph->GetTitle());
      // Adjustment in case the title has several lines (#splitline)
      ht = TMath::Max(ht, 1.2*l.GetYsize()/(gPad->GetY2() - gPad->GetY1()));
      Double_t wndc = l.GetXsize()/(gPad->GetX2() - gPad->GetX1());
      wt = TMath::Min(0.7, 0.02+wndc);
   }
   if (title) {
      TText *t0 = (TText*)title->GetLine(0);
      if (t0) {
         if (!strcmp(t0->GetTitle(),theGraph->GetTitle())) return;
         t0->SetTitle(theGraph->GetTitle());
         if (wt > 0) title->SetX2NDC(title->GetX1NDC()+wt);
      }
      return;
   }

   Int_t talh = gStyle->GetTitleAlign()/10;
   if (talh < 1) talh = 1; if (talh > 3) talh = 3;
   Int_t talv = gStyle->GetTitleAlign()%10;
   if (talv < 1) talv = 1; if (talv > 3) talv = 3;

   Double_t xpos, ypos;
   xpos = gStyle->GetTitleX();
   ypos = gStyle->GetTitleY();

   if (talh == 2) xpos = xpos-wt/2.;
   if (talh == 3) xpos = xpos-wt;
   if (talv == 2) ypos = ypos+ht/2.;
   if (talv == 1) ypos = ypos+ht;

   TPaveText *ptitle = new TPaveText(xpos, ypos-ht, xpos+wt, ypos,"blNDC");

   // Box with the histogram title.
   ptitle->SetFillColor(gStyle->GetTitleFillColor());
   ptitle->SetFillStyle(gStyle->GetTitleStyle());
   ptitle->SetName("title");
   ptitle->SetBorderSize(gStyle->GetTitleBorderSize());
   ptitle->SetTextColor(gStyle->GetTitleTextColor());
   ptitle->SetTextFont(gStyle->GetTitleFont(""));
   if (gStyle->GetTitleFont("")%10 > 2)
   ptitle->SetTextSize(gStyle->GetTitleFontSize());
   ptitle->AddText(theGraph->GetTitle());
   ptitle->SetBit(kCanDelete);
   ptitle->Draw();
   ptitle->Paint();
}


//______________________________________________________________________________
void TGraphPainter::PaintGraphQQ(TGraph *theGraph, Option_t *option)
{
   /* Begin_Html
   Paint this graphQQ. No options for the time being.
   End_Html */

   TGraphQQ *theGraphQQ = (TGraphQQ*) theGraph;

   Double_t *theX    = theGraphQQ->GetX();
   Double_t  theXq1  = theGraphQQ->GetXq1();
   Double_t  theXq2  = theGraphQQ->GetXq2();
   Double_t  theYq1  = theGraphQQ->GetYq1();
   Double_t  theYq2  = theGraphQQ->GetYq2();
   TF1      *theF    = theGraphQQ->GetF();

   if (!theX){
      Error("TGraphQQ::Paint", "2nd dataset or theoretical function not specified");
      return;
   }

   if (theF){
      theGraphQQ->GetXaxis()->SetTitle("theoretical quantiles");
      theGraphQQ->GetYaxis()->SetTitle("data quantiles");
   }

   PaintGraphSimple(theGraph,option);

   Double_t xmin = gPad->GetUxmin();
   Double_t xmax = gPad->GetUxmax();
   Double_t ymin = gPad->GetUymin();
   Double_t ymax = gPad->GetUymax();
   Double_t yxmin, xymin, yxmax, xymax;
   Double_t xqmin = TMath::Max(xmin, theXq1);
   Double_t xqmax = TMath::Min(xmax, theXq2);
   Double_t yqmin = TMath::Max(ymin, theYq1);
   Double_t yqmax = TMath::Min(ymax, theYq2);

   TLine line1, line2, line3;
   line1.SetLineStyle(2);
   line3.SetLineStyle(2);
   yxmin = (theYq2-theYq1)*(xmin-theXq1)/(theXq2-theXq1) + theYq1;
   if (yxmin < ymin){
      xymin = (theXq2-theXq1)*(ymin-theYq1)/(theYq2-theYq1) + theXq1;
      line1.PaintLine(xymin, ymin, xqmin, yqmin);
   }
   else
      line1.PaintLine(xmin, yxmin, xqmin, yqmin);

   line2.PaintLine(xqmin, yqmin, xqmax, yqmax);

   yxmax = (theYq2-theYq1)*(xmax-theXq1)/(theXq2-theXq1) + theYq1;
   if (yxmax > ymax){
      xymax = (theXq2-theXq1)*(ymax-theYq1)/(theYq2-theYq1) + theXq1;
      line3.PaintLine(xqmax, yqmax, xymax, ymax);
   }
   else
      line3.PaintLine(xqmax, yqmax, xmax, yxmax);
}


//______________________________________________________________________________
void TGraphPainter::PaintGraphSimple(TGraph *theGraph, Option_t *option)
{
   /* Begin_Html
   Paint a simple graph, without errors bars.
   End_Html */

   if (strstr(option,"H") || strstr(option,"h")) {
      PaintGrapHist(theGraph, theGraph->GetN(), theGraph->GetX(), theGraph->GetY(), option);
   } else {
      PaintGraph(theGraph, theGraph->GetN(), theGraph->GetX(), theGraph->GetY(), option);
   }

   PaintHighlightPoint(theGraph, option);

   // Paint associated objects in the list of functions (for instance
   // the fit function).
   TList *functions = theGraph->GetListOfFunctions();
   if (!functions) return;
   TObjOptLink *lnk = (TObjOptLink*)functions->FirstLink();
   TObject *obj;

   while (lnk) {
      obj = lnk->GetObject();
      TVirtualPad *padsave = gPad;
      if (obj->InheritsFrom(TF1::Class())) {
         if (obj->TestBit(TF1::kNotDraw) == 0) obj->Paint("lsame");
      } else  {
         obj->Paint(lnk->GetOption());
      }
      lnk = (TObjOptLink*)lnk->Next();
      padsave->cd();
   }
   return;
}


//______________________________________________________________________________
void TGraphPainter::PaintPolyLineHatches(TGraph *theGraph, Int_t n, const Double_t *x, const Double_t *y)
{
   /* Begin_Html
   Paint a polyline with hatches on one side showing an exclusion zone. x and y
   are the the vectors holding the polyline and n the number of points in the
   polyline and <tt>w</tt> the width of the hatches. <tt>w</tt> can be negative.
   This method is not meant to be used directly. It is called automatically
   according to the line style convention.
   End_Html */

   Int_t i,j,nf;
   Double_t w = (theGraph->GetLineWidth()/100)*0.005;

   Double_t *xf = new Double_t[2*n];
   Double_t *yf = new Double_t[2*n];
   Double_t *xt = new Double_t[n];
   Double_t *yt = new Double_t[n];
   Double_t x1, x2, y1, y2, x3, y3, xm, ym, a, a1, a2, a3;

   // Compute the gPad coordinates in TRUE normalized space (NDC)
   Int_t ix1,iy1,ix2,iy2;
   Int_t iw = gPad->GetWw();
   Int_t ih = gPad->GetWh();
   Double_t x1p,y1p,x2p,y2p;
   gPad->GetPadPar(x1p,y1p,x2p,y2p);
   ix1 = (Int_t)(iw*x1p);
   iy1 = (Int_t)(ih*y1p);
   ix2 = (Int_t)(iw*x2p);
   iy2 = (Int_t)(ih*y2p);
   Double_t wndc  = TMath::Min(1.,(Double_t)iw/(Double_t)ih);
   Double_t hndc  = TMath::Min(1.,(Double_t)ih/(Double_t)iw);
   Double_t rh    = hndc/(Double_t)ih;
   Double_t rw    = wndc/(Double_t)iw;
   Double_t x1ndc = (Double_t)ix1*rw;
   Double_t y1ndc = (Double_t)iy1*rh;
   Double_t x2ndc = (Double_t)ix2*rw;
   Double_t y2ndc = (Double_t)iy2*rh;

   // Ratios to convert user space in TRUE normalized space (NDC)
   Double_t rx1,ry1,rx2,ry2;
   gPad->GetRange(rx1,ry1,rx2,ry2);
   Double_t rx = (x2ndc-x1ndc)/(rx2-rx1);
   Double_t ry = (y2ndc-y1ndc)/(ry2-ry1);

   // The first part of the filled area is made of the graph points.
   // Make sure that two adjacent points are different.
   xf[0] = rx*(x[0]-rx1)+x1ndc;
   yf[0] = ry*(y[0]-ry1)+y1ndc;
   nf = 0;
   for (i=1; i<n; i++) {
      if (x[i]==x[i-1] && y[i]==y[i-1]) continue;
      nf++;
      xf[nf] = rx*(x[i]-rx1)+x1ndc;
      if (xf[i]==xf[i-1]) xf[i] += 0.000001; // add an epsilon to avoid exact vertical lines.
      yf[nf] = ry*(y[i]-ry1)+y1ndc;
   }

   // For each graph points a shifted points is computed to build up
   // the second part of the filled area. First and last points are
   // treated as special cases, outside of the loop.
   if (xf[1]==xf[0]) {
      a = TMath::PiOver2();
   } else {
      a = TMath::ATan((yf[1]-yf[0])/(xf[1]-xf[0]));
   }
   if (xf[0]<=xf[1]) {
      xt[0] = xf[0]-w*TMath::Sin(a);
      yt[0] = yf[0]+w*TMath::Cos(a);
   } else {
      xt[0] = xf[0]+w*TMath::Sin(a);
      yt[0] = yf[0]-w*TMath::Cos(a);
   }

   if (xf[nf]==xf[nf-1]) {
      a = TMath::PiOver2();
   } else {
      a = TMath::ATan((yf[nf]-yf[nf-1])/(xf[nf]-xf[nf-1]));
   }
   if (xf[nf]>=xf[nf-1]) {
      xt[nf] = xf[nf]-w*TMath::Sin(a);
      yt[nf] = yf[nf]+w*TMath::Cos(a);
   } else {
      xt[nf] = xf[nf]+w*TMath::Sin(a);
      yt[nf] = yf[nf]-w*TMath::Cos(a);
   }

   Double_t xi0,yi0,xi1,yi1,xi2,yi2;
   for (i=1; i<nf; i++) {
      xi0 = xf[i];
      yi0 = yf[i];
      xi1 = xf[i+1];
      yi1 = yf[i+1];
      xi2 = xf[i-1];
      yi2 = yf[i-1];
      if (xi1==xi0) {
         a1 = TMath::PiOver2();
      } else {
         a1  = TMath::ATan((yi1-yi0)/(xi1-xi0));
      }
      if (xi1<xi0) a1 = a1+3.14159;
      if (xi2==xi0) {
         a2 = TMath::PiOver2();
      } else {
         a2  = TMath::ATan((yi0-yi2)/(xi0-xi2));
      }
      if (xi0<xi2) a2 = a2+3.14159;
      x1 = xi0-w*TMath::Sin(a1);
      y1 = yi0+w*TMath::Cos(a1);
      x2 = xi0-w*TMath::Sin(a2);
      y2 = yi0+w*TMath::Cos(a2);
      xm = (x1+x2)*0.5;
      ym = (y1+y2)*0.5;
      if (xm==xi0) {
         a3 = TMath::PiOver2();
      } else {
         a3 = TMath::ATan((ym-yi0)/(xm-xi0));
      }
      x3 = xi0-w*TMath::Sin(a3+1.57079);
      y3 = yi0+w*TMath::Cos(a3+1.57079);
      // Rotate (x3,y3) by PI around (xi0,yi0) if it is not on the (xm,ym) side.
      if ((xm-xi0)*(x3-xi0)<0 && (ym-yi0)*(y3-yi0)<0) {
         x3 = 2*xi0-x3;
         y3 = 2*yi0-y3;
      }
      if ((xm==x1) && (ym==y1)) {
         x3 = xm;
         y3 = ym;
      }
      xt[i] = x3;
      yt[i] = y3;
   }

   // Close the polygon if the first and last points are the same
   if (xf[nf]==xf[0] && yf[nf]==yf[0]) {
      xm = (xt[nf]+xt[0])*0.5;
      ym = (yt[nf]+yt[0])*0.5;
      if (xm==xf[0]) {
         a3 = TMath::PiOver2();
      } else {
         a3 = TMath::ATan((ym-yf[0])/(xm-xf[0]));
      }
      x3 = xf[0]+w*TMath::Sin(a3+1.57079);
      y3 = yf[0]-w*TMath::Cos(a3+1.57079);
      if ((xm-xf[0])*(x3-xf[0])<0 && (ym-yf[0])*(y3-yf[0])<0) {
         x3 = 2*xf[0]-x3;
         y3 = 2*yf[0]-y3;
      }
      xt[nf] = x3;
      xt[0]  = x3;
      yt[nf] = y3;
      yt[0]  = y3;
   }

   // Find the crossing segments and remove the useless ones
   Double_t xc, yc, c1, b1, c2, b2;
   Bool_t cross = kFALSE;
   Int_t nf2 = nf;
   for (i=nf2; i>0; i--) {
      for (j=i-1; j>0; j--) {
         if (xt[i-1]==xt[i] || xt[j-1]==xt[j]) continue;
         c1  = (yt[i-1]-yt[i])/(xt[i-1]-xt[i]);
         b1  = yt[i]-c1*xt[i];
         c2  = (yt[j-1]-yt[j])/(xt[j-1]-xt[j]);
         b2  = yt[j]-c2*xt[j];
         if (c1 != c2) {
            xc = (b2-b1)/(c1-c2);
            yc = c1*xc+b1;
            if (xc>TMath::Min(xt[i],xt[i-1]) && xc<TMath::Max(xt[i],xt[i-1]) &&
                xc>TMath::Min(xt[j],xt[j-1]) && xc<TMath::Max(xt[j],xt[j-1]) &&
                yc>TMath::Min(yt[i],yt[i-1]) && yc<TMath::Max(yt[i],yt[i-1]) &&
                yc>TMath::Min(yt[j],yt[j-1]) && yc<TMath::Max(yt[j],yt[j-1])) {
               nf++; xf[nf] = xt[i]; yf[nf] = yt[i];
               nf++; xf[nf] = xc   ; yf[nf] = yc;
               i = j;
               cross = kTRUE;
               break;
            } else {
               continue;
            }
         } else {
            continue;
         }
      }
      if (!cross) {
         nf++;
         xf[nf] = xt[i];
         yf[nf] = yt[i];
      }
      cross = kFALSE;
   }
   nf++; xf[nf] = xt[0]; yf[nf] = yt[0];

   // NDC to user coordinates
   for (i=0; i<nf+1; i++) {
      xf[i] = (1/rx)*(xf[i]-x1ndc)+rx1;
      yf[i] = (1/ry)*(yf[i]-y1ndc)+ry1;
   }

   // Draw filled area
   gPad->PaintFillArea(nf+1,xf,yf);
   theGraph->TAttLine::Modify(); // In case of PaintFillAreaHatches

   delete [] xf;
   delete [] yf;
   delete [] xt;
   delete [] yt;
}


//______________________________________________________________________________
void TGraphPainter::PaintStats(TGraph *theGraph, TF1 *fit)
{
   /* Begin_Html
   Paint the statistics box with the fit info.
   End_Html */

   Int_t dofit;
   TPaveStats *stats  = 0;
   TList *functions = theGraph->GetListOfFunctions();
   TIter next(functions);
   TObject *obj;
   while ((obj = next())) {
      if (obj->InheritsFrom(TPaveStats::Class())) {
         stats = (TPaveStats*)obj;
         break;
      }
   }

   if (stats) dofit  = stats->GetOptFit();
   else       dofit  = gStyle->GetOptFit();

   if (!dofit) fit = 0;
   if (!fit) return;
   if (dofit  == 1) dofit  =  111;
   Int_t nlines = 0;
   Int_t print_fval    = dofit%10;
   Int_t print_ferrors = (dofit/10)%10;
   Int_t print_fchi2   = (dofit/100)%10;
   Int_t print_fprob   = (dofit/1000)%10;
   Int_t nlinesf = print_fval + print_fchi2 + print_fprob;
   if (fit) nlinesf += fit->GetNpar();
   Bool_t done = kFALSE;
   Double_t  statw  = 1.8*gStyle->GetStatW();
   Double_t  stath  = 0.25*(nlines+nlinesf)*gStyle->GetStatH();
   if (stats) {
      stats->Clear();
      done = kTRUE;
   } else {
      stats  = new TPaveStats(
               gStyle->GetStatX()-statw,
               gStyle->GetStatY()-stath,
               gStyle->GetStatX(),
               gStyle->GetStatY(),"brNDC");

      stats->SetParent(functions);
      stats->SetOptFit(dofit);
      stats->SetOptStat(0);
      stats->SetFillColor(gStyle->GetStatColor());
      stats->SetFillStyle(gStyle->GetStatStyle());
      stats->SetBorderSize(gStyle->GetStatBorderSize());
      stats->SetTextFont(gStyle->GetStatFont());
      if (gStyle->GetStatFont()%10 > 2)
         stats->SetTextSize(gStyle->GetStatFontSize());
      stats->SetFitFormat(gStyle->GetFitFormat());
      stats->SetStatFormat(gStyle->GetStatFormat());
      stats->SetName("stats");

      stats->SetTextColor(gStyle->GetStatTextColor());
      stats->SetTextAlign(12);
      stats->SetBit(kCanDelete);
      stats->SetBit(kMustCleanup);
   }

   char t[64];
   char textstats[50];
   Int_t ndf = fit->GetNDF();
   snprintf(textstats,50,"#chi^{2} / ndf = %s%s / %d","%",stats->GetFitFormat(),ndf);
   snprintf(t,64,textstats,(Float_t)fit->GetChisquare());
   if (print_fchi2) stats->AddText(t);
   if (print_fprob) {
      snprintf(textstats,50,"Prob  = %s%s","%",stats->GetFitFormat());
      snprintf(t,64,textstats,(Float_t)TMath::Prob(fit->GetChisquare(),ndf));
      stats->AddText(t);
   }
   if (print_fval || print_ferrors) {
      for (Int_t ipar=0;ipar<fit->GetNpar();ipar++) {
         if (print_ferrors) {
            snprintf(textstats,50,"%-8s = %s%s #pm %s%s ",fit->GetParName(ipar),"%",stats->GetFitFormat(),"%",stats->GetFitFormat());
            snprintf(t,64,textstats,(Float_t)fit->GetParameter(ipar)
                            ,(Float_t)fit->GetParError(ipar));
         } else {
            snprintf(textstats,50,"%-8s = %s%s ",fit->GetParName(ipar),"%",stats->GetFitFormat());
            snprintf(t,64,textstats,(Float_t)fit->GetParameter(ipar));
         }
         t[63] = 0;
         stats->AddText(t);
      }
   }

   if (!done) functions->Add(stats);
   stats->Paint();
}


//______________________________________________________________________________
void TGraphPainter::Smooth(TGraph *theGraph, Int_t npoints, Double_t *x, Double_t *y, Int_t drawtype)
{
   /* Begin_Html
   Smooth a curve given by N points.
   <p>
   The original code is from an underlaying routine for Draw based on the
   CERN GD3 routine TVIPTE:
   <pre>
        Author - Marlow etc.   Modified by - P. Ward     Date -  3.10.1973
   </pre>
   This method draws a smooth tangentially continuous curve through
   the sequence of data points P(I) I=1,N where P(I)=(X(I),Y(I)).
   The curve is approximated by a polygonal arc of short vectors.
   The data points can represent open curves, P(1) != P(N) or closed
   curves P(2) == P(N). If a tangential discontinuity at P(I) is
   required, then set P(I)=P(I+1). Loops are also allowed.
   <p>
   Reference Marlow and Powell, Harwell report No.R.7092.1972
   MCCONALOGUE, Computer Journal VOL.13, NO4, NOV1970P p392 6
   <p>
   <ul>
   <li>  npoints   : Number of data points.
   <li>  x         : Abscissa
   <li>  y         : Ordinate
   </ul>
   End_Html */

   Int_t i, k, kp, km, npointsMax, banksize, n2, npt;
   Int_t maxiterations, finished;
   Int_t jtype, ktype, closed;
   Double_t sxmin, sxmax, symin, symax;
   Double_t delta;
   Double_t xorg, yorg;
   Double_t ratio_signs, xratio, yratio;
   Int_t flgic, flgis;
   Int_t iw, loptx;
   Double_t p1, p2, p3, p4, p5, p6;
   Double_t w1, w2, w3;
   Double_t a, b, c, r, s, t, z;
   Double_t co, so, ct, st, ctu, stu, xnt;
   Double_t dx1, dy1, dx2, dy2, dk1, dk2;
   Double_t xo, yo, dx, dy, xt, yt;
   Double_t xa, xb, ya, yb;
   Double_t u1, u2, u3, tj;
   Double_t cc, err;
   Double_t sb, sth;
   Double_t wsign, tsquare, tcube;
   c = t = co = so = ct = st = ctu = stu = dx1 = dy1 = dx2 = dy2 = 0;
   xt = yt = xa = xb = ya = yb = u1 = u2 = u3 = tj = sb = 0;

   npointsMax  = npoints*10;
   n2          = npointsMax-2;
   banksize    = n2;

   Double_t *qlx = new Double_t[npointsMax];
   Double_t *qly = new Double_t[npointsMax];
   if (!qlx || !qly) {
      Error("Smooth", "not enough space in memory");
      return;
   }

   //  Decode the type of curve (drawtype).

   loptx = kFALSE;
   jtype  = (drawtype%1000)-10;
   if (jtype > 0) { ktype = jtype; loptx = kTRUE; }
   else             ktype = drawtype%1000;

   Double_t ruxmin = gPad->GetUxmin();
   Double_t ruymin = gPad->GetUymin();
   if (ktype == 3) {
      xorg = ruxmin;
      yorg = ruymin;
   } else {
      xorg = TMath::Max((Double_t)0,ruxmin);
      yorg = TMath::Min(TMath::Max((Double_t)0,ruymin),gPad->GetUymax());
   }

   // delta is the accuracy required in constructing the curve.
   // If it is zero then the routine calculates a value otherwise
   // it uses this value. (default is 0.0)

   delta         = 0.00055;
   maxiterations = 20;

   //       Scale data to the range 0-ratio_signs in X, 0-1 in Y
   //       where ratio_signs is the ratio between the number of changes
   //       of sign in Y divided by the number of changes of sign in X

   sxmin = x[0];
   sxmax = x[0];
   symin = y[0];
   symax = y[0];
   Double_t six   = 1;
   Double_t siy   = 1;
   for (i=1;i<npoints;i++) {
      if (i > 1) {
         if ((x[i]-x[i-1])*(x[i-1]-x[i-2]) < 0) six++;
         if ((y[i]-y[i-1])*(y[i-1]-y[i-2]) < 0) siy++;
      }
      if (x[i] < sxmin) sxmin = x[i];
      if (x[i] > sxmax) sxmax = x[i];
      if (y[i] < symin) symin = y[i];
      if (y[i] > symax) symax = y[i];
   }
   closed = 0;
   Double_t dx1n   = TMath::Abs(x[npoints-1]-x[0]);
   Double_t dy1n   = TMath::Abs(y[npoints-1]-y[0]);
   if (dx1n < 0.01*(sxmax-sxmin) && dy1n < 0.01*(symax-symin))  closed = 1;
   if (sxmin == sxmax) {
      xratio = 1;
   } else {
      if (six > 1) ratio_signs = siy/six;
      else         ratio_signs = 20;
      xratio = ratio_signs/(sxmax-sxmin);
   }
   if (symin == symax) yratio = 1;
   else                yratio = 1/(symax-symin);

   qlx[0] = x[0];
   qly[0] = y[0];
   for (i=0;i<npoints;i++) {
      x[i] = (x[i]-sxmin)*xratio;
      y[i] = (y[i]-symin)*yratio;
   }

   //          "finished" is minus one if we must draw a straight line from P(k-1)
   //          to P(k). "finished" is one if the last call to PaintPolyLine has < n2
   //          points. "finished" is zero otherwise. npt counts the X and Y
   //          coordinates in work . When npt=n2 a call to IPL is made.

   finished = 0;
   npt      = 1;
   k        = 1;

   //           Convert coordinates back to original system

   //           Separate the set of data points into arcs P(k-1),P(k).
   //           Calculate the direction cosines. first consider whether
   //           there is a continuous tangent at the endpoints.

   if (!closed) {
      if (x[0] != x[npoints-1] || y[0] != y[npoints-1]) goto L40;
      if (x[npoints-2] == x[npoints-1] && y[npoints-2] == y[npoints-1]) goto L40;
      if (x[0] == x[1] && y[0] == y[1]) goto L40;
   }
   flgic = kFALSE;
   flgis = kTRUE;

   //           flgic is true if the curve is open and false if it is closed.
   //           flgis is true in the main loop, but is false if there is
   //           a deviation from the main loop.

   km = npoints - 1;

   //           Calculate direction cosines at P(1) using P(N-1),P(1),P(2).

   goto L100;
L40:
   flgic = kTRUE;
   flgis = kFALSE;

   //           Skip excessive consecutive equal points.

L50:
   if (k >= npoints) {
      finished = 1;  // Prepare to clear out remaining short vectors before returning
      if (npt > 1) goto L310;
      goto L390;
   }
   k++;
   if (x[k-1] == x[k-2] && y[k-1] == y[k-2])  goto L50;
L60:
   km = k-1;
   if (k > npoints) {
      finished = 1;  // Prepare to clear out remaining short vectors before returning
      if (npt > 1) goto L310;
      goto L390;
   }
   if (k < npoints) goto L90;
   if (!flgic) { kp = 2; goto L130;}

L80:
   if (flgis) goto L150;

   //           Draw a straight line from P(k-1) to P(k).

   finished = -1;
   goto L170;

   //           Test whether P(k) is a cusp.

L90:
   if (x[k-1] == x[k] && y[k-1] == y[k]) goto L80;
L100:
   kp = k+1;
   goto L130;

   //           Branch if the next section of the curve begins at a cusp.

L110:
   if (!flgis) goto L50;

   //           Carry forward the direction cosines from the previous arc.

L120:
   co = ct;
   so = st;
   k++;
   goto L60;

   //           Calculate the direction cosines at P(k).  If k=1 then
   //           N-1 is used for k-1. If k=N then 2 is used for k+1.
   //           direction cosines at P(k) obtained from P(k-1),P(k),P(k+1).

L130:
   dx1 = x[k-1]  - x[km-1];
   dy1 = y[k-1]  - y[km-1];
   dk1 = dx1*dx1 + dy1*dy1;
   dx2 = x[kp-1] - x[k-1];
   dy2 = y[kp-1] - y[k-1];
   dk2 = dx2*dx2 + dy2*dy2;
   ctu = dx1*dk2 + dx2*dk1;
   stu = dy1*dk2 + dy2*dk1;
   xnt = ctu*ctu + stu*stu;

   //           If both ctu and stu are zero,then default.This can
   //           occur when P(k)=P(k+1). I.E. A loop.

   if (xnt < 1.E-25) {
      ctu = dy1;
      stu =-dx1;
      xnt = dk1;
   }
   //           Normalise direction cosines.

   ct = ctu/TMath::Sqrt(xnt);
   st = stu/TMath::Sqrt(xnt);
   if (flgis) goto L160;

   //           Direction cosines at P(k-1) obtained from P(k-1),P(k),P(k+1).

   w3    = 2*(dx1*dy2-dx2*dy1);
   co    = ctu+w3*dy1;
   so    = stu-w3*dx1;
   xnt   = 1/TMath::Sqrt(co*co+so*so);
   co    = co*xnt;
   so    = so*xnt;
   flgis = kTRUE;
   goto L170;

   //           Direction cosines at P(k) obtained from P(k-2),P(k-1),P(k).

L150:
   w3    = 2*(dx1*dy2-dx2*dy1);
   ct    = ctu-w3*dy2;
   st    = stu+w3*dx2;
   xnt   = 1/TMath::Sqrt(ct*ct+st*st);
   ct    = ct*xnt;
   st    = st*xnt;
   flgis = kFALSE;
   goto L170;
L160:
   if (k <= 1) goto L120;

   //           For the arc between P(k-1) and P(k) with direction cosines co,
   //           so and ct,st respectively, calculate the coefficients of the
   //           parametric cubic represented by X(t) and Y(t) where
   //           X(t)=xa*t**3 + xb*t**2 + co*t + xo
   //           Y(t)=ya*t**3 + yb*t**2 + so*t + yo

L170:
   xo = x[k-2];
   yo = y[k-2];
   dx = x[k-1] - xo;
   dy = y[k-1] - yo;

   //           Initialise the values of X(TI),Y(TI) in xt and yt respectively.

   xt = xo;
   yt = yo;
   if (finished < 0) {  // Draw a straight line between (xo,yo) and (xt,yt)
      xt += dx;
      yt += dy;
      goto L300;
   }
   c  = dx*dx+dy*dy;
   a  = co+ct;
   b  = so+st;
   r  = dx*a+dy*b;
   t  = c*6/(TMath::Sqrt(r*r+2*(7-co*ct-so*st)*c)+r);
   tsquare = t*t;
   tcube   = t*tsquare;
   xa = (a*t-2*dx)/tcube;
   xb = (3*dx-(co+a)*t)/tsquare;
   ya = (b*t-2*dy)/tcube;
   yb = (3*dy-(so+b)*t)/tsquare;

   //           If the curve is close to a straight line then use a straight
   //           line between (xo,yo) and (xt,yt).

   if (.75*TMath::Max(TMath::Abs(dx*so-dy*co),TMath::Abs(dx*st-dy*ct)) <= delta) {
      finished = -1;
      xt += dx;
      yt += dy;
      goto L300;
   }

   //           Calculate a set of values 0 == t(0).LTCT(1) <  ...  < t(M)=TC
   //           such that polygonal arc joining X(t(J)),Y(t(J)) (J=0,1,..M)
   //           is within the required accuracy of the curve

   tj = 0;
   u1 = ya*xb-yb*xa;
   u2 = yb*co-xb*so;
   u3 = so*xa-ya*co;

   //           Given t(J), calculate t(J+1). The values of X(t(J)),
   //           Y(t(J)) t(J) are contained in xt,yt and tj respectively.

L180:
   s  = t - tj;
   iw = -2;

   //           Define iw here later.

   p1 = (2*u1)*tj-u3;
   p2 = (u1*tj-u3)*3*tj+u2;
   p3 = 3*tj*ya+yb;
   p4 = (p3+yb)*tj+so;
   p5 = 3*tj*xa+xb;
   p6 = (p5+xb)*tj+co;

   //           Test D(tj,THETA). A is set to (Y(tj+s)-Y(tj))/s.b is
   //           set to (X(tj+s)-X(tj))/s.

   cc  = 0.8209285;
   err = 0.1209835;
L190:
   iw -= 2;
L200:
   a   = (s*ya+p3)*s+p4;
   b   = (s*xa+p5)*s+p6;

   //           Set z to PSI(D/delta)-cc.

   w1 = -s*(s*u1+p1);
   w2 = s*s*u1-p2;
   w3 = 1.5*w1+w2;

   //           Set the estimate of (THETA-tj)/s.Then set the numerator
   //           of the expression (EQUATION 4.4)/s. Then set the square
   //           of D(tj,tj+s)/delta. Then replace z by PSI(D/delta)-cc.

   if (w3 > 0) wsign = TMath::Abs(w1);
   else        wsign = -TMath::Abs(w1);
   sth = 0.5+wsign/(3.4*TMath::Abs(w1)+5.2*TMath::Abs(w3));
   z   = s*sth*(s-s*sth)*(w1*sth+w1+w2);
   z   = z*z/((a*a+b*b)*(delta*delta));
   z   = (z+2.642937)*z/((.3715652*z+3.063444)*z+.2441889)-cc;

   //           Branch if z has been calculated

   if (iw > 0) goto L250;
   if (z > err) goto L240;
   goto L220;
L210:
   iw -= 2;
L220:
   if (iw+2 == 0) goto L190;
   if (iw+2 >  0) goto L290;

   //           Last part of arc.

L230:
   xt = x[k-1];
   yt = y[k-1];
   s  = 0;
   goto L300;

   //           z(s). find a value of s where 0 <= s <= sb such that
   //           TMath::Abs(z(s)) < err

L240:
   kp = 0;
   c  = z;
   sb = s;
L250:
   theGraph->Zero(kp,0,sb,err,s,z,maxiterations);
   if (kp == 2) goto L210;
   if (kp > 2) {
      Error("Smooth", "Attempt to plot outside plot limits");
      goto L230;
   }
   if (iw > 0) goto L200;

   //           Set z=z(s) for s=0.

   if (iw < 0) {
      z  = -cc;
      iw = 0;
      goto L250;
   }

   //           Set z=z(s) for s=sb.

   z  = c;
   iw = 1;
   goto L250;

   //           Update tj,xt and yt.

L290:
   xt = xt + s*b;
   yt = yt + s*a;
   tj = s  + tj;

   //           Convert coordinates to original system

L300:
   qlx[npt] = sxmin + xt/xratio;
   qly[npt] = symin + yt/yratio;
   npt++;

   //           If a fill area must be drawn and if the banks LX and
   //           LY are too small they are enlarged in order to draw
   //           the filled area in one go.

   if (npt < banksize)  goto L320;
   if (drawtype >= 1000 || ktype > 1) {
      Int_t newsize = banksize + n2;
      Double_t *qtemp = new Double_t[banksize];
      for (i=0;i<banksize;i++) qtemp[i] = qlx[i];
      delete [] qlx;
      qlx = new Double_t[newsize];
      for (i=0;i<banksize;i++) qlx[i]   = qtemp[i];
      for (i=0;i<banksize;i++) qtemp[i] = qly[i];
      delete [] qly;
      qly = new Double_t[newsize];
      for (i=0;i<banksize;i++) qly[i] = qtemp[i];
      delete [] qtemp;
      banksize = newsize;
      goto L320;
   }

   //           Draw the graph

L310:
   if (drawtype >= 1000) {
      gPad->PaintFillArea(npt,qlx,qly, "B");
   } else {
      if (ktype > 1) {
         if (!loptx) {
            qlx[npt]   = qlx[npt-1];
            qlx[npt+1] = qlx[0];
            qly[npt]   = yorg;
            qly[npt+1] = yorg;
         } else {
            qlx[npt]   = xorg;
            qlx[npt+1] = xorg;
            qly[npt]   = qly[npt-1];
            qly[npt+1] = qly[0];
         }
         gPad->PaintFillArea(npt+2,qlx,qly);
      }
      if (TMath::Abs(theGraph->GetLineWidth())>99) PaintPolyLineHatches(theGraph, npt, qlx, qly);
      gPad->PaintPolyLine(npt,qlx,qly);
   }
   npt = 1;
   qlx[0] = sxmin + xt/xratio;
   qly[0] = symin + yt/yratio;
L320:
   if (finished > 0) goto L390;
   if (finished < 0) { finished = 0; goto L110;}
   if (s > 0) goto L180;
   goto L110;

   //           Convert coordinates back to original system

L390:
   for (i=0;i<npoints;i++) {
      x[i] = sxmin + x[i]/xratio;
      y[i] = symin + y[i]/yratio;
   }

   delete [] qlx;
   delete [] qly;
}


//______________________________________________________________________________
void TGraphPainter::SetHighlight(TGraph *theGraph)
{
   // Set highlight (enable/disble) mode for theGraph

   gHighlightPoint = -1; // must be -1
   gHighlightGraph = 0;

   // delete previous highlight marker
   TIter next(gROOT->GetListOfCanvases());
   TVirtualPad *pad = 0;
   while ((pad = (TVirtualPad *)next()))
      if (pad && pad->FindObject(theGraph)) pad->Modified(kTRUE);
}


//______________________________________________________________________________
void TGraphPainter::SetHighlightPad(TVirtualPad *pad)
{
   // Set pad where will draw highlight object for current point of theGraph

   if (fHighlightPad) {
      Warning("SetHighlightPad", "only one pad as HighlightPad");
      return;
   }

   if (!pad) {
      TVirtualPad *padsave = gPad;
      fHighlightPad = (TVirtualPad *)gROOT->MakeDefCanvas();
      if (padsave) padsave->cd();
   } else
      fHighlightPad = pad;
   fHighlightPad->Connect("Closed()", "TGraphPainter", this, "HighlightPadNo()");
}


//______________________________________________________________________________
Int_t TGraphPainter::GetHighlightPointHelper(TGraph *theGraph) const
{
   if (theGraph == gHighlightGraph) return gHighlightPoint;
   else return -1;
}


//______________________________________________________________________________
void TGraphPainter::HighlightPoint(TGraph *theGraph)
{
   // Draw highlight object for current point of theGraph. If theGraph doesn't have
   // highlights (array of highlight objects) will be generated simple info text

   if (!fHighlightPad) return;
   if (fHighlightPad == gPad) { // only in special case
      if (theGraph->GetListOfHighlights())
         Warning("HighlightPoint", "HighlightPad is same as graph Pad");
      return;
   }

   TObjArray *highlights = theGraph->GetListOfHighlights();
   TObject *highObj = 0;
   if (!highlights || (highlights->IsEmpty())) {
      TText *info = new TText(0.5, 0.5, TString::Format("AddHighlight(%d, obj)", gHighlightPoint));
      info->SetBit(kCanDelete);
      info->SetNDC();
      info->SetTextAlign(22);
      info->SetTextSize(2.0*info->GetTextSize());
      info->SetTextColor(theGraph->GetMarkerColor());
      highObj = info;
   } else
      highObj = highlights->At(gHighlightPoint);

   Bool_t needreset = fHighlightPad->FindObject(gPad->GetPadSave()); // only in specific case
   TVirtualPad *padsave = gPad;
   fHighlightPad->Clear();
   fHighlightPad->cd();
   if (highObj) highObj->Draw();
   fHighlightPad->Update();
   if (padsave) {
      padsave->cd();
      if (needreset) ((TCanvas *)padsave)->ClearPadSave();
   }
}


////______________________________________________________________________________
//TVirtualPad *TGraphPainter::FindPadObject(const TObject *obj) const
//{
//   // Find (first) pad with obj
//
//   TIter next(gROOT->GetListOfCanvases());
//   TVirtualPad *pad;
//   while ((pad = (TVirtualPad *)next()))
//      if (pad && pad->FindObject(obj)) return pad;
//
//   return 0;
//}

// change logic from single and multi to many
// to JIRA
// minimal changes in original code
// unaffected original functionality
// please feel free to modify code


//
//Hello,
//I wrote a small implementation of the violin plot (http://en.wikipedia.org/wiki/Violin_plot)
//for TH2. Please feel free to include it if you think it could
//be useful to other users.
//The attached patch should be applied on top of v5-34-21.
//Attached is also an example plot.
//
// @(#)root/histpainter:$Id: TGraphPainter.h,v 1.00
// Author: Olivier Couet

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#ifndef ROOT_TGraphPainter
#define ROOT_TGraphPainter


//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TGraphPainter                                                        //
//                                                                      //
// helper class to draw graphs                                          //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#ifndef ROOT_Object
#include "TVirtualGraphPainter.h"
#endif

class TGraph;
class TF1;
class TVirtualPad;

class TGraphPainter : public TVirtualGraphPainter {

protected:
   TVirtualPad   *fHighlightPad; //!Pointer to highlight pad

public:

   TGraphPainter();

   virtual ~TGraphPainter();

   void           ComputeLogs(Int_t npoints, Int_t opt);
   virtual Int_t  DistancetoPrimitiveHelper(TGraph *theGraph, Int_t px, Int_t py);
   virtual void   DrawPanelHelper(TGraph *theGraph);
   virtual void   ExecuteEventHelper(TGraph *theGraph, Int_t event, Int_t px, Int_t py);
   virtual char  *GetObjectInfoHelper(TGraph *theGraph, Int_t px, Int_t py) const;
   TVirtualPad   *GetHighlightPad() const { return fHighlightPad; }
   virtual Int_t  GetHighlightPointHelper(TGraph *theGraph) const;
   void           HighlightPadNo() { fHighlightPad = 0; }
   virtual void   HighlightPoint(TGraph *theGraph);
   virtual void   PaintHighlightPoint(TGraph *theGraph, Option_t *option);
   void           PaintHelper(TGraph *theGraph, Option_t *option);
   virtual void   PaintGraph(TGraph *theGraph, Int_t npoints, const Double_t *x, const Double_t *y, Option_t *chopt);
   virtual void   PaintGrapHist(TGraph *theGraph, Int_t npoints, const Double_t *x, const Double_t *y, Option_t *chopt);
   void           PaintGraphAsymmErrors(TGraph *theGraph, Option_t *option);
   void           PaintGraphBentErrors(TGraph *theGraph, Option_t *option);
   void           PaintGraphErrors(TGraph *theGraph, Option_t *option);
   void           PaintGraphPolar(TGraph *theGraph, Option_t *option);
   void           PaintGraphQQ(TGraph *theGraph, Option_t *option);
   void           PaintGraphSimple(TGraph *theGraph, Option_t *option);
   void           PaintPolyLineHatches(TGraph *theGraph, Int_t n, const Double_t *x, const Double_t *y);
   void           PaintStats(TGraph *theGraph, TF1 *fit);
   virtual void   SetHighlight(TGraph *theGraph);
   virtual void   SetHighlightPad(TVirtualPad *pad);
   void           Smooth(TGraph *theGraph, Int_t npoints, Double_t *x, Double_t *y, Int_t drawtype);

   ClassDef(TGraphPainter,0)  // TGraph painter
};

#endif
// @(#)root/hist:$Id$
// Author: Olivier Couet 20/05/08

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/
#ifndef ROOT_TVirtualGraphPainter
#define ROOT_TVirtualGraphPainter

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TVirtualGraphPainter                                                 //
//                                                                      //
// Abstract base class for Graph painters                               //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#ifndef ROOT_TObject
#include "TObject.h"
#endif

class TGraph;
class TF1;

class TVirtualGraphPainter : public TObject {

private:
   static TVirtualGraphPainter   *fgPainter; //Pointer to class painter

public:
   TVirtualGraphPainter() { }
   virtual ~TVirtualGraphPainter() { }

   virtual Int_t DistancetoPrimitiveHelper(TGraph *theGraph, Int_t px, Int_t py) = 0;
   virtual void  DrawPanelHelper(TGraph *theGraph) = 0;
   virtual void  ExecuteEventHelper(TGraph *theGraph, Int_t event, Int_t px, Int_t py) = 0;
   virtual char *GetObjectInfoHelper(TGraph *theGraph, Int_t px, Int_t py) const = 0;
   virtual void  PaintHelper(TGraph *theGraph, Option_t *option) = 0;
   virtual void  PaintGraph(TGraph *theGraph, Int_t npoints, const Double_t *x, const Double_t *y, Option_t *chopt) = 0;
   virtual void  PaintGrapHist(TGraph *theGraph, Int_t npoints, const Double_t *x, const Double_t *y, Option_t *chopt) = 0;
   virtual void  PaintStats(TGraph *theGraph, TF1 *fit) = 0;

   static TVirtualGraphPainter *GetPainter();
   static void                  SetPainter(TVirtualGraphPainter *painter);

   ClassDef(TVirtualGraphPainter,0)  //Abstract interface for histogram painters
};

#endif
// @(#)root/hist:$Id$
// Author: Olivier Couet 20/05/08

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/
#ifndef ROOT_TVirtualGraphPainter
#define ROOT_TVirtualGraphPainter

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TVirtualGraphPainter                                                 //
//                                                                      //
// Abstract base class for Graph painters                               //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#ifndef ROOT_TObject
#include "TObject.h"
#endif

class TGraph;
class TF1;
class TVirtualPad;

class TVirtualGraphPainter : public TObject {

private:
   static TVirtualGraphPainter   *fgPainter; //Pointer to class painter

public:
   TVirtualGraphPainter() { }
   virtual ~TVirtualGraphPainter() { }

   virtual Int_t GetHighlightPointHelper(TGraph *theGraph) const = 0;
   virtual Int_t DistancetoPrimitiveHelper(TGraph *theGraph, Int_t px, Int_t py) = 0;
   virtual void  DrawPanelHelper(TGraph *theGraph) = 0;
   virtual void  ExecuteEventHelper(TGraph *theGraph, Int_t event, Int_t px, Int_t py) = 0;
   virtual char *GetObjectInfoHelper(TGraph *theGraph, Int_t px, Int_t py) const = 0;
   virtual void  PaintHelper(TGraph *theGraph, Option_t *option) = 0;
   virtual void  PaintGraph(TGraph *theGraph, Int_t npoints, const Double_t *x, const Double_t *y, Option_t *chopt) = 0;
   virtual void  PaintGrapHist(TGraph *theGraph, Int_t npoints, const Double_t *x, const Double_t *y, Option_t *chopt) = 0;
   virtual void  PaintStats(TGraph *theGraph, TF1 *fit) = 0;
   virtual void  SetHighlight(TGraph *theGraph) = 0;
   virtual void  SetHighlightPad(TVirtualPad *pad) = 0;

   static TVirtualGraphPainter *GetPainter();
   static void                  SetPainter(TVirtualGraphPainter *painter);

   ClassDef(TVirtualGraphPainter,0)  //Abstract interface for histogram painters
};

#endif
// Draw a graph with text attached to current point.
// The text is drawn in a TExec function, therefore if the text is
// moved interactively, it will be automatically updated.
// Author: Olivier Couet
void graphtext2() {
   TCanvas *c = new TCanvas("c","A Simple Graph Example with Text",700,500);
   c->SetGrid();

   const Int_t n = 10;
   TGraph *gr = new TGraph(n);
   gr->SetTitle("A Simple Graph Example with Text");
   gr->SetMarkerStyle(20);
   TExec *ex = new TExec("ex","drawtext2();");
   gr->GetListOfFunctions()->Add(ex);
   gr->SetHighlight();

   Double_t x, y;
   for (Int_t i=0;i<n;i++) {
      x = i*0.1;
      y = 10*sin(x+0.2);
      gr->SetPoint(i,x,y);

   }
   gr->Draw("ALP");

   TText *info = new TText(0.3, 2.5, "please move the mouse over the graph");
   info->SetTextSize(0.04);
   info->SetTextColor(kRed+1);
   info->SetBit(kCannotPick);
   info->Draw();
}

void drawtext2()
{
   Int_t i;
   Double_t x,y;
   TLatex *l;

   TGraph *g = (TGraph*)gPad->GetListOfPrimitives()->FindObject("Graph");
   i = g->GetHighlightPoint();
   if (i == -1) return;
   g->GetPoint(i,x,y);
   l = new TLatex(x,y+0.2,Form("%4.2f",y));
   l->SetTextSize(0.025);
   l->SetTextFont(42);
   l->SetTextAlign(21);
   l->Paint();
}
// Author: Jan Musinsky
// 30/09/2014

#include <TCanvas.h>
#include <TH1.h>
#include <TF1.h>
#include <TGraph.h>
#include <TText.h>

void highlight1()
{
   TCanvas *ch = new TCanvas("ch", "ch", 0, 0, 700, 500);
   const Int_t n = 500;
   Double_t x[n], y[n];
   TH1F *h[n];

   for (Int_t i = 0; i < n; i++) {
      h[i] = new TH1F(TString::Format("h_%02d", i), "", 100, -3.0, 3.0);
      // in practice gaus need reset parameters
      h[i]->FillRandom("gaus", 1000);
      h[i]->Fit("gaus", "Q");
      h[i]->SetMaximum(250); // for n > 200
      x[i] = i;
      y[i] = h[i]->GetFunction("gaus")->GetParameter(2);
   }

   TGraph *g = new TGraph(n, x, y);
   g->SetMarkerStyle(6);
   for (Int_t i = 0; i < n; i++) g->AddHighlight(i, h[i]);
   g->Draw("AP");
   g->SetHighlight();

   TPad *ph = new TPad("ph", "ph", 0.3, 0.4, 1.0, 1.0);
   ph->SetFillColor(kBlue - 10);
   ph->Draw();
   ph->cd();
   TText *info = new TText(0.5, 0.5, "please move the mouse over the graph");
   info->SetTextAlign(22);
   info->Draw();
   ch->cd();

   TGraph::SetHighlightPad(ph);
}
// Author: Jan Musinsky
// 30/09/2014

#include <TROOT.h>
#include <TFile.h>
#include <TNtuple.h>
#include <TGraph.h>
#include <TH1.h>
#include <TCanvas.h>
#include <TExec.h>
#include <TBox.h>
#include <TText.h>
#include <TMath.h>

TNtuple *ntuple = 0;
TGraph *graph = 0;

void highlight3()
{
   TFile *file = TFile::Open("$ROOTSYS/tutorials/hsimple.root");
   if (!file || file->IsZombie()) {
      Printf("please first run $ROOTSYS/tutorials/hsimple.C");
      return;
   }

   file->GetObject("ntuple", ntuple);
   if (!ntuple) return;

   TCanvas *c1 = new TCanvas("c1", "c1", 0,   0, 500, 500);
   const char *cut = "pz > 3.0";
   ntuple->Draw("px:py", cut);
   graph = (TGraph *)gPad->FindObject("Graph");
   graph->SetHighlight();
   TExec *ex = new TExec("ex", "HighlightBinId();");
   graph->GetListOfFunctions()->Add(ex);
   TText *info = new TText(0.0, 4.5, "please move the mouse over the graph");
   info->SetTextAlign(22);
   info->SetTextSize(0.03);
   info->SetTextColor(kRed+1);
   info->SetBit(kCannotPick);
   info->Draw();

   TCanvas *c2 = new TCanvas("c2", "c2", 505, 0, 600, 400);
   ntuple->Draw("TMath::Sqrt(px*px + py*py + pz*pz)>>histo(100, 0, 15)", cut);

   // must be as last
   ntuple->Draw("px:py:pz:i", cut, "goff");
}

void HighlightBinId()
{
   TCanvas *c2 = (TCanvas *)gROOT->GetListOfCanvases()->FindObject("c2");
   if (!c2) return;
   TH1F *histo = (TH1F *)c2->FindObject("histo");
   if (!histo) return;
   Int_t ih = graph->GetHighlightPoint();
   if (ih == -1) return;

   Double_t px = ntuple->GetV1()[ih];
   Double_t py = ntuple->GetV2()[ih];
   Double_t pz = ntuple->GetV3()[ih];
   Double_t i  = ntuple->GetV4()[ih];
   Double_t p  = TMath::Sqrt(px*px + py*py + pz*pz);
   Int_t hbin = histo->FindBin(p);

   Bool_t redraw = kFALSE;
   TBox *bh = (TBox *)c2->FindObject("TBox");
   if (!bh) {
      bh = new TBox();
      bh->SetFillColor(histo->GetLineColor());
      bh->SetFillStyle(3001);
      bh->SetBit(kCanDelete);
      redraw = kTRUE;
   }
   bh->SetX1(histo->GetBinLowEdge(hbin));
   bh->SetY1(histo->GetMinimum());
   bh->SetX2(histo->GetBinWidth(hbin) + histo->GetBinLowEdge(hbin));
   bh->SetY2(histo->GetBinContent(hbin));

   TText *th = (TText *)c2->FindObject("TText");
   if (!th) {
      th = new TText();
      th->SetName("TText");
      th->SetTextColor(graph->GetMarkerColor());
      th->SetBit(kCanDelete);
      redraw = kTRUE;
   }
   th->SetText(histo->GetXaxis()->GetXmax()*0.75, histo->GetMaximum()*0.5,
               TString::Format("id = %d", (Int_t)i));

   c2->Modified();
   c2->Update();

   if (!redraw) return;
   TVirtualPad *savepad = gPad;
   c2->cd();
   bh->Draw();
   th->Draw();
   c2->Update();
   if (savepad) savepad->cd();
}
void test1()
{
   gROOT->Macro("$ROOTSYS/tutorials/graphs/gerrors2.C");
   TGraphErrors *gr1 = (TGraphErrors *)gPad->GetListOfPrimitives()->At(2);
   TGraphErrors *gr2 = (TGraphErrors *)gPad->GetListOfPrimitives()->At(3);

   // or switch with TGraph context menu
   gr1->SetHighlight();
   gr2->SetHighlight();
}
void test2()
{
   gROOT->Macro("$ROOTSYS/tutorials/graphs/gerrors2.C");
   TGraphErrors *gr1 = (TGraphErrors *)gPad->GetListOfPrimitives()->At(2);
   TGraphErrors *gr2 = (TGraphErrors *)gPad->GetListOfPrimitives()->At(3);

   // or switch with TGraph context menu
   gr1->SetHighlight();
   gr2->SetHighlight();

   TPad *c1_1 = new TPad("c1_1", "c1_1", 0.40, 0.15, 0.70 ,0.40);
   //c1_1->SetFillStyle(0);
   c1_1->Draw();

   TGraph::SetHighlightPad(c1_1);
   //TGraph::SetHighlightPad(); // or make default canvas
}
void test3()
{

   gROOT->Macro("$ROOTSYS/tutorials/graphs/gerrors2.C");
   TGraphErrors *gr1 = (TGraphErrors *)gPad->GetListOfPrimitives()->At(2);
   TGraphErrors *gr2 = (TGraphErrors *)gPad->GetListOfPrimitives()->At(3);

   // or switch with TGraph context menu
   gr1->SetHighlight();
   gr2->SetHighlight();

   TPad *c1_1 = new TPad("c1_1", "c1_1", 0.40, 0.15, 0.70 ,0.40);
   //c1_1->SetFillStyle(0);
   c1_1->Draw();

   TGraph::SetHighlightPad(c1_1);
   //TGraph::SetHighlightPad(); // or make default canvas

   gr2->AddHighlight(1, new TText(0.5, 0.5, "point 1"));
   gr2->AddHighlight(3, new TText(0.5, 0.5, "point 3"));
   gr2->AddHighlight(5, new TText(0.5, 0.5, "point 5"));
   gr2->AddHighlight(7, new TText(0.5, 0.5, "point 7"));
}
void test5()
{
   TCanvas *c1 = new TCanvas("c1", "c1", 0,   0, 600, 300);
   TCanvas *c2 = new TCanvas("c2", "c2", 605, 0, 600, 300);

   const Int_t n = 20;
   Double_t x[n], y[n];
   for (Int_t i = 0; i < n; i++) {
      x[i] = i;
      y[i] = i;
   }

   TGraph *gr = new TGraph(n, x, y);
   gr->SetMarkerStyle(20);
   c1->cd();
   c1->SetGrid();
   gr->Draw("APC");
   gr->SetHighlight();
   TGraph::SetHighlightPad(c2);

   TH1F *h[n];
   for (Int_t i = 0; i < n; i++) {
      h[i] = new TH1F(TString::Format("h_%02d", i), "", 100, -5.0, 5.0);
      h[i]->SetTitle(h[i]->GetName());
      h[i]->FillRandom("gaus");
      gr->AddHighlight(i, h[i]);
   }

   gr->GetListOfHighlights()->SetOwner(kTRUE);
   gr->RemovePoint(5);
   gr->RemovePoint(9); // point with x = 10 (after remove previous point)
   delete h[14];
   delete h[17];
}

以上是关于c_cpp ROOT图表突出显示的主要内容,如果未能解决你的问题,请参考以下文章

c_cpp 方形按钮与背景动画触摸向下和向上(突出显示)

在 Datatables.net 中使用 Sparkline 条形图,我可以用不同的颜色突出显示图表上的一个条形吗?

Highcharts动态突出显示一列

如何在 Altair 图表上只显示一个系列

Tableau 图表大全12之凸显表

使用 .maphilight() 突出显示图像的特定区域