ROOT logo
/**
 * @file   QAPlotter.C
 * @author Christian Holm Christensen <cholm@nbi.dk>
 * @date   Thu Nov 17 12:08:04 2011
 * 
 * @brief  Class to plot QA trends
 * 
 * @ingroup pwglf_forward_qa_scripts
 * 
 */
#ifndef __CINT__
# include "QABase.h"
# include <TTree.h>
# include <TGraph.h>
# include <TGraphErrors.h>
# include <TGraphAsymmErrors.h>
# include <TMultiGraph.h>
# include <TH1.h>
# include <TLegend.h>
# include <TCanvas.h>
# include <TLine.h>
# include <TArrow.h>
# include <TArrayI.h>
# include <TMath.h>
# include <TChain.h>
#else 
class QABase;
class QARing;
class TTree;
class TGraphAsymmErrors;
class TGraph;
class TGraphErrors;
class TMultiGraph;
class RingQuantity;
class TArrayI;
class TH1;
#endif


/**
 * Class to plot QA trends 
 * 
 * @ingroup pwglf_forward_qa_scripts
 */
struct QAPlotter : public QABase
{
  /**
   * Ring class 
   */
  struct Ring : public QARing
  {
    /** 
     * Constuctor
     * 
     * @param d      Detector 
     * @param r      Ring 
     * @param useVar Use variance for errors (not min/max)
     */
    Ring(UShort_t d, Char_t r, Bool_t useVar=false)
      : QARing(d, r),
        fGChi2(0),
        fGC(0),
        fGDelta(0),
        fGXi(0),
        fGSigma(0),
        fGLow(0),
        fGSingles(0),
        fGLoss(0),
        fGBeta(0),
        fGOccupancy(0),
	fUseVar(useVar)
    {
      fGChi2           = new TGraphAsymmErrors;
      fGC              = new TGraphAsymmErrors;
      fGDelta          = new TGraphAsymmErrors;
      fGXi             = new TGraphAsymmErrors;
      fGSigma          = new TGraphAsymmErrors;
      fGLow            = new TGraph;
      fGSingles        = new TGraph;
      fGLoss           = new TGraph;
      fGBeta           = new TGraph;
      fGOccupancy      = new TGraphAsymmErrors;

      SetAtt(fGChi2,		"chi2",     "#LT#chi^{2}/#nu#GT");
      SetAtt(fGC,		"c",        "Constant");
      SetAtt(fGDelta,		"delta",    "#LT#Delta_{p}#GT");
      SetAtt(fGXi,		"xi",       "#LT#xi#GT");
      SetAtt(fGSigma,		"sigma",    "#LT#sigma#GT");
      SetAtt(fGLow,		"low",      "# of low statistics bins");
      SetAtt(fGSingles,		"singles",  "Fraction of single hits");
      SetAtt(fGLoss,            "loss",     "Data lossed due to cuts");
      SetAtt(fGOccupancy,	"occupancy","#LTOccupancy#GT");
      SetAtt(fGBeta,		"beta",     "Correlation of methods");

    }
    /** 
     * Static member function to get the ring color
     * 
     * @param d Detector number
     * @param r Ring identifer 
     * 
     * @return Color
     */
    static Color_t RingColor(UShort_t d, Char_t r)
    { 
      return ((d == 1 ? kRed : (d == 2 ? kGreen : kBlue))
	      + ((r == 'I' || r == 'i') ? 2 : -3));
    }
    /** 
     * Set graph attributes
     * 
     * @param g      Graph
     * @param name   Name of graph
     */
    void SetAtt(TGraph* g, const char* name, const char* /*title=""*/) 
    {
      Color_t c = RingColor(fD, fR);
      g->SetName(Form("FMD%d%c_%s", fD, fR, name));
      // g->SetTitle(Form("FMD%d%c %s", fD, fR, 
      // !title || title[0] == '\0' ? name : title));
      Int_t marker = 20+(fD-1) + (fR == 'I' ? 0 : 4);
      g->SetTitle(Form("FMD%d%c", fD, fR));
      g->SetLineColor(c);
      g->SetFillColor(c);
      g->SetMarkerColor(c);
      g->SetMarkerStyle(marker);
      g->SetLineWidth(2);
      switch (marker) { 
      case 20: g->SetMarkerSize(1.2); break;
      case 21: g->SetMarkerSize(1.2); break;
      case 22: g->SetMarkerSize(1.3); break;
      case 26: g->SetMarkerSize(1.1); break;
      }
    }
    /** 
     * Update a graph from a RingQuantity 
     * 
     * @param g      Graph to update
     * @param q      Quantity 
     * @param runNo  Run number 
     */
    void UpdateGraph(TGraphAsymmErrors* g, RingQuantity& q, 
		     UInt_t runNo, UInt_t /* n */) 
    {
      Double_t y  = q.mean;
      Double_t el = y-q.min;
      Double_t eh = q.max-y;
      if (fUseVar) { 
	//Info("UpdateGraph", "Setting errors on %s to variance",g->GetName());
	el = q.var; 
	eh = q.var; 
      }
      if (TMath::Abs(y) < 1e-6) return;
      Int_t    i  = g->GetN();
      g->SetPoint(i, runNo, y);
      g->SetPointError(i, 0, 0, el, eh);
    }
    /** 
     * Update all graphs
     * 
     * @param n     Entry number (not used)
     * @param runNo Run number 
     * 
     * @return true on success
     */
    Bool_t Update(UInt_t n, UInt_t runNo)
    {
      UpdateGraph(fGChi2,      *fChi2, 		runNo, n);
      UpdateGraph(fGC,         *fC, 		runNo, n);
      UpdateGraph(fGDelta,     *fDelta, 	runNo, n);
      UpdateGraph(fGXi,        *fXi, 		runNo, n);
      UpdateGraph(fGSigma,     *fSigma, 	runNo, n);
      UpdateGraph(fGOccupancy, *fOccupancy, 	runNo, n);

      fGLow->SetPoint(n, runNo, fFitStatus->nLow);
      
      if (fMerge->one > 1e-6)
	fGSingles->SetPoint(fGSingles->GetN(), runNo, fMerge->one);
      if (fCorrelation->beta > 1e-6)
	fGBeta->SetPoint(fGBeta->GetN(), runNo, fCorrelation->beta);
      if (-fDataLoss->full > 1e-6)
	fGLoss->SetPoint(fGLoss->GetN(), runNo, -fDataLoss->full);
      return true;
    }
    TGraphAsymmErrors* fGChi2;	   // Graph of ELoss reduced chi-square
    TGraphAsymmErrors* fGC;	   // Graph of ELoss constant 
    TGraphAsymmErrors* fGDelta;    // Graph of ELoss MPV
    TGraphAsymmErrors* fGXi;       // Graph of ELoss Landau width
    TGraphAsymmErrors* fGSigma;    // Graph of ELoss Gaus width
    TGraph*            fGLow;      // Graph of bins with low statistics
    TGraph*            fGSingles;  // Graph of fraction of singles
    TGraph*            fGLoss;     // Graph of 'lost' data 
    TGraph*            fGBeta;     // Graph of Poisson vs ELoss correlation
    TGraphAsymmErrors* fGOccupancy;// Graph of mean occupancy              
    Bool_t             fUseVar;    // Use variance 
  };
  // =================================================================
  /** 
   * Compatiblity constructor 
   * 
   * @param prodYear    Year
   * @param prodLetter  Letter
   * @param useVar      Use variance 
   */
  QAPlotter(Long_t prodYear, Char_t prodLetter, Bool_t useVar) 
    : QABase("", (prodYear < 2000 ? 2000 : 0) + prodYear, 
	     Form("LHC%02d%c", int(prodYear % 100), prodLetter), "pass0"), 
      fNAccepted(0),
      fVz(0), 
      fUseVar(useVar)
  {
    Info("QAPlotter", "Do we use variance? %s", fUseVar ? "yes" : "no");
    fFMD1i = new Ring(1, 'I', useVar); 
    fFMD2i = new Ring(2, 'I', useVar); 
    fFMD2o = new Ring(2, 'O', useVar); 
    fFMD3i = new Ring(3, 'I', useVar); 
    fFMD3o = new Ring(3, 'O', useVar); 
    fNAccepted = new TGraph;
    fNAccepted->SetName("nAccepted");
    fNAccepted->SetMarkerStyle(20);
    fNAccepted->SetLineWidth(2);

    fVz = new TGraphErrors;
    fVz->SetName("vz");
    fVz->SetMarkerStyle(20);
    fVz->SetLineWidth(2);
  }
  /** 
   * Constructor 
   */
  QAPlotter(const TString& dataType, 
	    Int_t          year, 
	    const TString& period, 
	    const TString& pass, 
	    Bool_t         useVar=true) 
    : QABase(dataType, year, period, pass),
      fNAccepted(0),
      fVz(0),
      fUseVar(useVar)
  {
    Info("QAPlotter", "Do we use variance? %s", fUseVar ? "yes" : "no");
    fFMD1i = new Ring(1, 'I', useVar); 
    fFMD2i = new Ring(2, 'I', useVar); 
    fFMD2o = new Ring(2, 'O', useVar); 
    fFMD3i = new Ring(3, 'I', useVar); 
    fFMD3o = new Ring(3, 'O', useVar); 
    fNAccepted = new TGraph;
    fNAccepted->SetName("nAccepted");
    fNAccepted->SetMarkerStyle(20);
    fNAccepted->SetLineWidth(2);

    fVz = new TGraphErrors;
    fVz->SetName("vz");
    fVz->SetMarkerStyle(20);
    fVz->SetLineWidth(2);
  }
  /** 
   * Add a file to be processed
   * 
   * @param filename Name of file 
   */
  void AddFile(const char* filename)
  {
    fFiles.Add(new TObjString(filename));
  }
  const char* GetUserInfo(TList* l, const char* name, const char* def) const
  {
    if (!l) {
      Warning("GetUserInfo", "No user information list");
      return def;
    }
    
    TObject* o = l->FindObject(name);
    if (!o) {
      Warning("GetUserInfo", "User information %s not found", name);
      l->ls();
      return def;
    }

    Info("GetUserInfo", "Got user information %s=%s", name, o->GetTitle());
    return o->GetTitle();
  }
  /** 
   * Make a tree 
   * 
   * @param read If true, read from file 
   * 
   * @return True on success 
   */
  Bool_t MakeTree(bool read)
  {
    if (fFiles.GetEntriesFast() <= 0) return QABase::MakeTree(read);
    if (fFiles.GetEntriesFast() == 1 && read) {
      TFile* file = TFile::Open(fFiles.At(0)->GetName(), "READ");
      if (file) {
	fTree       = static_cast<TTree*>(file->Get("T"));
	return true;
      }
    }
    TChain* chain = new TChain("T", "T");
    if (!chain->AddFileInfoList(&fFiles)) return false;
    
    fTree   = chain;
    
    return true;
  }

