Crombie Tools
PlotStack.cc
Go to the documentation of this file.
1 /**
2  @file PlotStack.cc
3 
4  Source file of PlotStack, including the functions used for creating the histograms.
5 
6  @author Daniel Abercrombie <dabercro@mit.edu>
7 */
8 
9 #include <cstdlib>
10 #include <fstream>
11 #include <algorithm>
12 #include <sqlite3.h>
13 
14 #include "TFile.h"
15 #include "TLegend.h"
16 #include "TProfile.h"
17 #include "TRegexp.h"
18 
19 #include "PlotStack.h"
20 
22 
23 //--------------------------------------------------------------------
24 
25 /**
26  The default constructor for PlotStack.
27  It changes the value of PlotBase::fMakeRatio to be true by default.
28  */
29 
31 {
32  fMakeRatio = true;
33 }
34 
35 //--------------------------------------------------------------------
37 { }
38 
39 //--------------------------------------------------------------------
40 std::vector<HistHolder*>
41 PlotStack::MergeHistograms(FileType type, std::vector<TH1D*> hists) {
42 
43  DisplayFunc(__func__);
44 
45  std::vector<HistHolder*> HistHolders;
46 
47  auto *fileInfo = GetFileInfo(type);
48  TString previousEntry = "";
49  TH1D *tempMCHist = NULL;
50  HistHolder *tempHistHolder = NULL;
51 
52  for (UInt_t iHist = 0; iHist != hists.size(); ++iHist) {
53 
54  Message(eDebug, "About to process Histogram", iHist, "out of", hists.size());
55  Message(eDebug, "Entry is", (*fileInfo)[iHist]->fEntry, "Previous entry is",previousEntry, "");
56  Message(eDebug, "Integral is", hists[iHist]->Integral());
57 
58  if (hists[iHist]->Integral() < 0) {
59  Message(eError, "Histogram for", (*fileInfo)[iHist]->fFileName, "has negative integral", hists[iHist]->Integral());
60  continue;
61  }
62 
63  if ((*fileInfo)[iHist]->fEntry != previousEntry) {
64 
65  Message(eDebug, "Creating a new histogram");
66 
67  previousEntry = (*fileInfo)[iHist]->fEntry;
68  TString tempName;
69  tempName.Format("StackedHist_%d", iHist);
70  tempMCHist = (TH1D*) hists[iHist]->Clone(tempName);
71  tempHistHolder = new HistHolder(tempMCHist, (*fileInfo)[iHist]->fEntry,
72  (*fileInfo)[iHist]->fColorStyle,
73  (*fileInfo)[iHist]->fTreeName,
74  (fForceTop == (*fileInfo)[iHist]->fEntry),
75  (type == kSignal));
76  HistHolders.push_back(tempHistHolder);
77 
78  } else {
79 
80  tempMCHist->Add(hists[iHist]);
81  Message(eDebug, "Added to previous histogram.");
82 
83  }
84 
85  Message(eDebug, "Number of unique entries so far:", HistHolders.size());
86 
87  }
88 
89  return HistHolders;
90 }
91 
92 //--------------------------------------------------------------------
93 void
94 PlotStack::MakeCanvas(TString FileBase, Int_t NumXBins, Double_t MinX, Double_t MaxX,
95  TString XLabel, TString YLabel, Bool_t logY)
96 {
97  bool reset_per = (fEventsPer == 0);
98  if (reset_per)
99  SetEventsPer((MaxX - MinX)/NumXBins);
100 
101  Double_t XBins[NumXBins+1];
102  ConvertToArray(NumXBins, MinX, MaxX, XBins);
103  MakeCanvas(FileBase, NumXBins, XBins, XLabel, YLabel, logY);
104 
105  if (reset_per)
106  SetEventsPer(0);
107 }
108 
109 //--------------------------------------------------------------------
110 void
111 PlotStack::MakeCanvas(TString FileBase, Int_t NumXBins, Double_t *XBins,
112  TString XLabel, TString YLabel, Bool_t logY) {
113  SetIncludeErrorBars(true);
114  std::vector<TH1D*> DataHists = GetHistList(NumXBins, XBins, kData);
115  Message(eDebug, "Number of Data Histograms:", DataHists.size());
116  SetIncludeErrorBars(false);
117  std::vector<TH1D*> MCHists = GetHistList(NumXBins, XBins, kBackground);
118  Message(eDebug, "Number of MC Histograms:", MCHists.size());
119  std::vector<TH1D*> SignalHists;
120  if (fSignalFileInfo.size() != 0)
121  SignalHists = GetHistList(NumXBins, XBins, kSignal);
122  Message(eDebug, "Number of Signal Histograms:", SignalHists.size());
123 
124  MakeCanvas(FileBase, DataHists, MCHists, SignalHists, XLabel, YLabel, logY);
125 }
126 
127 //--------------------------------------------------------------------
128 void
129 PlotStack::MakeCanvas(TString FileBase, TString XLabel, TString YLabel, Bool_t logY) {
130  try {
131  SetIncludeErrorBars(true);
132  std::vector<TH1D*> DataHists = GetHistList(FileBase, kData);
133  Message(eDebug, "Number of Data Histograms:", DataHists.size());
134  SetIncludeErrorBars(false);
135  std::vector<TH1D*> MCHists = GetHistList(FileBase, kBackground);
136  Message(eDebug, "Number of MC Histograms:", MCHists.size());
137  std::vector<TH1D*> SignalHists;
138  if (fSignalFileInfo.size() != 0)
139  SignalHists = GetHistList(FileBase, kSignal);
140  Message(eDebug, "Number of Signal Histograms:", SignalHists.size());
141 
142  MakeCanvas(FileBase, DataHists, MCHists, SignalHists, XLabel, YLabel, logY);
143  }
144  catch(out_of_range e) {
145  Message(eError, "Didn't get", FileBase, "from histograms...");
146  }
147 }
148 
149 //--------------------------------------------------------------------
150 void
151 PlotStack::MakeCanvas(TString FileBase, std::vector<TH1D*> DataHists, std::vector<TH1D*> MCHists, std::vector<TH1D*> SignalHists,
152  TString XLabel, TString YLabel, Bool_t logY) {
153  DisplayFunc(__func__);
154  Message(eInfo, "Making File :", FileBase);
155  Message(eInfo, "Plotting :", fDefaultExpr);
156  Message(eInfo, "Labeled :", XLabel);
157  Message(eInfo, "With cut :", fDefaultCut.GetTitle());
158 
159  if (YLabel == "") {
160  if (fEventsPer == 0)
161  YLabel = "Events/Bin";
162  else if (fEventsPer >= 10)
163  YLabel.Form("Events/%.0f", fEventsPer);
164  else if (fEventsPer < 0.1)
165  YLabel.Form("Events/%.3f", fEventsPer);
166  else if (fEventsPer < 1.0)
167  YLabel.Form("Events/%.2f", fEventsPer);
168  else
169  YLabel.Form("Events/%.1f", fEventsPer);
170  }
171 
172  const Int_t NumXBins = MCHists[0]->GetNbinsX();
173  const Double_t *XBins = MCHists[0]->GetXaxis()->GetXbins()->GetArray();
174 
175  SetLumiLabel(float(fLuminosity/1000.0));
176  ResetLegend();
177 
178  fRatioLines.clear();
179 
180  std::vector<TFile*> TemplateFiles;
181  TFile *templateFile = NULL;
182 
183  Message(eDebug, "Number of Templates:", fTemplateEntries.size());
184 
185  for (UInt_t iTemp = 0; iTemp != fTemplateEntries.size(); ++iTemp) {
186  Message(eDebug, "Getting template:", iTemp);
187  templateFile = TFile::Open(fTemplateFiles[iTemp]);
188  TemplateFiles.push_back(templateFile);
189  }
190 
191  SetLegendFill(true);
192  TH1D *DataHist = (TH1D*) DataHists[0]->Clone("DataHist");
193  Message(eDebug, "Final Data Histogram created at", DataHist);
194  DataHist->Reset("M");
195 
196  for (UInt_t iHist = 0; iHist < DataHists.size(); iHist++)
197  DataHist->Add(DataHists[iHist]);
198 
199  Message(eInfo, "Number of data events: ", (Int_t) DataHist->GetEntries(), ", integral:", DataHist->Integral("width")/(fEventsPer ? fEventsPer : 1.0));
200 
201  std::vector<HistHolder*> HistHolders = MergeHistograms(kBackground, MCHists);
202 
203  for (UInt_t iTemp = 0; iTemp != fTemplateEntries.size(); ++iTemp) {
204 
205  for (UInt_t iHist = 0; iHist != HistHolders.size(); ++iHist) {
206 
207  if (fTemplateEntries[iTemp] == HistHolders[iHist]->fEntry) {
208 
209  Message(eInfo, "Replacing histogram %s with a template",
210  fTemplateEntries[iTemp].Data());
211 
212  TH1D *templateHist = (TH1D*) TemplateFiles[iTemp]->Get(fTemplateHists[iTemp]);
213  TH1D *toFormat = (TH1D*) templateHist->Rebin(NumXBins, "", XBins);
214  toFormat->SetFillStyle(HistHolders[iHist]->fHist->GetFillStyle());
215  toFormat->SetFillColor(HistHolders[iHist]->fHist->GetFillColor());
216  toFormat->SetMarkerSize(HistHolders[iHist]->fHist->GetMarkerSize());
217  HistHolders[iHist]->fHist = toFormat;
218 
219  }
220  }
221  }
222 
223  std::vector<HistHolder*> SignalHolders = MergeHistograms(kSignal, SignalHists);
224 
225  if (fDumpRootName != "") {
226 
227  Message(eInfo, "Dumping histograms into", fDumpRootName);
228 
229  TH1D* tempHist;
230  TFile* dumpFile = new TFile(fDumpRootName,"RECREATE");
231 
232  // Background Histograms
233 
234  auto variable = fDefaultExpr;
235  if (variable.EndsWith("Up") or variable.EndsWith("Down"))
236  variable = variable(0, variable.Index(TRegexp("_[^_]+$")));
237 
238  for (UInt_t iHist = 0; iHist != HistHolders.size(); ++iHist) {
239 
240  tempHist = (TH1D*) HistHolders[iHist]->fHist->Clone();
241 
242  Message(eInfo, HistHolders[iHist]->fEntry, " : ",
243  tempHist->Integral(0, NumXBins + 1, "width")/(fEventsPer ? fEventsPer : 1.0));
244 
245  dumpFile->WriteTObject(tempHist, TString::Format("%s__%s__%s",
246  variable.Data(),
247  HistHolders[iHist]->fTree.Data(),
248  fHistSuff.Data()
249  )
250  );
251  }
252 
253  // Signal Histograms
254 
255  for (auto iHist = SignalHolders.begin(); iHist != SignalHolders.end(); ++iHist) {
256 
257  tempHist = (TH1D*) (*iHist)->fHist->Clone();
258 
259  Message(eInfo, (*iHist)->fTree, " : ",
260  tempHist->Integral(0, NumXBins + 1, "width")/(fEventsPer ? fEventsPer : 1.0));
261 
262  dumpFile->WriteTObject(tempHist, TString::Format("%s__%s__%s",
263  variable.Data(),
264  (*iHist)->fTree.Data(),
265  fHistSuff.Data()
266  )
267  );
268 
269  }
270 
271  // Data Histogram
272 
273  tempHist = (TH1D*) DataHist->Clone();
274  Message(eInfo, "Data : ", tempHist->Integral(0, NumXBins + 1, "width")/(fEventsPer ? fEventsPer : 1.0));
275  dumpFile->WriteTObject(tempHist, TString::Format("%s__data_obs__%s",
276  variable.Data(),
277  fHistSuff.Data()
278  )
279  );
280  dumpFile->Close();
281 
282  }
283 
284  if (fSortBackground) {
285  std::sort(HistHolders.begin(), HistHolders.end(), SortHistHolders);
286  Message(eInfo, "Backgrounds sorted");
287  }
288 
289  Message(eDebug, "Number of unique histograms: %i", HistHolders.size());
290 
291  std::vector<TH1D*> AllHists;
292  for (UInt_t iLarger = 0; iLarger != HistHolders.size(); ++iLarger) {
293 
294  Message(eDebug, "Stacking up histogram:", iLarger);
295  Message(eInfo, "Entry", HistHolders[iLarger]->fEntry, "has total integral",
296  HistHolders[iLarger]->fHist->Integral("width")/(fEventsPer ? fEventsPer : 1.0));
297 
298  for (UInt_t iSmaller = iLarger + 1; iSmaller != HistHolders.size(); ++iSmaller) {
299  Message(eDebug, "Adding", iSmaller, "to", iLarger);
300  HistHolders[iLarger]->fHist->Add(HistHolders[iSmaller]->fHist);
301  }
302 
303  Message(eDebug, "Histogram", iLarger, "has integral", HistHolders[iLarger]->fHist->Integral());
304 
305  if (HistHolders[iLarger]->fHist->Integral() > 0 || iLarger == 0) {
306 
307  if (iLarger != 0)
308  SetZeroError(HistHolders[iLarger]->fHist);
309  AllHists.push_back(HistHolders[iLarger]->fHist);
310 
311  if ((HistHolders[iLarger]->fHist->Integral() > fMinLegendFrac * HistHolders[0]->fHist->Integral()) || // If more than the fraction set
312  (iLarger == HistHolders.size() - 1)) // or the last histogram
313  AddLegendEntry(HistHolders[iLarger]->fEntry, 1, fStackLineWidth, 1); // Add legend properly
314  else if ((HistHolders[iLarger]->fHist->Integral() > fIgnoreInLinear * HistHolders[0]->fHist->Integral()) ||
315  logY) { // Otherwise if not ignored
316  if (HistHolders[iLarger + 1]->fHist->Integral() > 0) { // Check if the next histogram contribute
317  if (fOthersColor != 0)
318  HistHolders[iLarger]->fHist->SetFillColor(fOthersColor);
319  AddLegendEntry("Others", 1, fStackLineWidth, 1); // If so, make others legend
320  }
321  else // If not,
322  AddLegendEntry(HistHolders[iLarger]->fEntry, HistHolders[iLarger]->fColor, 1, 1); // Make normal legend entry
323  break; // Stop adding histograms
324  } else {
325  AllHists.pop_back();
326  break;
327  }
328  }
329 
330  Message(eDebug, "There are now", AllHists.size() ,"total histograms to plot.");
331 
332  }
333 
334  Message(eInfo, "Total background contribution:", HistHolders[0]->fHist->Integral("width")/(fEventsPer ? fEventsPer : 1.0));
335 
336  if (not DataHist->Integral()) {
337  auto* match = AllHists[0];
338  for (int i_bin = 1; i_bin <= NumXBins; ++i_bin) {
339  auto content = match->GetBinContent(i_bin);
340  DataHist->SetBinContent(i_bin, content);
341  DataHist->SetBinError(i_bin, sqrt(content));
342  }
343  }
344 
345  AddLegendEntry("Data", 1);
346  SetDataIndex(int(AllHists.size()));
347  AllHists.push_back(DataHist);
348 
349  if (fSortSignal) {
350  std::sort(SignalHolders.begin(), SignalHolders.end(), SortHistHolders);
351  Message(eInfo, "Signals sorted");
352  }
353 
354  for (UInt_t iHist = 0; iHist != SignalHolders.size(); ++iHist) {
355 
356  if (fAddSignal) { // Do some clever things if we're adding signal to backgrounds
357 
358  if (fMakeRatio) // All possible signals show up on the ratio pad
359  AddRatioLine(int(AllHists.size()));
360  if (AllHists.size() > 1)
361  SignalHolders[iHist]->fHist->Add(AllHists[0]); // Add the background to the signals
362 
363  }
364 
365  AllHists.push_back(SignalHolders[iHist]->fHist);
366  AddLegendEntry(SignalHolders[iHist]->fEntry, 1, 2, SignalHolders[iHist]->fColor);
367  Message(eDebug, "There are now", AllHists.size(), "total histograms to plot.");
368  }
369 
370  if (fPostFitFile != "") {
371  TString tempName = TempHistName();
372  TH1D* post_fit = new TH1D(tempName, tempName, NumXBins, XBins);
373 
374  const char* signal_name = fSignalFileInfo.size() == 0 ? "" : fSignalFileInfo[0]->fTreeName.Data();
375 
376  sqlite3 *conn;
377  if(sqlite3_open(fPostFitFile.Data(), &conn) != SQLITE_OK) {
378  Message(eError, "Can't open database in", fPostFitFile);
379  sqlite3_close(conn);
380  exit(50);
381  }
382 
383  for (int i_bin = 1; i_bin <= NumXBins; i_bin++) {
384  sqlite3_stmt *fetch_stmt;
385  sqlite3_prepare_v2(conn, R"SQL(
386 SELECT yield FROM postfit_yields
387 WHERE region = ? AND bin = ? AND signal = ?
388 )SQL", -1, &fetch_stmt, NULL);
389 
390  sqlite3_bind_text(fetch_stmt, 1, fRegion.Data(), -1, NULL);
391  sqlite3_bind_int(fetch_stmt, 2, i_bin);
392  sqlite3_bind_text(fetch_stmt, 3, signal_name, -1, NULL);
393 
394  int rc = sqlite3_step(fetch_stmt);
395 
396  post_fit->SetBinContent(i_bin, sqlite3_column_double(fetch_stmt, 0));
397 
398  sqlite3_finalize(fetch_stmt);
399  }
400 
401  sqlite3_close(conn);
402 
403  post_fit->SetLineWidth(2);
404  post_fit->SetLineColor(2);
405 
406  if (fMakeRatio)
407  AddRatioLine(int(AllHists.size()));
408  AllHists.push_back(post_fit);
409  AddLegendEntry("Post Fit", 2);
410 
411  }
412 
413  Message(eDebug, "There are now", AllHists.size() ,"total histograms to plot.");
414 
415  if (fMakeRatio)
417 
418  SetRatioIndex(0);
419 
420  if (not std::getenv("blind"))
421  BaseCanvas(AddOutDir(FileBase), AllHists, XLabel, YLabel, logY);
422 
423  if (not fPrepared) { // If Prepared, stored and owned properly by PlotPreparer base
424  for (UInt_t iHist = 0; iHist != AllHists.size(); ++iHist) {
425  delete AllHists[iHist];
426  AllHists[iHist] = nullptr;
427  }
428  for (UInt_t iHist = 0; iHist != MCHists.size(); ++iHist) {
429  delete MCHists[iHist];
430  MCHists[iHist] = nullptr;
431  }
432  for (UInt_t iHist = 0; iHist != DataHists.size(); ++iHist) {
433  delete DataHists[iHist];
434  DataHists[iHist] = nullptr;
435  }
436  }
437 
438  for (UInt_t iTemp = 0; iTemp != fTemplateEntries.size(); ++iTemp)
439  TemplateFiles[iTemp]->Close();
440 
441  CloseFiles();
442 }
443 
444 //--------------------------------------------------------------------
445 PlotStack*
447 {
448  PlotStack *newPlotter = new PlotStack();
449  *newPlotter = *this;
450  return newPlotter;
451 }