• Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

BCH1D.cxx

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008-2012, Daniel Kollar and Kevin Kroeninger.
00003  * All rights reserved.
00004  *
00005  * For the licensing terms see doc/COPYING.
00006  */
00007 
00008 // ---------------------------------------------------------
00009 
00010 #include "BCH1D.h"
00011 
00012 #include "BCLog.h"
00013 #include "BCMath.h"
00014 
00015 #include <TH1D.h>
00016 #include <TH2.h>
00017 #include <TLine.h>
00018 #include <TPolyLine.h>
00019 #include <TPaveLabel.h>
00020 #include <TLatex.h>
00021 #include <TError.h>
00022 #include <TCanvas.h>
00023 #include <TMarker.h>
00024 #include <TLegend.h>
00025 #include <TString.h>
00026 
00027 #include <math.h>
00028 
00029 // ---------------------------------------------------------
00030 
00031 BCH1D::BCH1D()
00032 {
00033    fHistogram = 0;
00034    fDefaultCLLimit = 95.; // in percent
00035 
00036    fModeFlag = 0;
00037 }
00038 
00039 // ---------------------------------------------------------
00040 
00041 BCH1D::~BCH1D()
00042 {
00043    if (fHistogram) delete fHistogram;
00044 }
00045 
00046 // ---------------------------------------------------------
00047 
00048 double BCH1D::GetMode()
00049 {
00050    return fHistogram->GetBinCenter(fHistogram->GetMaximumBin());
00051 }
00052 
00053 // ---------------------------------------------------------
00054 
00055 double BCH1D::GetQuantile(double probability)
00056 {
00057    int nquantiles = 1;
00058    double quantiles[1];
00059    double probsum[1];
00060 
00061    probsum[0] = probability;
00062 
00063    // use ROOT function to calculat quantile.
00064    fHistogram->GetQuantiles(nquantiles, quantiles, probsum);
00065 
00066    return quantiles[0];
00067 }
00068 
00069 // ---------------------------------------------------------
00070 
00071 double BCH1D::GetIntegral(double valuemin, double valuemax)
00072 {
00073    double integral = 0;
00074 
00075    int binmin = fHistogram->FindBin(valuemin);
00076    int binmax = fHistogram->FindBin(valuemax);
00077 
00078    // use ROOT function to calculate integral.
00079    integral = fHistogram->Integral(binmin, binmax);
00080 
00081    return integral;
00082 }
00083 
00084 // ---------------------------------------------------------
00085 
00086 double BCH1D::GetPValue(double probability)
00087 {
00088    // use ROOT function to calculate the integral from 0 to "probability".
00089    return fHistogram->Integral(1, fHistogram->FindBin(probability));
00090 }
00091 
00092 // ---------------------------------------------------------
00093 
00094 void BCH1D::SetDefaultCLLimit(double limit)
00095 {
00096    // check if limit is between 68% and 100%. Give a warning if not ...
00097    if(limit>=100. || limit<68.)
00098       BCLog::OutWarning(
00099          Form("BCH1D::SetDefaultCLLimit : Value %.1f out of range. Keeping default %.1f%% CL limit.",limit,fDefaultCLLimit));
00100 
00101    // ... or set value if true.
00102    else
00103       fDefaultCLLimit = limit;
00104 }
00105 
00106 // ---------------------------------------------------------
00107 
00108 void BCH1D::Print(const char * filename, int options, double ovalue, int ww, int wh)
00109 {
00110    char file[256];
00111    int i=0;
00112    while(i<255 && *filename!='\0')
00113       file[i++]=*filename++;
00114    file[i]='\0';
00115 
00116 // temporary
00117    fHistogram->SetLineWidth(1);
00118 
00119    // create temporary canvas
00120    TCanvas * c;
00121    if(ww > 0 && wh > 0)
00122       c = new TCanvas("c","c",ww,wh);
00123    else
00124       c = new TCanvas("c","c");
00125 
00126    c->cd();
00127    Draw(options, ovalue);
00128 
00129    gPad->RedrawAxis();
00130 
00131    // print to file.
00132    c->Print(file);
00133 }
00134 
00135 // ---------------------------------------------------------
00136 
00137 void BCH1D::Draw(int options, double ovalue)
00138 {
00139    double min, max;
00140    double mode;
00141    double thismode = GetMode();
00142 
00143    int nbins = fHistogram->GetNbinsX();
00144 
00145    fHistogram->Scale(1./fHistogram->Integral("width"));
00146 
00147     // todoKK:
00148    // - fix legend size, position and style
00149    // - maybe write a painer class?
00150    // options should start with letter indicating type, e.g.
00151     // L: legend
00152     //    - add legend
00153    //    - add written summary on plot (mean = xyz, ...)
00154    // B: band (or shaded area)
00155    //    - band type: smallest, central, ...
00156    //    - draw shaded band between two arbitrary values
00157    //    - add second (and third) band with arbitrary values, e.g. 90%, 95% prob. regions
00158    // D: drawing
00159     //    - draw histogram as normal histogram
00160     //    - draw histogram as smooth curve
00161    //    - black&white version with hatching
00162    //    - draw in log-scale
00163    //    - draw cumulative pdf
00164    // S: summary values (mean, rms, ...)
00165    //    - add indicator for mode, mean, median individually
00166    //    - add indicator for rms, smallest interval, central interval individually 
00167    //    - add indicator for quantiles (decentiles, quartiles) e.g. as red lines going through the whole histogram
00168 
00169    if(fModeFlag)
00170       mode=fMode;
00171    else
00172       mode=thismode;
00173 
00174    // define temporary line.
00175    TLine * line;
00176 
00177    //control if legend is required
00178    bool flagLegend=false;
00179    char confidenceLabel[25];
00180 
00181    // reset histogram
00182    fHistogram->SetLineColor(kBlack);
00183    fHistogram->SetLineWidth(1);
00184    fHistogram->SetFillStyle(0);
00185 
00186    // check drawing option.
00187    switch(options)
00188    {
00189       // Draw a band between 16% and 84% probability.
00190       // If the mode is outside the band only draw a limit.
00191       case 0:
00192          if (fabs(ovalue) >= 100 || ovalue==0.)
00193          {//default case if no args to Draw() supplied
00194 
00195             min = GetQuantile(.16);
00196             max = GetQuantile(.84);
00197 
00198             //draw a legend later
00199             flagLegend = true;
00200             sprintf(confidenceLabel, "Central 68%%");
00201 
00202             if ( fHistogram->FindBin(thismode) == fHistogram->GetNbinsX() )
00203             {
00204                min = GetQuantile(1.-(double)fDefaultCLLimit/100.);
00205                max = fHistogram->GetXaxis()->GetXmax();
00206                ovalue = fDefaultCLLimit;
00207                sprintf(confidenceLabel, "%g%% region", fDefaultCLLimit);
00208             }
00209             else if ( fHistogram->FindBin(thismode)==1)
00210             {
00211                min = fHistogram->GetXaxis()->GetXmin();
00212                max = GetQuantile((double)fDefaultCLLimit/100.);
00213                ovalue = -fDefaultCLLimit;
00214                sprintf(confidenceLabel, "%g%% region", fDefaultCLLimit);
00215             }
00216          }
00217 
00218          else if(ovalue < 0)
00219          {
00220             min = fHistogram->GetXaxis()->GetXmin();
00221             max = GetQuantile(-ovalue/100.);
00222          }
00223          else
00224          {
00225             min = GetQuantile(1. - ovalue/100.);
00226             max = fHistogram->GetXaxis()->GetXmax();
00227          }
00228 
00229          // do the drawing
00230          DrawShadedLimits(mode, min, max, ovalue);
00231 
00232          // add legend for the symbols mean, mode, median, confidence band
00233          if(flagLegend)
00234             this ->DrawLegend(confidenceLabel);
00235 
00236          break;
00237 
00238       // Draw a line at "ovalue".
00239       case 1:
00240 
00241          fHistogram->Draw();
00242          min = fHistogram->GetBinLowEdge(1);
00243          max = fHistogram->GetBinLowEdge(nbins+1);
00244          if(min<=ovalue && ovalue<=max)
00245          {
00246             line = new TLine();
00247             line->SetLineColor(kRed);
00248             line->DrawLine(ovalue, 0., ovalue, 1.05 * fHistogram->GetMaximum());
00249          }
00250 
00251          break;
00252 
00253       // Draw a shaded band at the smallest interval.
00254       case 2:
00255 
00256          if(ovalue<50) // just to ensure there's some sense in the number
00257             ovalue = 68.; // default is 68%
00258 
00259          GetSmallestInterval(min, max, ovalue/100.);
00260          DrawShadedLimits(mode, min, max, 0.);
00261 
00262          break;
00263 
00264       // Draw a shaded band at the smallest intervals
00265       case 3:
00266 
00267          if(ovalue<50) // just to ensure there's some sense in the number
00268             ovalue = 68.; // default is 68%
00269 
00270          DrawSmallest(mode,ovalue);
00271 
00272          break;
00273 
00274       // Draw just one bin for fixed delta prior
00275       case 4:
00276 
00277           DrawDelta(ovalue);
00278 
00279           break;
00280 
00281       // Sort out bad options and warn.
00282       default:
00283 
00284          BCLog::OutError(Form("BCH1D::Draw : Invalid option %d",options));
00285          break;
00286    }
00287 }
00288 // ---------------------------------------------------------
00289 void BCH1D::DrawDelta(double value) const
00290 {
00291     // draw histogram with axes first
00292     double xmin = fHistogram->GetXaxis()->GetXmin();
00293     double xmax = fHistogram->GetXaxis()->GetXmax();
00294     double ysize = 1.3 * fHistogram->GetMaximum();
00295 
00296     TH2D*  hsc = new TH2D(
00297           TString::Format("h2scale_%s_%d",fHistogram->GetName(),BCLog::GetHIndex()),"",
00298           50, xmin, xmax, 10, 0., ysize);
00299     hsc->SetStats(0);
00300     hsc->SetXTitle(fHistogram->GetXaxis()->GetTitle());
00301     hsc->SetYTitle(fHistogram->GetYaxis()->GetTitle());
00302     hsc->Draw();
00303 
00304     // write mode location
00305 
00306    TLatex * tmax_text = new TLatex();
00307    tmax_text->SetTextSize(0.035);
00308    tmax_text->SetTextFont(62);
00309    tmax_text->SetTextAlign(22); // center
00310 
00311    double xprint=(xmax+xmin)/2.;
00312    double yprint=ysize*(1-1.4*tmax_text->GetTextSize());
00313 
00314    tmax_text->DrawLatex(xprint,yprint, TString::Format("%s = %g", fHistogram->GetXaxis()->GetTitle(), value));
00315    delete tmax_text;
00316 
00317    // create a temporary histogram, to hold only one non-zero bin
00318    TH1D * hist_temp = new TH1D(TString::Format("h1scale_%s_%d", fHistogram->GetName(), BCLog::GetHIndex()), "", 100, xmin, xmax);
00319    hist_temp->SetBinContent(hist_temp->FindBin(value), fHistogram->GetMaximum());
00320    hist_temp->Draw("same");
00321 }
00322 
00323 // ---------------------------------------------------------
00324 void BCH1D::DrawLegend(const char* text)
00325 {
00326    //draw on top right corner
00327 
00328    TLegend* legend = new TLegend(0.73, 0.72, 0.86, 0.85);
00329    legend->SetFillColor(kWhite);
00330    legend->SetBorderSize(1);
00331 
00332    TMarker* triangle = new TMarker(0, 0, 23);
00333    triangle->SetMarkerColor(kRed);
00334    legend->AddEntry(triangle, "Global mode", "P");
00335 
00336    TMarker* diamond = new TMarker(0, 0, 27);
00337    diamond->SetMarkerColor(kBlue);
00338    legend->AddEntry(diamond, "Mean", "P");
00339 
00340    TLine * line;
00341    line = new TLine();
00342    line->SetLineStyle(2);
00343    line->SetLineColor(kGreen + 2);
00344    legend->AddEntry(line, "Median", "l");
00345 
00346    TLegend* band = new TLegend(0, 0, 1, 1);
00347    band->SetFillColor(kYellow);
00348    legend->AddEntry(band, text, "F");
00349 
00350    legend->SetTextAlign(12);
00351 
00352    //fine tuned by hand so text legible even with several plots in a row
00353    legend->SetTextSize(0.016);
00354 
00355    legend->Draw();
00356 }
00357 
00358 // ---------------------------------------------------------
00359 
00360 // TODO Are graphics objects ever deleted from the heap? search for new TH*
00361 // In most cases, plotting won't work as expected if the histograms are deleted in here
00362 // as the TCanvas then remains empty.
00363 
00364 void BCH1D::DrawShadedLimits(double mode, double min, double max, double limit)
00365 {
00366    double maximum = fHistogram->GetMaximum();
00367 
00368    double x0 = mode;
00369    double y0 = fHistogram->GetBinContent( fHistogram->FindBin(mode) );
00370 
00371    double x1 = fHistogram->GetMean();
00372    double y1 = fHistogram->GetBinContent( fHistogram->FindBin(x1) );
00373 
00374    double x2 = GetQuantile(.5); // median
00375    double y2 = fHistogram->GetBinContent( fHistogram->FindBin(x2) );
00376 
00377    double ysize = maximum*1.3;
00378 
00379    double xmin = fHistogram->GetXaxis()->GetXmin();
00380    double xmax = fHistogram->GetXaxis()->GetXmax();
00381 
00382    // draw histogram with axes first
00383    TH2D * hsc = new TH2D(
00384          TString::Format("h2scale_%s_%d",fHistogram->GetName(),BCLog::GetHIndex()),"",
00385          10, xmin, xmax, 10, 0., ysize);
00386    hsc->SetStats(0);
00387    hsc->SetXTitle(fHistogram->GetXaxis()->GetTitle());
00388    hsc->SetYTitle(fHistogram->GetYaxis()->GetTitle());
00389    hsc->Draw();
00390 
00391    // draw histogram
00392    fHistogram->SetLineWidth(1);
00393    fHistogram->Draw("same");
00394 
00395    // draw yellow shaded region between min and max
00396    TH1D * hist_shaded = GetSubHisto(min,max,TString::Format("%s_sub_%d",fHistogram->GetName(),BCLog::GetHIndex()));
00397    hist_shaded->SetFillStyle(1001);
00398    hist_shaded->SetFillColor(kYellow);
00399 
00400    // draw shaded histogram
00401    hist_shaded->Draw("same");
00402 
00403    gPad->RedrawAxis();
00404 
00405    // draw triangle for mode
00406    TPolyLine * tmax;
00407 
00408    double dx = 0.01*(xmax-xmin);
00409    double dy = 0.04*(ysize);
00410    y0+=dy/5.;
00411    double tmax_x[] = {x0, x0 + dx, x0 - dx, x0};
00412    double tmax_y[] = {y0, y0 + dy, y0 + dy, y0};
00413    tmax = new TPolyLine(4,tmax_x,tmax_y);
00414    tmax->SetLineColor(kRed);
00415    tmax->SetLineWidth(1);
00416    tmax->SetFillColor(kRed);
00417    tmax->Draw();
00418    tmax->Draw("f");
00419 
00420    // draw diamond for mean
00421    TPolyLine * tmean;
00422 
00423    y1+=dy/5.;
00424 //   double tmean_x[] = {x1, x1 + dx, x1 - dx, x1};
00425 //   double tmean_y[] = {y1, y1 + dy, y1 + dy, y1};
00426    double tmean_x[] = {x1, x1 + dx, x1 , x1 - dx, x1};
00427    double tmean_y[] = {y1, y1 + dy/2., y1 + dy, y1 + dy/2., y1};
00428    tmean = new TPolyLine(5,tmean_x,tmean_y);
00429    tmean->SetLineColor(kBlue);
00430 //   tmean->SetFillColor(kWhite);
00431    tmean->SetLineWidth(1);
00432 //   tmean->SetLineStyle(1);
00433    tmean->Draw();
00434 
00435 /*
00436    // draw arrow for median
00437    TPolyLine * tmed;
00438    TPolyLine * tmed2;
00439 
00440 //   y2+=dy/5.;
00441    y2=0.+dy/5.;
00442    double tmed_x[] = {x2 + dx, x2, x2 - dx};
00443    double tmed_y[] = {y2 + dy, y2, y2 + dy};
00444    double tmed2_x[] = {x2, x2};
00445    double tmed2_y[] = {y2, y2 + dy*2.};
00446    tmed = new TPolyLine(3,tmed_x,tmed_y);
00447    tmed2 = new TPolyLine(2,tmed2_x,tmed2_y);
00448    tmed->SetLineColor(kGreen+2);
00449    tmed->SetLineWidth(1);
00450    tmed2->SetLineColor(kGreen+2);
00451    tmed2->SetLineWidth(1);
00452    tmed->Draw();
00453    tmed2->Draw();
00454 */
00455    // draw dashed line for median
00456    TLine * line;
00457    line = new TLine();
00458    line->SetLineStyle(2);
00459    line->SetLineColor(kGreen+2);
00460    line->DrawLine(x2, 0., x2, y2);
00461 
00462 
00463    // write mode location and shaded band
00464 
00465    // format of the number
00466    double delta_max = fmax(fabs(max-x1),fabs(x1-min));
00467 
00468    int sd = 2 + (int)log10(fabs(x1/delta_max));
00469 
00470    if( (int)log10(x1) > (int)log10(delta_max) )
00471       sd++;
00472 
00473    TLatex * tmax_text = new TLatex();
00474    tmax_text->SetTextSize(0.035);
00475    tmax_text->SetTextFont(62);
00476    tmax_text->SetTextAlign(22); // center
00477 //   tmax_text->SetTextAlign(13); // top-left
00478 
00479    double xprint=(xmax+xmin)/2.;
00480 //   double xprint=xmin+(xmax-xmin)/20.;
00481    double yprint=ysize*(1-1.4*tmax_text->GetTextSize());
00482 
00483    if(fabs(limit)<50) // just to ensure there's some sense in the number
00484       tmax_text->DrawLatex(xprint,yprint,
00485          TString::Format( TString::Format("%%s^{med} = %%.%dg ^{+%%.2g}_{ -%%.2g}",sd),
00486             fHistogram->GetXaxis()->GetTitle(), x2, max-x2, x2-min));
00487 
00488    else if (limit<0)
00489       tmax_text->DrawLatex(xprint,yprint,
00490          TString::Format( TString::Format("%%s (%d%%%% prob.) < %%.4g",-(int)limit),
00491             fHistogram->GetXaxis()->GetTitle(), max));
00492 
00493    else if (limit>0)
00494       tmax_text->DrawLatex(xprint,yprint,
00495          TString::Format( TString::Format("%%s (%d%%%% prob.) > %%.4g",(int)limit),
00496             fHistogram->GetXaxis()->GetTitle(), min));
00497 
00498 /*
00499    TLegend * leg = new TLegend(.61,.7,.9,.88);
00500    leg->SetFillColor(kWhite);
00501    leg->SetFillStyle(0);
00502    leg->SetBorderSize(0);
00503    leg->AddEntry(line,"Median", "l");
00504    TH1D * hh0 = new TH1D("hh0","",10,0,10);
00505    hh0->SetMarkerStyle(23);
00506    hh0->SetMarkerColor(kBlue);
00507    hh0->SetMarkerSize(1);
00508    leg->AddEntry(hh0,"Mean","p");
00509    TH1D * hh1 = new TH1D("hh1","",10,0,10);
00510    hh1->SetMarkerStyle(23);
00511    hh1->SetMarkerColor(kRed);
00512    hh1->SetMarkerSize(1);
00513    leg->AddEntry(hh1,"Mode","p");
00514    leg->AddEntry(hist_shaded, "Central 68%", "f");
00515    leg ->Draw();
00516 */
00517 
00518 }
00519 
00520 // ---------------------------------------------------------
00521 
00522 void BCH1D::DrawSmallest(double mode, double prob, bool drawmean)
00523 {
00524    // prepare triangle for mode
00525    TPolyLine * tmax;
00526 
00527    double x0 = mode;
00528    double y0 = fHistogram->GetBinContent( fHistogram->FindBin(mode) );
00529    double xmin = fHistogram->GetXaxis()->GetXmin();
00530    double xmax = fHistogram->GetXaxis()->GetXmax();
00531    double ysize = 1.3 * fHistogram->GetMaximum();
00532 
00533    double x1 = fHistogram->GetMean();
00534    double y1 = fHistogram->GetBinContent( fHistogram->FindBin(x1) );
00535 
00536    double x2 = GetQuantile(.5); // median
00537    double y2 = fHistogram->GetBinContent( fHistogram->FindBin(x2) );
00538 
00539    double dx = 0.01*(xmax-xmin);
00540    double dy = 0.04*(ysize);
00541    double tmax_x[] = {x0, x0 + dx, x0 - dx, x0};
00542    double tmax_y[] = {y0, y0 + dy, y0 + dy, y0};
00543    tmax = new TPolyLine(4,tmax_x,tmax_y);
00544    tmax->SetLineColor(kRed);
00545    tmax->SetFillColor(kRed);
00546 
00547    // draw histogram with axes first
00548    TH2D * hsc = new TH2D(
00549          TString::Format("h2scale_%s_%d",fHistogram->GetName(),BCLog::GetHIndex()),"",
00550          10, xmin, xmax, 10, 0., ysize);
00551    hsc->SetStats(0);
00552    hsc->SetXTitle(fHistogram->GetXaxis()->GetTitle());
00553    hsc->SetYTitle(fHistogram->GetYaxis()->GetTitle());
00554    hsc->Draw();
00555 
00556    // histogram to be filled with band
00557    TH1D * hist_temp1 = (TH1D*) fHistogram->Clone();
00558    hist_temp1->Scale(1.0/fHistogram->Integral("width"));
00559    hist_temp1->SetFillColor(kYellow);
00560    hist_temp1->SetFillStyle(1001);
00561 
00562    // temporary histogram
00563    TH1D * hist_temp2 = (TH1D*) fHistogram->Clone();
00564    hist_temp2->Scale(1.0/fHistogram->Integral("width"));
00565 
00566    // clear content
00567    hist_temp1->Reset();
00568 
00569    // loop over original histogram and copy bin untils integral equals
00570    // "prob"
00571    prob /= 100.;
00572 
00573    // integral
00574    double sum = 0.0;
00575 
00576    int n=0;
00577    int nbins=fHistogram->GetNbinsX();
00578 
00579    // loop
00580    while (sum < prob && n < nbins)
00581    {
00582       n++;
00583 
00584       // find bin with maximum
00585       int bin = hist_temp2->GetMaximumBin();
00586 
00587       // copy bin to new histogram
00588       double val = hist_temp2->GetBinContent(bin);
00589       hist_temp1->SetBinContent(bin, val);
00590 
00591       // remove maximum from temporary histogram
00592       hist_temp2->SetBinContent(bin, 0.0);
00593 
00594       // integrate by summing
00595       sum += val * hist_temp2->GetBinWidth(bin);
00596    }
00597 
00598    // scale histogram
00599    hist_temp1->Scale(fHistogram->Integral("width"));
00600 
00601    // draw histograms
00602    fHistogram->Draw("same");
00603    hist_temp1->Draw("same");
00604 
00605    // draw triangle for mode
00606    tmax->Draw("f");
00607 
00608    if(drawmean)
00609    {
00610       // draw triangle for mean
00611       // draw diamond for mean
00612       TPolyLine * tmean;
00613 
00614       y1+=dy/5.;
00615 //      double tmean_x[] = {x1, x1 + dx, x1 - dx, x1};
00616 //      double tmean_y[] = {y1, y1 + dy, y1 + dy, y1};
00617       double tmean_x[] = {x1, x1 + dx, x1 , x1 - dx, x1};
00618       double tmean_y[] = {y1, y1 + dy/2., y1 + dy, y1 + dy/2., y1};
00619       tmean = new TPolyLine(5,tmean_x,tmean_y);
00620       tmean->SetLineColor(kBlue);
00621 //      tmean->SetFillColor(kWhite);
00622       tmean->SetLineWidth(1);
00623 //      tmean->SetLineStyle(1);
00624       tmean->Draw();
00625 
00626       // draw dashed line for median
00627       TLine * line;
00628       line = new TLine();
00629       line->SetLineStyle(2);
00630       line->SetLineColor(kGreen+2);
00631       line->DrawLine(x2, 0., x2, y2);
00632    }
00633 
00634    // free memory
00635    delete hist_temp2;
00636 }
00637 
00638 // ---------------------------------------------------------
00639 
00640 double BCH1D::GetSmallestInterval(double & min, double & max, double content)
00641 {
00642    if(content<=0. || content>= 1.)
00643       return 0.;
00644 
00645    int nbins = fHistogram->GetNbinsX();
00646 
00647    double factor = fHistogram->Integral("width");
00648    if(factor==0)
00649       return 0.;
00650 
00651    // normalize if not yet done
00652    fHistogram->Scale(1./factor);
00653 
00654    double xmin = fHistogram->GetXaxis()->GetXmin();
00655    double xmax = fHistogram->GetXaxis()->GetXmax();
00656    double width = xmax - xmin;
00657 
00658    double xdown=xmin;
00659    double xup=xmax;
00660 
00661    int ndiv = 10;
00662 //   if(nbins<100)
00663 //      ndiv = 1000;
00664 //   if(nbins>1000)
00665 //      ndiv = 10;
00666 
00667    int warn=0;
00668 
00669    double integral_out=0.;
00670 
00671    // loop through the bins
00672    for(int i=1;i<nbins+1;i++)
00673    {
00674       if(fHistogram->Integral(i,nbins,"width") < content)
00675          break;
00676 
00677       // get width of the starting bin
00678       double firstbinwidth = fHistogram->GetBinWidth(i);
00679 
00680       // divide i-th bin in ndiv divisions
00681       // integrate starting at each of these divisions
00682       for(int j=0;j<ndiv;j++)
00683       {
00684          double dxdown = (double)(ndiv-j)/(double)ndiv * firstbinwidth;
00685          xdown = fHistogram->GetBinLowEdge(i) + firstbinwidth - dxdown;
00686          double integral = dxdown * fHistogram->GetBinContent(i);
00687 
00688          if(integral>content)
00689          {
00690             // content fits within one bin
00691             xup = xdown + content / fHistogram->GetBinContent(i);
00692             warn = 1;
00693          }
00694          else
00695             for(int k=i+1;k<nbins+1;k++)
00696             {
00697 
00698                double thisbin = fHistogram->GetBinContent(k) * fHistogram->GetBinWidth(k);
00699 
00700                if(integral+thisbin==content)
00701                {
00702                   xup = fHistogram->GetBinLowEdge(k+1);
00703                   break;
00704                }
00705 
00706                if(integral+thisbin>content)
00707                {
00708                   xup = fHistogram->GetBinLowEdge(k) + (content-integral)/thisbin * fHistogram->GetBinWidth(k);
00709                   integral += thisbin * (xup-fHistogram->GetBinLowEdge(k))/fHistogram->GetBinWidth(k);
00710                   break;
00711                }
00712 
00713                integral += thisbin;
00714             }
00715 
00716          if(integral < content)
00717             continue;
00718 
00719          if(xup - xdown < width)
00720          {
00721             // store necessary information
00722             width = xup - xdown;
00723             xmin  = xdown;
00724             xmax  = xup;
00725             integral_out = integral;
00726          }
00727       }
00728    }
00729 
00730    if(warn)
00731    {
00732       BCLog::OutWarning(
00733             Form("BCH1D::GetSmallestInterval : The requested content of %d%% fits within one bin.",(int)(content*100)));
00734       BCLog::OutWarning("BCH1D::GetSmallestInterval : MAKE FINER BINNING (OR CHANGE RANGE) !!!");
00735    }
00736 
00737    // restore normalization to state before calling this method
00738    fHistogram->Scale(factor);
00739 
00740    min=xmin;
00741    max=xmax;
00742 
00743    return integral_out;
00744 }
00745 
00746 // ---------------------------------------------------------
00747 
00748 double BCH1D::IntegralWidth(double min, double max)
00749 {
00750    int imin = fHistogram->FindBin(min);
00751    int imax = fHistogram->FindBin(max);
00752 
00753    int nbins = fHistogram->GetNbinsX();
00754 
00755    // if outside of histogram range, return -1.
00756    if ( imin<1 || imin>nbins || imax<1 || imax>nbins )
00757       return -1.;
00758 
00759    if ( imin==imax )
00760       return -1.;
00761 
00762    // swap values if necessary
00763    if (imin>imax)
00764    {
00765       int i=imin;
00766       double x=min;
00767       imin=imax, min=max;
00768       imax=i, max=x;
00769    }
00770 
00771    // calculate first bin
00772    double first = ( fHistogram->GetBinLowEdge(imin+1) - min ) * fHistogram->GetBinContent(imin);
00773 
00774    // calculate last bin
00775    double last = ( max - fHistogram->GetBinLowEdge(imax) ) * fHistogram->GetBinContent(imax);
00776 
00777    // calculate inbetween
00778    double inbetween=0.;
00779    if(imax-imin>1)
00780       inbetween = fHistogram->Integral(imin+1, imax-1, "width");
00781 
00782    return first + inbetween + last;
00783 }
00784 
00785 // ---------------------------------------------------------
00786 
00787 TH1D * BCH1D::GetSubHisto(double min, double max, const char * name)
00788 {
00789    if(min>max)
00790    {
00791       double t=min;
00792       min=max;
00793       max=t;
00794    }
00795 
00796    int imin = fHistogram->FindBin(min);
00797    int imax = fHistogram->FindBin(max);
00798 
00799    int nbins = fHistogram->GetNbinsX();
00800    double xmin = fHistogram->GetXaxis()->GetXmin();
00801    double xmax = fHistogram->GetXaxis()->GetXmax();
00802 
00803    if( min==max || (min<=xmin && max>=xmax) )
00804    {
00805       TH1D * h0 = (TH1D*) fHistogram->Clone(name);
00806       return h0;
00807    }
00808 
00809    if (imin<1)
00810    {
00811       imin=1;
00812       min=xmin;
00813    }
00814    if (imax>nbins)
00815    {
00816       imax=nbins;
00817       max=xmax;
00818    }
00819 
00820    double * xb = new double[nbins+3]; // nbins+1 original bin edges + 2 new bins
00821    int n=0; // counter
00822 
00823    int domin=1;
00824    int domax=1;
00825 
00826    for (int i=1;i<nbins+2;i++)
00827    {
00828       double x0 = fHistogram->GetBinLowEdge(i);
00829 
00830       if (min<x0 && domin)
00831       {
00832          xb[n++]=min;
00833          domin=0;
00834       }
00835       else if (min==x0)
00836          domin=0;
00837 
00838       if (max<x0 && domax)
00839       {
00840          xb[n++]=max;
00841          domax=0;
00842       }
00843       else if (max==x0)
00844          domax=0;
00845 
00846       xb[n++]=x0;
00847    }
00848 
00849    // now define the new histogram
00850    TH1D * h0 = new TH1D(name,"",n-1,xb);
00851    for(int i=1;i<n;i++)
00852    {
00853       double x0 = h0->GetBinCenter(i);
00854       if(x0<min || x0>max)
00855          continue;
00856 
00857       int bin=fHistogram->FindBin(x0);
00858       h0->SetBinContent(i, fHistogram->GetBinContent(bin));
00859    }
00860 
00861    return h0;
00862 }
00863 
00864 // ---------------------------------------------------------
00865 
00866 TH1D * BCH1D::GetSmallestIntervalHistogram(double level)
00867 {
00868    // create a new histogram which will be returned and all yellow
00869    TH1D * hist_yellow = (TH1D*) fHistogram->Clone();
00870    hist_yellow->Reset();
00871    hist_yellow->SetFillStyle(1001);
00872    hist_yellow->SetFillColor(kYellow);
00873 
00874    // copy a temporary histogram
00875    TH1D * hist_temp = (TH1D*) fHistogram->Clone(TString::Format("%s_%i",fHistogram->GetName(),BCLog::GetHIndex()));
00876    double factor = hist_temp->Integral("");
00877 
00878    if(factor == 0)
00879       return 0;
00880 
00881    hist_temp->Scale(1. / factor);
00882 
00883    // here's the algorithm:
00884    // 1. find the maximum bin in the temporary histogram and copy it to
00885    // the yellow histogram.
00886    // 2. remove this bin from the temporary histogram.
00887    // 3. repeat this until a total of "level" probability is copied to
00888    // the yellow histogram.
00889 
00890    double sumprob = 0.0;
00891 
00892    while (sumprob < level)
00893    {
00894       // find maximum bin and value
00895       int bin = hist_temp->GetMaximumBin();
00896       double value = hist_temp->GetMaximum();
00897 
00898       // copy "1" into the corresponding bin in the yellow histogram
00899       hist_yellow->SetBinContent(bin, 1.0);
00900 
00901       // set the bin value in the temporary histogram to zero
00902       hist_temp->SetBinContent(bin, 0.0);
00903 
00904       // increase probability sum
00905       sumprob += value;
00906    }
00907 
00908    delete hist_temp;
00909 
00910    return hist_yellow;
00911 }
00912 
00913 // ---------------------------------------------------------
00914 
00915 std::vector<double> BCH1D::GetSmallestIntervals(double content)
00916 {
00917    std::vector<double> v;
00918 
00919    TH1D * hist = GetSmallestIntervalHistogram(content);
00920 
00921    int nbins = hist->GetNbinsX();
00922    int ninter = 0;
00923    int lastbin = -1;
00924 
00925    double max = -1;
00926    double localmax = -1;
00927    double localmaxpos = -1;
00928    double localint = 0;
00929    bool flag = false;
00930 
00931    for (int i = 1; i <= nbins; ++i)
00932    {
00933       // interval starts here
00934       if (!flag && hist->GetBinContent(i) > 0.)
00935       {
00936          flag = true;
00937          v.push_back(hist->GetBinLowEdge(i));
00938 
00939          // remember start position of the interval
00940          lastbin = i;
00941 
00942          // increase number of intervals
00943          ninter++;
00944 
00945          // reset local maximum
00946          localmax = fHistogram->GetBinContent(i);
00947          localmaxpos = hist->GetBinLowEdge(i);
00948 
00949          // reset local integral
00950          localint = 0;
00951       }
00952 
00953       // interval stops here
00954       if ((flag && !(hist->GetBinContent(i) > 0.)) || (flag && i == nbins))
00955       {
00956          flag = false;
00957          v.push_back(hist->GetBinLowEdge(i) + hist->GetBinWidth(i));
00958 
00959          // set right bin to maximum if on edge
00960          if (i == nbins && localmax < fHistogram->GetBinContent(i))
00961             localmaxpos = hist->GetBinCenter(i) + 0.5 * hist->GetBinWidth(i);
00962 
00963          // find the absolute maximum
00964          if (localmax > max)
00965             max = localmax;
00966 
00967          // save local maximum
00968          v.push_back(localmax);
00969          v.push_back(localmaxpos);
00970 
00971          // save local integral
00972          v.push_back(localint);
00973       }
00974 
00975       // find local maximum
00976       if (i < nbins && localmax < fHistogram->GetBinContent(i))
00977       {
00978          localmax = fHistogram->GetBinContent(i);
00979          localmaxpos = hist->GetBinCenter(i);
00980       }
00981 
00982       // increase area
00983       localint += fHistogram->GetBinContent(i) / fHistogram->Integral();
00984    }
00985 
00986    // rescale absolute heights to relative heights
00987    for (int i = 0; i < ninter; ++i)
00988       v[i*5+2] = v.at(i*5+2) / max;
00989 
00990    return v;
00991 }
00992 
00993 // ---------------------------------------------------------

Generated by  doxygen 1.7.1