  /** 
   * Run the job
   * 
   */
  void Run()
  {
    Init(true);
    if (!fTree) {
      Error("Run", "No input tree");
      return;
    }
    fFirst = 0xFFFFFFFF;
    fLast  = 0;

    UInt_t nEntries = fTree->GetEntries();
    UInt_t j = 0;
    fRuns.Set(nEntries);
    Info("Run", "Got %d runs", nEntries);
    TList* l = fTree->GetUserInfo();
    fPeriod   = GetUserInfo(l, "period", "?");
    fPass     = GetUserInfo(l, "pass",   "?");
    fDataType = GetUserInfo(l, "type",   "?");
      

    for (UInt_t i = 0; i < nEntries; i++) {
      fTree->GetEntry(i);

      UInt_t run = fGlobal->runNo;
      UInt_t nev = fGlobal->nAccepted;

      fFirst = TMath::Min(run, fFirst);
      fLast  = TMath::Max(run, fLast);
      fRuns[i] = run;

      Info("Run", "Got run %d with %d accepted events", run, nev);
      fNAccepted->SetPoint(i, run, nev);
      fVz->SetPoint(i, run, fGlobal->meanVz);
      fVz->SetPointError(i, 0, fGlobal->sigmaVz);

      if (nev <= 100) continue;
      static_cast<Ring*>(fFMD1i)->Update(j, run);
      static_cast<Ring*>(fFMD2i)->Update(j, run);
      static_cast<Ring*>(fFMD2o)->Update(j, run);
      static_cast<Ring*>(fFMD3i)->Update(j, run);
      static_cast<Ring*>(fFMD3o)->Update(j, run);
      j++;
    }
    
    Plot();
  }
  /** 
   * Plot results
   * 
   */
  void Plot()
  {
    // fTeXName = Form("trend_%09d_%09d", fFirst, fLast);
    TString title;
    if (!fPeriod.IsNull() && !fPass.IsNull()) 
      title.Form("QA trends for %s/%s runs %d --- %d", 
		 fPeriod.Data(), fPass.Data(), fFirst, fLast);
    else
      title.Form("QA trends for runs %d --- %d", fFirst, fLast);
    MakeCanvas(title);

    CanvasTitle("# of accepted events");
    fNAccepted->Draw("apl");
    PutCanvasTitle("# of accepted events");
    AddRuns(fNAccepted->GetHistogram(), "# of accepted events");

    TLine* l = new TLine(fFirst, 100, fLast, 100);
    l->SetLineColor(kRed+2);
    l->SetLineStyle(2);
    l->Draw();
    PrintCanvas("nAccepted");

    CanvasTitle("#LTv_{z}#GT");
    fVz->Draw("apl");
    PutCanvasTitle("Mean z coordinate of interaction point");
    AddRuns(fVz->GetHistogram(), "#LTv_{z}#GT");
    PrintCanvas("vz");

    TMultiGraph* chi2		= new TMultiGraph;		
    TMultiGraph* c		= new TMultiGraph;		
    TMultiGraph* delta		= new TMultiGraph;		
    TMultiGraph* xi		= new TMultiGraph;		
    TMultiGraph* sigma		= new TMultiGraph;		
    TMultiGraph* low		= new TMultiGraph;		
    TMultiGraph* singles	= new TMultiGraph;	
    TMultiGraph* loss           = new TMultiGraph;
    TMultiGraph* occ	= new TMultiGraph;	
    TMultiGraph* beta		= new TMultiGraph;		
    chi2	->SetName("chi2");	       
    c		->SetName("c");		       
    delta	->SetName("delta");	       
    xi		->SetName("xi");	       
    sigma	->SetName("sigma");	       
    low		->SetName("low");	       
    singles	->SetName("singles");    
    loss        ->SetName("loss");
    beta	->SetName("beta");          
    occ	->SetName("occupancy");


    AddToMulti(fFMD1i,chi2, c, delta, xi, sigma, low, singles, loss, beta, occ);
    AddToMulti(fFMD2i,chi2, c, delta, xi, sigma, low, singles, loss, beta, occ);
    AddToMulti(fFMD2o,chi2, c, delta, xi, sigma, low, singles, loss, beta, occ);
    AddToMulti(fFMD3i,chi2, c, delta, xi, sigma, low, singles, loss, beta, occ);
    AddToMulti(fFMD3o,chi2, c, delta, xi, sigma, low, singles, loss, beta, occ);

    PlotMulti(chi2, 	"#LT#chi^{2}/#nu#GT from #Delta fits", true);
    PlotMulti(c, 	"#LTc#GT from #Delta fits");
    PlotMulti(delta, 	"#LT#Delta_{p}#GT from #Delta fits");
    PlotMulti(xi, 	"#LT#xi#GT from #Delta fits");
    PlotMulti(sigma, 	"#LT#sigma#GT from #Delta fits");
    PlotMulti(low, 	"Bins with too low statistics");
    PlotMulti(singles, 	"Fraction of single hits");
    PlotMulti(loss,     "% of hits 'lost' due to merging+cuts");
    PlotMulti(occ,      "#LTOccupancy#GT [%]", true);
    PlotMulti(beta, 	"Correlation of methods");

    fStore->cd();
    fNAccepted->Write();
    chi2->Write();
    c->Write();
    delta->Write();
    sigma->Write();
    low->Write();
    singles->Write();
    loss->Write();
    occ->Write();
    beta->Write();

    std::ofstream doc(".doc");
    doc << fPeriod << " " << fPass << " ("
	<< fDataType << ")" << std::endl;
    doc.close();

    Close(false); // Do not delete PNGs
  }
  /** 
   * Add graphs from a ring to the multi graphs
   * 
   * @param qr        Ring
   * @param chi2      ELoss reduced chi-square	   
   * @param c 	      ELoss constant 		   
   * @param delta     ELoss MPV		   
   * @param xi 	      ELoss Landau width	   
   * @param sigma     ELoss Gaus width		   
   * @param low       bins with low statistics	   
   * @param singles   fraction of singles	   
   * @param loss      'lost' data 		   
   * @param beta      Poisson vs ELoss correlation
   * @param occupancy mean occupancy              
   */
  void AddToMulti(QARing* qr, 
		  TMultiGraph* chi2,
		  TMultiGraph* c,
		  TMultiGraph* delta,
		  TMultiGraph* xi,
		  TMultiGraph* sigma,
		  TMultiGraph* low,
		  TMultiGraph* singles,
		  TMultiGraph* loss,
		  TMultiGraph* beta,
		  TMultiGraph* occupancy)
  {
    Ring* r = static_cast<Ring*>(qr);
    chi2	->Add(r->fGChi2);
    c		->Add(r->fGC);
    delta	->Add(r->fGDelta);
    xi		->Add(r->fGXi);
    sigma	->Add(r->fGSigma);
    low		->Add(r->fGLow);
    singles	->Add(r->fGSingles);
    loss        ->Add(r->fGLoss);
    occupancy	->Add(r->fGOccupancy);
    beta	->Add(r->fGBeta);
  }
  /** 
   * Plot a multi-graph
   * 
   * @param mg     Multi graph
   * @param title  Title
   * @param logy   If true, make @f$\log@f$ scale 
   */
  void PlotMulti(TMultiGraph* mg, const char* title, Bool_t logy=false)
  {
    CanvasTitle(title);
    // fCanvas->SetBottomMargin(.15);
    fCanvas->SetLeftMargin(.08);
    fCanvas->SetTopMargin(.1);
    fCanvas->SetLogy(logy);
    // fCanvas->SetRightMargin(.2);
    mg->Draw("apl");
    
    TH1*     h   = mg->GetHistogram();
    Double_t max = h->GetMaximum();
    Double_t min = h->GetMinimum();
    if (h->GetMinimum() == 0) {
      min = min - .1*(max-min);
      h->SetMinimum(min);
    }
    Int_t    x1  = h->GetXaxis()->GetXmin();
    Int_t    x2  = h->GetXaxis()->GetXmax();
    
    TLegend* l = new TLegend(.1, .91, .97, .95);
    l->SetNColumns(5);
    l->SetFillColor(0);
    l->SetFillStyle(0);
    l->SetBorderSize(0);
    l->SetTextFont(42);
    TIter next(mg->GetListOfGraphs());
    mg->GetListOfGraphs();
    TGraph* g = 0;

    // Get the runs we have here 
    TArrayI runs(fRuns.GetSize());
    runs.Reset(INT_MAX);
    Int_t   j = 0;
    while ((g = static_cast<TGraph*>(next()))) { 
      l->AddEntry(g, g->GetTitle(), "lp");
      Double_t* xs = g->GetX();
      Int_t     n  = g->GetN();
      for (Int_t i = 0; i < n; i++) {
	if (FindRun(runs, Int_t(xs[i])) >= 0) continue;
	runs.SetAt(xs[i], j++);
      }
      Double_t ymean = g->GetMean(2);
      Double_t xh    = x2 - .03 * Double_t(x2-x1); 
      TLine* lm = new TLine(x1, ymean, xh, ymean);
      lm->SetLineColor(g->GetLineColor());
      lm->SetLineStyle(2);
      lm->SetLineWidth(1);
      lm->Draw();
      TLatex* al = new TLatex(xh, ymean, g->GetTitle());
      al->SetTextColor(g->GetLineColor());
      al->SetTextFont(42);
      al->SetTextSize(.02);
      al->SetTextAlign(12);
      al->Draw();
    }
    l->Draw();

    TList areas;
    areas.SetOwner();
    AddRuns(h, title, &runs, &areas);

    PrintCanvas(mg->GetName(), &areas);
  }
  /** 
   * Find a run 
   * 
   * @param runs List of runs 
   * @param run  Run to find
   * 
   * @return Index of run in run list
   */
  Int_t FindRun(const TArrayI& runs, Int_t run) 
  {
    std::sort(&(runs.fArray[0]), &(runs.fArray[runs.GetSize()]));
    Int_t idx = TMath::BinarySearch(runs.GetSize(), runs.fArray, run);
    if (idx >= runs.GetSize() || idx < 0 || runs[idx] != run) return -1;
    return idx;
  }
  /** 
   * Add run labels at appropriate places on the plot
   * 
   * @param h      Frame histogram
   * @param title  Title 
   * @param runs   List of runs, if any
   * @param areas  Other areas 
   */
  void AddRuns(TH1* h, const char* title, TArrayI* runs=0, 
	       TList* areas=0)
  {
    h->GetXaxis()->SetNoExponent();
    // h->GetXaxis()->SetTitleOffset(1);
    TString ytitle(title);
    if (fUseVar) ytitle.Append(" (errors: variance)");
    else         ytitle.Append(" (errors: min/max)");
    h->SetYTitle(ytitle.Data());
    h->SetXTitle("Run #");
    // Info("AddRuns", "%s: %s vs %s", h->GetName(), 
    //      h->GetXaxis()->GetTitle(), h->GetYaxis()->GetTitle());
  
    Int_t    r1  = h->GetXaxis()->GetXmin();
    Int_t    r2  = h->GetXaxis()->GetXmax();
    Double_t lx  = 0;
    Double_t tx  = .025; // (r2 - r1) / 18;
    Double_t wx  = 1 - fCanvas->GetLeftMargin() - fCanvas->GetRightMargin();
    Double_t dy  = .025;
    Double_t y   = fCanvas->GetBottomMargin()+dy;
    for (Int_t i = 0; i < fRuns.GetSize(); i++) {
      Int_t    r = fRuns[i];
      Double_t x = fCanvas->GetLeftMargin() + wx*Double_t(r-r1)/(r2-r1);

      // Skip runs out of range 
      if (r < r1 || r > r2) continue;

      // Skip runs not in the graphs 
      if (runs) {
	if (FindRun(*runs, r) < 0) { 
	  continue;
	}
      }
	  

      if (TMath::Abs(x - lx) < tx) y += dy;
      else                         y =  fCanvas->GetBottomMargin() + dy;


      // Info(h->GetName(), "%6d (x,y)=(%12f,%12f) |lx-x|=|%f-x|=%f", 
      //      r, x, y, lx, TMath::Abs(lx-x));
      lx = x;
      
      Double_t* xa = fNAccepted->GetX();
      Int_t     na = fNAccepted->GetN();
      Int_t idx = TMath::BinarySearch(na, xa, Double_t(r));
      Color_t color = kBlue+3;
      if (idx >= 0  && idx < na  && r == xa[idx] && 
	  fNAccepted->GetY()[idx] < 10000) 
	color = kRed+3;

      TLatex* ll = new TLatex(x, y, Form("%d", r));
      ll->SetNDC();
      ll->SetTextAlign(21);
      ll->SetTextSize(0.02);
      ll->SetTextColor(color);
      ll->SetTextFont(42);
      // ll->SetTextAngle(90);
      ll->Draw();
      TLine* tl = new TLine(x, y, x, 1-fCanvas->GetTopMargin());
      tl->SetBit(TLine::kLineNDC);
      tl->SetLineStyle(3);
      tl->SetLineColor(color);
      tl->Draw();

      if (!areas) continue;
      
      TObjString* area = new TObjString;
      TString&    spec = area->String();
      spec.Form("<span style=\"left: %d%%; bottom: %d%%;\" "
		"onClick='window.location=\"%09d/index.html\"' "
		"onMouseOver='this.style.cursor=\"pointer\"' "
		"alt=\"%d\""
		">%d</span>",
		UInt_t(100*x)-2, UInt_t(100*y), r, r, r);
      
#if 0
      spec.Form("<area shape='rect' alt='%d' title='%d' href='qa_%09d.html' "
		"coords='%d,%d,%d,%d'>", r, r, r, 
		UInt_t(cw*(x-tx)), 0, UInt_t(cw*(x+tx)), ch);
#endif
      areas->Add(area);
    }
  }
  /** 
   * Output list of runs 
   * 
   * @param o Output stream
   */
  void WriteRuns(std::ostream& o)
  {
    o << "<div class='jobid'><!--JOBID--></div>\n"
      << "<div class='runs'>\n"
      << "  Runs:<br> ";
    for (Int_t i = 0; i < fRuns.GetSize(); i++) {
      o << "<a href='" << Form("%09d", fRuns[i]) << "/index.html'>"
	<< fRuns[i] << "</a> " << std::flush;
    }
    o << "\n"
      << "</div>" << std::endl;
  }
  /** 
   * Write page footer 
   * 
   */
  void WriteFooter()
  {
    WriteRuns(*fHtml);
    QABase::WriteFooter();
  }
  /** 
   * Write out image footer 
   * 
   * @param o Output stream
   * @param pngName Name of the PNG file 
   */
  void WriteImageFooter(std::ostream& o, const char* pngName)
  {
    WriteRuns(o);
    QABase::WriteImageFooter(o, pngName);
  }
  TGraph*       fNAccepted; // Graph of number of accepted events
  TGraphErrors* fVz;        // Graph of mean vertex
  UInt_t        fFirst;     // First run
  UInt_t        fLast;      // Last run
  TArrayI       fRuns;      // Seen runs 
  TObjArray     fFiles;
  Bool_t        fUseVar;    // Use variance rather than min/max 
};
 
