BCH2D.cxx
1 /*
2  * Copyright (C) 2007-2018, 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 "BCH2D.h"
12 
13 #include <TGraph.h>
14 #include <TH2.h>
15 #include <TLegendEntry.h>
16 #include <TLine.h>
17 #include <TMarker.h>
18 #include <TObject.h>
19 #include <TPad.h>
20 #include <TROOT.h>
21 #include <TString.h>
22 #include <TStyle.h>
23 
24 #include <algorithm>
25 #include <math.h>
26 
27 // ---------------------------------------------------------
28 BCH2D::BCH2D(const TH2* const h)
29  : BCHistogramBase(h, 2)
30  , fBandType(kSmallestInterval)
31  , fDrawProfileX(false)
32  , fProfileXType(kProfileMean)
33  , fProfileXLineColor(kBlack)
34  , fProfileXLineStyle(2)
35  , fDrawProfileY(false)
36  , fProfileYType(kProfileMean)
37  , fProfileYLineColor(kBlack)
38  , fProfileYLineStyle(2)
39 {
40  SetDrawLocalMode(true, false);
41  SetDrawGlobalMode(true, false);
42 }
43 
44 // ---------------------------------------------------------
45 BCH2D::BCH2D(const BCH2D& other)
46  : BCHistogramBase(other)
47 {
48  CopyOptions(other);
49 }
50 
51 // ---------------------------------------------------------
52 void BCH2D::CopyOptions(const BCH2D& other)
53 {
55  fBandType = other.fBandType;
64 }
65 
66 // ---------------------------------------------------------
67 void BCH2D::CheckIntervals(std::vector<double>& intervals)
68 {
69  if (fBandType != kNoBands)
70  BCHistogramBase::CheckIntervals(intervals, +1);
71 }
72 
73 // ---------------------------------------------------------
74 std::vector<double> BCH2D::DefaultIntervals(int nbands)
75 {
76  std::vector<double> intervals;
77 
78  switch (fBandType) {
79 
80  case kNoBands:
81  return intervals;
82 
83  case kSmallestInterval:
84  default:
85  return BCHistogramBase::DefaultIntervals(nbands);
86 
87  }
88 }
89 
90 // ---------------------------------------------------------
91 void BCH2D::DrawBands(const std::string& options)
92 {
93  if (fBandType == kNoBands) {
94  GetHistogram()->Draw((options + "colz").data());
95  gPad->Update();
96  return;
97  }
98 
99  if (fNBands == 0)
100  return;
101 
102  std::vector<double> intervals = fIntervals;
103  CheckIntervals(intervals);
104 
105  if (intervals.empty())
106  return;
107 
108  // set contour levels
109  std::vector<double> levels;
110  std::vector<std::string> legend_text;
111  switch (fBandType) {
112 
113  // // using 1D slicings
114  // case kCentralIntervalOfYGivenX:
115  // case kCentralIntervalOfXGivenY:
116  // case kSmallestIntervalOfYGivenX:
117  // case kSmallestIntervalOfXGivenY:
118  // case kUpperLimitOfYGivenX:
119  // case kUpperLimitOfXGivenY:
120  // case kLowerLimitOfYGivenX:
121  // case kLowerLimitOfXGivenY:
122  // break;
123 
124  case kSmallestInterval:
125  default:
126  std::vector<std::pair<double, double> > dens_mass = GetSmallestIntervalBounds(intervals, fBandOvercoverage);
127  for (unsigned i = 0; i < dens_mass.size(); ++i) {
128  levels.push_back(dens_mass[dens_mass.size() - i - 1].first);
129  legend_text.push_back(Form("smallest %.1f %% interval(s)", 100 * dens_mass[i].second));
130  }
131  // levels.push_back(GetHistogram()->GetMaximum());
132  break;
133  }
134 
135  // make sure enough colors have been designated
136  while (levels.size() > fBandColors.size())
137  fBandColors.push_back(fBandColors.back() - 1);
138 
139  // set contour colors
140  std::vector<int> colors;
141  for (int i = levels.size() - 1; i >= 0; --i)
142  colors.push_back(fBandColors[i]);
143 
144  // set contour levels
145  GetHistogram()->SetContour(levels.size(), &levels[0]);
146 
147  if (fBandFillStyle <= 0) {
148  GetHistogram()->SetLineColor(GetLineColor());
149  GetHistogram()->Draw(Form("%scont%d", options.data(), static_cast<int>(std::abs(fBandFillStyle))));
150  } else {
151  gStyle->SetPalette(colors.size(), &colors[0]);
152  GetHistogram()->SetFillStyle(fBandFillStyle);
153  GetHistogram()->Draw((options + "cont").data());
154  }
155  gPad->Update();
156 
157  // Set legend entries
158  for (unsigned i = 0; i < levels.size(); ++i) {
159  if (fBandFillStyle > 0) {
160  TLegendEntry* le = AddBandLegendEntry((TObject*)0, legend_text[i].data(), "F");
161  le->SetFillColor(colors[levels.size() - i - 1]);
162  le->SetFillStyle(1001/*fBandFillStyle*/);
163  le->SetLineColor(0);
164  le->SetLineWidth(0);
165  le->SetLineStyle(0);
166  } else {
167  TLegendEntry* le = AddBandLegendEntry(GetHistogram(), legend_text[i].data(), "L");
168  le->SetLineColor(GetLineColor());
169  le->SetLineStyle(levels.size() - i);
170  }
171  }
172 }
173 
174 // ---------------------------------------------------------
176 {
179 }
180 
181 // ---------------------------------------------------------
183 {
184 
185  unsigned n_i = (axis == kProfileY) ? GetHistogram()->GetNbinsY() : GetHistogram()->GetNbinsX();
186  unsigned n_j = (axis == kProfileY) ? GetHistogram()->GetNbinsX() : GetHistogram()->GetNbinsY();
187 
188  TGraph* g = new TGraph();
189 
190  // loop over bins of axis to be profiled
191  for (unsigned i = 1; i <= n_i; ++i) {
192 
193  switch (bt) {
194 
195  case kProfileMedian: {
196 
197  // calculate 50% of total probability mass in slice
198  double median_prob = 0.5 * ((axis == kProfileY) ? GetHistogram()->Integral(1, n_j, i, i, "width") : GetHistogram()->Integral(i, i, 1, n_j, "width"));
199  if (median_prob <= 0)
200  break;
201 
202  double prob_sum = 0;
203  // loop until 50% of probability mass is found
204  for (unsigned j = 1; j <= n_j; ++j) {
205  prob_sum += (axis == kProfileY) ? GetHistogram()->Integral(j, j, i, i, "width") : GetHistogram()->Integral(i, i, j, j, "width");
206  if (prob_sum > median_prob) {
207  if (axis == kProfileY)
208  g->SetPoint(g->GetN(), GetHistogram()->GetXaxis()->GetBinLowEdge(j), GetHistogram()->GetYaxis()->GetBinCenter(i));
209  else
210  g->SetPoint(g->GetN(), GetHistogram()->GetXaxis()->GetBinCenter(i), GetHistogram()->GetYaxis()->GetBinLowEdge(j));
211  break;
212  }
213  }
214  break;
215  }
216 
217  case kProfileMode: {
218  double max_val = 0;
219  unsigned j_max_val = 0;
220  for (unsigned j = 1; j <= n_j; ++j) {
221  double val = (axis == kProfileY) ? GetHistogram()->GetBinContent(j, i) : GetHistogram()->GetBinContent(i, j);
222  if (val > max_val) {
223  j_max_val = j;
224  max_val = val;
225  }
226  }
227  if (j_max_val > 0) {
228  if (axis == kProfileY)
229  g->SetPoint(g->GetN(), GetHistogram()->GetXaxis()->GetBinCenter(j_max_val), GetHistogram()->GetYaxis()->GetBinCenter(i));
230  else
231  g->SetPoint(g->GetN(), GetHistogram()->GetXaxis()->GetBinCenter(i), GetHistogram()->GetYaxis()->GetBinCenter(j_max_val));
232  }
233  break;
234  }
235 
236  case kProfileMean:
237  default: {
238  // calculate total probability mass in slice
239  double mass_sum = 0;
240  double sum = 0 ;
241  for (unsigned j = 0; j <= n_j; ++j) {
242  double mass = (axis == kProfileY) ? GetHistogram()->Integral(j, j, i, i, "width") : GetHistogram()->Integral(i, i, j, j, "width");
243  mass_sum += mass;
244  sum += mass * ((axis == kProfileY) ? GetHistogram()->GetXaxis()->GetBinCenter(j) : GetHistogram()->GetYaxis()->GetBinCenter(j));
245  }
246  if (mass_sum >= 0) {
247  if (axis == kProfileY)
248  g->SetPoint(g->GetN(), sum / mass_sum, GetHistogram()->GetYaxis()->GetBinCenter(i));
249  else
250  g->SetPoint(g->GetN(), GetHistogram()->GetXaxis()->GetBinCenter(i), sum / mass_sum);
251  }
252  break;
253  }
254  }
255 
256  }
257 
258  // return the graph
259  return g;
260 }
261 
262 // ---------------------------------------------------------
264 {
265  if (fDrawProfileX) {
266  TGraph* graph_profile = CalculateProfileGraph(kProfileX, fProfileXType);
267  graph_profile->SetLineColor(fProfileXLineColor);
268  graph_profile->SetLineStyle(fProfileXLineStyle);
269  graph_profile->Draw("sameL");
270  fROOTObjects.push_back(graph_profile);
271  std::string xtext = "profile x";
272  switch (fProfileXType) {
273  case kProfileMode:
274  xtext += " (mode)";
275  break;
276  case kProfileMedian:
277  xtext += " (median)";
278  break;
279  case kProfileMean:
280  default:
281  xtext += " (mean)";
282  break;
283  }
284  AddLegendEntry(graph_profile, xtext.data(), "L");
285  }
286  if (fDrawProfileY) {
287  TGraph* graph_profile = CalculateProfileGraph(kProfileY, fProfileYType);
288  graph_profile->SetLineColor(fProfileYLineColor);
289  graph_profile->SetLineStyle(fProfileYLineStyle);
290  graph_profile->Draw("sameL");
291  fROOTObjects.push_back(graph_profile);
292  std::string ytext = "profile y";
293  switch (fProfileYType) {
294  case kProfileMode:
295  ytext += " (mode)";
296  break;
297  case kProfileMedian:
298  ytext += " (median)";
299  break;
300  case kProfileMean:
301  default:
302  ytext += " (mean)";
303  break;
304  }
305  AddLegendEntry(graph_profile, ytext.data(), "L");
306  }
307 }
bool fDrawProfileX
flag for drawing x profile.
Definition: BCH2D.h:286
std::vector< int > fBandColors
The colors of the color scheme.
int fProfileYLineColor
color of y profile.
Definition: BCH2D.h:310
virtual void DrawMarkers()
Draw markers (global mode, local mode, etc.).
BCH2DProfileType fProfileXType
profile type of x profile.
Definition: BCH2D.h:290
virtual void DrawBands(const std::string &options="same")
Draw band, or if band type set to no bands, histogram.
Definition: BCH2D.cxx:91
virtual std::vector< double > DefaultIntervals(int nbands=-1)
Return default intervals.
Definition: BCH2D.cxx:74
BCH2DProfileAxis
Enum for axis to profile.
Definition: BCH2D.h:70
TLegendEntry * AddLegendEntry(TObject *obj, const std::string &label, const std::string &options)
Add legend entry, checking first for unused extra entries.
short fBandFillStyle
The fill style for the bands.
A class for handling 2D distributions.
Definition: BCH2D.h:37
no bands
Definition: BCH2D.h:48
virtual void CheckIntervals(std::vector< double > &intervals, int sort)
Check intervals: remove values below 0 or above 1.
TH2 * GetHistogram()
Return the TH2 histogram.
Definition: BCH2D.h:100
virtual void CopyOptions(const BCHistogramBase &other)
Copy options from.
virtual void DrawMarkers()
Draw Markers: global mode, local mode, etc.
Definition: BCH2D.cxx:175
std::vector< double > fIntervals
intervals to draw.
BCH2D(const TH2 *const h=0)
The complete constructor.
Definition: BCH2D.cxx:28
std::vector< std::pair< double, double > > GetSmallestIntervalBounds(std::vector< double > masses, bool overcoverage=true)
Get probability density levels bounding from below the smallest-interval levels with probability mass...
BCH2DProfileType
Enum for type of profile.
Definition: BCH2D.h:62
void SetDrawGlobalMode(bool flag=true, bool arrows=true)
Set drawing of global mode.
A base class for drawing histograms in BAT style.
BCH2DProfileType fProfileYType
profile type of y profile.
Definition: BCH2D.h:306
smallest intervals containing probability mass
Definition: BCH2D.h:49
virtual std::vector< double > DefaultIntervals(int nbands=-1)
Return default intervals.
bool fBandOvercoverage
flag for whether bands should overcover.
std::vector< TObject * > fROOTObjects
Storage for plot objects.
BCH2DBandType fBandType
band type.
Definition: BCH2D.h:278
void SetDrawLocalMode(bool flag=true, bool arrows=true)
Set drawing of global mode.
int GetLineColor() const
int fProfileXLineStyle
line style of x profile.
Definition: BCH2D.h:298
virtual void CheckIntervals(std::vector< double > &intervals)
Check intervals: remove values below 0 or above 1, and sort to proper order band type.
Definition: BCH2D.cxx:67
void CopyOptions(const BCH2D &other)
copy options from
Definition: BCH2D.cxx:52
int fProfileXLineColor
color of x profile.
Definition: BCH2D.h:294
bool fDrawProfileY
flag for drawing y profile.
Definition: BCH2D.h:302
void DrawProfileGraphs()
Draw the profiles along x and y.
Definition: BCH2D.cxx:263
int fProfileYLineStyle
line style of y profile.
Definition: BCH2D.h:314
unsigned fNBands
Number of credibility interval bands to draw.
TLegendEntry * AddBandLegendEntry(TObject *obj, const std::string &label, const std::string &options)
Add band legend entry, creating unused extra entries if necessary.
TGraph * CalculateProfileGraph(BCH2DProfileAxis axis, BCH2DProfileType pt=kProfileMean)
Return a graph of the profile along x or y.
Definition: BCH2D.cxx:182