1 #ifndef CROMBIE_PLOTTER_H 2 #define CROMBIE_PLOTTER_H 32 void draw (
const std::string& filebase);
36 void scale (
double lumi);
42 : hist{hist}, xsec{xsec}, entry{entry}, type{type}, style{style} {}
60 CutReader(
double& cut,
double& expr,
double& weight,
double&
sub,
Hist::Hist& hist)
61 : cut{cut}, expr{expr}, weight{weight},
sub{
sub}, hist{hist} {}
65 hist.
fill(expr, weight * sub);
95 const std::vector<PlotConfig::Plot>& plots,
98 const bool unblind =
false,
99 const std::vector<std::pair<std::string, std::string>>& plotstodo = {}) {
107 FilteredPlots filtered_plots;
110 if (plotstodo.size()) {
114 for (
unsigned p_index = 0; p_index != plots.size(); ++p_index)
115 p_indices[plots[p_index].name] = p_index;
117 for (
auto& todo : plotstodo) {
118 auto sel_pair = std::make_pair(todo.first, selections.
selections.at(todo.first));
120 if (filtered_sels.find(todo.first) == filtered_sels.end())
121 filtered_sels.insert(sel_pair);
123 auto f_plot = filtered_plots.find(todo.second);
125 if (f_plot == filtered_plots.end())
126 filtered_plots.insert(
128 {plots[p_indices.at(todo.second)],
134 f_plot->second.second.insert(sel_pair);
140 for (
auto& plot : plots)
141 filtered_plots.insert({plot.name, {plot, filtered_sels}});
147 [plots{std::move(filtered_plots)},
148 sels{std::move(filtered_sels)},
156 using ExprIter = FilteredPlots::value_type;
161 auto exprs = Misc::comprehension<std::string>(plots,
162 [&get_expr] (
const ExprIter& iter) {
163 return get_expr(iter.second.first);
166 using SelIter = Selection::Selections::value_type;
168 [] (
const SelIter& iter) {
return iter.second.data; } :
169 [] (
const SelIter& iter) {
return iter.second.mc; };
171 auto get_cut = [&info, unblind] (
const SelIter& iter) {
174 not unblind and iter.second.blinded) ?
175 std::string{
"0"} : iter.second.cut;
178 auto weights = Misc::comprehension<std::string>(sels, get_weight);
179 auto cuts = Misc::comprehension<std::string>(sels, get_cut);
183 for (
auto& expr : exprs) {
184 for (
auto& cut : cuts) {
185 if (cut.find(expr) != std::string::npos)
190 LoadTree::Tree loaded{info.
name, this_unc.exprs(exprs, weights, cuts, info.cuts, nminus1)};
192 auto* weighthist = loaded.get<TH1>(mchistname);
196 std::list<CutReader> readers {};
198 auto add_reader = [&readers, &loaded, weighthist] (
const auto& sel,
const auto& expr,
const auto& weight,
199 const auto&
sub,
auto&
hist,
unsigned bin = 1) {
200 hist.set_total(weighthist->GetBinContent(bin));
201 readers.emplace_back(loaded.result(sel), loaded.result(expr),
202 loaded.result(weight), loaded.result(sub),
206 const auto& systematics = this_unc.full_systematic_infos();
208 for (
auto& p_iter : plots) {
209 auto& plot = p_iter.second.first;
210 for (
auto& sel : p_iter.second.second) {
211 auto& plotvec = output[sel.first +
"_" + p_iter.first];
213 plotvec.reserve(info.cuts.size());
214 for (
auto& sub : info.cuts) {
215 plotvec.push_back(plot.get_hist());
216 auto& lastplot = plotvec.back();
217 auto cut = get_cut(sel);
218 auto expr = get_expr(plot);
220 auto weight = get_weight(sel);
221 add_reader(selection, expr, weight, sub, lastplot);
223 for (
auto& sys : systematics) {
224 auto uncexpr = [&this_unc, &sys] (
const auto& expr) {
225 return this_unc.expr(sys.key, expr, sys.suff);
227 auto sysexpr = uncexpr(expr);
228 auto sysselection = uncexpr(selection);
229 auto sysweight = uncexpr(weight);
231 if (sysexpr != expr or
232 sysselection != selection or
234 add_reader(sysselection, sysexpr, sysweight, sub,
235 (sys.suff ==
"Up" or sys.suff ==
"Down" ?
236 lastplot.get_unc_hist(sys.key + sys.suff) :
237 lastplot.get_env_hist(sys.key)),
245 while (loaded.next()) {
246 for (
auto& reader : readers)
274 for (
auto& plots : outputs.at(
dir.name)) {
276 for (
auto& plot : plots) {
277 auto& outputplot = output[plot.first];
278 for (
unsigned iproc = 0; iproc != plot.second.size(); ++iproc)
279 outputplot.add(iproc,
dir, plot.second.at(iproc));
283 for (
auto& plot : output)
284 plot.second.scale(lumi);
295 if (
dir.find(proc.treename) ==
dir.end())
296 dir[proc.treename] =
PlotInfo(hist, info.
xs, proc.legendentry, info.
type, proc.style);
298 auto& toadd =
dir[proc.treename];
299 toadd.hist.add(hist);
308 hist->SetLineColor(kBlack);
312 hist->SetMarkerStyle(8);
313 hist->SetMarkerColor(style);
314 hist->SetLineColor(style);
317 hist->SetLineStyle(style);
320 hist->SetFillStyle(1001);
321 hist->SetFillColor(style);
329 TLegend legend(
const Hist::Hist& hist,
unsigned numlabels) {
332 double x_left = ((bins.first * 2)/bins.second) ? 0.15 : 0.65;
334 Debug::Debug(__PRETTY_FUNCTION__,
"max bin", bins.first, bins.second, (bins.first * 2)/bins.second, x_left);
337 TLegend leg{x_left, 0.875 - std::min(0.5, 0.075 * numlabels), x_left + 0.25, 0.875};
338 leg.SetBorderSize(0);
348 for (
auto& proc :
dir.second) {
354 proc.second.hist.scale(lumi, proc.second.xsec);
365 std::map<FileConfig::Type, Types::map<TH1D*>> hists;
369 using StyledHist = std::pair<short, Hist::Hist>;
370 StyledHist data_hist {};
371 StyledHist signal_hist {};
373 for (
auto& proc :
dir.second) {
375 switch(proc.second.type) {
377 data_hist.first = proc.second.style;
378 data_hist.second.
add(proc.second.hist);
381 bkg_hist.add(proc.second.hist);
384 signal_hist.first = proc.second.style;
385 signal_hist.second.add(proc.second.hist);
387 auto* newhist = proc.second.hist.roothist();
388 auto& histcol = hists[proc.second.type];
389 if (histcol.find(proc.second.entry) != histcol.end())
390 histcol[proc.second.entry]->Add(newhist);
393 style(newhist, proc.second.type, proc.second.style);
394 histcol[proc.second.entry] = newhist;
400 auto sorted_vec = [] (
auto& hists) {
401 std::vector<std::pair<std::string, TH1D*>> sortvec;
402 sortvec.insert(sortvec.end(), hists.begin(), hists.end());
403 std::sort(sortvec.begin(), sortvec.end(), [] (
auto& a,
auto& b) {
404 Debug::Debug(__PRETTY_FUNCTION__, a.second->Integral());
405 return a.second->Integral() > b.second->Integral();
413 THStack hs{
"hs",
""};
415 auto max = bkg_hist.max_w_unc();
418 max = std::max(dat.second->GetMaximum(), max);
422 auto mc = mcvec.end();
423 while(mc != mcvec.begin())
424 hs.Add((--mc)->second);
426 unsigned numlabels = 0;
427 for (
auto&
type : hists)
428 numlabels +=
type.second.size();
431 TLegend leg{legend(bkg_hist, numlabels)};
434 for (
auto& mc : mcvec)
435 leg.AddEntry(mc.second, mc.first.data(),
"f");
438 TCanvas canv{
"canv",
"canv", 600, 700};
441 const double bottom = mcvec.size() ? 0.3 : 0.0;
443 TPad pad1{
"pad1",
"pad1", 0.0, bottom, 1.0, 1.0};
444 Debug::Debug(__PRETTY_FUNCTION__,
"Pad number", pad1.GetNumber(), pad1.GetMother(), &canv);
445 pad1.SetBottomMargin(bottom ? 0.025 : 0.1);
449 const double nomfont = 0.03;
450 const double titleoff = 1.55;
455 hs.GetYaxis()->SetLabelSize(nomfont/(1 - bottom));
456 hs.GetYaxis()->SetTitleSize(nomfont/(1 - bottom));
457 hs.GetYaxis()->SetTitleOffset(titleoff);
458 hs.GetYaxis()->SetTitle(
"Events/Bin");
460 hs.GetXaxis()->SetLabelSize(0);
461 hs.GetXaxis()->SetTitleSize(0);
463 auto* bkg_sum = bkg_hist.roothist();
464 bkg_sum->SetFillStyle(3001);
465 bkg_sum->SetFillColor(kGray);
466 bkg_sum->Draw(
"e2,same");
468 for (
auto& sig : sigvec) {
469 leg.AddEntry(sig.second, sig.first.data(),
"lp");
470 sig.second->Add(bkg_sum);
471 sig.second->Draw(
"hist,same");
475 for (
auto& data : hists[FileConfig::Type::Data]) {
476 Debug::Debug(__PRETTY_FUNCTION__,
"Drawing data hist with", data.second->Integral(),
"entries");
477 leg.AddEntry(data.second, data.first.data(),
"lp");
478 data.second->Draw(
"PE,same");
482 TPad pad2{
"pad2",
"pad2", 0.0, 0.0, 1.0, bottom};
483 Debug::Debug(__PRETTY_FUNCTION__,
"Pad number", pad2.GetNumber(), pad2.GetMother(), &canv);
487 pad2.SetTopMargin(0.025);
488 pad2.SetBottomMargin(0.4);
491 auto bkg_ratio = bkg_hist.ratio(bkg_hist);
492 auto data_ratio = data_hist.second.ratio(bkg_hist);
494 auto set_yaxis = [bottom, titleoff] (
auto*
hist) {
495 auto* axis = hist->GetYaxis();
496 axis->SetNdivisions(504,
true);
497 axis->SetTitle(
"Data/Pred.");
498 axis->SetTitleOffset((bottom)/(1-bottom) * titleoff);
503 auto* bhist = set_yaxis(bkg_ratio.roothist());
505 for (
auto* axis : {bhist->GetXaxis(), bhist->GetYaxis()}) {
506 axis->SetTitleSize(nomfont/bottom);
507 axis->SetLabelSize(nomfont/bottom);
510 bhist->SetFillStyle(3001);
511 bhist->SetFillColor(kGray);
513 static double minratio {std::stod(
Misc::env(
"minratio",
"0.0"))};
514 bhist->SetMinimum(std::max(std::min(bkg_ratio.min_w_unc(), data_ratio.min_w_unc(
false)), minratio));
516 static double maxratio {std::stod(
Misc::env(
"maxratio",
"2.0"))};
517 bhist->SetMaximum(std::min(std::max(bkg_ratio.max_w_unc(), data_ratio.max_w_unc()), maxratio));
535 constexpr
double toplocation = 0.96;
536 latex.SetTextSize(0.035);
538 latex.SetTextAlign(31);
540 std::stringstream lumistream;
541 lumistream << std::setprecision(3) <<
currentlumi/1000.0;
542 std::string lumilabel;
543 lumistream >> lumilabel;
544 lumilabel +=
" fb^{-1} (13 TeV)";
546 latex.DrawLatex(0.95, toplocation, lumilabel.data());
548 latex.SetTextFont(62);
549 latex.SetTextAlign(11);
550 latex.DrawLatex(0.12, toplocation,
"CMS");
551 latex.SetTextSize(0.030);
552 latex.SetTextFont(52);
553 latex.SetTextAlign(11);
555 latex.DrawLatex(0.2, toplocation,
"Preliminary");
558 for (
auto& suff : {
".pdf",
".png",
".C"}) {
559 auto output = filebase + suff;
560 canv.SaveAs(output.data());