//
// EOF
//

  
  
 QAPlotter.C:1
 QAPlotter.C:2
 QAPlotter.C:3
 QAPlotter.C:4
 QAPlotter.C:5
 QAPlotter.C:6
 QAPlotter.C:7
 QAPlotter.C:8
 QAPlotter.C:9
 QAPlotter.C:10
 QAPlotter.C:11
 QAPlotter.C:12
 QAPlotter.C:13
 QAPlotter.C:14
 QAPlotter.C:15
 QAPlotter.C:16
 QAPlotter.C:17
 QAPlotter.C:18
 QAPlotter.C:19
 QAPlotter.C:20
 QAPlotter.C:21
 QAPlotter.C:22
 QAPlotter.C:23
 QAPlotter.C:24
 QAPlotter.C:25
 QAPlotter.C:26
 QAPlotter.C:27
 QAPlotter.C:28
 QAPlotter.C:29
 QAPlotter.C:30
 QAPlotter.C:31
 QAPlotter.C:32
 QAPlotter.C:33
 QAPlotter.C:34
 QAPlotter.C:35
 QAPlotter.C:36
 QAPlotter.C:37
 QAPlotter.C:38
 QAPlotter.C:39
 QAPlotter.C:40
 QAPlotter.C:41
 QAPlotter.C:42
 QAPlotter.C:43
 QAPlotter.C:44
 QAPlotter.C:45
 QAPlotter.C:46
 QAPlotter.C:47
 QAPlotter.C:48
 QAPlotter.C:49
 QAPlotter.C:50
 QAPlotter.C:51
 QAPlotter.C:52
 QAPlotter.C:53
 QAPlotter.C:54
 QAPlotter.C:55
 QAPlotter.C:56
 QAPlotter.C:57
 QAPlotter.C:58
 QAPlotter.C:59
 QAPlotter.C:60
 QAPlotter.C:61
 QAPlotter.C:62
 QAPlotter.C:63
 QAPlotter.C:64
 QAPlotter.C:65
 QAPlotter.C:66
 QAPlotter.C:67
 QAPlotter.C:68
 QAPlotter.C:69
 QAPlotter.C:70
 QAPlotter.C:71
 QAPlotter.C:72
 QAPlotter.C:73
 QAPlotter.C:74
 QAPlotter.C:75
 QAPlotter.C:76
 QAPlotter.C:77
 QAPlotter.C:78
 QAPlotter.C:79
 QAPlotter.C:80
 QAPlotter.C:81
 QAPlotter.C:82
 QAPlotter.C:83
 QAPlotter.C:84
 QAPlotter.C:85
 QAPlotter.C:86
 QAPlotter.C:87
 QAPlotter.C:88
 QAPlotter.C:89
 QAPlotter.C:90
 QAPlotter.C:91
 QAPlotter.C:92
 QAPlotter.C:93
 QAPlotter.C:94
 QAPlotter.C:95
 QAPlotter.C:96
 QAPlotter.C:97
 QAPlotter.C:98
 QAPlotter.C:99
 QAPlotter.C:100
 QAPlotter.C:101
 QAPlotter.C:102
 QAPlotter.C:103
 QAPlotter.C:104
 QAPlotter.C:105
 QAPlotter.C:106
 QAPlotter.C:107
 QAPlotter.C:108
 QAPlotter.C:109
 QAPlotter.C:110
 QAPlotter.C:111
 QAPlotter.C:112
 QAPlotter.C:113
 QAPlotter.C:114
 QAPlotter.C:115
 QAPlotter.C:116
 QAPlotter.C:117
 QAPlotter.C:118
 QAPlotter.C:119
 QAPlotter.C:120
 QAPlotter.C:121
 QAPlotter.C:122
 QAPlotter.C:123
 QAPlotter.C:124
 QAPlotter.C:125
 QAPlotter.C:126
 QAPlotter.C:127
 QAPlotter.C:128
 QAPlotter.C:129
 QAPlotter.C:130
 QAPlotter.C:131
 QAPlotter.C:132
 QAPlotter.C:133
 QAPlotter.C:134
 QAPlotter.C:135
 QAPlotter.C:136
 QAPlotter.C:137
 QAPlotter.C:138
 QAPlotter.C:139
 QAPlotter.C:140
 QAPlotter.C:141
 QAPlotter.C:142
 QAPlotter.C:143
 QAPlotter.C:144
 QAPlotter.C:145
 QAPlotter.C:146
 QAPlotter.C:147
 QAPlotter.C:148
 QAPlotter.C:149
 QAPlotter.C:150
 QAPlotter.C:151
 QAPlotter.C:152
 QAPlotter.C:153
 QAPlotter.C:154
 QAPlotter.C:155
 QAPlotter.C:156
 QAPlotter.C:157
 QAPlotter.C:158
 QAPlotter.C:159
 QAPlotter.C:160
 QAPlotter.C:161
 QAPlotter.C:162
 QAPlotter.C:163
 QAPlotter.C:164
 QAPlotter.C:165
 QAPlotter.C:166
 QAPlotter.C:167
 QAPlotter.C:168
 QAPlotter.C:169
 QAPlotter.C:170
 QAPlotter.C:171
 QAPlotter.C:172
 QAPlotter.C:173
 QAPlotter.C:174
 QAPlotter.C:175
 QAPlotter.C:176
 QAPlotter.C:177
 QAPlotter.C:178
 QAPlotter.C:179
 QAPlotter.C:180
 QAPlotter.C:181
 QAPlotter.C:182
 QAPlotter.C:183
 QAPlotter.C:184
 QAPlotter.C:185
 QAPlotter.C:186
 QAPlotter.C:187
 QAPlotter.C:188
 QAPlotter.C:189
 QAPlotter.C:190
 QAPlotter.C:191
 QAPlotter.C:192
 QAPlotter.C:193
 QAPlotter.C:194
 QAPlotter.C:195
 QAPlotter.C:196
 QAPlotter.C:197
 QAPlotter.C:198
 QAPlotter.C:199
 QAPlotter.C:200
 QAPlotter.C:201
 QAPlotter.C:202
 QAPlotter.C:203
 QAPlotter.C:204
 QAPlotter.C:205
 QAPlotter.C:206
 QAPlotter.C:207
 QAPlotter.C:208
 QAPlotter.C:209
 QAPlotter.C:210
 QAPlotter.C:211
 QAPlotter.C:212
 QAPlotter.C:213
 QAPlotter.C:214
 QAPlotter.C:215
 QAPlotter.C:216
 QAPlotter.C:217
 QAPlotter.C:218
 QAPlotter.C:219
 QAPlotter.C:220
 QAPlotter.C:221
 QAPlotter.C:222
 QAPlotter.C:223
 QAPlotter.C:224
 QAPlotter.C:225
 QAPlotter.C:226
 QAPlotter.C:227
 QAPlotter.C:228
 QAPlotter.C:229
 QAPlotter.C:230
 QAPlotter.C:231
 QAPlotter.C:232
 QAPlotter.C:233
 QAPlotter.C:234
 QAPlotter.C:235
 QAPlotter.C:236
 QAPlotter.C:237
 QAPlotter.C:238
 QAPlotter.C:239
 QAPlotter.C:240
 QAPlotter.C:241
 QAPlotter.C:242
 QAPlotter.C:243
 QAPlotter.C:244
 QAPlotter.C:245
 QAPlotter.C:246
 QAPlotter.C:247
 QAPlotter.C:248
 QAPlotter.C:249
 QAPlotter.C:250
 QAPlotter.C:251
 QAPlotter.C:252
 QAPlotter.C:253
 QAPlotter.C:254
 QAPlotter.C:255
 QAPlotter.C:256
 QAPlotter.C:257
 QAPlotter.C:258
 QAPlotter.C:259
 QAPlotter.C:260
 QAPlotter.C:261
 QAPlotter.C:262
 QAPlotter.C:263
 QAPlotter.C:264
 QAPlotter.C:265
 QAPlotter.C:266
 QAPlotter.C:267
 QAPlotter.C:268
 QAPlotter.C:269
 QAPlotter.C:270
 QAPlotter.C:271
 QAPlotter.C:272
 QAPlotter.C:273
 QAPlotter.C:274
 QAPlotter.C:275
 QAPlotter.C:276
 QAPlotter.C:277
 QAPlotter.C:278
 QAPlotter.C:279
 QAPlotter.C:280
 QAPlotter.C:281
 QAPlotter.C:282
 QAPlotter.C:283
 QAPlotter.C:284
 QAPlotter.C:285
 QAPlotter.C:286
 QAPlotter.C:287
 QAPlotter.C:288
 QAPlotter.C:289
 QAPlotter.C:290
 QAPlotter.C:291
 QAPlotter.C:292
 QAPlotter.C:293
 QAPlotter.C:294
 QAPlotter.C:295
 QAPlotter.C:296
 QAPlotter.C:297
 QAPlotter.C:298
 QAPlotter.C:299
 QAPlotter.C:300
 QAPlotter.C:301
 QAPlotter.C:302
 QAPlotter.C:303
 QAPlotter.C:304
 QAPlotter.C:305
 QAPlotter.C:306
 QAPlotter.C:307
 QAPlotter.C:308
 QAPlotter.C:309
 QAPlotter.C:310
 QAPlotter.C:311
 QAPlotter.C:312
 QAPlotter.C:313
 QAPlotter.C:314
 QAPlotter.C:315
 QAPlotter.C:316
 QAPlotter.C:317
 QAPlotter.C:318
 QAPlotter.C:319
 QAPlotter.C:320
 QAPlotter.C:321
 QAPlotter.C:322
 QAPlotter.C:323
 QAPlotter.C:324
 QAPlotter.C:325
 QAPlotter.C:326
 QAPlotter.C:327
 QAPlotter.C:328
 QAPlotter.C:329
 QAPlotter.C:330
 QAPlotter.C:331
 QAPlotter.C:332
 QAPlotter.C:333
 QAPlotter.C:334
 QAPlotter.C:335
 QAPlotter.C:336
 QAPlotter.C:337
 QAPlotter.C:338
 QAPlotter.C:339
 QAPlotter.C:340
 QAPlotter.C:341
 QAPlotter.C:342
 QAPlotter.C:343
 QAPlotter.C:344
 QAPlotter.C:345
 QAPlotter.C:346
 QAPlotter.C:347
 QAPlotter.C:348
 QAPlotter.C:349
 QAPlotter.C:350
 QAPlotter.C:351
 QAPlotter.C:352
 QAPlotter.C:353
 QAPlotter.C:354
 QAPlotter.C:355
 QAPlotter.C:356
 QAPlotter.C:357
 QAPlotter.C:358
 QAPlotter.C:359
 QAPlotter.C:360
 QAPlotter.C:361
 QAPlotter.C:362
 QAPlotter.C:363
 QAPlotter.C:364
 QAPlotter.C:365
 QAPlotter.C:366
 QAPlotter.C:367
 QAPlotter.C:368
 QAPlotter.C:369
 QAPlotter.C:370
 QAPlotter.C:371
 QAPlotter.C:372
 QAPlotter.C:373
 QAPlotter.C:374
 QAPlotter.C:375
 QAPlotter.C:376
 QAPlotter.C:377
 QAPlotter.C:378
 QAPlotter.C:379
 QAPlotter.C:380
 QAPlotter.C:381
 QAPlotter.C:382
 QAPlotter.C:383
 QAPlotter.C:384
 QAPlotter.C:385
 QAPlotter.C:386
 QAPlotter.C:387
 QAPlotter.C:388
 QAPlotter.C:389
 QAPlotter.C:390
 QAPlotter.C:391
 QAPlotter.C:392
 QAPlotter.C:393
 QAPlotter.C:394
 QAPlotter.C:395
 QAPlotter.C:396
 QAPlotter.C:397
 QAPlotter.C:398
 QAPlotter.C:399
 QAPlotter.C:400
 QAPlotter.C:401
 QAPlotter.C:402
 QAPlotter.C:403
 QAPlotter.C:404
 QAPlotter.C:405
 QAPlotter.C:406
 QAPlotter.C:407
 QAPlotter.C:408
 QAPlotter.C:409
 QAPlotter.C:410
 QAPlotter.C:411
 QAPlotter.C:412
 QAPlotter.C:413
 QAPlotter.C:414
 QAPlotter.C:415
 QAPlotter.C:416
 QAPlotter.C:417
 QAPlotter.C:418
 QAPlotter.C:419
 QAPlotter.C:420
 QAPlotter.C:421
 QAPlotter.C:422
 QAPlotter.C:423
 QAPlotter.C:424
 QAPlotter.C:425
 QAPlotter.C:426
 QAPlotter.C:427
 QAPlotter.C:428
 QAPlotter.C:429
 QAPlotter.C:430
 QAPlotter.C:431
 QAPlotter.C:432
 QAPlotter.C:433
 QAPlotter.C:434
 QAPlotter.C:435
 QAPlotter.C:436
 QAPlotter.C:437
 QAPlotter.C:438
 QAPlotter.C:439
 QAPlotter.C:440
 QAPlotter.C:441
 QAPlotter.C:442
 QAPlotter.C:443
 QAPlotter.C:444
 QAPlotter.C:445
 QAPlotter.C:446
 QAPlotter.C:447
 QAPlotter.C:448
 QAPlotter.C:449
 QAPlotter.C:450
 QAPlotter.C:451
 QAPlotter.C:452
 QAPlotter.C:453
 QAPlotter.C:454
 QAPlotter.C:455
 QAPlotter.C:456
 QAPlotter.C:457
 QAPlotter.C:458
 QAPlotter.C:459
 QAPlotter.C:460
 QAPlotter.C:461
 QAPlotter.C:462
 QAPlotter.C:463
 QAPlotter.C:464
 QAPlotter.C:465
 QAPlotter.C:466
 QAPlotter.C:467
 QAPlotter.C:468
 QAPlotter.C:469
 QAPlotter.C:470
 QAPlotter.C:471
 QAPlotter.C:472
 QAPlotter.C:473
 QAPlotter.C:474
 QAPlotter.C:475
 QAPlotter.C:476
 QAPlotter.C:477
 QAPlotter.C:478
 QAPlotter.C:479
 QAPlotter.C:480
 QAPlotter.C:481
 QAPlotter.C:482
 QAPlotter.C:483
 QAPlotter.C:484
 QAPlotter.C:485
 QAPlotter.C:486
 QAPlotter.C:487
 QAPlotter.C:488
 QAPlotter.C:489
 QAPlotter.C:490
 QAPlotter.C:491
 QAPlotter.C:492
 QAPlotter.C:493
 QAPlotter.C:494
 QAPlotter.C:495
 QAPlotter.C:496
 QAPlotter.C:497
 QAPlotter.C:498
 QAPlotter.C:499
 QAPlotter.C:500
 QAPlotter.C:501
 QAPlotter.C:502
 QAPlotter.C:503
 QAPlotter.C:504
 QAPlotter.C:505
 QAPlotter.C:506
 QAPlotter.C:507
 QAPlotter.C:508
 QAPlotter.C:509
 QAPlotter.C:510
 QAPlotter.C:511
 QAPlotter.C:512
 QAPlotter.C:513
 QAPlotter.C:514
 QAPlotter.C:515
 QAPlotter.C:516
 QAPlotter.C:517
 QAPlotter.C:518
 QAPlotter.C:519
 QAPlotter.C:520
 QAPlotter.C:521
 QAPlotter.C:522
 QAPlotter.C:523
 QAPlotter.C:524
 QAPlotter.C:525
 QAPlotter.C:526
 QAPlotter.C:527
 QAPlotter.C:528
 QAPlotter.C:529
 QAPlotter.C:530
 QAPlotter.C:531
 QAPlotter.C:532
 QAPlotter.C:533
 QAPlotter.C:534
 QAPlotter.C:535
 QAPlotter.C:536
 QAPlotter.C:537
 QAPlotter.C:538
 QAPlotter.C:539
 QAPlotter.C:540
 QAPlotter.C:541
 QAPlotter.C:542
 QAPlotter.C:543
 QAPlotter.C:544
 QAPlotter.C:545
 QAPlotter.C:546
 QAPlotter.C:547
 QAPlotter.C:548
 QAPlotter.C:549
 QAPlotter.C:550
 QAPlotter.C:551
 QAPlotter.C:552
 QAPlotter.C:553
 QAPlotter.C:554
 QAPlotter.C:555
 QAPlotter.C:556
 QAPlotter.C:557
 QAPlotter.C:558
 QAPlotter.C:559
 QAPlotter.C:560
 QAPlotter.C:561
 QAPlotter.C:562
 QAPlotter.C:563
 QAPlotter.C:564
 QAPlotter.C:565
 QAPlotter.C:566
 QAPlotter.C:567
 QAPlotter.C:568
 QAPlotter.C:569
 QAPlotter.C:570
 QAPlotter.C:571
 QAPlotter.C:572
 QAPlotter.C:573
 QAPlotter.C:574
 QAPlotter.C:575
 QAPlotter.C:576
 QAPlotter.C:577
 QAPlotter.C:578
 QAPlotter.C:579
 QAPlotter.C:580
 QAPlotter.C:581
 QAPlotter.C:582
 QAPlotter.C:583
 QAPlotter.C:584
 QAPlotter.C:585
 QAPlotter.C:586
 QAPlotter.C:587
 QAPlotter.C:588
 QAPlotter.C:589
 QAPlotter.C:590
 QAPlotter.C:591
 QAPlotter.C:592
 QAPlotter.C:593
 QAPlotter.C:594
 QAPlotter.C:595
 QAPlotter.C:596
 QAPlotter.C:597
 QAPlotter.C:598
 QAPlotter.C:599
 QAPlotter.C:600
 QAPlotter.C:601
 QAPlotter.C:602
 QAPlotter.C:603
 QAPlotter.C:604
 QAPlotter.C:605
 QAPlotter.C:606
 QAPlotter.C:607
 QAPlotter.C:608
 QAPlotter.C:609
 QAPlotter.C:610
 QAPlotter.C:611
 QAPlotter.C:612
 QAPlotter.C:613
 QAPlotter.C:614
 QAPlotter.C:615
 QAPlotter.C:616
 QAPlotter.C:617
 QAPlotter.C:618
 QAPlotter.C:619
 QAPlotter.C:620
 QAPlotter.C:621
 QAPlotter.C:622
 QAPlotter.C:623
 QAPlotter.C:624
 QAPlotter.C:625
 QAPlotter.C:626
 QAPlotter.C:627
 QAPlotter.C:628
 QAPlotter.C:629
 QAPlotter.C:630
 QAPlotter.C:631
 QAPlotter.C:632
 QAPlotter.C:633
 QAPlotter.C:634
 QAPlotter.C:635
 QAPlotter.C:636
 QAPlotter.C:637
 QAPlotter.C:638
 QAPlotter.C:639
 QAPlotter.C:640
 QAPlotter.C:641
 QAPlotter.C:642
 QAPlotter.C:643
 QAPlotter.C:644
 QAPlotter.C:645
 QAPlotter.C:646
 QAPlotter.C:647
 QAPlotter.C:648
 QAPlotter.C:649
 QAPlotter.C:650
 QAPlotter.C:651
 QAPlotter.C:652
 QAPlotter.C:653
 QAPlotter.C:654
 QAPlotter.C:655
 QAPlotter.C:656
 QAPlotter.C:657
 QAPlotter.C:658
 QAPlotter.C:659
 QAPlotter.C:660
 QAPlotter.C:661
 QAPlotter.C:662
 QAPlotter.C:663
 QAPlotter.C:664
 QAPlotter.C:665
 QAPlotter.C:666
 QAPlotter.C:667
 QAPlotter.C:668
 QAPlotter.C:669
 QAPlotter.C:670
 QAPlotter.C:671
 QAPlotter.C:672
 QAPlotter.C:673
 QAPlotter.C:674
 QAPlotter.C:675
 QAPlotter.C:676
 QAPlotter.C:677
 QAPlotter.C:678
 QAPlotter.C:679
 QAPlotter.C:680
 QAPlotter.C:681
 QAPlotter.C:682
 QAPlotter.C:683
 QAPlotter.C:684
 QAPlotter.C:685
 QAPlotter.C:686
 QAPlotter.C:687
 QAPlotter.C:688
 QAPlotter.C:689
 QAPlotter.C:690
 QAPlotter.C:691
 QAPlotter.C:692
 QAPlotter.C:693
 QAPlotter.C:694
 QAPlotter.C:695
 QAPlotter.C:696
 QAPlotter.C:697
 QAPlotter.C:698
 QAPlotter.C:699
 QAPlotter.C:700
 QAPlotter.C:701
 QAPlotter.C:702
 QAPlotter.C:703
 QAPlotter.C:704
 QAPlotter.C:705
 QAPlotter.C:706
 QAPlotter.C:707
 QAPlotter.C:708
 QAPlotter.C:709
 QAPlotter.C:710
 QAPlotter.C:711
 QAPlotter.C:712
 QAPlotter.C:713
 QAPlotter.C:714
 QAPlotter.C:715
 QAPlotter.C:716
 QAPlotter.C:717