ROOT Graph Highlight (simple)
void quantiles2() {
// demo for quantiles
// Authors: Rene Brun, Eddy Offermann
const Int_t nq = 100;
const Int_t nshots = 10;
Double_t xq[nq]; // position where to compute the quantiles in [0,1]
Double_t yq[nq]; // array to contain the quantiles
for (Int_t i=0;i<nq;i++) xq[i] = Float_t(i+1)/nq;
TGraph *gr70 = new TGraph(nshots);
TGraph *gr90 = new TGraph(nshots);
TGraph *gr98 = new TGraph(nshots);
TGraph *grq[nq];
for (Int_t ig = 0; ig < nq; ig++) grq[ig] = new TGraph(nshots);
TH1F *h = new TH1F("h","demo quantiles",50,-3,3);
for (Int_t shot=0;shot<nshots;shot++) {
h->FillRandom("gaus",50);
h->GetQuantiles(nq,yq,xq);
gr70->SetPoint(shot,shot+1,yq[70]);
gr90->SetPoint(shot,shot+1,yq[90]);
gr98->SetPoint(shot,shot+1,yq[98]);
for (Int_t ig = 0; ig < nq; ig++)
grq[ig]->SetPoint(shot,shot+1,yq[ig]);
}
//show the original histogram in the top pad
TCanvas *c1 = new TCanvas("c1","demo quantiles",10,10,600,900);
c1->SetFillColor(41);
c1->Divide(1,3);
c1->cd(1);
h->SetFillColor(38);
h->Draw();
// show the final quantiles in the middle pad
c1->cd(2);
gPad->SetFrameFillColor(33);
gPad->SetGrid();
TGraph *gr = new TGraph(nq,xq,yq);
gr->SetTitle("final quantiles");
gr->SetMarkerStyle(21);
gr->SetMarkerColor(kRed);
gr->SetMarkerSize(0.3);
gr->SetHighlight();
gr->Draw("ap");
// prepare quantiles
TList *lq = new TList();
for (Int_t ig = 0; ig < nq; ig++) {
grq[ig]->SetMinimum(gr->GetYaxis()->GetXmin());
grq[ig]->SetMaximum(gr->GetYaxis()->GetXmax());
grq[ig]->SetMarkerStyle(23);
grq[ig]->SetMarkerColor(ig%100);
grq[ig]->SetTitle(TString::Format("q%02d", ig));
lq->Add(grq[ig]);
}
TString command = TString::Format("(TList *)0x%lx", (ULong_t)lq);
command = TString::Format("HighlightQuantile(%s)", command.Data());
TExec *ex = new TExec("ex", command.Data());
gr->GetListOfFunctions()->Add(ex);
TText *info = new TText(0.1, 2.4, "please move the mouse over the graph");
info->SetTextSize(0.08);
info->SetTextColor(gr->GetMarkerColor());
info->SetBit(kCannotPick);
info->Draw();
// show the evolution of some quantiles in the bottom pad
c1->cd(3);
gPad->SetFrameFillColor(17);
gPad->DrawFrame(0,0,nshots+1,3.2);
gPad->SetGrid();
gr98->SetMarkerStyle(22);
gr98->SetMarkerColor(kRed);
gr98->Draw("lp");
gr90->SetMarkerStyle(21);
gr90->SetMarkerColor(kBlue);
gr90->Draw("lp");
gr70->SetMarkerStyle(20);
gr70->SetMarkerColor(kMagenta);
gr70->Draw("lp");
// add a legend
TLegend *legend = new TLegend(0.85,0.74,0.95,0.95);
legend->SetTextFont(72);
legend->SetTextSize(0.05);
legend->AddEntry(gr98," q98","lp");
legend->AddEntry(gr90," q90","lp");
legend->AddEntry(gr70," q70","lp");
legend->Draw();
}
void HighlightQuantile(TList *lq = 0)
{
// show the evolution of all quantiles in the bottom pad
if (!lq) return;
TVirtualPad *savepad = gPad;
TCanvas *c1 = (TCanvas *)gROOT->GetListOfCanvases()->FindObject("c1");
c1->cd(2);
TGraph *gr = (TGraph *)gPad->FindObject("Graph");
if (!gr) return;
Int_t iq = gr->GetHighlightPoint();
if (iq == -1) return;
c1->cd(3);
lq->At(iq)->Draw("alp");
savepad->cd();
}
// Author: Jan Musinsky
// 05/10/2014
#include <TROOT.h>
#include <TFile.h>
#include <TNtuple.h>
#include <TGraph.h>
#include <TH2.h>
#include <TCanvas.h>
#include <TExec.h>
#include <TBox.h>
#include <TText.h>
TGraph *hgraph1 = 0;
TGraph *hgraph2 = 0;
TList *list1 = 0;
TList *list2 = 0;
void InitGraphs(TNtuple *nt, TH1F *histo, Int_t hcase);
void HighlightSelectGraph();
void highlight3()
{
TFile *file = TFile::Open("$ROOTSYS/tutorials/hsimple.root");
if (!file || file->IsZombie()) {
Printf("can not open $ROOTSYS/tutorials/hsimple.root file");
return;
}
TNtuple *ntuple;
file->GetObject("ntuple", ntuple);
if (!ntuple) return;
TExec *ex = new TExec("ex", "HighlightSelectGraph()");
const char *cut = "pz > 3.0";
TCanvas *c1 = new TCanvas("c1", "c1", 0, 0, 700, 500);
c1->Divide(1, 2);
// case1, histo1, pz distribution
c1->cd(1);
ntuple->Draw("pz>>histo1(100, 2.0, 12.0)", cut);
TH1F *histo1 = (TH1F *)gPad->FindObject("histo1");
hgraph1 = new TGraph(histo1); // graph from histo
hgraph1->Draw("P");
hgraph1->SetHighlight();
hgraph1->GetListOfFunctions()->Add(ex);
TText *info1 = new TText(7.0, histo1->GetMaximum()*0.6,
"please move the mouse over this histo");
info1->SetTextColor(histo1->GetLineColor());
info1->SetBit(kCannotPick);
info1->Draw();
// case2, histo2, px*py*pz distribution
c1->cd(2);
ntuple->Draw("(px*py*pz)>>histo2(100, -50.0, 50.0)", cut);
TH1F *histo2 = (TH1F *)gPad->FindObject("histo2");
histo2->SetLineColor(kGreen+2);
hgraph2 = new TGraph(histo2); // graph from histo
hgraph2->Draw("P");
hgraph2->SetHighlight();
hgraph2->GetListOfFunctions()->Add(ex);
TText *info2 = new TText(10.0, histo2->GetMaximum()*0.7,
"please move the mouse over this histo");
info2->SetTextColor(histo2->GetLineColor());
info2->SetBit(kCannotPick);
info2->Draw();
TCanvas *c2 = new TCanvas("c2", "c2", 705, 0, 500, 500);
// common graph (all entries, all histo bins)
ntuple->Draw("px:py", cut);
TGraph *gcommon = (TGraph *)gPad->FindObject("Graph");
gcommon->SetBit(kCanDelete, kFALSE); // will be redraw
TH2F *htemp = (TH2F *)gPad->FindObject("htemp");
gcommon->SetTitle(htemp->GetTitle());
gcommon->GetXaxis()->SetTitle(htemp->GetXaxis()->GetTitle());
gcommon->GetYaxis()->SetTitle(htemp->GetYaxis()->GetTitle());
gcommon->Draw("AP");
// must be as last
ntuple->Draw("px:py:pz", cut, "goff");
InitGraphs(ntuple, histo1, 1);
InitGraphs(ntuple, histo2, 2);
}
void InitGraphs(TNtuple *nt, TH1F *histo, Int_t hcase)
{
Long64_t nev = nt->GetSelectedRows();
Double_t *px = nt->GetV1();
Double_t *py = nt->GetV2();
Double_t *pz = nt->GetV3();
TList *list = new TList();
if (hcase == 1) list1 = list;
else if (hcase == 2) list2 = list;
else return;
Int_t nbins = histo->GetNbinsX();
Int_t bin;
TGraph *g;
for (bin = 0; bin < nbins; bin++) {
g = new TGraph();
g->SetName(TString::Format("g%sbin_%d", histo->GetName(), bin+1));
g->SetBit(kCannotPick);
g->SetMarkerStyle(25);
g->SetMarkerColor(histo->GetLineColor());
list->Add(g);
}
Double_t value = 0.0;
for (Long64_t ie = 0; ie < nev; ie++) {
if (hcase == 1) value = pz[ie];
if (hcase == 2) value = px[ie]*py[ie]*pz[ie];
bin = histo->FindBin(value) - 1;
g = (TGraph *)list->At(bin);
if (!g) continue; // under/overflow
g->SetPoint(g->GetN(), py[ie], px[ie]); // reverse as px:py
}
}
void HighlightSelectGraph()
{
TCanvas *c2 = (TCanvas *)gROOT->GetListOfCanvases()->FindObject("c2");
if (!c2) return;
TGraph *gcommon = (TGraph *)c2->FindObject("Graph");
if (!gcommon) return;
TGraph *g = 0;
if (hgraph1->GetHighlightPoint() != -1) // case1
g = (TGraph *)list1->At(hgraph1->GetHighlightPoint());
else if (hgraph2->GetHighlightPoint() != -1) // case2
g = (TGraph *)list2->At(hgraph2->GetHighlightPoint());
if (!g) return;
TVirtualPad *savepad = gPad;
c2->cd();
gcommon->Draw("AP");
if (g->GetN() > 0) g->Draw("P");
//gcommon->SetTitle(TString::Format("%d / %d", g->GetN(), gcommon->GetN()));
c2->Update();
savepad->cd();
}
// 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 HighlightBinId();
void highlight2()
{
TFile *file = TFile::Open("$ROOTSYS/tutorials/hsimple.root");
if (!file || file->IsZombie()) {
Printf("can not open $ROOTSYS/tutorials/hsimple.root file");
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(kCannotPick);
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();
savepad->cd();
}
// Author: Jan Musinsky
// 30/09/2014
#include <TCanvas.h>
#include <TH1.h>
#include <TF1.h>
#include <TGraph.h>
#include <TList.h>
#include <TExec.h>
#include <TText.h>
TList *l = 0;
TGraph *g = 0;
void HighlightHisto();
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;
l = new TList();
for (Int_t i = 0; i < n; i++) {
h = new TH1F(TString::Format("h_%03d", i), "", 100, -3.0, 3.0);
// in practice gaus need reset parameters
h->FillRandom("gaus", 1000);
h->Fit("gaus", "Q");
h->SetMaximum(250.0); // for n > 200
l->Add(h);
x[i] = i;
y[i] = h->GetFunction("gaus")->GetParameter(2);
}
g = new TGraph(n, x, y);
g->SetMarkerStyle(6);
g->Draw("AP");
g->SetHighlight();
TExec *ex = new TExec("ex", "HighlightHisto()");
g->GetListOfFunctions()->Add(ex);
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();
}
void HighlightHisto()
{
TVirtualPad *ph = (TVirtualPad *)gPad->FindObject("ph");
if (!ph) return;
Int_t ih = g->GetHighlightPoint();
if (ih == -1) return;
TVirtualPad *savepad = gPad;
ph->cd();
l->At(ih)->Draw();
savepad->cd();
}
// 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);
gr->SetHighlight();
TExec *ex = new TExec("ex","drawtext2();");
gr->GetListOfFunctions()->Add(ex);
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();
}
// @(#)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 GetHighlightPointHelper(const 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;
static TVirtualGraphPainter *GetPainter();
static void SetPainter(TVirtualGraphPainter *painter);
ClassDef(TVirtualGraphPainter,0) //Abstract interface for histogram painters
};
#endif
// @(#)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;
virtual Int_t GetHighlightPointHelper(const TGraph *theGraph) const;
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);
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 "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()
{
/* 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
}
}
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*)"";
}
//______________________________________________________________________________
Int_t TGraphPainter::GetHighlightPointHelper(const TGraph *theGraph) const
{
// Return the highlighted point for theGraph
if (theGraph == gHighlightGraph) return gHighlightPoint;
else return -1;
}
//______________________________________________________________________________
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::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;
}
// @(#)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
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 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() 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 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
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;
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);
}
//______________________________________________________________________________
Int_t TGraph::GetHighlightPoint() const
{
// Return the highlighted point for the graph
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 the graph
// by default highlight mode is disable
SetBit(kIsHighlight, highlight);
TVirtualGraphPainter *painter = TVirtualGraphPainter::GetPainter();
if (painter) painter->SetHighlight(this);
}
//______________________________________________________________________________
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
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 Apply(TF1 *f);
virtual void Browse(TBrowser *b);
virtual Double_t Chisquare(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() 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 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(std::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
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;
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);
std::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(TF1 *func, 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
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(ROOT::Fit::kGraph, 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 (!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(std::ostream &out, Option_t *option /*= ""*/)
{
// Save primitive as a C++ statement(s) on output stream out
char quote = '"';
out << " " << std::endl;
static Int_t frameNumber = 0;
frameNumber++;
if (fNpoints >= 1) {
Int_t i;
TString fXName = TString(GetName()) + Form("_fx%d",frameNumber);
TString fYName = TString(GetName()) + Form("_fy%d",frameNumber);
out << " Double_t " << fXName << "[" << fNpoints << "] = {" << std::endl;
for (i = 0; i < fNpoints-1; i++) out << " " << fX[i] << "," << std::endl;
out << " " << fX[fNpoints-1] << "};" << std::endl;
out << " Double_t " << fYName << "[" << fNpoints << "] = {" << std::endl;
for (i = 0; i < fNpoints-1; i++) out << " " << fY[i] << "," << std::endl;
out << " " << fY[fNpoints-1] << "};" << std::endl;
if (gROOT->ClassSaved(TGraph::Class())) out << " ";
else out << " TGraph *";
out << "graph = new TGraph(" << fNpoints << "," << fXName << "," << fYName << ");" << std::endl;
} else {
if (gROOT->ClassSaved(TGraph::Class())) out << " ";
else out << " TGraph *";
out << "graph = new TGraph();" << std::endl;
}
out << " graph->SetName(" << quote << GetName() << quote << ");" << std::endl;
out << " graph->SetTitle(" << quote << GetTitle() << quote << ");" << std::endl;
SaveFillAttributes(out, "graph", 0, 1001);
SaveLineAttributes(out, "graph", 1, 1, 1);
SaveMarkerAttributes(out, "graph", 1, 1, 1);
if (fHistogram) {
TString hname = fHistogram->GetName();
hname += frameNumber;
fHistogram->SetName(Form("Graph_%s", hname.Data()));
fHistogram->SavePrimitive(out, "nodraw");
out << " graph->SetHistogram(" << fHistogram->GetName() << ");" << std::endl;
out << " " << std::endl;
}
// save list of functions
TIter next(fFunctions);
TObject *obj;
while ((obj = next())) {
obj->SavePrimitive(out, Form("nodraw #%d\n",++frameNumber));
if (obj->InheritsFrom("TPaveStats")) {
out << " graph->GetListOfFunctions()->Add(ptstats);" << std::endl;
out << " ptstats->SetParent(graph->GetListOfFunctions());" << std::endl;
} else {
out << " graph->GetListOfFunctions()->Add("
<< Form("%s%d",obj->GetName(),frameNumber) << ");" << std::endl;
}
}
const char *l;
l = strstr(option, "multigraph");
if (l) {
out << " multigraph->Add(graph," << quote << l + 10 << quote << ");" << std::endl;
return;
}
l = strstr(option, "th2poly");
if (l) {
out << " " << l + 7 << "->AddBin(graph);" << std::endl;
return;
}
out << " graph->Draw(" << quote << option << quote << ");" << std::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);
}
//______________________________________________________________________________
Int_t TGraph::GetHighlightPoint() const
{
// Return the highlighted point for the graph
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 the graph
// by default highlight mode is disable
SetBit(kIsHighlight, highlight);
TVirtualGraphPainter *painter = TVirtualGraphPainter::GetPainter();
if (painter) painter->SetHighlight(this);
}
//______________________________________________________________________________
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(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(std::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;
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);
std::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(TF1 *func, 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
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(ROOT::Fit::kGraph, 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 (!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(std::ostream &out, Option_t *option /*= ""*/)
{
// Save primitive as a C++ statement(s) on output stream out
char quote = '"';
out << " " << std::endl;
static Int_t frameNumber = 0;
frameNumber++;
if (fNpoints >= 1) {
Int_t i;
TString fXName = TString(GetName()) + Form("_fx%d",frameNumber);
TString fYName = TString(GetName()) + Form("_fy%d",frameNumber);
out << " Double_t " << fXName << "[" << fNpoints << "] = {" << std::endl;
for (i = 0; i < fNpoints-1; i++) out << " " << fX[i] << "," << std::endl;
out << " " << fX[fNpoints-1] << "};" << std::endl;
out << " Double_t " << fYName << "[" << fNpoints << "] = {" << std::endl;
for (i = 0; i < fNpoints-1; i++) out << " " << fY[i] << "," << std::endl;
out << " " << fY[fNpoints-1] << "};" << std::endl;
if (gROOT->ClassSaved(TGraph::Class())) out << " ";
else out << " TGraph *";
out << "graph = new TGraph(" << fNpoints << "," << fXName << "," << fYName << ");" << std::endl;
} else {
if (gROOT->ClassSaved(TGraph::Class())) out << " ";
else out << " TGraph *";
out << "graph = new TGraph();" << std::endl;
}
out << " graph->SetName(" << quote << GetName() << quote << ");" << std::endl;
out << " graph->SetTitle(" << quote << GetTitle() << quote << ");" << std::endl;
SaveFillAttributes(out, "graph", 0, 1001);
SaveLineAttributes(out, "graph", 1, 1, 1);
SaveMarkerAttributes(out, "graph", 1, 1, 1);
if (fHistogram) {
TString hname = fHistogram->GetName();
hname += frameNumber;
fHistogram->SetName(Form("Graph_%s", hname.Data()));
fHistogram->SavePrimitive(out, "nodraw");
out << " graph->SetHistogram(" << fHistogram->GetName() << ");" << std::endl;
out << " " << std::endl;
}
// save list of functions
TIter next(fFunctions);
TObject *obj;
while ((obj = next())) {
obj->SavePrimitive(out, Form("nodraw #%d\n",++frameNumber));
if (obj->InheritsFrom("TPaveStats")) {
out << " graph->GetListOfFunctions()->Add(ptstats);" << std::endl;
out << " ptstats->SetParent(graph->GetListOfFunctions());" << std::endl;
} else {
out << " graph->GetListOfFunctions()->Add("
<< Form("%s%d",obj->GetName(),frameNumber) << ");" << std::endl;
}
}
const char *l;
l = strstr(option, "multigraph");
if (l) {
out << " multigraph->Add(graph," << quote << l + 10 << quote << ");" << std::endl;
return;
}
l = strstr(option, "th2poly");
if (l) {
out << " " << l + 7 << "->AddBin(graph);" << std::endl;
return;
}
out << " graph->Draw(" << quote << option << quote << ");" << std::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;
}
diff --git a/hist/hist/inc/TGraph.h b/hist/hist/inc/TGraph.h
index 51496e4..c847fe4 100644
--- a/hist/hist/inc/TGraph.h
+++ b/hist/hist/inc/TGraph.h
@@ -80,7 +80,8 @@ public:
// TGraph status bits
enum {
kClipFrame = BIT(10), // clip to the frame boundary
- kNotEditable = BIT(18) // bit set if graph is non editable
+ kNotEditable = BIT(18), // bit set if graph is non editable
+ kIsHighlight = BIT(19) // bit set if graph is highlight
};
TGraph();
@@ -122,6 +123,7 @@ public:
virtual void FitPanel(); // *MENU*
Bool_t GetEditable() const;
TF1 *GetFunction(const char *name) const;
+ virtual Int_t GetHighlightPoint() const;
TH1F *GetHistogram() const;
TList *GetListOfFunctions() const { return fFunctions; }
virtual Double_t GetCorrelationFactor() const;
@@ -160,6 +162,7 @@ public:
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);
@@ -174,6 +177,7 @@ public:
virtual Int_t RemovePoint(Int_t ipoint);
virtual void SavePrimitive(std::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
virtual void SetHistogram(TH1F *h) {fHistogram = h;}
virtual void SetMaximum(Double_t maximum=-1111); // *MENU*
virtual void SetMinimum(Double_t minimum=-1111); // *MENU*
diff --git a/hist/hist/src/TGraph.cxx b/hist/hist/src/TGraph.cxx
index b9f734a..bd1482f 100644
--- a/hist/hist/src/TGraph.cxx
+++ b/hist/hist/src/TGraph.cxx
@@ -2222,6 +2222,30 @@ void TGraph::SetEditable(Bool_t editable)
//______________________________________________________________________________
+Int_t TGraph::GetHighlightPoint() const
+{
+ // Return the highlighted point for the graph
+
+ 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 the graph
+ // by default highlight mode is disable
+
+ SetBit(kIsHighlight, highlight);
+
+ TVirtualGraphPainter *painter = TVirtualGraphPainter::GetPainter();
+ if (painter) painter->SetHighlight(this);
+}
+
+
+//______________________________________________________________________________
void TGraph::SetMaximum(Double_t maximum)
{
// Set the maximum of the graph.
diff --git a/hist/hist/inc/TVirtualGraphPainter.h b/hist/hist/inc/TVirtualGraphPainter.h
index 30db223..0c98c76 100644
--- a/hist/hist/inc/TVirtualGraphPainter.h
+++ b/hist/hist/inc/TVirtualGraphPainter.h
@@ -35,6 +35,7 @@ public:
TVirtualGraphPainter() { }
virtual ~TVirtualGraphPainter() { }
+ virtual Int_t GetHighlightPointHelper(const 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;
@@ -43,6 +44,7 @@ public:
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;
static TVirtualGraphPainter *GetPainter();
static void SetPainter(TVirtualGraphPainter *painter);
diff --git a/hist/histpainter/inc/TGraphPainter.h b/hist/histpainter/inc/TGraphPainter.h
index 86c364b..8cfa3f5 100644
--- a/hist/histpainter/inc/TGraphPainter.h
+++ b/hist/histpainter/inc/TGraphPainter.h
@@ -41,6 +41,8 @@ public:
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;
+ virtual Int_t GetHighlightPointHelper(const TGraph *theGraph) const;
+ 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);
@@ -52,6 +54,7 @@ public:
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);
void Smooth(TGraph *theGraph, Int_t npoints, Double_t *x, Double_t *y, Int_t drawtype);
ClassDef(TGraphPainter,0) // TGraph painter
diff --git a/hist/histpainter/src/TGraphPainter.cxx b/hist/histpainter/src/TGraphPainter.cxx
index d918099..fb12db1 100644
--- a/hist/histpainter/src/TGraphPainter.cxx
+++ b/hist/histpainter/src/TGraphPainter.cxx
@@ -30,10 +30,14 @@
#include "TLatex.h"
#include "TArrow.h"
#include "TFrame.h"
+#include "TMarker.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);
@@ -654,11 +658,34 @@ Int_t TGraphPainter::DistancetoPrimitiveHelper(TGraph *theGraph, Int_t px, Int_t
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;
+ 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
+ }
+ }
+ if (gHighlightGraph == theGraph) distanceOld = distance;
}
if (distance < kMaxDiff) return distance;
@@ -1009,6 +1036,61 @@ char *TGraphPainter::GetObjectInfoHelper(TGraph * /*theGraph*/, Int_t /*px*/, In
//______________________________________________________________________________
+Int_t TGraphPainter::GetHighlightPointHelper(const TGraph *theGraph) const
+{
+ // Return the highlighted point for theGraph
+
+ if (theGraph == gHighlightGraph) return gHighlightPoint;
+ else return -1;
+}
+
+
+//______________________________________________________________________________
+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::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
@@ -3330,6 +3412,8 @@ void TGraphPainter::PaintGraphSimple(TGraph *theGraph, Option_t *option)
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();
diff --git a/hist/hist/inc/TGraph.h b/hist/hist/inc/TGraph.h
index f2f9809..5263351 100644
--- a/hist/hist/inc/TGraph.h
+++ b/hist/hist/inc/TGraph.h
@@ -74,13 +74,14 @@ protected:
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);
+ 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
+ kNotEditable = BIT(18), // bit set if graph is non editable
+ kIsHighlight = BIT(19) // bit set if graph is highlight
};
TGraph();
@@ -122,6 +123,7 @@ public:
virtual void FitPanel(); // *MENU*
Bool_t GetEditable() const;
TF1 *GetFunction(const char *name) const;
+ virtual Int_t GetHighlightPoint() const;
TH1F *GetHistogram() const;
TList *GetListOfFunctions() const { return fFunctions; }
virtual Double_t GetCorrelationFactor() const;
@@ -153,13 +155,14 @@ public:
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);
@@ -174,6 +177,7 @@ public:
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
virtual void SetHistogram(TH1F *h) {fHistogram = h;}
virtual void SetMaximum(Double_t maximum=-1111); // *MENU*
virtual void SetMinimum(Double_t minimum=-1111); // *MENU*
diff --git a/hist/hist/src/TGraph.cxx b/hist/hist/src/TGraph.cxx
index 54fee08..32537a7 100644
--- a/hist/hist/src/TGraph.cxx
+++ b/hist/hist/src/TGraph.cxx
@@ -2218,6 +2218,30 @@ void TGraph::SetEditable(Bool_t editable)
//______________________________________________________________________________
+Int_t TGraph::GetHighlightPoint() const
+{
+ // Return the highlighted point for the graph
+
+ 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 the graph
+ // by default highlight mode is disable
+
+ SetBit(kIsHighlight, highlight);
+
+ TVirtualGraphPainter *painter = TVirtualGraphPainter::GetPainter();
+ if (painter) painter->SetHighlight(this);
+}
+
+
+//______________________________________________________________________________
void TGraph::SetMaximum(Double_t maximum)
{
// Set the maximum of the graph.
ROOT5 = branch v5-34-00-patches (06.10.2014) ROOT6 = branch master (06.10.2014)
git diff hist/hist/inc/TVirtualGraphPainter.h hist/histpainter/inc/TGraphPainter.h hist/histpainter/src/TGraphPainter.cxx > ROOT_5_6.patch
git diff hist/hist/inc/TGraph.h hist/hist/src/TGraph.cxx > ROOT_5.patch
git diff hist/hist/inc/TGraph.h hist/hist/src/TGraph.cxx > ROOT_6.patch
git apply ROOT_5_6.patch git apply ROOT_5.patch
git apply ROOT_5_6.patch git apply ROOT_6.patch