BAT  0.9.4
The Bayesian analysis toolkit
 All Classes Namespaces Functions Variables Enumerations
BCH1D.cxx
1 /*
2  * Copyright (C) 2007-2014, the BAT core developer team
3  * All rights reserved.
4  *
5  * For the licensing terms see doc/COPYING.
6  * For documentation see http://mpp.mpg.de/bat
7  */
8 
9 // ---------------------------------------------------------
10 
11 #include "BCH1D.h"
12 
13 #include "BCLog.h"
14 #include "BCMath.h"
15 
16 #include <TH1D.h>
17 #include <TROOT.h>
18 #include <TStyle.h>
19 #include <TH2.h>
20 #include <TLine.h>
21 #include <TPolyLine.h>
22 #include <TPaveLabel.h>
23 #include <TLatex.h>
24 #include <TError.h>
25 #include <TCanvas.h>
26 #include <TMarker.h>
27 #include <TArrow.h>
28 #include <TLegend.h>
29 #include <TLegendEntry.h>
30 #include <TString.h>
31 
32 #include <math.h>
33 
34 unsigned int BCH1D::fHCounter=0;
35 
36 // ---------------------------------------------------------
37 BCH1D::BCH1D(TH1D * hist)
38  : fHistogram(hist)
39  , fDefaultCLLimit(95.) // in percent
40  , fMode(0)
41  , fModeFlag(0)
42 {}
43 
44 // ---------------------------------------------------------
46 {
47  for (unsigned i = 0; i < fROOTObjects.size(); ++i)
48  delete fROOTObjects[i];
49 }
50 
51 // ---------------------------------------------------------
53 {
54  return fHistogram->GetBinCenter(fHistogram->GetMaximumBin());
55 }
56 
57 // ---------------------------------------------------------
58 double BCH1D::GetQuantile(double probability)
59 {
60  int nquantiles = 1;
61  double quantiles[1];
62  double probsum[1];
63 
64  probsum[0] = probability;
65 
66  // use ROOT function to calculate quantile.
67  fHistogram->GetQuantiles(nquantiles, quantiles, probsum);
68 
69  return quantiles[0];
70 }
71 
72 // ---------------------------------------------------------
73 double BCH1D::GetIntegral(double valuemin, double valuemax)
74 {
75  double integral = 0;
76 
77  int binmin = fHistogram->FindBin(valuemin);
78  int binmax = fHistogram->FindBin(valuemax);
79 
80  // use ROOT function to calculate integral.
81  integral = fHistogram->Integral(binmin, binmax);
82 
83  return integral;
84 }
85 
86 // ---------------------------------------------------------
87 double BCH1D::GetPValue(double probability)
88 {
89  // use ROOT function to calculate the integral from 0 to "probability".
90  return fHistogram->Integral(1, fHistogram->FindBin(probability));
91 }
92 
93 // ---------------------------------------------------------
94 void BCH1D::SetDefaultCLLimit(double limit)
95 {
96  // check if limit is between 68% and 100%. Give a warning if not ...
97  if(limit>=100. || limit<68.)
98  BCLog::OutWarning(
99  Form("BCH1D::SetDefaultCLLimit : Value %.1f out of range. Keeping default %.1f%% CL limit.",limit,fDefaultCLLimit));
100 
101  // ... or set value if true.
102  else
103  fDefaultCLLimit = limit;
104 }
105 
106 // ---------------------------------------------------------
107 void BCH1D::SetColorScheme(int scheme)
108 {
109  fColors.clear();
110 
111  // color numbering
112  // 0,1,2 : intervals
113  // 3 : quantile lines
114  // 4 : mean, mode, median
115 
116  if (scheme == 0) {
117  fColors.push_back(18);
118  fColors.push_back(16);
119  fColors.push_back(14);
120  fColors.push_back(kBlack);
121  fColors.push_back(kBlack);
122  }
123  else if (scheme == 1) {
124  fColors.push_back(kGreen);
125  fColors.push_back(kYellow);
126  fColors.push_back(kRed);
127  fColors.push_back(kBlack);
128  fColors.push_back(kBlack);
129  }
130  else if (scheme == 2) {
131  fColors.push_back(kBlue+4);
132  fColors.push_back(kBlue+2);
133  fColors.push_back(kBlue);
134  fColors.push_back(kOrange);
135  fColors.push_back(kOrange);
136  }
137  else if (scheme == 3) {
138  fColors.push_back(kRed+4);
139  fColors.push_back(kRed+2);
140  fColors.push_back(kRed);
141  fColors.push_back(kGreen);
142  fColors.push_back(kGreen);
143  }
144  else {
145  SetColorScheme(1);
146  }
147 }
148 
149 // ---------------------------------------------------------
150 void BCH1D::Print(const char* filename, std::string options, std::vector<double> intervals, int ww, int wh)
151 {
152  char file[256];
153  int i=0;
154  while(i<255 && *filename!='\0')
155  file[i++]=*filename++;
156  file[i]='\0';
157 
158  // option flags
159  bool flag_logx = false;
160  bool flag_logy = false;
161  bool flag_rescale = false;
162 
163  // check content of options string
164  if (options.find("logx") < options.size()) {
165  flag_logx = true;
166  }
167 
168  if (options.find("logy") < options.size()) {
169  flag_logy = true;
170  }
171 
172  if (options.find("R") < options.size()) {
173  flag_rescale = true;
174  }
175 
176  // create temporary canvas
177  TCanvas * c;
178  unsigned int cindex = getNextIndex();
179  if(ww > 0 && wh > 0)
180  c = new TCanvas(TString::Format("c_bch1d_%d",cindex), TString::Format("c_bch1d_%d",cindex), ww, wh);
181  else
182  c = new TCanvas(TString::Format("c_bch1d_%d",cindex));
183 
184  // add c to list of objects
185  fROOTObjects.push_back(c);
186 
187  c->cd();
188 
189  // set log axis
190  if (flag_logx) {
191  c->SetLogx();
192  }
193 
194  // set log axis
195  if (flag_logy) {
196  c->SetLogy();
197  }
198 
199  Draw(options, intervals);
200 
201  if (flag_rescale) {
202  double top = gPad->GetTopMargin();
203  double bottom = gPad->GetBottomMargin();
204  double left = gPad->GetLeftMargin();
205  double right = gPad->GetRightMargin();
206 
207  double dx = 1.-right - left;
208  double dy = 1.-top-bottom;
209  double ratio = dy/dx;
210  double ynew = c->GetWindowWidth()/ratio;
211  c->SetCanvasSize(c->GetWindowWidth(), (int) (ynew + 0.5));
212  gPad->RedrawAxis();
213 
214  c->Modified();
215  c->Update();
216  }
217 
218  // print to file.
219  c->Print(file);
220 }
221 
222 // ---------------------------------------------------------
223 void BCH1D::Print(const char* filename, std::string options, double interval, int ww, int wh)
224 {
225  std::vector<double> tempvec;
226  tempvec.push_back(interval);
227  Print(filename, options, tempvec, ww, wh);
228 }
229 
230 // ---------------------------------------------------------
231 void BCH1D::Draw(std::string options, std::vector<double> intervals)
232 {
233  // option flags
234  bool flag_legend = false;
235  bool flag_logy = false;
236  bool flag_mode = false;
237  bool flag_median = false;
238  bool flag_mean = false;
239  bool flag_quartiles = false;
240  bool flag_deciles = false;
241  bool flag_percentiles = false;
242  bool flag_smooth1 = false;
243  bool flag_smooth3 = false;
244  bool flag_smooth5 = false;
245  bool flag_smooth10 = false;
246 
247  // band type
248  int bandtype = 0;
249 
250  // number of bands
251  int nbands = 0; // number of shaded bands
252 
253  // define draw options called in TH1D::Draw(...)
254  std::string draw_options = "";
255 
256  // check content of options string
257  if (options.find("smooth1") < options.size()) {
258  flag_smooth1 = true;
259  }
260 
261  if (options.find("smooth3") < options.size()) {
262  flag_smooth3 = true;
263  }
264 
265  if (options.find("smooth5") < options.size()) {
266  flag_smooth5 = true;
267  }
268 
269  if (options.find("smooth10") < options.size()) {
270  flag_smooth10 = true;
271  }
272 
273  if (options.find("same") < options.size()) {
274  draw_options.append("SAME");
275  }
276 
277  if (options.find("logy") < options.size()) {
278  flag_logy = true;
279  }
280 
281  if (options.find("L") < options.size()) {
282  flag_legend = true;
283  }
284 
285  if (options.find("D1") < options.size()) {
286  draw_options.append("C");
287  }
288 
289  if (options.find("BTsi") < options.size()) {
290  bandtype = 1;
291  }
292  else if (options.find("BTul") < options.size()) {
293  bandtype = 2;
294  }
295  else if (options.find("BTll") < options.size()) {
296  bandtype = 3;
297  }
298  else {
299  bandtype = 0;
300  }
301 
302  if (options.find("B1") < options.size()) {
303  nbands = 1;
304  if (bandtype == 0 && intervals.size() != 2) {
305  intervals.clear();
306  intervals.push_back(0.1587);
307  intervals.push_back(0.8413);
308  }
309  else if (bandtype == 1 && intervals.size() != 1) {
310  intervals.clear();
311  intervals.push_back(0.6827);
312  }
313  else if (bandtype == 2 && intervals.size() != 1) {
314  intervals.clear();
315  intervals.push_back(0.90);
316  }
317  else if (bandtype == 3 && intervals.size() != 1) {
318  intervals.clear();
319  intervals.push_back(0.10);
320  }
321  }
322 
323  if (options.find("B2") < options.size()) {
324  nbands = 2;
325  if (bandtype == 0 && intervals.size() != 4) {
326  intervals.clear();
327  intervals.push_back(0.1587);
328  intervals.push_back(0.8413);
329  intervals.push_back(0.0228);
330  intervals.push_back(0.9772);
331  }
332  else if (bandtype == 1 && intervals.size() != 2) {
333  intervals.clear();
334  intervals.push_back(0.6827);
335  intervals.push_back(0.9545);
336  }
337  else if (bandtype == 2 && intervals.size() != 2) {
338  intervals.clear();
339  intervals.push_back(0.90);
340  intervals.push_back(0.95);
341  }
342  else if (bandtype == 3 && intervals.size() != 2) {
343  intervals.clear();
344  intervals.push_back(0.10);
345  intervals.push_back(0.05);
346  }
347  }
348 
349  if (options.find("B3") < options.size()) {
350  nbands = 3;
351  if (bandtype == 0 && intervals.size() != 6) {
352  intervals.clear();
353  intervals.push_back(0.1587);
354  intervals.push_back(0.8413);
355  intervals.push_back(0.0228);
356  intervals.push_back(0.9772);
357  intervals.push_back(0.0013);
358  intervals.push_back(0.9987);
359  }
360  else if (bandtype == 1 && intervals.size() != 3) {
361  intervals.clear();
362  intervals.push_back(0.6827);
363  intervals.push_back(0.9545);
364  intervals.push_back(0.9973);
365  }
366  else if (bandtype == 2 && intervals.size() != 3) {
367  intervals.clear();
368  intervals.push_back(0.90);
369  intervals.push_back(0.95);
370  intervals.push_back(0.99);
371  }
372  else if (bandtype == 3 && intervals.size() != 3) {
373  intervals.clear();
374  intervals.push_back(0.10);
375  intervals.push_back(0.05);
376  intervals.push_back(0.01);
377  }
378  }
379 
380  if (options.find("CS0") < options.size()) {
381  SetColorScheme(0);
382  }
383  else if (options.find("CS1") < options.size()) {
384  SetColorScheme(1);
385  }
386  else if (options.find("CS2") < options.size()) {
387  SetColorScheme(2);
388  }
389  else if (options.find("CS3") < options.size()) {
390  SetColorScheme(3);
391  }
392  else {
393  SetColorScheme(1);
394  }
395 
396  if (options.find("mode") < options.size()) {
397  if (fModeFlag)
398  flag_mode = true;
399  }
400  if (options.find("median") < options.size()) {
401  flag_median = true;
402  }
403  if (options.find("mean") < options.size()) {
404  flag_mean = true;
405  }
406  if (options.find("quartiles") < options.size()) {
407  flag_quartiles = true;
408  }
409  if (options.find("deciles") < options.size()) {
410  flag_deciles = true;
411  }
412  if (options.find("percentiles") < options.size()) {
413  flag_percentiles = true;
414  }
415 
416  // normalize histogram to unity
417  fHistogram->Scale(1./fHistogram->Integral("width"));
418 
419  // prepare legend
420  TLegend* legend = new TLegend();
421  legend->SetBorderSize(0);
422  legend->SetFillColor(kWhite);
423  legend->SetTextAlign(12);
424  legend->SetTextFont(62);
425  legend->SetTextSize(0.03);
426 
427  // add legend to list of objects
428  fROOTObjects.push_back(legend);
429 
430  // smooth
431  if (flag_smooth1) {
432  fHistogram->Smooth(1);
433  fHistogram->Scale(1.0/fHistogram->Integral("width"));
434  }
435  if (flag_smooth3) {
436  fHistogram->Smooth(3);
437  fHistogram->Scale(1.0/fHistogram->Integral("width"));
438  }
439 
440  if (flag_smooth5) {
441  fHistogram->Smooth(5);
442  fHistogram->Scale(1.0/fHistogram->Integral("width"));
443  }
444  if (flag_smooth10) {
445  fHistogram->Smooth(10);
446  fHistogram->Scale(1.0/fHistogram->Integral("width"));
447  }
448 
449  // draw histogram
450  fHistogram->Draw(draw_options.c_str());
451 
452  // draw bands
453  for (int i = 0; i < nbands; ++i) {
454  int col = GetColor(nbands-i-1);
455 
456  double prob_low = 0;
457  double prob_high = 0;
458  double prob_interval = 0;
459  double xlow = 0;
460  double xhigh = 0;
461 
462  TH1D * hist_band = 0;
463 
464  if (bandtype == 0) {
465  prob_low = intervals[2*(nbands-i)-2];
466  prob_high = intervals[2*(nbands-i)-1];
467  xlow = GetQuantile(prob_low);
468  xhigh = GetQuantile(prob_high);
469  prob_interval = prob_high - prob_low;
470 
471  hist_band = GetSubHisto(xlow, xhigh, TString::Format("%s_sub_%d", fHistogram->GetName(), BCLog::GetHIndex()));
472  }
473  else if (bandtype == 1) {
474  prob_interval = GetSmallestInterval(xlow, xhigh, intervals[nbands-1-i]);
475  hist_band = GetSmallestIntervalHistogram(intervals[nbands-1-i]);
476  for (int ibin = 1; ibin <= hist_band->GetNbinsX(); ++ibin)
477  hist_band->SetBinContent(ibin, hist_band->GetBinContent(ibin)*fHistogram->GetBinContent(ibin));
478  }
479  else if(bandtype == 2) {
480  xlow = 0.;
481  xhigh = GetQuantile(intervals[nbands-1-i]);
482  hist_band = GetSubHisto(xlow, xhigh, TString::Format("%s_sub_%d", fHistogram->GetName(), BCLog::GetHIndex()));
483  prob_interval = intervals[nbands-1-i];
484  }
485  else if(bandtype == 3) {
486  xlow = GetQuantile(intervals[nbands-1-i]);
487  xhigh = GetQuantile(1.);
488  hist_band = GetSubHisto(xlow, xhigh, TString::Format("%s_sub_%d", fHistogram->GetName(), BCLog::GetHIndex()));
489  prob_interval = 1.-intervals[nbands-1-i];
490  }
491 
492  // set style of band histogram
493  hist_band->SetFillStyle(1001);
494  hist_band->SetFillColor(col);
495  hist_band->SetLineColor(col);
496 
497  // draw shaded histogram
498  hist_band->Draw(std::string(draw_options+std::string("same")).c_str());
499 
500  // draw histogram again
501  fHistogram->Draw(std::string(std::string("SAME")+draw_options).c_str());
502 
503  // add to legend
504  std::string legend_label;
505  if (bandtype == 0)
506  legend_label.append(Form("central %.1f%% interval ", prob_interval*100));
507  else if (bandtype == 1)
508  legend_label.append(Form("smallest %.1f%% interval(s)", prob_interval*100));
509  else if (bandtype == 2)
510  legend_label.append(Form("%.0f%% upper limit", prob_interval*100));
511  else if (bandtype == 3)
512  legend_label.append(Form("%.0f%% lower limit", prob_interval*100));
513 
514  legend->AddEntry(hist_band, legend_label.c_str(), "F");
515 
516  // add hist_band to list of objects
517  fROOTObjects.push_back(hist_band);
518  }
519 
520  gPad->RedrawAxis();
521 
522  // prepare size of histogram
523  double ymin = 0;
524  double ymaxhist = fHistogram->GetBinContent(fHistogram->GetMaximumBin());
525  double ymax = ymaxhist;
526 
527  // check if log axis
528  if (flag_logy)
529  ymin = 1e-4*ymaxhist;
530 
531  // quantiles
532  TLine* line_quantiles = new TLine();
533  line_quantiles->SetLineStyle(2);
534  line_quantiles->SetLineColor(GetColor(3));
535 
536  if (flag_quartiles) {
537  for (int i = 1; i < 4; ++i) {
538  double quantile_x = GetQuantile(0.25*i);
539  int quantile_xbin = fHistogram->FindBin(quantile_x);
540  double quantile_y = fHistogram->GetBinContent(quantile_xbin);
541  double quantile_ymin = 0;
542  if (flag_logy)
543  quantile_ymin = 1e-4*ymaxhist;
544  line_quantiles->DrawLine(quantile_x, quantile_ymin, quantile_x, quantile_y);
545  }
546  TLegendEntry* le = legend->AddEntry(line_quantiles, "quartiles", "L");
547  if (nbands>0)
548  le->SetFillColor(GetColor(0));
549  else
550  le->SetFillColor(kWhite);
551  le->SetFillStyle(1001);
552  }
553 
554  if (flag_deciles) {
555  for (int i = 1; i < 10; ++i) {
556  double quantile_x = GetQuantile(0.10*i);
557  int quantile_xbin = fHistogram->FindBin(quantile_x);
558  double quantile_y = fHistogram->GetBinContent(quantile_xbin);
559  double quantile_ymin = 0;
560  if (flag_logy)
561  quantile_ymin = 1e-4*ymaxhist;
562  line_quantiles->DrawLine(quantile_x, quantile_ymin, quantile_x, quantile_y);
563  }
564  TLegendEntry* le = legend->AddEntry(line_quantiles, "deciles", "FL");
565  le->SetFillColor(GetColor(0));
566  le->SetFillStyle(1001);
567  }
568 
569  if (flag_percentiles) {
570  for (int i = 1; i < 100; ++i) {
571  double quantile_x = GetQuantile(0.01*i);
572  int quantile_xbin = fHistogram->FindBin(quantile_x);
573  double quantile_y = fHistogram->GetBinContent(quantile_xbin);
574  double quantile_ymin = 0;
575  if (flag_logy)
576  quantile_ymin = 1e-4*ymaxhist;
577  line_quantiles->DrawLine(quantile_x, quantile_ymin, quantile_x, quantile_y);
578  }
579  TLegendEntry* le = legend->AddEntry(line_quantiles, "percentiles", "L");
580  le->SetFillColor(GetColor(0));
581  le->SetFillStyle(1001);
582  }
583 
584  // add line_quantiles to list of ROOT objects
585  fROOTObjects.push_back(line_quantiles);
586 
587  // mean, mode, median
588  TMarker* marker_mode = new TMarker(fMode, 0.50*ymaxhist, 24);
589  marker_mode->SetMarkerColor(GetColor(4));
590  marker_mode->SetMarkerSize(1.5);
591 
592  TMarker* marker_mean = new TMarker(GetMean(), 0.55*ymaxhist, 20);
593  marker_mean->SetMarkerColor(GetColor(4));
594  marker_mean->SetMarkerSize(1.5);
595 
596  TMarker* marker_median = new TMarker(GetMedian(), 0.45*ymaxhist, 21);
597  marker_median->SetMarkerColor(GetColor(4));
598  marker_median->SetMarkerSize(1.5);
599 
600  // mode
601  TArrow* arrow_mode = new TArrow(fMode, 0.485*ymaxhist,
602  fMode, ymin,
603  0.02, "|>");
604  arrow_mode->SetLineColor(GetColor(4));
605  arrow_mode->SetFillColor(GetColor(4));
606 
607  // standard deviation
608  TArrow* arrow_std = new TArrow(GetMean()-GetRMS(), 0.55*ymaxhist,
609  GetMean()+GetRMS(), 0.55*ymaxhist,
610  0.02, "<|>");
611  arrow_std->SetLineColor(GetColor(4));
612  arrow_std->SetFillColor(GetColor(4));
613 
614  // central interval
615  TArrow* arrow_ci = new TArrow(GetQuantile(0.1587), 0.45*ymaxhist,
616  GetQuantile(0.8413), 0.45*ymaxhist,
617  0.02, "<|>");
618  arrow_ci->SetLineColor(GetColor(4));
619  arrow_ci->SetFillColor(GetColor(4));
620 
621  // add marker_mean and arrow_std to list of ROOT objects
622  fROOTObjects.push_back(marker_mode);
623  fROOTObjects.push_back(marker_mean);
624  fROOTObjects.push_back(marker_median);
625  fROOTObjects.push_back(arrow_std);
626  fROOTObjects.push_back(arrow_ci);
627 
628  if (flag_mode) {
629  arrow_mode->Draw();
630  marker_mode->Draw();
631  TLegendEntry* le = legend->AddEntry(marker_mode, "global mode", "P");
632  le->SetMarkerStyle(24);
633  le->SetMarkerSize(1.5);
634  le->SetMarkerColor(GetColor(4));
635  }
636 
637  if (flag_mean) {
638  arrow_std->Draw();
639  marker_mean->Draw();
640  TLegendEntry* le = legend->AddEntry(arrow_std, "mean and standard deviation", "PL");
641  le->SetLineColor(GetColor(4));
642  le->SetMarkerStyle(20);
643  le->SetMarkerSize(1.5);
644  le->SetMarkerColor(GetColor(4));
645  }
646 
647  if (flag_median) {
648  arrow_ci->Draw();
649  marker_median->Draw();
650  TLegendEntry* le = legend->AddEntry(arrow_ci, "median and central 68.3% interval", "PL");
651  le->SetLineColor(GetColor(4));
652  le->SetMarkerStyle(21);
653  le->SetMarkerSize(1.5);
654  le->SetMarkerColor(GetColor(4));
655  }
656 
657  // calculate legend height in NDC coordinates
658  double height = 0.03*legend->GetNRows();
659 
660  // make room for legend
661  if (flag_legend)
662  ymax*=(1.15+height);
663  else
664  ymax*=1.1;
665 
666  fHistogram->GetYaxis()->SetRangeUser(ymin, 1.05*ymaxhist);
667 
668  // calculate dimensions in NDC variables
669 
670  if (flag_legend)
671  gPad->SetTopMargin(0.02);
672 
673  double xlegend1 = gPad->GetLeftMargin() + 0.10 * (1.0 - gPad->GetRightMargin() - gPad->GetLeftMargin());
674  double xlegend2 = 1.0-gPad->GetRightMargin();
675  double ylegend1 = 1.-gPad->GetTopMargin()-height;
676  double ylegend2 = 1.-gPad->GetTopMargin();
677 
678  // place legend on top of histogram
679  legend->SetX1NDC(xlegend1);
680  legend->SetX2NDC(xlegend2);
681  legend->SetY1NDC(ylegend1);
682  legend->SetY2NDC(ylegend2);
683 
684  // draw legend
685  if (flag_legend) {
686  legend->Draw();
687  }
688 
689  // rescale top margin
690  gPad->SetTopMargin(1.-ylegend1+0.01);
691 
692  gPad->RedrawAxis();
693 
694  return;
695 }
696 
697 // ---------------------------------------------------------
698 void BCH1D::Draw(std::string options, double interval)
699 {
700  std::vector<double> tempvec;
701  tempvec.push_back(interval);
702  Draw(options, tempvec);
703 }
704 
705 // ---------------------------------------------------------
706 void BCH1D::DrawDelta(double value) const
707 {
708  // draw histogram with axes first
709  double xmin = fHistogram->GetXaxis()->GetXmin();
710  double xmax = fHistogram->GetXaxis()->GetXmax();
711  double ysize = 1.3 * fHistogram->GetMaximum();
712 
713  TH2D* hsc = new TH2D(
714  TString::Format("h2scale_%s_%d",fHistogram->GetName(),BCLog::GetHIndex()),"",
715  50, xmin, xmax, 10, 0., ysize);
716  hsc->SetStats(0);
717  hsc->SetXTitle(fHistogram->GetXaxis()->GetTitle());
718  hsc->SetYTitle(fHistogram->GetYaxis()->GetTitle());
719  hsc->Draw();
720 
721  // write mode location
722 
723  TLatex * tmax_text = new TLatex();
724  tmax_text->SetTextSize(0.035);
725  tmax_text->SetTextFont(62);
726  tmax_text->SetTextAlign(22); // center
727 
728  double xprint=(xmax+xmin)/2.;
729  double yprint=ysize*(1-1.4*tmax_text->GetTextSize());
730 
731  tmax_text->DrawLatex(xprint,yprint, TString::Format("%s = %g", fHistogram->GetXaxis()->GetTitle(), value));
732  delete tmax_text;
733 
734  // create a temporary histogram, to hold only one non-zero bin
735  TH1D * hist_temp = new TH1D(TString::Format("h1scale_%s_%d", fHistogram->GetName(), BCLog::GetHIndex()), "", 100, xmin, xmax);
736  hist_temp->SetBinContent(hist_temp->FindBin(value), fHistogram->GetMaximum());
737  hist_temp->Draw("same");
738  fROOTObjects.push_back(hist_temp);
739 }
740 
741 // ---------------------------------------------------------
742 double BCH1D::GetSmallestInterval(double & min, double & max, double content)
743 {
744  if(content<=0. || content>= 1.)
745  return 0.;
746 
747  int nbins = fHistogram->GetNbinsX();
748 
749  double factor = fHistogram->Integral("width");
750  if(factor==0)
751  return 0.;
752 
753  // normalize if not yet done
754  fHistogram->Scale(1./factor);
755 
756  double xmin = fHistogram->GetXaxis()->GetXmin();
757  double xmax = fHistogram->GetXaxis()->GetXmax();
758  double width = xmax - xmin;
759 
760  double xdown=xmin;
761  double xup=xmax;
762 
763  int ndiv = 10;
764  int warn=0;
765 
766  double integral_out=0.;
767 
768  // loop through the bins
769  for(int i=1;i<nbins+1;i++)
770  {
771  if(fHistogram->Integral(i,nbins,"width") < content)
772  break;
773 
774  // get width of the starting bin
775  double firstbinwidth = fHistogram->GetBinWidth(i);
776 
777  // divide i-th bin in ndiv divisions
778  // integrate starting at each of these divisions
779  for(int j=0;j<ndiv;j++)
780  {
781  double dxdown = (double)(ndiv-j)/(double)ndiv * firstbinwidth;
782  xdown = fHistogram->GetBinLowEdge(i) + firstbinwidth - dxdown;
783  double integral = dxdown * fHistogram->GetBinContent(i);
784 
785  if(integral>content)
786  {
787  // content fits within one bin
788  xup = xdown + content / fHistogram->GetBinContent(i);
789  warn = 1;
790  }
791  else
792  for(int k=i+1;k<nbins+1;k++)
793  {
794 
795  double thisbin = fHistogram->GetBinContent(k) * fHistogram->GetBinWidth(k);
796 
797  if(integral+thisbin==content)
798  {
799  xup = fHistogram->GetBinLowEdge(k+1);
800  break;
801  }
802 
803  if(integral+thisbin>content)
804  {
805  xup = fHistogram->GetBinLowEdge(k) + (content-integral)/thisbin * fHistogram->GetBinWidth(k);
806  integral += thisbin * (xup-fHistogram->GetBinLowEdge(k))/fHistogram->GetBinWidth(k);
807  break;
808  }
809 
810  integral += thisbin;
811  }
812 
813  if(integral < content)
814  continue;
815 
816  if(xup - xdown < width)
817  {
818  // store necessary information
819  width = xup - xdown;
820  xmin = xdown;
821  xmax = xup;
822  integral_out = integral;
823  }
824  }
825  }
826 
827  if(warn)
828  {
829  BCLog::OutWarning(
830  Form("BCH1D::GetSmallestInterval : The requested content of %d%% fits within one bin.",(int)(content*100)));
831  BCLog::OutWarning("BCH1D::GetSmallestInterval : MAKE FINER BINNING (OR CHANGE RANGE) !!!");
832  }
833 
834  // restore normalization to state before calling this method
835  fHistogram->Scale(factor);
836 
837  min=xmin;
838  max=xmax;
839 
840  return integral_out;
841 }
842 
843 // ---------------------------------------------------------
844 double BCH1D::IntegralWidth(double min, double max)
845 {
846  int imin = fHistogram->FindBin(min);
847  int imax = fHistogram->FindBin(max);
848 
849  int nbins = fHistogram->GetNbinsX();
850 
851  // if outside of histogram range, return -1.
852  if ( imin<1 || imin>nbins || imax<1 || imax>nbins )
853  return -1.;
854 
855  if ( imin==imax )
856  return -1.;
857 
858  // swap values if necessary
859  if (imin>imax)
860  {
861  int i=imin;
862  double x=min;
863  imin=imax, min=max;
864  imax=i, max=x;
865  }
866 
867  // calculate first bin
868  double first = ( fHistogram->GetBinLowEdge(imin+1) - min ) * fHistogram->GetBinContent(imin);
869 
870  // calculate last bin
871  double last = ( max - fHistogram->GetBinLowEdge(imax) ) * fHistogram->GetBinContent(imax);
872 
873  // calculate inbetween
874  double inbetween=0.;
875  if(imax-imin>1)
876  inbetween = fHistogram->Integral(imin+1, imax-1, "width");
877 
878  return first + inbetween + last;
879 }
880 
881 // ---------------------------------------------------------
882 TH1D * BCH1D::GetSubHisto(double min, double max, const char * name)
883 {
884  if(min>max)
885  {
886  double t=min;
887  min=max;
888  max=t;
889  }
890 
891  int imin = fHistogram->FindBin(min);
892  int imax = fHistogram->FindBin(max);
893 
894  int nbins = fHistogram->GetNbinsX();
895  double xmin = fHistogram->GetXaxis()->GetXmin();
896  double xmax = fHistogram->GetXaxis()->GetXmax();
897 
898  if( min==max || (min<=xmin && max>=xmax) )
899  {
900  TH1D * h0 = (TH1D*) fHistogram->Clone(name);
901  return h0;
902  }
903 
904  if (imin<1)
905  {
906  imin=1;
907  min=xmin;
908  }
909  if (imax>nbins)
910  {
911  imax=nbins;
912  max=xmax;
913  }
914 
915  std::vector<double> xb(nbins + 3); // nbins+1 original bin edges + 2 new bins
916  int n=0; // counter
917 
918  int domin=1;
919  int domax=1;
920 
921  for (int i=1;i<nbins+2;i++)
922  {
923  double x0 = fHistogram->GetBinLowEdge(i);
924 
925  if (min<x0 && domin)
926  {
927  xb[n++]=min;
928  domin=0;
929  }
930  else if (min==x0)
931  domin=0;
932 
933  if (max<x0 && domax)
934  {
935  xb[n++]=max;
936  domax=0;
937  }
938  else if (max==x0)
939  domax=0;
940 
941  xb[n++]=x0;
942  }
943 
944  // now define the new histogram
945  TH1D * h0 = new TH1D(name,"",n-1, &xb[0]);
946  for(int i=1;i<n;i++)
947  {
948  double x0 = h0->GetBinCenter(i);
949  if(x0<min || x0>max)
950  continue;
951 
952  int bin=fHistogram->FindBin(x0);
953  h0->SetBinContent(i, fHistogram->GetBinContent(bin));
954  }
955 
956  return h0;
957 }
958 
959 // ---------------------------------------------------------
961 {
962  // create a new histogram which will be returned and all yellow
963  TH1D * hist_yellow = (TH1D*) fHistogram->Clone();
964  hist_yellow->Reset();
965  hist_yellow->SetFillStyle(1001);
966  hist_yellow->SetFillColor(kYellow);
967 
968  // copy a temporary histogram
969  TH1D * hist_temp = (TH1D*) fHistogram->Clone(TString::Format("%s_%i",fHistogram->GetName(),BCLog::GetHIndex()));
970  double factor = hist_temp->Integral("");
971 
972  if(factor == 0)
973  return 0;
974 
975  hist_temp->Scale(1. / factor);
976 
977  // here's the algorithm:
978  // 1. find the maximum bin in the temporary histogram and copy it to
979  // the yellow histogram.
980  // 2. remove this bin from the temporary histogram.
981  // 3. repeat this until a total of "level" probability is copied to
982  // the yellow histogram.
983 
984  double sumprob = 0.0;
985 
986  while (sumprob < level)
987  {
988  // find maximum bin and value
989  int bin = hist_temp->GetMaximumBin();
990  double value = hist_temp->GetMaximum();
991 
992  // copy "1" into the corresponding bin in the yellow histogram
993  hist_yellow->SetBinContent(bin, 1.0);
994 
995  // set the bin value in the temporary histogram to zero
996  hist_temp->SetBinContent(bin, 0.0);
997 
998  // increase probability sum
999  sumprob += value;
1000  }
1001 
1002  delete hist_temp;
1003 
1004  return hist_yellow;
1005 }
1006 
1007 // ---------------------------------------------------------
1008 std::vector<double> BCH1D::GetSmallestIntervals(double content)
1009 {
1010  std::vector<double> v;
1011 
1012  TH1D * hist = GetSmallestIntervalHistogram(content);
1013 
1014  int nbins = hist->GetNbinsX();
1015  int ninter = 0;
1016 
1017  double max = -1;
1018  double localmax = -1;
1019  double localmaxpos = -1;
1020  double localint = 0;
1021  bool flag = false;
1022 
1023  for (int i = 1; i <= nbins; ++i)
1024  {
1025  // interval starts here
1026  if (!flag && hist->GetBinContent(i) > 0.)
1027  {
1028  flag = true;
1029  v.push_back(hist->GetBinLowEdge(i));
1030 
1031  // increase number of intervals
1032  ninter++;
1033 
1034  // reset local maximum
1035  localmax = fHistogram->GetBinContent(i);
1036  localmaxpos = hist->GetBinLowEdge(i);
1037 
1038  // reset local integral
1039  localint = 0;
1040  }
1041 
1042  // interval stops here
1043  if ((flag && !(hist->GetBinContent(i) > 0.)) || (flag && i == nbins))
1044  {
1045  flag = false;
1046  v.push_back(hist->GetBinLowEdge(i) + hist->GetBinWidth(i));
1047 
1048  // set right bin to maximum if on edge
1049  if (i == nbins && localmax < fHistogram->GetBinContent(i))
1050  localmaxpos = hist->GetBinCenter(i) + 0.5 * hist->GetBinWidth(i);
1051 
1052  // find the absolute maximum
1053  if (localmax > max)
1054  max = localmax;
1055 
1056  // save local maximum
1057  v.push_back(localmax);
1058  v.push_back(localmaxpos);
1059 
1060  // save local integral
1061  v.push_back(localint);
1062  }
1063 
1064  // find local maximum
1065  if (i < nbins && localmax < fHistogram->GetBinContent(i))
1066  {
1067  localmax = fHistogram->GetBinContent(i);
1068  localmaxpos = hist->GetBinCenter(i);
1069  }
1070 
1071  // increase area
1072  localint += fHistogram->GetBinContent(i) / fHistogram->Integral();
1073  }
1074 
1075  // rescale absolute heights to relative heights
1076  for (int i = 0; i < ninter; ++i)
1077  v[i*5+2] = v.at(i*5+2) / max;
1078 
1079  delete hist;
1080 
1081  return v;
1082 }
~BCH1D()
Definition: BCH1D.cxx:45
double GetRMS()
Definition: BCH1D.h:87
BCH1D(TH1D *hist=0)
Definition: BCH1D.cxx:37
double GetPValue(double probability)
Definition: BCH1D.cxx:87
double GetIntegral(double valuemin, double valuemax)
Definition: BCH1D.cxx:73
TH1D * GetSubHisto(double min, double max, const char *name)
Definition: BCH1D.cxx:882
double GetMean()
Definition: BCH1D.h:58
void DrawDelta(double value) const
Definition: BCH1D.cxx:706
void SetColorScheme(int scheme)
Definition: BCH1D.cxx:107
static int GetHIndex()
Definition: BCLog.h:164
double GetMedian()
Definition: BCH1D.h:67
void Print(const char *filename, std::string options="BTsiB3CS1D0Lmeanmode", std::vector< double > intervals=std::vector< double >(0), int ww=0, int wh=0)
Definition: BCH1D.cxx:150
TH1D * GetSmallestIntervalHistogram(double level)
Definition: BCH1D.cxx:960
double IntegralWidth(double min, double max)
Definition: BCH1D.cxx:844
double GetMode()
Definition: BCH1D.cxx:52
int GetColor(int index)
Definition: BCH1D.h:128
std::vector< double > GetSmallestIntervals(double content=0.68)
Definition: BCH1D.cxx:1008
double GetSmallestInterval(double &min, double &max, double content=.68)
Definition: BCH1D.cxx:742
double GetQuantile(double probablity)
Definition: BCH1D.cxx:58
void SetDefaultCLLimit(double limit)
Definition: BCH1D.cxx:94
void Draw(std::string options="BTsiB3CS1D0Lmeanmode", std::vector< double > intervals=std::vector< double >(0))
Definition: BCH1D.cxx:231