BCAux.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 "BCAux.h"
12 #include "BCLog.h"
13 #include "config.h"
14 
15 #include <TCanvas.h>
16 #include <TDirectory.h>
17 #include <TH1.h>
18 #include <TH2.h>
19 #include <TLegend.h>
20 #include <TLegendEntry.h>
21 #include <TList.h>
22 #include <TPad.h>
23 
24 #include <algorithm>
25 #include <cmath>
26 #include <functional>
27 #include <limits>
28 
29 // ---------------------------------------------------------
31 {
32  BCLog::OutWarning("BCAux::SetStyle() is deprecated and no longer does anything. Please do not use it.");
33 }
34 
35 // ---------------------------------------------------------
36 void BCAux::DefaultToPDF(std::string& filename)
37 {
38  if (filename.empty())
39  return;
40 
41  size_t ext_pos = filename.find_last_of(".");
42  if (ext_pos == std::string::npos)
43  filename += ".pdf";
44  else {
45  std::string ext = filename.substr(ext_pos);
46  std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
47  if (ext == ".")
48  filename += "pdf";
49  else if (ext != ".pdf" && ext != ".ps")
50  filename += ".pdf";
51  }
52 }
53 
54 // ---------------------------------------------------------
55 TH2* BCAux::Transpose(const TH2* const h, const std::string& name)
56 {
57 
58  if (h == NULL)
59  return NULL;
60 
61  std::string newName(name);
62  if (newName.empty())
63  newName = std::string(h->GetName()) + "_tr";
64 
65  int nbins_x = h->GetNbinsY();
66  double xmin = h->GetYaxis()->GetXmin();
67  double xmax = h->GetYaxis()->GetXmax();
68  std::string xtitle = h->GetYaxis()->GetTitle();
69 
70  int nbins_y = h->GetNbinsX();
71  double ymin = h->GetXaxis()->GetXmin();
72  double ymax = h->GetXaxis()->GetXmax();
73  std::string ytitle = h->GetXaxis()->GetTitle();
74 
75  std::string title = std::string(h->GetTitle()) + ";" + xtitle + ";" + ytitle + ";" + h->GetZaxis()->GetTitle();
76 
77  TH2* ht = OwnClone(h);
78  ht->SetBins(nbins_x, xmin, xmax, nbins_y, ymin, ymax);
79  ht->SetNameTitle(newName.data(), title.data());
80 
81  return ht;
82 }
83 
84 // ---------------------------------------------------------
85 BCAux::BCRange BCAux::RangeType(double xmin, double xmax)
86 {
87  if (xmin > xmax)
88  // return -RangeType(xmax,xmin);
89  return BCAux::kReverseRange;
90  if (xmin == xmax)
91  return BCAux::kEmptyRange;
92  if (std::isfinite(xmin) && std::isfinite(xmax))
93  return BCAux::kFiniteRange;
94  if (std::isfinite(xmax))
96  if (std::isfinite(xmin))
98  return BCAux::kInfiniteRange;
99 }
100 
101 // ---------------------------------------------------------
102 void BCAux::MakeFinite(double& xmin, double& xmax)
103 {
104  if (!std::isfinite(xmin))
105  xmin = -std::numeric_limits<double>::max();
106  if (!std::isfinite(xmax))
107  xmax = +std::numeric_limits<double>::max();
108 }
109 
110 // ---------------------------------------------------------
111 std::string BCAux::SafeName(const std::string& name)
112 {
113  std::string res(name);
114  res.erase(std::remove_if(res.begin(), res.end(), std::not1(std::ptr_fun(BCAux::AllowedCharacter))), res.end());
115  return res;
116 }
117 
118 // ---------------------------------------------------------
120 {
121  if (::isalnum(c))
122  return true;
123  if (c == '_')
124  return true;
125  return false;
126 }
127 
128 // ---------------------------------------------------------
129 namespace { static const char* ROOToptions = "HISTSAME"; }
130 
131 // ---------------------------------------------------------
133 {
134  switch (style) {
136  prior.SetDrawGlobalMode(false);
137  prior.SetDrawLocalMode(false);
138  prior.SetDrawMean(false);
139  prior.SetDrawMedian(false);
140  prior.SetDrawLegend(false);
141  prior.SetBandType(BCH1D::kNoBands);
142  prior.SetROOToptions(ROOToptions);
143  prior.SetLineColor(13);
144  prior.SetMarkerColor(13);
145  prior.SetNLegendColumns(1);
146  prior.SetColorScheme(BCHistogramBase::kBlackWhite);
147  prior.SetLineStyle(1);
148  prior.SetLineColor(kGray + 1);
149  prior.SetLineWidth(2);
150  posterior.CopyOptions(prior);
151  posterior.SetDrawGlobalMode(true);
152  posterior.SetBandType(BCH1D::kSmallestInterval);
153  posterior.SetNBands(3);
154  posterior.SetColorScheme(BCHistogramBase::kGreenYellowRed);
155  posterior.SetLineWidth(1);
156  break;
157 
160  break;
161 
163  default:
164  posterior.SetDrawGlobalMode(false);
165  posterior.SetDrawLocalMode(false);
166  posterior.SetDrawMean(false);
167  posterior.SetDrawMedian(false);
168  posterior.SetDrawLegend(false);
169  posterior.SetBandType(BCH1D::kNoBands);
170  posterior.SetROOToptions(ROOToptions);
171  posterior.SetColorScheme(BCHistogramBase::kBlackWhite);
172  posterior.SetNLegendColumns(1);
173  posterior.SetLineWidth(2);
174  prior.CopyOptions(posterior);
175  prior.SetLineColor(kGray + 1);
176  break;
177  }
178 }
179 
180 // ---------------------------------------------------------
182 {
183  switch (style) {
185  prior.SetDrawGlobalMode(false);
186  prior.SetDrawLocalMode(true, false);
187  prior.SetDrawMean(false);
188  prior.SetDrawLegend(false);
190  prior.SetBandFillStyle(-3);
191  prior.SetNBands(1);
192  prior.SetNSmooth(0);
193  prior.SetROOToptions(ROOToptions);
194  prior.SetLineColor(13);
195  prior.SetMarkerColor(13);
196  prior.SetLocalModeMarkerStyle(25);
197  prior.SetNLegendColumns(1);
198  prior.SetColorScheme(BCHistogramBase::kBlackWhite);
199  prior.SetLineStyle(1);
200  prior.SetLineWidth(1);
201  posterior.CopyOptions(prior);
202  posterior.SetNBands(3);
203  posterior.SetBandFillStyle(1001);
204  posterior.SetColorScheme(BCHistogramBase::kGreenYellowRed);
205  posterior.SetLocalModeMarkerStyle(21);
206  break;
207 
210  break;
211 
213  default:
214  posterior.SetDrawGlobalMode(false);
215  posterior.SetDrawLocalMode(true, false);
216  posterior.SetDrawMean(false);
217  posterior.SetDrawLegend(false);
219  posterior.SetBandFillStyle(-3);
220  posterior.SetNBands(1);
221  posterior.SetNSmooth(0);
222  posterior.SetROOToptions(ROOToptions);
223  posterior.SetColorScheme(BCHistogramBase::kBlackWhite);
224  posterior.SetNLegendColumns(1);
225  posterior.SetLineWidth(2);
226  posterior.SetLocalModeMarkerStyle(21);
227  prior.CopyOptions(posterior);
228  prior.SetLineColor(kGray + 1);
229  prior.SetMarkerColor(kGray + 1);
230  break;
231  }
232 }
233 
234 
235 // ---------------------------------------------------------
236 void BCAux::DrawKnowledgeUpdate(BCHistogramBase& prior, BCHistogramBase& posterior, bool draw_prior_first, BCTrash<TObject>& trash)
237 {
238  if (prior.GetDimension() != posterior.GetDimension()) {
239  BCLog::OutError("BCAux::DrawKnowledgeUpdate : prior and posterior dimension do not match.");
240  return;
241  }
242 
243  if (!prior.Valid() || !posterior.Valid()) {
244  if (!prior.Valid() && posterior.Valid())
245  BCLog::OutError("BCAux::DrawKnowledgeUpdate : prior invalid.");
246  else if (prior.Valid() && !posterior.Valid())
247  BCLog::OutError("BCAux::DrawKnowledgeUpdate : posterior invalid.");
248  else
249  BCLog::OutError("BCAux::DrawKnowledgeUpdate : prior and posterior invalid.");
250  return;
251  }
252 
253  gPad->SetLogx(prior.GetLogx() || posterior.GetLogx());
254  gPad->SetLogy(prior.GetLogy() || posterior.GetLogy());
255  gPad->SetGridx(prior.GetGridx() || posterior.GetGridx());
256  gPad->SetGridx(prior.GetGridy() || posterior.GetGridy());
257  if (prior.GetDimension() > 2)
258  gPad->SetLogy(prior.GetLogz() || posterior.GetLogz());
259 
260  // get ranges
261  double minx = std::min<double>(prior.GetHistogram()->GetXaxis()->GetXmin(), posterior.GetHistogram()->GetXaxis()->GetXmin());
262  double maxx = std::max<double>(prior.GetHistogram()->GetXaxis()->GetXmax(), posterior.GetHistogram()->GetXaxis()->GetXmax());
263 
264  double miny = 0;
265  double maxy = 0;
266 
267  if (prior.GetDimension() == 1) {
268  miny = 0.0;
269  maxy = 1.1 * std::max<double>(prior.GetHistogram()->GetMaximum(), posterior.GetHistogram()->GetMaximum());
270  if (gPad->GetLogy()) {
271  miny = 0.5 * std::min<double>(prior.GetHistogram()->GetMinimum(0), posterior.GetHistogram()->GetMinimum(0));
272  maxy *= 2;
273  }
274  } else {
275  miny = std::min<double>(prior.GetHistogram()->GetYaxis()->GetXmin(), posterior.GetHistogram()->GetYaxis()->GetXmin());
276  maxy = std::max<double>(prior.GetHistogram()->GetYaxis()->GetXmax(), posterior.GetHistogram()->GetYaxis()->GetXmax());
277  }
278 
279  // draw axes
280  TH2D* h2_axes;
281  {
283  h2_axes = new TH2D(Form("h2_axes_knowledge_update_%s_%s", prior.GetHistogram()->GetName(), posterior.GetHistogram()->GetName()),
284  Form(";%s;%s", prior.GetHistogram()->GetXaxis()->GetTitle(), prior.GetHistogram()->GetYaxis()->GetTitle()),
285  10, minx, maxx, 10, miny, maxy);
286  }
287  trash.Put(h2_axes);
288  h2_axes->SetStats(false);
289  h2_axes->Draw();
290 
291  // turn off legends
292  prior.SetDrawLegend(false);
293  posterior.SetDrawLegend(false);
294 
295  // Draw histograms
296  // ROOT options for both prior and posterior should contain "same"
297  // (as they do by default)
298  if (!draw_prior_first)
299  posterior.Draw();
300  prior.Draw();
301  if (draw_prior_first)
302  posterior.Draw();
303 
304  // create / draw legend(s)
305 
306  if (prior.GetHistogram()->GetDimension() > 1 || prior.GetLegend().GetNRows() > 0)
307  prior.GetLegend().SetHeader(prior.GetHistogram()->GetTitle());
308  else
309  prior.GetLegend().AddEntry(prior.GetHistogram(), 0, "L");
310  if (posterior.GetLegend().GetNRows() > 0)
311  posterior.GetLegend().SetHeader(posterior.GetHistogram()->GetTitle());
312  else
313  posterior.GetLegend().AddEntry(posterior.GetHistogram(), 0, "L");
314 
315 
316  double y1ndc_prior = prior.ResizeLegend();
317  double y1ndc_posterior = posterior.ResizeLegend();
318 
319  // Draw prior legend on top left
320  // Draw posterior legend on top right
321 #if ROOTVERSION >= 6000000
322  prior.GetLegend().SetX2(prior.GetLegend().GetX1() + 45e-2 * (prior.GetLegend().GetX2() - prior.GetLegend().GetX1()));
323  posterior.GetLegend().SetX1(posterior.GetLegend().GetX1() + 55e-2 * (posterior.GetLegend().GetX2() - posterior.GetLegend().GetX1()));
324 #else
325  prior.GetLegend().SetX2NDC(prior.GetLegend().GetX1NDC() + 45e-2 * (prior.GetLegend().GetX2NDC() - prior.GetLegend().GetX1NDC()));
326  posterior.GetLegend().SetX1NDC(posterior.GetLegend().GetX1NDC() + 55e-2 * (posterior.GetLegend().GetX2NDC() - posterior.GetLegend().GetX1NDC()));
327 #endif
328 
329  prior.GetLegend().Draw();
330  posterior.GetLegend().Draw();
331 
332  gPad->SetTopMargin(1 - std::min<double>(y1ndc_prior, y1ndc_posterior) + 0.01);
333 
334  gPad->RedrawAxis();
335  gPad->Update();
336 }
337 
338 // ---------------------------------------------------------
339 unsigned BCAux::PrintPlots(std::vector<BCH1D>& h1, std::vector<BCH2D>& h2, const std::string& filename, unsigned hdiv, unsigned vdiv)
340 {
341  const unsigned nplots = h1.size() + h2.size();
342  if (nplots == 0) {
343  BCLog::OutWarning("BCAux::PrintPlots : No plots to print");
344  return 0;
345  }
346 
347  BCLog::OutSummary(Form("Printing all marginalized distributions (%lu x 1D + %lu x 2D = %u) into file %s", h1.size(), h2.size(), nplots, filename.c_str()));
348  // give out warning if too many plots
349  if (nplots > 100)
350  BCLog::OutDetail("This can take a while...");
351 
352  // setup the canvas and file
353  if (hdiv < 1) hdiv = 1;
354  if (vdiv < 1) vdiv = 1;
355 
356  int c_width = 297 * 4;
357  int c_height = 210 * 4;
358  if (hdiv < vdiv)
359  std::swap(c_width, c_height);
360 
361  TCanvas c("c", "canvas", c_width, c_height);
362  c.Divide(hdiv, vdiv);
363 
364  // open file
365  c.Print((filename + "[").data());
366 
367  unsigned n = 0;
368 
369  // 1D
370  for (unsigned i = 0; i < h1.size(); ++i) {
371  // if current page is full, switch to new page
372  if (i != 0 && i % (hdiv * vdiv) == 0) {
373  c.Print(filename.c_str());
374  c.Clear("D");
375  }
376 
377  // go to next pad
378  c.cd(i % (hdiv * vdiv) + 1)->ResetAttPad();
379 
380  h1[i].Draw();
381 
382  if (++n % 100 == 0)
383  BCLog::OutDetail(Form(" --> %d plots done", n));
384  }
385  if (h1.size() > 0) {
386  c.Print(filename.c_str());
387  c.Clear("D");
388  }
389 
390  // 2D
391  for (unsigned i = 0; i < h2.size(); ++i) {
392  // if current page is full, switch to new page
393  if (i != 0 && i % (hdiv * vdiv) == 0) {
394  c.Print(filename.c_str());
395  c.Clear("D");
396  }
397 
398  // go to next pad
399  c.cd(i % (hdiv * vdiv) + 1)->ResetAttPad();
400 
401  h2[i].Draw();
402 
403  if (++n % 100 == 0)
404  BCLog::OutDetail(Form(" --> %d plots done", n));
405  }
406  if (h2.size() > 0) {
407  c.Print(filename.c_str());
408  c.Clear("D");
409  }
410 
411  // close file
412  c.Print(std::string( filename + "]").c_str());
413 
414  if (nplots > 100 && nplots % 100 != 0)
415  BCLog::OutDetail(Form(" --> %d plots done", nplots));
416 
417  // return total number of drawn histograms
418  return nplots;
419 }
420 
421 // ---------------------------------------------------------
422 BCAux::RootSideEffectGuard::RootSideEffectGuard() :
423  fDirectory(gDirectory)
424 {
425  gDirectory = NULL;
426 }
427 
428 // ---------------------------------------------------------
429 BCAux::RootSideEffectGuard::~RootSideEffectGuard()
430 {
431  gDirectory = fDirectory;
432 }
Posterior drawn with detailed info, prior drawn as overlaid line.
Definition: BCAux.h:121
void SetLocalModeMarkerStyle(int s)
Set Local mode marker style.
void DrawKnowledgeUpdate(BCHistogramBase &prior, BCHistogramBase &posterior, bool draw_prior_first, BCTrash< TObject > &trash)
Draw knowledge update plot into current TPad.
Definition: BCAux.cxx:236
void MakeFinite(double &xmin, double &xmax)
Make an infinite range finite by setting inf values to max.
Definition: BCAux.cxx:102
void SetLineColor(int c)
Set histogram line color.
TLegend & GetLegend()
T * OwnClone(const T *o)
Create a clone of the input but avoid registering the object with ROOT so it cannot be deleted twice...
Definition: BCAux.h:189
bool GetLogz() const
BCRange
Range types.
Definition: BCAux.h:88
void SetBandType(BCH1DBandType bt)
Set band type.
Definition: BCH1D.h:163
A guard object to prevent ROOT from taking over ownership of TNamed objects.
Definition: BCAux.h:171
bool GetLogx() const
unsigned PrintPlots(std::vector< BCH1D > &h1, std::vector< BCH2D > &h2, const std::string &filename, unsigned hdiv=1, unsigned vdiv=1)
Print plots.
Definition: BCAux.cxx:339
A class for handling 2D distributions.
Definition: BCH2D.h:37
void CopyOptions(const BCH1D &other)
Copy options from other.
Definition: BCH1D.cxx:50
virtual void Draw()
Draw distribution into the active pad.
BCAux::BCRange RangeType(double xmin, double xmax)
Return type of range as a BCAux::BCRange enum.
Definition: BCAux.cxx:85
TH2 * Transpose(const TH2 *const h, const std::string &name="")
Transpose a TH2.
Definition: BCAux.cxx:55
Prior drawn with detailed info, posterior drawn as overlaid line.
Definition: BCAux.h:122
std::string SafeName(const std::string &name)
Convert a name into a safe name for use in ROOT object naming.
Definition: BCAux.cxx:111
void SetStyle()
Definition: BCAux.cxx:30
void SetNLegendColumns(unsigned n)
Set number of columns in legend.
void SetDrawGlobalMode(bool flag=true, bool arrows=true)
Set drawing of global mode.
A base class for drawing histograms in BAT style.
smallest intervals containing probability mass
Definition: BCH2D.h:49
bool GetLogy() const
virtual void SetColorScheme(BCHColorScheme scheme)
Sets the color scheme.
lower < upper, lower limit finite, upper limit infinite
Definition: BCAux.h:91
void SetDrawMedian(bool flag=true, bool central68=true)
Set drawing of median.
Definition: BCH1D.h:182
unsigned GetDimension() const
void SetKnowledgeUpdateDrawingStyle(BCH1D &prior, BCH1D &posterior, BCAux::BCKnowledgeUpdateDrawingStyle style=BCAux::kKnowledgeUpdateDefaultStyle)
Use pre-made drawing options for knowledge update plots.
Definition: BCAux.cxx:132
void SetDrawLocalMode(bool flag=true, bool arrows=true)
Set drawing of global mode.
BCKnowledgeUpdateDrawingStyle
An enumerator for the knowledge update drawing style presets.
Definition: BCAux.h:119
void SetNSmooth(unsigned n)
Sets number of times to smooth the histogram using ROOT&#39;s smoothing function.
void SetDrawLegend(bool flag=true)
Set drawing of legend.
virtual double ResizeLegend()
Resize legend and set it for placement at the top of the pad.
Simple line-drawn histograms.
Definition: BCAux.h:120
void SetDrawMean(bool flag=true, bool stddev=true)
Set drawing of mean.
virtual bool Valid() const
Whether histogram has been set and filled.
void SetBandFillStyle(short f)
Set band fill style.
void CopyOptions(const BCH2D &other)
copy options from
Definition: BCH2D.cxx:52
void SetROOToptions(const std::string &options)
Set ROOT drawing options.
void SetColorScheme(BCHColorScheme scheme)
Sets the color scheme.
Definition: BCH1D.cxx:61
A class for handling 1D distributions.
Definition: BCH1D.h:34
void SetNBands(unsigned n)
Sets number of credibility interval bands to draw.
void DefaultToPDF(std::string &filename)
Force file extension to be .pdf if not already .pdf or .ps.
Definition: BCAux.cxx:36
void SetLineWidth(int w)
Set histogram line width.
lower > upper
Definition: BCAux.h:94
bool GetGridy() const
lower limit == upper limit
Definition: BCAux.h:93
lower < upper, lower and upper limits finite
Definition: BCAux.h:89
lower < upper, lower limit infinite, upper limit finite
Definition: BCAux.h:90
bool AllowedCharacter(char c)
Definition: BCAux.cxx:119
lower < upper, lower and upper limits infinite
Definition: BCAux.h:92
void SetMarkerColor(int c)
Set marker color (used for mean, median, and mode).
void SetBandType(BCH2DBandType bt)
Set band type.
Definition: BCH2D.h:184
void SetLineStyle(int s)
Set histogram line style.
bool GetGridx() const