MaCh3  2.8.0
Reference Guide
PredictivePlotting.cpp
Go to the documentation of this file.
1 //MaCh3 Includes
4 #include <numeric>
5 
6 //this file has lots of usage of the ROOT plotting interface that only takes floats, turn this warning off for this CU for now
7 #pragma GCC diagnostic ignored "-Wfloat-conversion"
8 #pragma GCC diagnostic ignored "-Wconversion"
9 
13 
16 
17 std::vector<std::string> FindSamples(const std::string& File)
18 {
19  TFile *file = M3::Open(File, "READ", __FILE__, __LINE__);
20  TDirectoryFile *PredicitveDir = file->Get<TDirectoryFile>("Predictive");
21 
22  std::vector<std::string> SampleNames;
23  //Get all entries in input file
24  TIter next(PredicitveDir->GetListOfKeys());
25  TKey *key = nullptr;
26 
27  // Loop through all entries
28  while ((key = static_cast<TKey*>(next()))) {
29  // get directory names, ignore flux
30  auto classname = std::string(key->GetClassName());
31  auto dirname = std::string(key->GetName());
32 
33  if (classname != "TDirectoryFile") continue;
34  dirname = std::string(key->GetName());
35 
36  if(dirname == "Total") continue;
37  if(dirname == "BetaParameters") continue;
38  if(dirname == "Correlations") continue;
39 
40  SampleNames.push_back(dirname);
41  MACH3LOG_DEBUG("Entering Sample {}", dirname);
42  }
43 
44  file->Close();
45  delete file;
46  return SampleNames;
47 }
48 
49 std::vector<int> FindDimensions(const std::string& File, const std::vector<std::string>& Samples)
50 {
51  TFile *file = M3::Open(File, "READ", __FILE__, __LINE__);
52  TDirectoryFile *PredicitveDir = file->Get<TDirectoryFile>("Predictive");
53 
54  std::vector<int> SampleDimension;
55  for (const auto& sample : Samples)
56  {
57  // Get directory for this sample
58  TDirectoryFile* SampleDir = PredicitveDir->Get<TDirectoryFile>(sample.c_str());
59 
60  int Dimension = 0;
61 
62  while (true)
63  {
64  // Construct name Tutorial_mc_dimX
65  std::string histName = fmt::format("{}_mc_dim{}", sample, Dimension);
66 
67  TH2D* hist = SampleDir->Get<TH2D>(histName.c_str());
68  if (!hist) break; // stop when next dimension does not exist
69 
70  Dimension++;
71  }
72 
73  MACH3LOG_DEBUG("Sample '{}' has dimension {}", sample, Dimension);
74  SampleDimension.push_back(Dimension);
75  }
76 
77  file->Close();
78  delete file;
79 
80  return SampleDimension;
81 }
82 
83 
84 std::vector<std::vector<std::string>> FindModes(const std::string& File,
85  const std::vector<std::string>& SampleNames)
86 {
87  TFile *file = M3::Open(File, "READ", __FILE__, __LINE__);
88  TDirectoryFile *PredictiveDir = file->Get<TDirectoryFile>("Predictive");
89 
90  std::vector<std::vector<std::string>> ModeNames(SampleNames.size());
91 
92  for(size_t iSample = 0; iSample < SampleNames.size(); iSample++)
93  {
94  TDirectoryFile* SampleDir = PredictiveDir->Get<TDirectoryFile>(SampleNames[iSample].c_str());
95  if(!SampleDir) continue;
96 
97  TDirectoryFile* ByModeDir = SampleDir->Get<TDirectoryFile>("ByMode");
98  if(!ByModeDir) continue;
99 
100  // Loop over all keys in ByModeDir
101  TIter next(ByModeDir->GetListOfKeys());
102  TKey* key;
103 
104  while ((key = static_cast<TKey*>(next())))
105  {
106  TObject* obj = key->ReadObj();
107  if (!obj->InheritsFrom("TH1")) continue;
108 
109  std::string histName = obj->GetName();
110 
111  // Example: sample_mode_dim0 → extract "mode"
112  std::string prefix = SampleNames[iSample] + "_";
113  std::string suffix = "_dim0";
114 
115  if (histName.find(prefix) == 0 &&
116  histName.rfind(suffix) == histName.size() - suffix.size())
117  {
118  std::string Mode = histName.substr(prefix.size(),
119  histName.size() - prefix.size() - suffix.size());
120  MACH3LOG_DEBUG("Found mode '{}' for sample {}", Mode, SampleNames[iSample]);
121  ModeNames[iSample].push_back(Mode);
122  }
123  }
124  }
125 
126  file->Close();
127  delete file;
128 
129  return ModeNames;
130 }
131 
132 
133 void PretifyHistogram(TH1* Hist, const std::string& SampleName) {
134  Hist->SetTitle(PlotMan->style().prettifySampleName(SampleName).c_str());
135  auto BinWidthScale = PlotMan->style().getBinWidthScale(Hist->GetXaxis()->GetTitle());
136  auto PrettyX = PlotMan->style().prettifyKinematicName(Hist->GetXaxis()->GetTitle());
137  PlotMan->style().setTH1XRange(Hist);
138  Hist->GetXaxis()->SetTitle(PrettyX.c_str());
139  Hist->GetYaxis()->SetTitle(fmt::format("Events/{:.0f}", BinWidthScale).c_str());
140  M3::ScaleHistogram(Hist, BinWidthScale);
141 }
142 
143 double GetPValue(const TH2D* hist)
144 {
145  double pvalue = 0;
146  std::string TempTile = hist->GetTitle();
147  std::string temp = "=";
148 
149  std::string::size_type SizeType = TempTile.find(temp);
150  TempTile.erase(0, SizeType+1);
151  pvalue = atof(TempTile.c_str());
152  return pvalue;
153 }
154 
155 void PrintPosteriorPValue(const YAML::Node& Settings,
156  const std::vector<TFile*>& InputFiles,
157  const std::vector<std::string>& SampleNames)
158 {
159  MACH3LOG_INFO("Starting {}", __func__);
160  auto Titles = Get<std::vector<std::string>>(Settings["FileTitle"], __FILE__, __LINE__);
161  std::vector<std::vector<double>> FlucDrawVec(InputFiles.size());
162  // KS: Alternatively try "_drawfluc_draw"
163  std::string FlucutationType = "_predfluc_draw";
164  //KS: P-values per each sample
165  std::cout<<"\\begin{table}[htb]"<<std::endl;
166  std::cout<<"\\centering"<<std::endl;
167  std::cout<<"\\begin{tabular}{ | l | ";
168 
169  for(unsigned int f = 0; f < InputFiles.size(); f++)
170  {
171  std::cout<<"c | ";
172  }
173 
174  std::cout<<"} \\hline"<<std::endl;
175  std::cout<<"Sample ";
176  for(unsigned int f = 0; f < InputFiles.size(); f++)
177  {
178  std::cout<<"& \\multicolumn{1}{| c |}{" + Titles[f] +" p-value} ";
179  }
180  std::cout<<"\\\\"<<std::endl;
181  for(unsigned int f = 0; f < InputFiles.size(); f++)
182  {
183  std::cout<<" & Fluctuation of Prediction ";
184  }
185  std::cout<<"\\\\ \\hline"<<std::endl;
186  for(unsigned int i = 0; i < SampleNames.size(); i++)
187  {
188  std::cout<<SampleNames[i];
189  for(unsigned int f = 0; f < InputFiles.size(); f++)
190  {
191  std::string TempString = "Predictive/" + SampleNames[i]+"/"+SampleNames[i] + FlucutationType;
192  TH2D *hist2D = InputFiles[f]->Get<TH2D>(TempString.c_str());
193  double FlucDraw = GetPValue(hist2D);
194  std::cout<<" & "<<FlucDraw;
195  FlucDrawVec[f].push_back(FlucDraw);
196  }
197  std::cout<<" \\\\"<<std::endl;
198  }
199  std::cout<<"Total ";
200  for(unsigned int f = 0; f < InputFiles.size(); f++)
201  {
202  TH2D *hFlucPred = InputFiles[f]->Get<TH2D>(("Predictive/Total/Total" + FlucutationType).c_str());
203  double FlucDraw = GetPValue(hFlucPred);
204  std::cout<<" & "<<FlucDraw;
205  }
206  std::cout<<" \\\\ \\hline"<<std::endl;
207  std::cout<<"\\hline"<<std::endl;
208  std::cout<<"\\end{tabular}"<<std::endl;
209  std::cout<<"\\end{table}"<<std::endl;
210 
211  auto Threshold = GetFromManager<double>(Settings["Significance"], 0.05, __FILE__ , __LINE__);
212  for(unsigned int f = 0; f < InputFiles.size(); f++)
213  {
214  MACH3LOG_INFO("Calculating Shape for file {}", Titles[f]);
215 
216  CheckBonferoniCorrectedpValue(SampleNames, FlucDrawVec[f], Threshold);
217  MACH3LOG_INFO("Combined pvalue following Fisher method: {:.4f}", FisherCombinedPValue(FlucDrawVec[f]));
218  }
219 }
220 
221 void OverlayViolin(const YAML::Node& Settings,
222  const std::vector<TFile*>& InputFiles,
223  const std::vector<std::string>& SampleNames,
224  const std::vector<int>& SampleDimension,
225  const std::unique_ptr<TCanvas>& canv)
226 {
227  MACH3LOG_INFO("Starting {}", __func__);
228  canv->Clear();
229 
230  canv->SetTopMargin(0.10);
231  canv->SetBottomMargin(0.12);
232  canv->SetRightMargin(0.075);
233  canv->SetLeftMargin(0.14);
234 
235  auto PosteriorColor = Get<std::vector<Color_t >>(Settings["PosteriorColor"], __FILE__, __LINE__);
236  auto Titles = Get<std::vector<std::string>>(Settings["FileTitle"], __FILE__, __LINE__);
237  const int nFiles = static_cast<int>(InputFiles.size());
238 
239  //KS: No idea why but ROOT changed treatment of violin in R6. If you have non uniform binning this will results in very hard to see violin plots.
240  TCandle::SetScaledViolin(false);
241  for(size_t iSample = 0; iSample < SampleNames.size(); iSample++)
242  {
243  for(int iDim = 0; iDim < SampleDimension[iSample]; iDim++)
244  {
245  std::vector<std::unique_ptr<TH2D>> ViolinHist(nFiles);
246  for(int iFile = 0; iFile < nFiles; iFile++)
247  {
248  InputFiles[iFile]->cd();
249  ViolinHist[iFile] = M3::Clone(InputFiles[iFile]->Get<TH2D>(("Predictive/" + SampleNames[iSample]
250  + "/" + SampleNames[iSample] + "_mc_dim" + iDim).Data()));
251  ViolinHist[iFile]->SetTitle(PlotMan->style().prettifySampleName(SampleNames[iSample]).c_str());
252  ViolinHist[iFile]->SetLineColor(PosteriorColor[iFile]);
253  ViolinHist[iFile]->SetMarkerColor(PosteriorColor[iFile]);
254  ViolinHist[iFile]->SetFillColorAlpha(PosteriorColor[iFile], 0.35);
255  ViolinHist[iFile]->SetFillStyle(1001);
256  PlotMan->style().setTH1XRange(ViolinHist[iFile].get());
257  ViolinHist[iFile]->GetXaxis()->SetTitle(PlotMan->style().prettifyKinematicName(
258  ViolinHist[iFile]->GetXaxis()->GetTitle()).c_str());
259  ViolinHist[iFile]->GetYaxis()->SetTitle("Events");
260  }
261 
262  ViolinHist[0]->Draw("violinX(03100300)");
263  for(int iFile = 1; iFile < nFiles; iFile++) {
264  ViolinHist[iFile]->Draw("violinX(03100300) same");
265  }
266 
267  TLegend legend(0.50, 0.52, 0.90, 0.88);
268  for(int ig = 0; ig < nFiles; ig++) {
269  legend.AddEntry(ViolinHist[ig].get(), Form("%s", Titles[ig].c_str()), "lpf");
270  }
271  legend.SetLineStyle(0);
272  legend.SetTextSize(0.03);
273  legend.Draw();
274 
275  canv->Print("Overlay_Predictive.pdf", "pdf");
276  }
277  }
278 }
279 
280 void OverlayPredicitve(const YAML::Node& Settings,
281  const std::vector<TFile*>& InputFiles,
282  const std::vector<std::string>& SampleNames,
283  const std::vector<int>& SampleDimension,
284  const std::unique_ptr<TCanvas>& canv)
285 {
286  MACH3LOG_INFO("Starting {}", __func__);
287  canv->Clear();
288 
289  TPad* pad1 = new TPad("pad1","pad1",0,0.25,1,1);
290  pad1->AppendPad();
291  TPad* pad2 = new TPad("pad2","pad2",0,0,1,0.25);
292  pad2->AppendPad();
293 
294  pad1->SetGrid();
295  pad2->SetGrid();
296 
297  pad1->SetLeftMargin(canv->GetLeftMargin());
298  pad1->SetRightMargin(canv->GetRightMargin());
299  pad1->SetTopMargin(canv->GetTopMargin());
300  pad1->SetBottomMargin(0);
301 
302  pad2->SetLeftMargin(canv->GetLeftMargin());
303  pad2->SetRightMargin(canv->GetRightMargin());
304  pad2->SetTopMargin(0);
305  pad2->SetBottomMargin(0.28);
306 
307  auto PosteriorColor = Get<std::vector<Color_t >>(Settings["PosteriorColor"], __FILE__, __LINE__);
308  auto Titles = Get<std::vector<std::string>>(Settings["FileTitle"], __FILE__, __LINE__);
309 
310  if(Titles.size() < InputFiles.size() || PosteriorColor.size() < InputFiles.size()){
311  MACH3LOG_ERROR("Passed {} files, while only {} titles and {} colors", InputFiles.size(), Titles.size(), PosteriorColor.size());
312  throw MaCh3Exception(__FILE__, __LINE__);
313  }
314  for(size_t iSample = 0; iSample < SampleNames.size(); iSample++)
315  {
316  const int nFiles = static_cast<int>(InputFiles.size());
317  auto SampleName = SampleNames[iSample];
318  const int nDims = (SampleDimension[iSample] == 2) ? 2 : 1;
319  for(int iDim = 0; iDim < nDims; iDim++) {
320  std::string DataLocation = "";
321  if(nDims == 2) {
322  DataLocation = "Predictive/" + SampleName + "/Data_" + SampleName + "_Dim" + std::to_string(iDim);
323  } else {
324  DataLocation = "SampleFolder/data_" + SampleName;
325  }
326  TH1D* hist = InputFiles[0]->Get<TH1D>((DataLocation).c_str());
327 
328  auto BinWidthScale = PlotMan->style().getBinWidthScale(hist->GetXaxis()->GetTitle());
329  std::unique_ptr<TH1D> DataHist = M3::Clone(hist);
330  //KS: +1 for data, we want to get integral before scaling of the histogram
331  std::vector<double> Integral(nFiles+1);
332  Integral[nFiles] = DataHist->Integral();
333 
334  auto DataPoissonErrors = PoissonGraphScaled(DataHist.get(), BinWidthScale);
335  M3::ScaleHistogram(DataHist.get(), BinWidthScale);
336  DataHist->SetLineColor(kBlack);
337  DataPoissonErrors->SetLineColor(kBlack);
338  std::vector<std::unique_ptr<TH1D>> PredHist(nFiles);
339 
340  for(int iFile = 0; iFile < nFiles; iFile++)
341  {
342  InputFiles[iFile]->cd();
343  std::string HistLocation = "";
344  if(nDims == 2) {
345  HistLocation = "Predictive/" + SampleName + "/" + SampleName + "_mc_PostPred_dim" + std::to_string(iDim);
346  } else {
347  HistLocation = "Predictive/" + SampleName + "/" + SampleName + "_mc_PostPred";
348  }
349  PredHist[iFile] = M3::Clone(InputFiles[iFile]->Get<TH1D>((HistLocation).c_str()));
350  Integral[iFile] = PredHist[iFile]->Integral();
351  PlotMan->style().setTH1XRange(PredHist[iFile].get());
352  PredHist[iFile]->SetLineColor(PosteriorColor[iFile]);
353  PredHist[iFile]->SetMarkerColor(PosteriorColor[iFile]);
354  PredHist[iFile]->SetFillColorAlpha(PosteriorColor[iFile], 0.35);
355  PredHist[iFile]->SetFillStyle(1001);
356  PretifyHistogram(PredHist[iFile].get(), SampleName);
357  }
358  pad1->cd();
359 
360  PredHist[0]->Draw("p e2");
361  for(int iFile = 1; iFile < nFiles; iFile++) {
362  PredHist[iFile]->Draw("p e2 same");
363  }
364  DataPoissonErrors->Draw("p same");
365 
366  auto legend = std::make_unique<TLegend>(0.50,0.52,0.90,0.88);
367  legend->AddEntry(DataPoissonErrors.get(), Form("Data, #int=%.2f", Integral[nFiles]),"le");
368  for(int ig = 0; ig < nFiles; ig++ ) {
369  legend->AddEntry(PredHist[ig].get(), Form("%s, #int=%.2f", Titles[ig].c_str(), Integral[ig]), "lpf");
370  }
371  legend->SetLineStyle(0);
372  legend->SetTextSize(0.03);
373  legend->Draw();
374 
376  pad2->cd();
377 
378  auto line = std::make_unique<TLine>(PredHist[0]->GetXaxis()->GetBinLowEdge(PredHist[0]->GetXaxis()->GetFirst()), 1.0, PredHist[0]->GetXaxis()->GetBinUpEdge(PredHist[0]->GetXaxis()->GetLast()), 1.0);
379 
380  line->SetLineWidth(2);
381  line->SetLineColor(kBlack);
382  line->Draw("");
383 
384  std::unique_ptr<TH1D> RatioPlotData = M3::Clone(DataHist.get());
385  std::vector<std::unique_ptr<TH1D>> RatioPlot(nFiles);
386 
387  for(int ig = 0; ig < nFiles; ig++ )
388  {
389  RatioPlot[ig] = M3::Clone(DataHist.get());
390  RatioPlot[ig]->SetLineColor(PosteriorColor[ig]);
391  RatioPlot[ig]->SetMarkerColor(PosteriorColor[ig]);
392  RatioPlot[ig]->SetFillColorAlpha(PosteriorColor[ig], 0.35);
393  RatioPlot[ig]->SetFillStyle(1001);
394  RatioPlot[ig]->GetYaxis()->SetTitle("Data/MC");
395  PlotMan->style().setTH1XRange(RatioPlot[ig].get());
396  auto PrettyX = PlotMan->style().prettifyKinematicName(PredHist[0]->GetXaxis()->GetTitle());
397  RatioPlot[ig]->GetXaxis()->SetTitle(PrettyX.c_str());
398  RatioPlot[ig]->SetBit(TH1D::kNoTitle);
399  RatioPlot[ig]->GetXaxis()->SetTitleSize(0.12);
400  RatioPlot[ig]->GetYaxis()->SetTitleOffset(0.4);
401  RatioPlot[ig]->GetYaxis()->SetTitleSize(0.10);
402 
403  RatioPlot[ig]->GetXaxis()->SetLabelSize(0.10);
404  RatioPlot[ig]->GetYaxis()->SetLabelSize(0.10);
405 
406  RatioPlot[ig]->Divide(PredHist[ig].get());
407  PassErrorToRatioPlot(RatioPlot[ig].get(), PredHist[ig].get(), DataHist.get());
408  }
409 
410  RatioPlotData->Divide(DataHist.get());
411  PassErrorToRatioPlot(RatioPlotData.get(), DataHist.get(), DataHist.get());
412 
414 
415  RatioPlot[0]->Draw("p e2");
416  for(int ig = 1; ig < nFiles; ig++ ) {
417  RatioPlot[ig]->Draw("p e2 same");
418  }
419  RatioPlotData->Draw("he same");
420 
421  canv->Print("Overlay_Predictive.pdf", "pdf");
422  }
423  }
424 
425  delete pad1;
426  delete pad2;
427 }
428 
429 void OverlayPredicitveByMode(const YAML::Node& Settings,
430  const std::vector<TFile*>& InputFiles,
431  const std::vector<std::string>& SampleNames,
432  const std::vector<int>& SampleDimension,
433  const std::vector<std::vector<std::string>>& Modes,
434  const std::unique_ptr<TCanvas>& canv)
435 {
436  MACH3LOG_INFO("Starting {}", __func__);
437  canv->cd();
438  constexpr auto DefaultColor = kBlack;
439  auto Titles = Get<std::vector<std::string>>(Settings["FileTitle"], __FILE__, __LINE__);
440  auto RelevantModesName = Get<std::vector<std::string>>(Settings["RelevantModesName"], __FILE__, __LINE__);
441  auto RelevantColors = Get<std::vector<Color_t>>(Settings["RelevantModesColors"], __FILE__, __LINE__);
442  int nRelevantModes = static_cast<int>(RelevantModesName.size());
443  const int nFiles = static_cast<int>(InputFiles.size());
444  if(Titles.size() < InputFiles.size()){
445  MACH3LOG_ERROR("Passed {} files, while only {} titles", InputFiles.size(), Titles.size());
446  throw MaCh3Exception(__FILE__, __LINE__);
447  }
448  if(RelevantModesName.size() != RelevantColors.size()) {
449  MACH3LOG_ERROR("Colors ({}) doesn't match relevant modes {}", RelevantColors.size(), RelevantModesName.size());
450  throw MaCh3Exception(__FILE__, __LINE__);
451  }
452  for(int iFile = 0; iFile < nFiles; iFile++ )
453  {
454  for(size_t iSample = 0; iSample < SampleNames.size(); iSample++)
455  {
456  auto SampleName = SampleNames[iSample];
457  for(int iDim = 0; iDim < SampleDimension[iSample]; iDim++)
458  {
459  const int nDims = (SampleDimension[iSample] == 2) ? 2 : 1;
460  std::string HistLocation = "";
461  if(nDims == 2) {
462  HistLocation = "Predictive/" + SampleName + "/" + SampleName + "_mc_PostPred_dim" + std::to_string(iDim);
463  } else {
464  HistLocation = "Predictive/" + SampleName + "/" + SampleName + "_mc_PostPred";
465  }
466  std::unique_ptr<TH1D> Sample_MC_Full = M3::Clone(InputFiles[iFile]->Get<TH1D>((HistLocation).c_str()));
467  Sample_MC_Full->SetLineColor(kOrange);
468  Sample_MC_Full->SetLineWidth(2);
469  Sample_MC_Full->SetMarkerColor(kOrange);
470  PretifyHistogram(Sample_MC_Full.get(), SampleName);
471 
472  std::string DataLocation = "";
473  std::unique_ptr<TH1D> Sample_Data;
474  if(nDims == 2) {
475  DataLocation = "Predictive/" + SampleName + "/Data_" + SampleName + "_Dim" + std::to_string(iDim);
476  } else if(nDims == 1) {
477  DataLocation = "SampleFolder/data_" + SampleName;
478  }
479  if(DataLocation != "") {
480  Sample_Data = M3::Clone(InputFiles[iFile]->Get<TH1D>((DataLocation).c_str()));
481  Sample_Data->SetLineColor(kBlack);
482  Sample_Data->SetLineWidth(2);
483  Sample_Data->SetMarkerColor(kBlack);
484  PretifyHistogram(Sample_Data.get(), SampleName);
485  }
486  int nModes = static_cast<int>(Modes[iSample].size());
487  // Simple map to keep track which mode is relevant and which will be added to "Other"
488  std::vector<bool> isRelevantMode(nModes, false);
489  std::vector<Color_t > ColorMap(nModes, DefaultColor);
490  for(int iMode = 0; iMode < nModes; iMode++) {
491  for(int iRelevant = 0; iRelevant < nRelevantModes; iRelevant++) {
492  if(Modes[iSample][iMode] == RelevantModesName[iRelevant]) {
493  isRelevantMode[iMode] = true;
494  ColorMap[iMode] = RelevantColors[iRelevant];
495  }
496  }
497  }
498  auto Sample_Stack = std::make_unique<THStack>(SampleName.c_str(), SampleName.c_str());
499  // This will hold values for "Other" modes
500  std::unique_ptr<TH1D> Sample_MC_Other;
501  // KS: Store histogram for each mode
502  std::vector<std::unique_ptr<TH1D>> Sample_MC(nModes);
503  std::vector<double> Integrals(nModes, 0.);
504  for(int iMode = 0; iMode < nModes; iMode++)
505  {
506  std::string FileLocaction = "Predictive/" + SampleName + "/ByMode/" + SampleName
507  + "_" + Modes[iSample][iMode] + "_dim" + std::to_string(iDim);
508  auto SpectraByMode = InputFiles[iFile]->Get<TH2D>((FileLocaction).c_str());
509  if(SpectraByMode == nullptr){
510  MACH3LOG_ERROR("Something went wrong and didn't find histogram: {}", FileLocaction);
511  throw MaCh3Exception(__FILE__, __LINE__);
512  }
513  Sample_MC[iMode] = MakeSummaryFromSpectra(SpectraByMode, SpectraByMode->GetTitle());
514  Integrals[iMode] = Sample_MC[iMode]->Integral();
515  PretifyHistogram(Sample_MC[iMode].get(), SampleName);
516 
517  if(Sample_MC_Other == nullptr) {
518  Sample_MC_Other = M3::Clone(Sample_MC[iMode].get());
519  Sample_MC_Other->Reset();
520  Sample_MC_Other->SetFillColor(DefaultColor);
521  Sample_MC_Other->SetLineColor(DefaultColor);
522  }
523  if(!isRelevantMode[iMode]) {
524  Sample_MC_Other->Add(Sample_MC[iMode].get());
525  }
526  Sample_MC[iMode]->SetFillColor(ColorMap[iMode]);
527  Sample_MC[iMode]->SetLineColor(ColorMap[iMode]);
528  } // end loop over modes
529  Sample_Stack->Add(Sample_MC_Other.get());
530  // KS: We do this other way around as we want to have most relevant modes first
531  for(int iMode = nModes-1; iMode >= 0; iMode--) {
532  if(isRelevantMode[iMode]) Sample_Stack->Add( Sample_MC[iMode].get() );
533  }
534  Sample_Stack->Draw("hist");
535  Sample_MC_Full->Draw("SAME he");
536  if(Sample_Data) Sample_Data->Draw("SAME pe");
537  canv->cd();
538  Sample_Stack->GetXaxis();
539  Sample_Stack->SetTitle(Sample_MC_Other->GetTitle());
540  Sample_Stack->GetXaxis()->SetTitle(Sample_MC_Other->GetXaxis()->GetTitle());
541  Sample_Stack->GetYaxis()->SetTitle(Sample_MC_Other->GetYaxis()->GetTitle());
542 
543  double FullIntegral = std::accumulate(Integrals.begin(), Integrals.end(), 0.0);
544  double OtherIntegral = 0.;
545  TLegend legend(0.50,0.52,0.85,0.88);
546  if(Sample_Data) legend.AddEntry(Sample_Data.get(), "Data","ple");
547  legend.AddEntry(Sample_MC_Full.get(), Titles[iFile].c_str(),"fple");
548  for(int iMode = 0; iMode < nModes; iMode++) {
549  if(isRelevantMode[iMode]) {
550  std::string Label = Form("%s: %.1f%%", Modes[iSample][iMode].c_str(), Integrals[iMode]/FullIntegral*100);
551  legend.AddEntry(Sample_MC[iMode].get(), Label.c_str() ,"lf");
552  } else{
553  OtherIntegral += Integrals[iMode]/FullIntegral;
554  }
555  }
556  legend.AddEntry(Sample_MC_Other.get(), Form("Other: %.1f%%", OtherIntegral*100), "lf");
557  legend.SetTextSize(0.03);
558  legend.Draw();
559 
560  canv->Print("Overlay_Predictive.pdf", "pdf");
561  } // end loop over dimensions
562  } // end loop over samples
563  } // end loop over files
564 }
565 
566 
568 void GetMeanError(TH1D* hist, double &Mean, double &Error){
569  TF1 *Gauss = hist->GetFunction("Fit"); //This name is hardcoded be careful
570  //KS: Get mean and error from Gauss
571  Mean = Gauss->GetParameter(1);
572  Error = Gauss->GetParameter(2);
573 
574  //KS: Get mean and error from HPD
575  //Mean = hist->GetMean();
576  //Error = hpost->GetRMS();
577 }
578 
580 void PrintPosteriorEventRates(const std::vector<TFile*>& InputFiles,
581  const std::vector<std::string>& SampleNames) {
582  MACH3LOG_INFO("Starting {}", __func__);
583  MACH3LOG_INFO("");
584 
585  double mean, error;
586  //KS: We now prepare to make tables for TN etc.
587  std::cout<<"\\begin{table}[htb]"<<std::endl;
588  std::cout<<"\\centering"<<std::endl;
589  std::cout<<"\\begin{tabular}{ | l |";
590  for(unsigned int f = 0; f < InputFiles.size(); f++)
591  {
592  std::cout<<" c |";
593  }
594  std::cout<<"} \\hline"<<std::endl;
595  std::cout<<"Sample ";
596  for(unsigned int f = 0; f < InputFiles.size(); f++)
597  {
598  std::cout<<"& Event Rates ";
599  }
600  std::cout<<"\\\\ \\hline"<<std::endl;
601  for(unsigned int i = 0; i < SampleNames.size(); i++)
602  {
603  std::cout<<SampleNames[i];
604  std::string TempString = "Predictive/" + SampleNames[i]+"/"+SampleNames[i]+"_sum";
605  for(unsigned int f = 0; f < InputFiles.size(); f++)
606  {
607  TH1D *hist = static_cast<TH1D*>(InputFiles[f]->Get(TempString.c_str()));
608  GetMeanError(hist, mean, error);
609  std::cout<<" & "<<mean<<" $\\pm$ "<<error;
610  }
611  std::cout<<" \\\\"<<std::endl;
612  }
613  std::cout<<"Total";
614  for(unsigned int f = 0; f < InputFiles.size(); f++)
615  {
616  TH1D *histTot = static_cast<TH1D*>(InputFiles[f]->Get("Predictive/Total/Total_sum"));
617  GetMeanError(histTot, mean, error);
618  std::cout<<" & "<<mean<<" $\\pm$ "<<error;
619  }
620  std::cout<<" \\\\"<<std::endl;
621  std::cout<<"\\hline"<<std::endl;
622  std::cout<<"\\end{tabular}"<<std::endl;
623  std::cout<<"\\end{table}"<<std::endl;
624  MACH3LOG_INFO("");
625 }
626 
628 void PrintPosteriorFractionalUncertainties(const std::vector<TFile*>& InputFiles,
629  const std::vector<std::string>& SampleNames) {
630  MACH3LOG_INFO("Starting {}", __func__);
631  MACH3LOG_INFO("");
632  double mean, error;
633 
634  //KS: Fractional uncertainties on the prior and posterior predictive event rates.
635  std::cout<<"\\begin{table}[htb]"<<std::endl;
636  std::cout<<"\\centering"<<std::endl;
637  std::cout<<"\\begin{tabular}{ | l |";
638  for(unsigned int f = 0; f < InputFiles.size(); f++)
639  {
640  std::cout<<" c |";
641  }
642  std::cout<<"} \\hline"<<std::endl;
643 
644  std::cout<<"Sample ";
645  for(unsigned int f = 0; f < InputFiles.size(); f++)
646  {
647  std::cout<<"& $\\delta N / N (\\%)$";
648  }
649  std::cout<<"\\\\ \\hline"<<std::endl;
650 
651  for(unsigned int i = 0; i < SampleNames.size(); i++)
652  {
653  std::cout<<SampleNames[i];
654  std::string TempString = "Predictive/" + SampleNames[i]+"/"+SampleNames[i]+"_sum";
655  for(unsigned int f = 0; f < InputFiles.size(); f++)
656  {
657  TH1D *hist = static_cast<TH1D*>(InputFiles[f]->Get(TempString.c_str()));
658  GetMeanError(hist, mean, error);
659  std::cout<<" & "<<error/mean*100;
660  }
661  std::cout<<" \\\\"<<std::endl;
662  }
663  std::cout<<"Total";
664  for(unsigned int f = 0; f < InputFiles.size(); f++)
665  {
666  TH1D *histTotal = static_cast<TH1D*>(InputFiles[f]->Get("Predictive/Total/Total_sum"));
667  GetMeanError(histTotal, mean, error);
668  std::cout<<" & "<<error/mean*100;
669  }
670  std::cout<<"\\\\ \\hline"<<std::endl;
671  std::cout<<"\\end{tabular}"<<std::endl;
672  std::cout<<"\\end{table}"<<std::endl;
673  MACH3LOG_INFO("");
674 }
675 
676 double GetLLH(TH1* hist)
677 {
678  std::string TempTile = hist->GetTitle();
679  std::string temp = "=";
680 
681  std::string::size_type SizeType = TempTile.find(temp);
682  TempTile.erase(0, SizeType+1);
683  double llh = atof(TempTile.c_str());
684  return llh;
685 }
686 
688 void PrintPredictiveLLH(const std::vector<TFile*>& InputFiles,
689  const std::vector<std::string>& SampleNames) {
690  MACH3LOG_INFO("Starting {}", __func__);
691  MACH3LOG_INFO("");
692 
693  std::vector<double> Total(InputFiles.size());
694  //KS: We now prepare to make tables for TN etc.
695  std::cout<<"\\begin{table}[htb]"<<std::endl;
696  std::cout<<"\\centering"<<std::endl;
697  std::cout<<"\\begin{tabular}{ | l |";
698  for(unsigned int f = 0; f < InputFiles.size(); f++)
699  {
700  Total[f] = 0.;
701  std::cout<<" c |";
702  }
703  std::cout<<"} \\hline"<<std::endl;
704  std::cout<<"Sample ";
705  for(unsigned int f = 0; f < InputFiles.size(); f++)
706  {
707  std::cout<<"& 2#log#mathcal{L}_{stat} ";
708  }
709  std::cout<<"\\\\ \\hline"<<std::endl;
710  for(unsigned int i = 0; i < SampleNames.size(); i++)
711  {
712  std::cout<<SampleNames[i];
713  std::string TempString = "Predictive/" + SampleNames[i]+"/"+SampleNames[i]+"_mc_PostPred";
714  for(unsigned int f = 0; f < InputFiles.size(); f++)
715  {
716  TH1 *hist = static_cast<TH1*>(InputFiles[f]->Get(TempString.c_str()));
717 
718  double llh = GetLLH(hist);
719  std::cout<<" & "<<llh;
720  Total[f] += llh;
721  }
722  std::cout<<" \\\\"<<std::endl;
723  }
724  std::cout<<"Total";
725  for(unsigned int f = 0; f < InputFiles.size(); f++) {
726  std::cout<<" & "<<Total[f];
727  }
728  std::cout<<" \\\\"<<std::endl;
729  std::cout<<"\\hline"<<std::endl;
730  std::cout<<"\\end{tabular}"<<std::endl;
731  std::cout<<"\\end{table}"<<std::endl;
732  std::cout<<" "<<std::endl;
733 }
734 
735 void PredictivePlotting(const std::string& ConfigName,
736  const std::vector<std::string>& FileNames)
737 {
738  auto canvas = std::make_unique<TCanvas>("canv", "canv", 1080, 1080);
739  // set the paper & margin sizes
740  canvas->SetTopMargin(0.11);
741  canvas->SetBottomMargin(0.16);
742  canvas->SetRightMargin(0.075);
743  canvas->SetLeftMargin(0.12);
744  canvas->SetGrid();
745 
746  gStyle->SetOptStat(0); //Set 0 to disable statistic box
747  gStyle->SetPalette(51);
748  gStyle->SetLegendBorderSize(0); //This option disables legends borders
749  gStyle->SetFillStyle(0);
750 
751  //To avoid TCanvas::Print> messages
752  gErrorIgnoreLevel = kWarning;
753 
754  auto Samples = FindSamples(FileNames[0]);
755  auto Dimensions = FindDimensions(FileNames[0], Samples);
756  auto Modes = FindModes(FileNames[0], Samples);
757 
758  std::vector<TFile*> InputFiles(FileNames.size());
759  for(size_t i = 0; i < FileNames.size(); i++) {
760  InputFiles[i] = M3::Open(FileNames[i], "READ", __FILE__, __LINE__);
761  }
762 
763  // Load the YAML file
764  YAML::Node Config = M3OpenConfig(ConfigName);
765  // Access the "MatrixPlotter" section
766  YAML::Node settings = Config["PredictivePlotting"];
767  canvas->Print("Overlay_Predictive.pdf[", "pdf");
768 
769  // Make overlay of 1D hists
770  OverlayPredicitve(settings, InputFiles, Samples, Dimensions, canvas);
771  // Make overlay of violin plots
772  OverlayViolin(settings, InputFiles, Samples, Dimensions, canvas);
773  // Make By Mode post pred
774  if(Modes[0].size() != 0) OverlayPredicitveByMode(settings, InputFiles, Samples, Dimensions, Modes, canvas);
775  // Get PValue per sample
776  PrintPosteriorPValue(settings, InputFiles, Samples);
777  // KS: Print Fractional Uncertainties into Latex table format
778  PrintPosteriorEventRates(InputFiles, Samples);
779  // KS: Print Fractional Uncertainties into Latex table format
780  PrintPosteriorFractionalUncertainties(InputFiles, Samples);
781  // KS: Print Predictive LLH into Latex table format
782  PrintPredictiveLLH(InputFiles, Samples);
783  canvas->Print("Overlay_Predictive.pdf]", "pdf");
784 
785  for(size_t i = 0; i < FileNames.size(); i++)
786  {
787  InputFiles[i]->Close();
788  delete InputFiles[i];
789  }
790 }
791 
792 
793 int main(int argc, char **argv)
794 {
796  if (argc < 3)
797  {
798  MACH3LOG_ERROR("Need at least two arguments, {} <Config.Yaml> <Prior/Post_PredOutput.root>", argv[0]);
799  throw MaCh3Exception(__FILE__, __LINE__);
800  }
801  std::string ConfigName = std::string(argv[1]);
802  // Collect all remaining arguments as file names
803  std::vector<std::string> FileNames;
804  for (int i = 2; i < argc; ++i) {
805  FileNames.emplace_back(argv[i]);
806  }
807 
809  PlotMan->initialise();
810 
811  PredictivePlotting(ConfigName, FileNames);
812 
813  if(PlotMan) delete PlotMan;
814  return 0;
815 }
std::unique_ptr< TH1D > MakeSummaryFromSpectra(const TH2D *Spectra, const std::string &name)
Build a 1D posterior-predictive summary from a violin spectrum.
#define MACH3LOG_DEBUG
Definition: MaCh3Logger.h:34
#define MACH3LOG_ERROR
Definition: MaCh3Logger.h:37
#define MACH3LOG_INFO
Definition: MaCh3Logger.h:35
void SetMaCh3LoggerFormat()
Set messaging format of the logger.
Definition: MaCh3Logger.h:60
double GetLLH(TH1 *hist)
void OverlayPredicitve(const YAML::Node &Settings, const std::vector< TFile * > &InputFiles, const std::vector< std::string > &SampleNames, const std::vector< int > &SampleDimension, const std::unique_ptr< TCanvas > &canv)
double GetPValue(const TH2D *hist)
void PrintPosteriorPValue(const YAML::Node &Settings, const std::vector< TFile * > &InputFiles, const std::vector< std::string > &SampleNames)
void PredictivePlotting(const std::string &ConfigName, const std::vector< std::string > &FileNames)
int main(int argc, char **argv)
std::vector< std::string > FindSamples(const std::string &File)
void GetMeanError(TH1D *hist, double &Mean, double &Error)
KS: Get mean and error from gaussian fit to event distribution.
void OverlayPredicitveByMode(const YAML::Node &Settings, const std::vector< TFile * > &InputFiles, const std::vector< std::string > &SampleNames, const std::vector< int > &SampleDimension, const std::vector< std::vector< std::string >> &Modes, const std::unique_ptr< TCanvas > &canv)
void PrintPredictiveLLH(const std::vector< TFile * > &InputFiles, const std::vector< std::string > &SampleNames)
KS Print Predictive LLH into Latex table format.
void OverlayViolin(const YAML::Node &Settings, const std::vector< TFile * > &InputFiles, const std::vector< std::string > &SampleNames, const std::vector< int > &SampleDimension, const std::unique_ptr< TCanvas > &canv)
void PretifyHistogram(TH1 *Hist, const std::string &SampleName)
std::vector< std::vector< std::string > > FindModes(const std::string &File, const std::vector< std::string > &SampleNames)
std::vector< int > FindDimensions(const std::string &File, const std::vector< std::string > &Samples)
M3::Plotting::PlottingManager * PlotMan
void PrintPosteriorFractionalUncertainties(const std::vector< TFile * > &InputFiles, const std::vector< std::string > &SampleNames)
KS: Print Fractional Uncertainties into Latex table format.
void PrintPosteriorEventRates(const std::vector< TFile * > &InputFiles, const std::vector< std::string > &SampleNames)
KS Print event rates in Latex like table.
std::unique_ptr< TGraphAsymmErrors > PoissonGraphScaled(const TH1D *hist, double scale, double cl)
Create a TGraphAsymmErrors from a histogram using exact Poisson confidence intervals instead of symme...
double FisherCombinedPValue(const std::vector< double > &pvalues)
KS: Combine p-values using Fisher's method.
void PassErrorToRatioPlot(TH1D *RatioHist, TH1D *Hist1, TH1D *DataHist)
Propagate numerator uncertainties to a ratio histogram.
void CheckBonferoniCorrectedpValue(const std::vector< std::string > &SampleNameVec, const std::vector< double > &PValVec, const double Threshold)
KS: For more see https://www.t2k.org/docs/technotes/429/TN429_v8#page=63.
#define M3OpenConfig(filename)
Macro to simplify calling LoadYaml with file and line info.
Definition: YamlHelper.h:589
The main class to be used in plotting scripts.
void initialise()
initalise this PlottingManager.
const StyleManager & style() const
Get the StyleManager contained within this PlottingManager, for doing style related things.
void setTH1XRange(TH1 *hist) const
Set plotting range for histogram.
double getBinWidthScale(const std::string &Name) const
Get bin-width scaling factor for a given kinematic variable.
std::string prettifySampleName(const std::string &origName) const
Convert hideous and vulgar internal sample name into a beautiful presentable name.
Definition: StyleManager.h:49
std::string prettifyKinematicName(const std::string &origName) const
Convert hideous and vulgar internal kinematics name into a beautiful presentable name.
Definition: StyleManager.h:58
Custom exception class used throughout MaCh3.
void SetSymmetricRatioRange(const std::vector< std::unique_ptr< TH1D >> &RatioPlot)
Set a symmetric Y-axis range around 1 for ratio plots.
std::unique_ptr< ObjectType > Clone(const ObjectType *obj, const std::string &name="")
KS: Creates a copy of a ROOT-like object and wraps it in a smart pointer.
void ScaleHistogram(TH1 *Sample_Hist, const double scale)
Scale histogram to get divided by bin width.
TFile * Open(const std::string &Name, const std::string &Type, const std::string &File, const int Line)
Opens a ROOT file with the given name and mode.