00001
00002
00003
00004 #include <algorithm>
00005 #include <cassert>
00006 #include <cmath>
00007 #include <fstream>
00008 #include <iostream>
00009 #include <iomanip>
00010 #include <sstream>
00011
00012
00013 #include "TArrow.h"
00014 #include "TBox.h"
00015 #include "TCanvas.h"
00016 #include "TFile.h"
00017 #include "TGraphAsymmErrors.h"
00018 #include "TH1.h"
00019 #include "TF1.h"
00020 #include "TLine.h"
00021 #include "TPaveStats.h"
00022 #include "TStyle.h"
00023
00024
00025 #include "PhysicsNtuple/DataBlock.h"
00026 #include "PhysicsNtuple/Hist1d.h"
00027 #include "Plot.h"
00028
00029 using namespace std;
00030
00031
00032 double Plot::GetChi2(const Hist &lhs, const Hist &rhs, const string &option, ostream &o)
00033 {
00034 TH1 *hL = lhs.GetHist();
00035 TH1 *hR = rhs.GetHist();
00036
00037 if(!hL || !hR)
00038 {
00039 cerr << "GetChi2() - null histogram pointers" << endl;
00040 return 0.0;
00041 }
00042 if(hL -> GetNbinsX() != hR -> GetNbinsX())
00043 {
00044 cerr << "GetChi2() - histograms have unequal number of bins" << endl;
00045 return 0.0;
00046 }
00047
00048 unsigned int ndof = 0;
00049 double chi2 = 0.0;
00050
00051 int lbin = 1, hbin = hL -> GetNbinsX();
00052
00053 if(option.find("U") != string::npos || option.find("u") != string::npos)
00054 {
00055 --lbin;
00056 }
00057 if(option.find("O") != string::npos || option.find("o") != string::npos)
00058 {
00059 ++hbin;
00060 }
00061 if(!(lbin < hbin))
00062 {
00063 cerr << "GetChi2() - invalid range of histogram bins" << endl;
00064 return 0.0;
00065 }
00066
00067 const map<int, pair<Band, Band> >& bandL = lhs.GetErrorBand();
00068 const map<int, pair<Band, Band> >& bandR = rhs.GetErrorBand();
00069
00070 for(int ibin = lbin; ibin <= hbin; ++ibin)
00071 {
00072 const double valueL = hL -> GetBinContent(ibin);
00073 const double valueR = hR -> GetBinContent(ibin);
00074
00075 if(!(valueL > 0.0) && !(valueR > 0.0))
00076 {
00077 continue;
00078 }
00079
00080 const double nom = (valueL - valueR)*(valueL - valueR);
00081 double den = 0.0;
00082
00083 const map<int, pair<Band, Band> >::const_iterator lit = bandL.find(ibin);
00084 if(lit != bandL.end())
00085 {
00086 const Band &band = (lit -> second).second;
00087 assert(band.Bin() == ibin && "Mismatched bin number");
00088
00089 if(band.Low() > band.High())
00090 {
00091 den += band.Low();
00092 }
00093 else
00094 {
00095 den += band.High();
00096 }
00097 }
00098 else
00099 {
00100 den += valueL;
00101 }
00102
00103 const map<int, pair<Band, Band> >::const_iterator rit = bandR.find(ibin);
00104 if(rit != bandR.end())
00105 {
00106 const Band &band = (rit -> second).second;
00107 assert(band.Bin() == ibin && "Mismatched bin number");
00108
00109 if(band.Low() > band.High())
00110 {
00111 den += band.Low();
00112 }
00113 else
00114 {
00115 den += band.High();
00116 }
00117 }
00118 else
00119 {
00120 den += valueR;
00121 }
00122
00123 if(!(den > 0.0))
00124 {
00125 cerr << "Plot::GetChi2 - bin error is zero" << endl;
00126 continue;
00127 }
00128
00129 chi2 += nom/den;
00130 ++ndof;
00131 }
00132
00133 if(!(ndof > 0))
00134 {
00135 return 0.0;
00136 }
00137
00138 if(option.find("P") != string::npos || option.find("V") != string::npos)
00139 {
00140 o << "chi2/ndof = " << chi2 << "/" << ndof << " = " << chi2/ndof << endl;
00141 }
00142
00143 if(option.find("chi2") != string::npos)
00144 {
00145 return chi2;
00146 }
00147 else if(option.find("ndof") != string::npos)
00148 {
00149 return ndof;
00150 }
00151
00152 return chi2/ndof;
00153 }
00154
00155
00156 Plot::Style::Style()
00157 :lwidth(2),
00158 lstyle(1),
00159 lcolor(1),
00160 mstyle(-1),
00161 msize(0),
00162 mcolor(0),
00163 stat(1),
00164 rebin(0),
00165 xmin(+1.0),
00166 xmax(-1.0),
00167 statx(0.75),
00168 staty(0.5),
00169 statw(0.25),
00170 stath(0.23),
00171 option(),
00172 xtitle(),
00173 ytitle()
00174 {
00175 }
00176
00177
00178 Plot::Style::~Style()
00179 {
00180 }
00181
00182
00183 void Plot::Style::Print(ostream &o) const
00184 {
00185 o << "lwidth = " << lwidth << endl;
00186 o << "lstyle = " << lstyle << endl;
00187 o << "lcolor = " << lcolor << endl;
00188 o << "mstyle = " << mstyle << endl;
00189 o << "msize = " << msize << endl;
00190 o << "mcolor = " << mcolor << endl;
00191 o << "stat = " << stat << endl;
00192 o << "rebin = " << rebin << endl;
00193 o << "xmin = " << xmin << endl;
00194 o << "xmax = " << xmax << endl;
00195 o << "statx = " << statx << endl;
00196 o << "staty = " << staty << endl;
00197 o << "statw = " << statw << endl;
00198 o << "stath = " << stath << endl;
00199 o << "option = " << option << endl;
00200 o << "xtitle = " << xtitle << endl;
00201 o << "ytitle = " << ytitle << endl;
00202 }
00203
00204
00205 bool Plot::Style::Read(string path)
00206 {
00207 std::ifstream infile(path.c_str());
00208 if(!infile || !infile.is_open())
00209 {
00210 cerr << "Style::Read - failed to open file " << path << endl;
00211 return false;
00212 }
00213
00214
00215 while(!infile.eof())
00216 {
00217 std::string line;
00218 std::getline(infile, line);
00219
00220 const string::size_type epos = line.find("=");
00221
00222 if(line.empty() || line.find("#") != string::npos || epos == string::npos)
00223 {
00224 continue;
00225 }
00226
00227 Set(line.substr(0, epos), line.substr(epos + 1));
00228 }
00229
00230 return true;
00231 }
00232
00233
00234 bool Plot::Style::Set(string name, string value)
00235 {
00236
00237
00238 if(name.find("lwidth") != string::npos) lwidth = atoi(value.c_str());
00239 if(name.find("lstyle") != string::npos) lstyle = atoi(value.c_str());
00240 if(name.find("lcolor") != string::npos) lcolor = atoi(value.c_str());
00241 if(name.find("mstyle") != string::npos) mstyle = atoi(value.c_str());
00242 if(name.find("msize" ) != string::npos) msize = atoi(value.c_str());
00243 if(name.find("mcolor") != string::npos) mcolor = atoi(value.c_str());
00244 if(name.find("stat" ) != string::npos) stat = atoi(value.c_str());
00245 if(name.find("rebin" ) != string::npos) rebin = atoi(value.c_str());
00246 if(name.find("xmin" ) != string::npos) xmin = atof(value.c_str());
00247 if(name.find("xmax" ) != string::npos) xmax = atof(value.c_str());
00248 if(name.find("statx" ) != string::npos) statx = atof(value.c_str());
00249 if(name.find("staty" ) != string::npos) staty = atof(value.c_str());
00250 if(name.find("statw" ) != string::npos) statw = atof(value.c_str());
00251 if(name.find("stath" ) != string::npos) stath = atof(value.c_str());
00252 if(name.find("option") != string::npos) option = value;
00253 if(name.find("xtitle") != string::npos) xtitle = value;
00254 if(name.find("ytitle") != string::npos) ytitle = value;
00255
00256 return true;
00257 }
00258
00259
00260 double Plot::GetChi2(TH1 *h1, TH1 *h2, const string &option, const string &tag)
00261 {
00262 if(!h1 || !h2)
00263 {
00264 cerr << "GetChi2() - invalid histogram pointers" << endl;
00265 return 0.0;
00266 }
00267 if(h1 -> GetNbinsX() != h2 -> GetNbinsX())
00268 {
00269 cerr << "GetChi2() - histograms have unequal number of bins" << endl;
00270 return 0.0;
00271 }
00272
00273 double ndof = 0.0;
00274 double chi2 = 0.0;
00275
00276 int lbin = 1, hbin = h1 -> GetNbinsX();
00277
00278 if(option.find("U") != string::npos || option.find("u") != string::npos)
00279 {
00280 --lbin;
00281 }
00282 if(option.find("O") != string::npos || option.find("o") != string::npos)
00283 {
00284 ++hbin;
00285 }
00286 if(!(lbin < hbin))
00287 {
00288 cerr << "GetChi2() - invalid range of histogram bins" << endl;
00289 return 0.0;
00290 }
00291
00292 for(int ibin = lbin; ibin <= hbin; ++ibin)
00293 {
00294 const double value1 = h1 -> GetBinContent(ibin);
00295 const double value2 = h2 -> GetBinContent(ibin);
00296
00297 if(value1 > 0.0 && value2 > 0.0)
00298 {
00299 chi2 += (value1 - value2) * (value1 - value2)/value1;
00300 ndof += 1.0;
00301 }
00302 }
00303
00304 if(!(ndof > 0.0))
00305 {
00306 return 0.0;
00307 }
00308
00309 if(option.find("P") != string::npos || option.find("V") != string::npos || !tag.empty())
00310 {
00311 if(tag.empty())
00312 {
00313 cout << "chi2/ndof = " << chi2 << "/" << ndof << " = " << chi2/ndof << endl;
00314 }
00315 else
00316 {
00317 cout << tag << ": chi2/ndof = " << chi2 << "/" << ndof << " = " << chi2/ndof << endl;
00318 }
00319 }
00320
00321 return chi2/ndof;
00322 }
00323
00324
00325 const string Plot::Format(const double v, const int w, const int p)
00326 {
00327 stringstream ss;
00328 ss << std::fixed << std::setw(w) << std::setprecision(p) << v;
00329 return ss.str();
00330 }
00331
00332
00333 Plot::Hist::Hist(string fpath)
00334 :fFilePath(),
00335 fHistPath(),
00336 fHistPathL(),
00337 fHistPathH(),
00338 fHist(0),
00339 fHistL(0),
00340 fHistH(0),
00341 fProtons(0.0),
00342 fErrorColor(-1),
00343 fErrorStyle(1001),
00344 fAGraph(0),
00345 fError(),
00346 fArray()
00347 {
00348 Set(fpath);
00349 }
00350
00351
00352 Plot::Hist::~Hist()
00353 {
00354 if(fHist) delete fHist;
00355 if(fHistL) delete fHistL;
00356 if(fHistH) delete fHistH;
00357
00358 ClearError();
00359 }
00360
00361
00362 bool Plot::Hist::Set(const string fpath)
00363 {
00364 if(fpath.size() < 6)
00365 {
00366 return false;
00367 }
00368
00369 TFile *file = new TFile(fpath.c_str(), "READ");
00370 if(!file -> IsOpen())
00371 {
00372 cerr << "Failed to open ROOT file " << fpath << endl;
00373 return false;
00374 }
00375
00376 fFilePath = fpath;
00377
00378 return true;
00379 }
00380
00381
00382 void Plot::Hist::SetProtons(const double protons)
00383 {
00384 if(protons > 0.0)
00385 {
00386 fProtons = protons;
00387 }
00388 }
00389
00390
00391 TH1* Plot::Hist::Get(const string hpath)
00392 {
00393 pair<TH1 *, double> result = Read(hpath);
00394
00395 if(!result.first)
00396 {
00397 return 0;
00398 }
00399
00400 fHistPath = hpath;
00401
00402 fHist = result.first;
00403
00404 if(result.second > 0.0)
00405 {
00406 fProtons = result.second;
00407 }
00408
00409 return fHist;
00410 }
00411
00412
00413 TGraphAsymmErrors* Plot::Hist::SetLH(const string lpath, const string hpath)
00414 {
00415 pair<TH1 *, double> lresult = Read(lpath);
00416 pair<TH1 *, double> hresult = Read(hpath);
00417
00418 if(!lresult.first || !hresult.first)
00419 {
00420 return 0;
00421 }
00422
00423 if(fHistL) delete fHistL;
00424 if(fHistH) delete fHistH;
00425
00426 fHistPathL = lpath;
00427 fHistPathH = hpath;
00428
00429 fHistL = lresult.first;
00430 fHistH = hresult.first;
00431
00432 return ComputeError();
00433 }
00434
00435
00436 TGraphAsymmErrors* Plot::Hist::ComputeError()
00437 {
00438 TH1 *hC = fHist;
00439 TH1 *hL = fHistL;
00440 TH1 *hH = fHistH;
00441
00442 if(!hC || !hL || !hH)
00443 {
00444 return 0;
00445 }
00446
00447 ClearError();
00448
00449 const int nbin = hC -> GetNbinsX();
00450
00451 if(hL -> GetNbinsX() != nbin || hH -> GetNbinsX() != nbin)
00452 {
00453 cerr << "Error::Compute - mismatched number of bins" << endl;
00454 return 0;
00455 }
00456
00457 int npoint = 0;
00458 for(int ibin = 1; ibin <= nbin; ++ibin)
00459 {
00460 if(hC -> GetBinContent(ibin) > 0)
00461 {
00462 ++npoint;
00463 }
00464 }
00465
00466 double* x = Create(npoint);
00467 double* y = Create(npoint);
00468 double* exl = Create(npoint);
00469 double* exh = Create(npoint);
00470 double* eyl = Create(npoint);
00471 double* eyh = Create(npoint);
00472
00473 npoint = 0;
00474 for(int ibin = 1; ibin <= nbin; ++ibin)
00475 {
00476 if(!(hC -> GetBinContent(ibin) > 0))
00477 {
00478 continue;
00479 }
00480
00481 const double xc = hC -> GetXaxis() -> GetBinCenter(ibin);
00482 const double xl = hC -> GetXaxis() -> GetBinLowEdge(ibin);
00483 const double xh = hC -> GetXaxis() -> GetBinUpEdge(ibin);
00484
00485 const double yc = hC -> GetBinContent(ibin);
00486 const double yl = hL -> GetBinContent(ibin);
00487 const double yh = hH -> GetBinContent(ibin);
00488
00489 if(yl > yh)
00490 {
00491 cerr << "Error::Compute - low value " << yl << " larger than high value " << yh<< endl;
00492 continue;
00493 }
00494
00495 if(yc < yl || yh < yc)
00496 {
00497 cerr << "Error::Compute - low and/or high error have wrong limit" << yh << endl;
00498 continue;
00499 }
00500
00501 const double error_stat = std::sqrt(yc);
00502 const double error_low = error_stat + yc - yl;
00503 const double error_high = error_stat + yh - yc;
00504
00505
00506
00507
00508 x[npoint] = xc;
00509 y[npoint] = yc;
00510
00511 exl[npoint] = xc - xl;
00512 exh[npoint] = xh - xc;
00513
00514 eyl[npoint] = error_low;
00515 eyh[npoint] = error_high;
00516
00517 ++npoint;
00518
00519 const Band xb(ibin, xc, xl, xh);
00520 const Band yb(ibin, yc, yl - error_stat, yh + error_stat);
00521
00522 const pair<Band, Band> np(xb, yb);
00523
00524 if(!fError.insert(map<int, pair<Band, Band> >::value_type(ibin, np)).second)
00525 {
00526 cerr << "Error::Compute - bin " << ibin << " already exists" << endl;
00527 }
00528
00529 TBox *box = new TBox(xb.Low(), yb.Low(), xb.High(), yb.High());
00530
00531 if(!fBox.insert(map<int, TBox *>::value_type(ibin, box)).second)
00532 {
00533 cerr << "Error::Compute - bin " << ibin << " already exists" << endl;
00534 }
00535
00536
00537 if(error_low > error_high)
00538 {
00539 hC -> SetBinError(ibin, error_low);
00540 }
00541 else
00542 {
00543 hC -> SetBinError(ibin, error_high);
00544 }
00545 }
00546
00547 fAGraph = new TGraphAsymmErrors(npoint, x, y, exl, exh, eyl, eyh);
00548
00549 return fAGraph;
00550 }
00551
00552
00553 TH1* Plot::Hist::operator->() const
00554 {
00555 return fHist;
00556 }
00557
00558
00559 double Plot::Hist::GetEntries(string option) const
00560 {
00561 TH1 *h = fHist;
00562
00563 if(option.find("l") != string::npos)
00564 {
00565 h = fHistL;
00566 }
00567 else if(option.find("h") != string::npos)
00568 {
00569 h = fHistH;
00570 }
00571
00572 if(!h)
00573 {
00574 return 0.0;
00575 }
00576
00577 long double area = 0.0;
00578
00579 int lbin = 1, hbin = h -> GetNbinsX();
00580
00581 if(option.find("u") != string::npos)
00582 {
00583 --lbin;
00584 }
00585 if(option.find("o") != string::npos)
00586 {
00587 ++hbin;
00588 }
00589
00590 for(int ibin = lbin; ibin <= hbin; ++ibin)
00591 {
00592 const long double value = h -> GetBinContent(ibin);
00593
00594 if(value > 0.0)
00595 {
00596 area += value;
00597 }
00598 }
00599
00600 return static_cast<double>(area);
00601 }
00602
00603
00604 double Plot::Hist::GetProtons() const
00605 {
00606 return fProtons;
00607 }
00608
00609
00610 const map<int, pair<Plot::Band, Plot::Band> >& Plot::Hist::GetErrorBand() const
00611 {
00612 return fError;
00613 }
00614
00615
00616 void Plot::Hist::Rebin(const int rebin)
00617 {
00618 if(!fHist || rebin < 1)
00619 {
00620 return;
00621 }
00622
00623 fHist -> Rebin(rebin);
00624
00625 if(fHistL && fHistH)
00626 {
00627 fHistL -> Rebin(rebin);
00628 fHistH -> Rebin(rebin);
00629
00630 ComputeError();
00631 }
00632 }
00633
00634
00635 TH1* Plot::Hist::Scale(const Hist &other, string option)
00636 {
00637 if(!fHist)
00638 {
00639 return 0;
00640 }
00641
00642 const double area = GetEntries("uo");
00643
00644 double scale = 1.0;
00645
00646 if(option.find("area") != string::npos)
00647 {
00648 if(area > 0.0)
00649 {
00650 scale = 1.0/area;
00651 }
00652 }
00653 else if(option.find("ent") != string::npos)
00654 {
00655 const double area_other = other.GetEntries("");
00656 if(area > 0.0 && area_other > 0.0)
00657 {
00658 scale = area_other/area;
00659 }
00660 }
00661 else if(option.find("pot") != string::npos)
00662 {
00663 if(fProtons > 0.0 && other.GetProtons() > 0.0)
00664 {
00665 scale = other.GetProtons()/fProtons;
00666 }
00667 }
00668
00669 const double entries = GetEntries("uo");
00670 const double entriesl = GetEntries("l uo");
00671 const double entriesh = GetEntries("h uo");
00672
00673 fHist -> Scale(scale);
00674
00675 if(fHistL) fHistL -> Scale(scale);
00676 if(fHistH) fHistH -> Scale(scale);
00677
00678 if(option.find("area") == string::npos)
00679 {
00680 fHist -> SetEntries(entries * scale);
00681
00682 if(fHistL) fHistL -> SetEntries(entriesl * scale);
00683 if(fHistH) fHistH -> SetEntries(entriesh * scale);
00684 }
00685
00686 ComputeError();
00687
00688 return fHist;
00689 }
00690
00691
00692 TCanvas* Plot::Hist::Draw(string option, string cname)
00693 {
00694 if(!fHist)
00695 {
00696 return 0;
00697 }
00698
00699 TH1 *h = fHist;
00700
00701 TCanvas *canvas = 0;
00702
00703 if(!cname.empty())
00704 {
00705 canvas = new TCanvas(cname.c_str(), cname.c_str(), 0, 0, 650, 400);
00706 canvas -> cd();
00707
00708 if(option.find("grid") != string::npos)
00709 {
00710 canvas -> SetGrid();
00711 }
00712 if(cname.find("log") != string::npos)
00713 {
00714 canvas -> SetLogy();
00715 }
00716 canvas -> Draw();
00717 }
00718
00719 h -> Draw(option.c_str());
00720
00721 if(option.find("E") != string::npos)
00722 {
00723 TH1 *hc = dynamic_cast<TH1 *> (fHist -> Clone("hc"));
00724 hc -> SetDirectory(0);
00725 hc -> Draw("same HIST");
00726 }
00727
00728 if(fErrorColor > 0 && fErrorStyle > 0)
00729 {
00730 const int bmin = fHist -> GetXaxis() -> GetFirst();
00731 const int bmax = fHist -> GetXaxis() -> GetLast();
00732
00733 for(map<int, TBox *>::const_iterator it = fBox.begin(); it != fBox.end(); ++it)
00734 {
00735 const int ibin = it -> first;
00736
00737 if(ibin < bmin || ibin > bmax)
00738 {
00739 continue;
00740 }
00741
00742 TBox *box = it -> second;
00743 if(!box)
00744 {
00745 continue;
00746 }
00747
00748 box -> SetFillColor(fErrorColor);
00749 box -> SetFillStyle(fErrorStyle);
00750 box -> Draw();
00751 }
00752 }
00753
00754 gPad -> Modified();
00755 gPad -> Update();
00756
00757 return canvas;
00758 }
00759
00760
00761 void Plot::Hist::SetErrorStyle(const int color, const int style)
00762 {
00763 fErrorColor = color;
00764 fErrorStyle = style;
00765 }
00766
00767
00768 void Plot::Hist::Move(float x, float y, float w, float h, string option)
00769 {
00770 if(!fHist || !gPad)
00771 {
00772 return;
00773 }
00774
00775 gPad -> Modified();
00776 gPad -> Update();
00777
00778 TPaveStats* stat = dynamic_cast<TPaveStats *> (fHist -> FindObject("stats"));
00779 if(!stat)
00780 {
00781 if(option.find("V") != string::npos)
00782 {
00783 cerr << "Hist::Move - no statistics box is present" << endl;
00784 }
00785 return;
00786 }
00787
00788 int color = fHist -> GetLineColor();
00789 if(option.find("M") != string::npos)
00790 {
00791 color = fHist -> GetMarkerColor();
00792 }
00793
00794 stat -> SetStatFormat("6.3f");
00795 stat -> SetTextColor(color);
00796 stat -> SetLineColor(color);
00797
00798
00799 if(option.find("V") != string::npos)
00800 {
00801 cout << "Hist::Move - left lower corner = (" << x << ", " << y << ") and "
00802 << "right upper corner = (" << x + w << ", " << y + h << ")" << endl;
00803 }
00804
00805 stat -> SetX1NDC(x);
00806 stat -> SetY1NDC(y);
00807 stat -> SetX2NDC(x + w);
00808 stat -> SetY2NDC(y + h);
00809
00810 gPad -> Modified();
00811 gPad -> Update();
00812 }
00813
00814
00815
00816 TH1* Plot::Hist::GetHist(string option) const
00817 {
00818 TH1 *h = fHist;
00819
00820 if(option.find("l") != string::npos)
00821 {
00822 h = fHistL;
00823 }
00824 else if(option.find("h") != string::npos)
00825 {
00826 h = fHistH;
00827 }
00828
00829 return h;
00830 }
00831
00832
00833 TH1* Plot::Hist::GetRatio(const Hist &other, string option,
00834 const double min_, const double max_, const double factor) const
00835 {
00836 if(!fHist || !other.GetHist())
00837 {
00838 cerr << "Error::GetRatio - invalid histogram pointer(s)" << endl;
00839 return 0;
00840 }
00841
00842 TH1 *hC = fHist;
00843 TH1 *hL = fHistL;
00844 TH1 *hH = fHistH;
00845 TH1 *hO = other.GetHist();
00846
00847 const int nbin = hC -> GetNbinsX();
00848 const double nmin = 1000;
00849
00850 if(hC -> GetNbinsX() != nbin)
00851 {
00852 cerr << "Error::GetRatio - mismatched number of bins" << endl;
00853 return 0;
00854 }
00855
00856 TH1 *hR = CreateRatio(hC, hO, option, nmin);
00857 if(!hR)
00858 {
00859 cerr << "Error::GetRatio - failed to create ratio histogram" << endl;
00860 return 0;
00861 }
00862 else if(option.find("merge") != string::npos)
00863 {
00864 if(hL && hH)
00865 {
00866 Anp::Hist1d<double> histL(*hR);
00867 Anp::Hist1d<double> histH(*hR);
00868
00869 histL.Reset();
00870 histH.Reset();
00871
00872 histL.Fill(*hL);
00873 histH.Fill(*hH);
00874
00875 hL = Anp::CreateTH1<double>(histL, "hL");
00876 hH = Anp::CreateTH1<double>(histH, "hH");
00877 }
00878
00879 Anp::Hist1d<double> histC(*hR);
00880 Anp::Hist1d<double> histO(*hR);
00881
00882 histC.Reset();
00883 histO.Reset();
00884
00885 histC.Fill(*hC);
00886 histO.Fill(*hO);
00887
00888 hC = Anp::CreateTH1<double>(histC, "hC");
00889 hO = Anp::CreateTH1<double>(histO, "hO");
00890 }
00891
00892 double miny = -1.0, maxy = -1.0;
00893
00894 const int rbin = hR -> GetNbinsX();
00895
00896 for(int ibin = 1; ibin <= rbin; ++ibin)
00897 {
00898 const double valueC = hC -> GetBinContent(ibin);
00899 const double valueO = hO -> GetBinContent(ibin);
00900
00901 if(!(valueC > 0) || !(valueO > 0))
00902 {
00903 continue;
00904 }
00905
00906 if(std::fabs(hC ->GetBinLowEdge(ibin)-hO->GetBinLowEdge(ibin)) > 0.00001*hC->GetBinWidth(ibin))
00907 {
00908 cerr << "Hist::GetRatio - invalid lower bin edge for hC and hO" << endl;
00909 continue;
00910 }
00911
00912 double errorC = hC -> GetBinError(ibin);
00913
00914 if(hH && hL)
00915 {
00916 if(std::fabs(hC ->GetBinLowEdge(ibin)-hH->GetBinLowEdge(ibin)) > 0.00001*hC->GetBinWidth(ibin) ||
00917 std::fabs(hC ->GetBinLowEdge(ibin)-hL->GetBinLowEdge(ibin)) > 0.00001*hC->GetBinWidth(ibin))
00918 {
00919 cerr << "Hist::GetRatio - invalid lower bin edge for hC and hL or hH" << endl;
00920 continue;
00921 }
00922
00923 const double errorH = hH -> GetBinContent(ibin) - valueC;
00924 const double errorL = valueC - hL -> GetBinContent(ibin);
00925
00926
00927
00928
00929 assert(!(errorH < 0.0) && !(errorL < 0.0) && "Negative errors");
00930
00931 errorC = std::sqrt(valueC);
00932
00933 if(errorH > errorL)
00934 {
00935 errorC += errorH;
00936 }
00937 else
00938 {
00939 errorC += errorL;
00940 }
00941 }
00942
00943 const double errorO = hO -> GetBinError(ibin);
00944
00945 const double ratio = valueO/valueC;
00946 const double error = ratio*(errorO/valueO + errorC/valueC);
00947
00948 hR -> SetBinContent(ibin, ratio);
00949 hR -> SetBinError(ibin, error);
00950
00951 if(maxy < 0.0)
00952 {
00953 miny = ratio - error;
00954 maxy = ratio + error;
00955 }
00956 else
00957 {
00958 miny = std::min<double>(miny, ratio - error);
00959 maxy = std::max<double>(maxy, ratio + error);
00960 }
00961 }
00962
00963 if(maxy > 0.0)
00964 {
00965 const double span = std::fabs(maxy) + std::fabs(miny);
00966 hR -> GetYaxis() -> SetRangeUser(miny - span*factor, maxy + span*factor);
00967 }
00968
00969 if(min_ < max_)
00970 {
00971 hR -> GetYaxis() -> SetRangeUser(min_, max_);
00972 }
00973
00974 if(option.find("l") != string::npos)
00975 {
00976 TLine *line = 0;
00977
00978 if(min_ < max_)
00979 {
00980 line = new TLine(min_, 1.0, max_, 1.0);
00981 }
00982 else
00983 {
00984 line = new TLine(hR -> GetXaxis() -> GetXmin(), 1.0, hR -> GetXaxis() -> GetXmax(), 1.0);
00985 }
00986
00987 line -> SetLineWidth(1);
00988 hR -> GetListOfFunctions() -> Add(line);
00989 }
00990
00991 if(option.find("merge") != string::npos)
00992 {
00993 if(hO) delete hO;
00994 if(hC) delete hC;
00995 if(hL) delete hL;
00996 if(hH) delete hH;
00997 }
00998
00999 return hR;
01000 }
01001
01002
01003 std::pair<TH1 *, double> Plot::Hist::Read(const string &hpath)
01004 {
01005 pair<TH1 *, double> result(0, 0.0);
01006
01007 if(fFilePath.size() < 6)
01008 {
01009 return result;
01010 }
01011
01012 TFile *file = new TFile(fFilePath.c_str(), "READ");
01013 if(!file -> IsOpen())
01014 {
01015 cerr << "Hist::Read - Failed to open ROOT file " << fFilePath << endl;
01016 return result;
01017 }
01018
01019 TH1 *h = dynamic_cast<TH1 *>(file -> Get(hpath.c_str()));
01020 if(!h)
01021 {
01022 cerr << "Plot::Read - failed to find histogram " << hpath << endl;
01023 return result;
01024 }
01025
01026 h = dynamic_cast<TH1 *>(h -> Clone());
01027 h -> SetDirectory(0);
01028
01029 result.first = h;
01030
01031 DataBlock *block = dynamic_cast<DataBlock *>(file -> Get("block"));
01032 if(block)
01033 {
01034 result.second = block -> GetProtonsOut();
01035 }
01036 else
01037 {
01038 cout << "Plot::Get() - failed to find DataBlock in " << file -> GetName() << endl;
01039 }
01040
01041
01042 file -> Close();
01043
01044 return result;
01045 }
01046
01047
01048 TH1* Plot::Hist::CreateRatio(TH1 *hC, TH1 *hO, const string &option, double nmin) const
01049 {
01050 if(!hC || !hO)
01051 {
01052 return 0;
01053 }
01054
01055 const int nbin = hC -> GetNbinsX();
01056
01057 if(hC -> GetNbinsX() != nbin)
01058 {
01059 cerr << "Plot::CreateRatio - mismatched number of bins" << endl;
01060 return 0;
01061 }
01062
01063 TH1 *hR = 0;
01064
01065 if(option.find("merge") != string::npos)
01066 {
01067 Anp::Hist1d<double> hist(*hO);
01068
01069 hist.Merge(nmin);
01070 hist.Reset();
01071 hist.Fill(*hC);
01072 hist.Merge(nmin);
01073
01074 hR = Anp::CreateTH1<double>(hist, "hR");
01075 }
01076 else
01077 {
01078 hR = dynamic_cast<TH1 *>(hO -> Clone("hR"));
01079
01080 if(!hR)
01081 {
01082 cerr << "Plot::CreateRatio - failed to clone histogram" << endl;
01083 return 0;
01084 }
01085 }
01086
01087 if(hR)
01088 {
01089 hR -> Reset();
01090 hR -> SetDirectory(0);
01091 hR -> SetStats(false);
01092 hR -> GetXaxis() -> SetTitle(hO -> GetXaxis() -> GetTitle());
01093 hR -> GetXaxis() -> CenterTitle();
01094 }
01095
01096 return hR;
01097 }
01098
01099
01100 double* Plot::Hist::Create(const int size)
01101 {
01102 if(size < 1)
01103 {
01104 cerr << "Error::Create - can not create zero size array" << endl;
01105 return 0;
01106 }
01107
01108 double *a = new double[size];
01109
01110 for(int i = 0; i < size; ++i)
01111 {
01112 a[i] = 0.0;
01113 }
01114
01115 fArray.push_back(a);
01116
01117 return a;
01118 }
01119
01120
01121 void Plot::Hist::ClearError()
01122 {
01123 if(fAGraph)
01124 {
01125 delete fAGraph;
01126 fAGraph = 0;
01127 }
01128
01129 for(vector<double *>::iterator it = fArray.begin(); it != fArray.end(); ++it)
01130 {
01131 double *a = *it;
01132 if(a)
01133 {
01134 delete [] a;
01135 }
01136 }
01137
01138 for(map<int, TBox *>::iterator it = fBox.begin(); it != fBox.end(); ++it)
01139 {
01140 TBox *box = it -> second;
01141 if(box) delete box;
01142 }
01143
01144 fArray.clear();
01145 fError.clear();
01146 fBox.clear();
01147 }
01148
01149
01150 Plot::Range::Range(const double factor, const double min, const double max)
01151 :fFactor(factor),
01152 fMin(min),
01153 fMax(max)
01154 {
01155 if(!(fFactor > 1.0))
01156 {
01157 fFactor = 1.0;
01158 }
01159 }
01160
01161
01162 Plot::Range::~Range()
01163 {
01164 }
01165
01166
01167 void Plot::Range::Set(const double factor, const double min, const double max)
01168 {
01169 fFactor = factor;
01170 if(min < max)
01171 {
01172 fMin = min;
01173 fMax = max;
01174 }
01175 }
01176
01177
01178 void Plot::Range::Add(TH1 * h)
01179 {
01180 if(h)
01181 {
01182 fHist.push_back(h);
01183 }
01184 }
01185
01186
01187 void Plot::Range::Resize(string option, const double min_, const double max_)
01188 {
01189 if(option.find("Y") != string::npos)
01190 {
01191 double min = 0.0, max = 0.0;
01192 for(HistVec::iterator hit = fHist.begin(); hit != fHist.end(); ++hit)
01193 {
01194 TH1 *h = *hit;
01195 const std::pair<double, double> pmm = GetMinMax(h, option);
01196
01197 if(hit == fHist.begin())
01198 {
01199 min = pmm.first;
01200 max = pmm.second;
01201 }
01202 else
01203 {
01204 min = std::min(min, pmm.first);
01205 max = std::max(max, pmm.second);
01206 }
01207 }
01208
01209 if(option.find("min") != string::npos)
01210 {
01211 min = min_;
01212 }
01213 if(option.find("max") != string::npos)
01214 {
01215 max = max_;
01216 }
01217
01218 if(min < 0.0)
01219 {
01220 min *= fFactor;
01221 }
01222 else
01223 {
01224 min /= fFactor;
01225 }
01226
01227 if(max < 0.0)
01228 {
01229 max /= fFactor;
01230 }
01231 else
01232 {
01233 max *= fFactor;
01234 }
01235
01236 if(option.find("V") != string::npos)
01237 {
01238 cout << "Range::Resize - setting y axis range from " << min << " to " << max << endl;
01239 }
01240
01241 for(HistVec::iterator hit = fHist.begin(); hit != fHist.end(); ++hit)
01242 {
01243 TH1 *h = *hit;
01244
01245 h -> GetYaxis() -> SetRangeUser(min, max);
01246 }
01247 }
01248 else if(option.find("X") != string::npos && min_ < max_)
01249 {
01250 if(option.find("V") != string::npos)
01251 {
01252 cout << "Range::Resize - setting x axis range from " << min_ << " to " << max_ << endl;
01253 }
01254
01255 for(HistVec::iterator hit = fHist.begin(); hit != fHist.end(); ++hit)
01256 {
01257 TH1 *h = *hit;
01258
01259 h -> GetXaxis() -> SetRangeUser(min_, max_);
01260 }
01261 }
01262 }
01263
01264
01265
01266 const std::pair<double, double> Plot::Range::GetMinMax(TH1 *h, const string &option) const
01267 {
01268 if(!h || h -> GetNbinsX() < 1)
01269 {
01270 return pair<double, double> (0.0, 0.0);
01271 }
01272
01273 bool init = false, use_error = false;
01274 double min = 0.0, max = 0.0;
01275
01276 if(option.find("E") != string::npos)
01277 {
01278 use_error = true;
01279 }
01280
01281 for(int ibin = 1; ibin <= h -> GetNbinsX(); ++ibin)
01282 {
01283 double value = h -> GetBinContent(ibin);
01284 double error = h -> GetBinError(ibin);
01285
01286 if(!(value > 0.0))
01287 {
01288 continue;
01289 }
01290
01291 if(use_error)
01292 {
01293 value += error;
01294 }
01295
01296 if(!init)
01297 {
01298 min = value;
01299 max = value;
01300 init = true;
01301 continue;
01302 }
01303
01304
01305 min = std::min(min, value);
01306 max = std::max(max, value);
01307 }
01308
01309 return pair<double, double> (min, max);
01310 }
01311
01312
01313
01314 Plot::Band::Band()
01315 :bin(0),
01316 center(0.0),
01317 low(0.0),
01318 high(0.0)
01319 {
01320 }
01321
01322
01323 Plot::Band::Band(int bin_, double center_, double low_, double high_)
01324 :bin(bin_),
01325 center(center_),
01326 low(low_),
01327 high(high_)
01328 {
01329 }
01330
01331
01332 Plot::Band::~Band()
01333 {
01334 }
01335
01336
01337 int Plot::Band::Bin() const
01338 {
01339 return bin;
01340 }
01341
01342
01343 double Plot::Band::Center() const
01344 {
01345 return center;
01346 }
01347
01348
01349 double Plot::Band::Low() const
01350 {
01351 return low;
01352 }
01353
01354
01355 double Plot::Band::High() const
01356 {
01357 return high;
01358 }
01359
01360
01361 bool Plot::operator==(const Band &lhs, const Band &rhs)
01362 {
01363 return (lhs.Bin() == rhs.Bin());
01364 }
01365
01366
01367 void Plot::TestHist(TH1 *hO, TH1 *hC, string option)
01368 {
01369 const double nmin = 1000;
01370
01371 vector<Anp::Bin<double> > bvec;
01372
01373 map<int, double> bmap;
01374
01375 Anp::Hist1d<double> histO(*hO);
01376 Anp::Hist1d<double> histC(*hC);
01377
01378 cout << "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" << endl;
01379 histO.Print();
01380 const unsigned int nmergeO = histO.Merge(1000.0);
01381 histO.Print();
01382
01383 cout << "Merged " << nmergeO << " bins" << endl;
01384
01385 cout << "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" << endl;
01386 histC.Print();
01387 const unsigned int nmergeC = histC.Merge(1000.0);
01388 histC.Print();
01389
01390 cout << "Merged " << nmergeC << " bins" << endl;
01391
01392 cout << "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN" << endl;
01393 histO.Reset();
01394 histO.Fill(*hC);
01395 histO.Print();
01396
01397 cout << "Attempting draw test..." << endl;
01398
01399 TH1 *h1 = Anp::CreateTH1<double>(histO, "h1");
01400 TH1 *h2 = Anp::CreateTH1<double>(histC, "h2");
01401
01402 hC -> SetLineColor(1);
01403 hC -> SetLineWidth(2);
01404 hC -> SetFillColor(0);
01405 h1 -> SetLineColor(2);
01406 h2 -> SetLineColor(4);
01407
01408 if(!h1)
01409 {
01410 cerr << "Failed to create h1" << endl;
01411 return;
01412 }
01413 if(!h2)
01414 {
01415 cerr << "Failed to create h2" << endl;
01416 return;
01417 }
01418
01419 TCanvas *canvas = new TCanvas("ctest", "ctest", 0, 0, 650, 400);
01420 canvas -> SetGrid();
01421 canvas -> Draw();
01422
01423 hC -> Draw("HIST");
01424 h1 -> Draw("sames");
01425 h2 -> Draw("sames");
01426
01427 cout << "Finished draw test" << endl;
01428
01429 return;
01430
01431 const int nbin = hC -> GetNbinsX();
01432
01433 for(int ibin = 1; ibin <= nbin; ++ibin)
01434 {
01435 const double value = hO -> GetBinContent(ibin);
01436 const double edge = hO -> GetBinLowEdge(ibin);
01437
01438 Anp::Bin<double> bin(ibin, edge);
01439 bin.add(value);
01440
01441 bvec.push_back(bin);
01442 }
01443
01444 unsigned int osize = bvec.size();
01445 double osum = 0.0;
01446
01447 if(option.find("V") != string::npos)
01448 {
01449 for(unsigned int ibin = 0; ibin < bvec.size(); ++ibin)
01450 {
01451 const Anp::Bin<double> &bin = bvec[ibin];
01452 cout << "ibin = " << ibin << ", edge = " << bin.edge() << ", sum = " << bin.sum() << endl;
01453 osum += bin.sum();
01454 }
01455 }
01456
01457 std::sort(bvec.begin(), bvec.end());
01458
01459 vector<Anp::Bin<double> >::iterator bit = bvec.begin();
01460 while(bit != bvec.end())
01461 {
01462 if(bit -> sum() > nmin || bit == bvec.begin() || bit + 1 == bvec.end())
01463 {
01464 ++bit;
01465 continue;
01466 }
01467
01468 vector<Anp::Bin<double> >::iterator lit = bit - 1;
01469 vector<Anp::Bin<double> >::iterator hit = bit + 1;
01470
01471 if(lit -> sum() < hit -> sum())
01472 {
01473 Anp::Bin<double> bin(0, lit -> edge());
01474
01475 bin.add(bit -> sum());
01476 bin.add(lit -> sum());
01477
01478 bvec.erase(lit, hit + 1);
01479
01480 bvec.push_back(bin);
01481 }
01482 else
01483 {
01484 Anp::Bin<double> bin(0, bit -> edge());
01485
01486 bin.add(bit -> sum());
01487 bin.add(hit -> sum());
01488
01489 bvec.erase(bit, hit + 1);
01490
01491 bvec.push_back(bin);
01492 }
01493
01494 std::sort(bvec.begin(), bvec.end());
01495
01496 bit = bvec.begin();
01497 }
01498
01499 if(option.find("V") != string::npos)
01500 {
01501 double nsum = 0.0;
01502 for(unsigned int ibin = 0; ibin < bvec.size(); ++ibin)
01503 {
01504 const Anp::Bin<double> &bin = bvec[ibin];
01505 cout << "ibin = " << ibin << ", edge = " << bin.edge() << ", sum = " << bin.sum() << endl;
01506 nsum += bin.sum();
01507 }
01508
01509 cout << "old bvec size = " << osize << endl;
01510 cout << "new bvec size = " << bvec.size() << endl;
01511 cout << "osum - nsum = " << osum << " - " << nsum << " = " << osum - nsum << endl;
01512 }
01513 }
01514
01515
01516 void Plot::TestError(TH1 *hI, string option)
01517 {
01518 cout << "Plot::TestError - option = " << option << endl;
01519
01520 TH1 *hO = dynamic_cast<TH1 *>(hI -> Clone("hO"));
01521 TH1 *hN = dynamic_cast<TH1 *>(hI -> Clone("hN"));
01522
01523 hO -> SetDirectory(0);
01524 hN -> SetDirectory(0);
01525
01526 const int nbin = hN -> GetNbinsX();
01527
01528 for(int ibin = 1; ibin <= nbin; ++ibin)
01529 {
01530 const double value = hN -> GetBinContent(ibin);
01531
01532 if(option.find("half") != std::string::npos)
01533 {
01534 hN -> SetBinError(ibin, 0.5*std::sqrt(value));
01535 }
01536 else
01537 {
01538 hN -> SetBinError(ibin, std::sqrt(value));
01539 }
01540 }
01541
01542 hO -> SetLineColor(2);
01543 hN -> SetLineColor(4);
01544
01545 TCanvas *canvas = new TCanvas("ctest", "ctest", 0, 0, 720, 450);
01546 canvas -> SetGrid();
01547 canvas -> Draw();
01548
01549 hO -> Draw("E1");
01550 hN -> Draw("E1 sames");
01551 }