#include "TCanvas.h"
#include "TH1.h"
#include "TStyle.h"
#include "TROOT.h"
#include "TFile.h"
#include "TDirectory.h"
#include "TLegend.h"
#include "TLatex.h"
#include "THStack.h"
#include "TParameter.h"
#include "TMap.h"
#include "TMath.h"
#include "TGraphAsymmErrors.h"
#include "TGraphErrors.h"
#include "TArrow.h"
#include "TLine.h"
#include "TH2.h"
#include "TH3.h"
#include "TProfile.h"
#include "TProfile2D.h"
#include "TGaxis.h"
#include "TFormula.h"
#include "TF1.h"
#include "TF2.h"
#include "TFitResult.h"
#include "TRandom3.h"
#include "TObjArray.h"
#include "QFramework/TQNamedTaggable.h"
#include "QFramework/TQHWWPlotter.h"
#include "QFramework/TQSampleDataReader.h"
#include "QFramework/TQHistogramUtils.h"
#include "QFramework/TQStringUtils.h"
#include "QFramework/TQUtils.h"
#include "QFramework/TQIterator.h"
#include "QFramework/TQLibrary.h"
#include <iostream>
#include <fstream>
#include <sstream>
#include <cstdlib>
#include <stdlib.h>
#include <cmath>
#define DEFAULTTEXTSIZE 0.0375
ClassImp(TQHWWPlotter)
TQHWWPlotter::TQHWWPlotter() : TQROOTPlotter() {
WARNclass("The TQHWWPlotter class is deprecated and will be removed in future versions of CAF. Please switch to using TQDefaultPlotter instead!");
}
TQHWWPlotter::TQHWWPlotter(TQSampleFolder * baseSampleFolder) : TQROOTPlotter(baseSampleFolder) {
WARNclass("The TQHWWPlotter class is deprecated and will be removed in future versions of CAF. Please switch to using TQDefaultPlotter instead!");
}
TQHWWPlotter::TQHWWPlotter(TQSampleDataReader * dataSource) : TQROOTPlotter(dataSource) {
WARNclass("The TQHWWPlotter class is deprecated and will be removed in future versions of CAF. Please switch to using TQDefaultPlotter instead!");
}
TQHWWPlotter::~TQHWWPlotter() {
}
bool TQHWWPlotter::setScheme(TString scheme) {
TString energy = this->getTagStringDefault("energy","(?)");
TString lumi = this->getTagStringDefault("luminosity","(?)");
if(this->fReader && this->fReader->getSampleFolder()){
this->fReader->getSampleFolder()->setTagBool("wildcarded?",true,"sig/?");
this->fReader->getSampleFolder()->setTagBool("wildcarded?",true,"bkg/?");
this->fReader->getSampleFolder()->setTagBool("wildcarded?",true,"data/?");
}
if (scheme.CompareTo("hww.minimal.uniflavour") == 0){
this->resetProcesses();
this->addBackground("bkg");
this->addData("data");
this->addSignal("sig/mh$(mh)");
return true;
}
if (scheme.CompareTo("hww.vbf") == 0){
resetProcesses();
addData("data/$(lepch)");
addBackground("bkg/$(lepch)/diboson/WW");
addBackground("bkg/$(lepch)/diboson/NonWW");
addBackground("bkg/$(lepch)/top/ttbar");
addBackground("bkg/$(lepch)/top/singletop");
addBackground("bkg/$(lepch)/Zjets");
addBackground("bkg/$(lepch)/Wjets");
addBackground("sig/$(lepch)/mh$(mh)/ggf");
addSignal("sig/$(lepch)/mh$(mh)/vbf");
setTotalBkgSystematics("bkg/$(lepch)");
clear();
setTagBool("style.autoStack", true);
setTagString("labels.0", "#sqrt{s} = "+energy+" TeV, #lower[-0.2]{#scale[0.6]{#int}} Ldt = "+lumi+" fb^{-1}");
setTagString("labels.1", "H#rightarrowWW^{*}#rightarrowl#nul#nu");
setTagBool("style.stackSignal", (scheme.CompareTo("hww.default.sigStacked") == 0));
return true;
}
if (scheme.CompareTo("hww.default") == 0 ||
scheme.CompareTo("hww.default.sigStacked") == 0) {
resetProcesses();
addData("data/$(lepch)");
addBackground("bkg/$(lepch)/diboson/WW");
addBackground("bkg/$(lepch)/diboson/NonWW");
addBackground("bkg/$(lepch)/top/ttbar");
addBackground("bkg/$(lepch)/top/singletop");
addBackground("bkg/$(lepch)/Zjets");
addBackground("bkg/$(lepch)/Wjets");
addBackground("");
addSignal("sig/$(lepch)/mh$(mh)");
setTotalBkgSystematics("bkg/$(lepch)");
clear();
setTagBool("style.autoStack", true);
setTagString("labels.0", "#sqrt{s} = "+energy+" TeV, #lower[-0.2]{#scale[0.6]{#int}} Ldt = "+lumi+" fb^{-1}");
setTagString("labels.1", "H#rightarrowWW^{*}#rightarrowl#nul#nu");
setTagBool("style.stackSignal", (scheme.CompareTo("hww.default.sigStacked") == 0));
return true;
} else if (scheme.CompareTo("hww.bkgsig") == 0 ||
scheme.CompareTo("hww.bkgsig.normalize") == 0 ||
scheme.CompareTo("hww.bkgggfvbf") == 0 ||
scheme.CompareTo("hww.bkgggfvbf.normalize") == 0) {
resetProcesses();
addBackground("bkg/$(lepch)");
if (scheme.Contains(".bkgsig")) {
addSignal("sig/$(lepch)/mh$(mh)");
} else if (scheme.Contains(".bkgggfvbf")) {
addSignal("sig/$(lepch)/mh$(mh)/ggf");
addSignal("sig/$(lepch)/mh$(mh)/vbf");
}
setTotalBkgSystematics("bkg/$(lepch)");
clear();
setTagBool("style.autoStack", true);
setTagBool("style.showTotalBkg", false);
setTagBool("normalize", scheme.EndsWith(".normalize"));
setTagInteger("style.nLegendCols", 1);
setTagDouble("style.legendHeight", 1.75);
setTagString("labels.0", "#sqrt{s} = "+energy+" TeV, #lower[-0.2]{#scale[0.6]{#int}} Ldt = "+lumi+" fb^{-1}");
setTagString("labels.1", "H#rightarrowWW^{*}#rightarrowl#nul#nu");
return true;
} else if (scheme.CompareTo("hww.databkgsig") == 0) {
resetProcesses();
addData("data/$(lepch)");
addBackground("bkg/$(lepch)");
addSignal("sig/$(lepch)/mh$(mh)");
setTotalBkgSystematics("bkg/$(lepch)");
clear();
setTagBool("style.autoStack", true);
setTagBool("style.showTotalBkg", false);
setTagBool("style.stackSignal", true);
setTagInteger("style.nLegendCols", 1);
setTagDouble("style.legendHeight", 1.75);
setTagString("labels.0", "#sqrt{s} = "+energy+" TeV, #lower[-0.2]{#scale[0.6]{#int}} Ldt = "+lumi+" fb^{-1}");
setTagString("labels.1", "H#rightarrowWW^{*}#rightarrowl#nul#nu");
return true;
} else if (scheme.CompareTo("comparePlots") == 0) {
setTagBool("normalize",true);
setTagBool("style.showRatio",true);
setTagBool("style.showSub",true);
setTagString("style.stackDrawOptions", "ep");
setTagBool("style.showTotalBkg", false);
setTagBool("errors.showX", false);
TQTaggableIterator itr(this->fProcesses);
while(itr.hasNext()){
TQNamedTaggable * process = itr.readNext();
if(!process) continue;
process->setTagBool(".ignoreProcessName",true);
process->setTagInteger("histLineWidth", 2);
process->setTagInteger("histMarkerStyle", 20);
if(getNProcesses(".isData") < 2)
process->setTagDouble( "histMarkerSize", 0.9);
else if(getNProcesses(".isData") < 4)
process->setTagDouble( "histMarkerSize", 0.8);
else
process->setTagDouble( "histMarkerSize", 0.7);
process->setTagInteger("histMarkerColor", process->getTagIntegerDefault("color",0) );
process->setTagInteger("histLineColor", process->getTagIntegerDefault("color",1) );
if(process->getTagBoolDefault(".isBackground",false))
{
if(getNProcesses(".isBackground") == 1)
this->setTagString("labels.totalStack",process->getTagStringDefault("title","Y"));
else
setTagString("labels.totalStack","sum");
}
else if(process->getTagBoolDefault(".isData",false))
{
if(getNProcesses("isData") == 1)
setTagString("labels.data",process->getTagStringDefault("title","X"));
else
setTagString("labels.data","X");
}
}
return true;
} else {
return false;
}
}
TCanvas * TQHWWPlotter::plotHistogram(TH1 * histo, const TString& options) {
TQSampleFolder * sfTmp = TQSampleFolder::newSampleFolder("sfTmp");
sfTmp->addObject(TQHistogramUtils::copyHistogram(histo), ".histograms+::histo");
TQTaggable tags(options);
TQHWWPlotter pl(sfTmp);
pl.resetProcesses();
pl.addData(".", TString::Format("drawOptions = '%s'",
tags.getTagStringDefault("drawOptions", "hist").Data()));
tags.removeTag("drawOptions");
pl.importTags(&tags);
TCanvas * cv = pl.plot("histo");
delete sfTmp;
return cv;
}
TCanvas * TQHWWPlotter::plotHistograms(TH1 * data, TH1* mc, const TString& options) {
TQTaggable tags(options);
TQSampleFolder * sfTmp = TQSampleFolder::newSampleFolder("sfTmp");
TQSampleFolder* dataSF = sfTmp->getSampleFolder("data+");
TQTaggable dataTags;
dataTags.importTagsWithoutPrefix(tags,"histstyles.data.");
dataSF->importTagsWithPrefix(dataTags,"style.default.");
dataSF->addObject(TQHistogramUtils::copyHistogram(data), ".histograms+::histogram");
TQSampleFolder* mcSF = sfTmp->getSampleFolder("mc+");
TQTaggable mcTags;
mcTags.importTagsWithoutPrefix(tags,"histstyles.mc.");
mcSF->importTagsWithPrefix(mcTags,"style.default.");
mcSF->addObject(TQHistogramUtils::copyHistogram(mc), ".histograms+::histogram");
TQHWWPlotter pl(sfTmp);
pl.resetProcesses();
pl.addData ("data", TString::Format("title='%s'",data->GetTitle()));
pl.addBackground("mc", TString::Format("title='%s'",mc->GetTitle()));
TCanvas * cv = pl.plot("histogram", options);
delete sfTmp;
return cv;
}
bool TQHWWPlotter::plotAndSaveHistogram(TH1 * histo, const TString& saveAs, const TString& options) {
TCanvas * cv = TQHWWPlotter::plotHistogram(histo, options);
if (cv) {
cv->SaveAs(saveAs.Data());
delete cv;
return true;
} else {
return false;
}
delete cv;
}
bool TQHWWPlotter::plotAndSaveHistograms(TH1 * data, TH1* mc, const TString& saveAs, const TString& options) {
TCanvas * cv = TQHWWPlotter::plotHistograms(data,mc, options);
if (cv) {
cv->SaveAs(saveAs.Data());
delete cv;
return true;
} else {
return false;
}
delete cv;
}
void TQHWWPlotter::setStyleIllinois(TQTaggable& tags){
double padScaling = 1.;
double ratioPadScaling = 1.;
double additionalTopMargin = 0.;
double ratioPadRatio = tags.getTagDoubleDefault("geometry.sub.height",0.35);
double titleOffset = tags.getTagDoubleDefault("style.titleOffset",1);
double textsize = tags.getTagDoubleDefault("style.textSize",DEFAULTTEXTSIZE);
bool showSub = tags.getTagBoolDefault ("style.showSub",false);
double legend_divider_x = 1. - tags.getTagDoubleDefault("geoemetry.legendPadRatio",0.25);
double geometry_left_margin = 0.20;
tags.setTagDouble("geometry.main.margins.right", 0.05);
tags.setTagDouble("geometry.main.margins.left", geometry_left_margin);
tags.setTagDouble("geometry.main.margins.top", textsize * 1.6 * padScaling);
tags.setTagDouble("geometry.main.xMin",0.);
tags.setTagDouble("geometry.main.xMax",legend_divider_x);
tags.setTagDouble("geometry.main.yMax",1.);
tags.setTagInteger("style.tickx",0);
tags.setTagInteger("style.ticky",0);
tags.setTagDouble("style.legendHeight",0.33 * (showSub ? 1.0 : 1.1));
tags.setTagDouble("geometry.legend.margins.right", 0.05);
tags.setTagDouble("geometry.legend.margins.top", textsize * 1.6 * padScaling);
tags.setTagDouble("geometry.legend.margins.left",0.16);
tags.setTagDouble("geometry.legend.margins.bottom", 0.);
tags.setTagInteger("geometry.canvas.height",600);
if (showSub){
tags.setTagInteger("geometry.canvas.width",700);
padScaling = 1. / (1. - ratioPadRatio) / 8. * 6.;
ratioPadScaling = (1. / ratioPadRatio) / 8. * 6.;
double legendPadScaling = 1.;
additionalTopMargin = 0.1 * (padScaling - 1);
tags.setTagDouble("geometry.sub.margins.top", 0.);
tags.setTagDouble("geometry.sub.margins.bottom",0.16);
tags.setTagDouble("geometry.sub.margins.left", geometry_left_margin);
tags.setTagDouble("geometry.sub.margins.right",0.05);
tags.setTagDouble("geometry.main.additionalTopMargin",additionalTopMargin);
tags.setTagDouble("geometry.main.scaling",padScaling);
tags.setTagDouble("geometry.sub.scaling",ratioPadScaling);
tags.setTagDouble("geometry.xscaling",legendPadScaling);
tags.setTagDouble("geometry.sub.xMin",0.);
tags.setTagDouble("geometry.sub.yMin",0.);
tags.setTagDouble("geometry.sub.xMax",legend_divider_x);
tags.setTagDouble("geometry.sub.yMax",ratioPadRatio);
tags.setTagDouble("geometry.main.yMin",ratioPadRatio);
tags.setTagDouble("geometry.main.margins.bottom", 0.);
tags.setTagBool("style.main.xAxis.showLabels",false);
tags.setTagBool("style.main.xAxis.showTitle",false);
} else {
tags.setTagInteger("geometry.canvas.width",800);
tags.setTagDouble("geometry.main.margins.bottom", 0.18);
tags.setTagDouble("geometry.main.yMin",0.);
}
tags.setTagDouble("geometry.legend.xMin",legend_divider_x);
tags.setTagDouble("geometry.legend.yMin", 0.);
tags.setTagDouble("geometry.legend.xMax",1.);
tags.setTagDouble("geometry.legend.yMax",1. - (1. - (showSub?ratioPadRatio:0)) *tags.getTagDoubleDefault("geometry.main.margins.top",0.3));
tags.setTagInteger("style.text.font",42);
tags.setTagDouble("style.textSize",DEFAULTTEXTSIZE);
tags.setTagInteger("style.markerType",20);
tags.setTagBool("errors.showX", false);
if (tags.getTagBoolDefault ("style.showEventYields",false))
tags.setTagDouble("legend.textSize",0.080);
tags.setTagBool("style.useLegendPad",true);
tags.setTagDouble("style.logMin",0.011);
tags.setTagDouble("legend.margin.right",-0.2);
tags.setTagDouble("geometry.main.xAxis.titleOffset",1.2*titleOffset);
tags.setTagDouble("geometry.main.xAxis.labelOffset",0.03);
tags.setTagDouble("geometry.main.xAxis.titleSize",showSub ? 0. : textsize*1.2);
tags.setTagDouble("geometry.main.xAxis.labelSize",showSub ? 0. : textsize);
tags.setTagDouble("geometry.main.yAxis.titleOffset",(showSub? 1.5:1.7)*titleOffset);
tags.setTagDouble("geometry.main.yAxis.labelOffset",0.03);
tags.setTagDouble("geometry.main.yAxis.titleSize",textsize*1.2);
tags.setTagDouble("geometry.main.yAxis.labelSize",textsize);
if(showSub){
tags.setTagDouble("geometry.sub.xAxis.titleOffset",1.1*titleOffset);
tags.setTagDouble("geometry.sub.xAxis.labelOffset",0.04);
tags.setTagDouble("geometry.sub.xAxis.titleSize",textsize*1.2);
tags.setTagDouble("geometry.sub.xAxis.labelSize",textsize);
tags.setTagDouble("geometry.sub.yAxis.titleOffset",1.5*titleOffset);
tags.setTagDouble("geometry.sub.yAxis.labelOffset",0.03);
tags.setTagDouble("geometry.sub.yAxis.titleSize",textsize*1.2);
tags.setTagDouble("geometry.sub.yAxis.labelSize",textsize);
}
double tickLength = tags.getTagDoubleDefault("style.tickLength",0.02);
tags.setTagDouble("geometry.main.yAxis.tickLength",-tickLength);
tags.setTagDouble("geometry.main.xAxis.tickLength",-tickLength);
tags.setTagDouble("geometry.sub.yAxis.tickLength", -tickLength);
tags.setTagDouble("geometry.sub.xAxis.tickLength",-tickLength);
tags.setTagInteger("style.main.xAxis.nDiv",50008);
tags.setTagInteger("style.main.yAxis.nDiv",50004);
tags.setTagInteger("style.main.lineColor",0);
tags.setTagInteger("style.main.markerColor",0);
tags.setTagInteger("style.ratio.mcErrorBand.fillColor",14);
tags.setTagInteger("style.ratio.mcErrorBand.fillStyle",3254);
tags.setTagInteger("style.significance.fillColor",kRed);
tags.setTagInteger("style.significance.fillStyle",3254);
tags.setTagInteger("style.significance.lineColor",0);
tags.setTagInteger("style.significance.lineStyle",0);
tags.setTagInteger("style.main.data.lineWidth",2);
tags.setTagInteger("style.main.data.lineColor",kBlack);
tags.setTagInteger("style.main.totalStack.fillColor",0);
tags.setTagInteger("style.main.totalStack.fillStyle",0);
tags.setTagInteger("style.main.totalStackError.fillColor",14);
tags.setTagInteger("style.main.totalStackError.fillStyle",3254);
tags.setTagInteger("style.sub.xAxis.nDiv",50008);
tags.setTagInteger("style.nLegendCols",1);
tags.setTagDouble("legend.xMin",0.0);
tags.setTagDouble("legend.yMin",0.0);
tags.setTagDouble("legend.xMax",1.0);
tags.setTagDouble("legend.yMax",1.0);
tags.setTagInteger("labels.info.align",11);
tags.setTagDouble("labels.info.size",0.8);
tags.setTagDouble("labels.info.xPos",0.);
tags.setTagDouble("labels.atlas.scale",1.);
if (showSub)
tags.setTagDouble("labels.atlas.xOffset",0.16);
else
tags.setTagDouble("labels.atlas.xOffset",0.20);
tags.setTagDouble("labels.drawATLAS.scale",1.21);
tags.setTagDouble("style.labels.scale",1.1);
tags.setTagDouble("style.labels.xOffset",geometry_left_margin+0.015);
tags.setTagBool("style.legend.textSizeFixed",true);
tags.setTagDouble("legend.textSize",0.132);
tags.setTagBool("legend.showTotalBkgErrorType",false);
tags.setTagString("legend.dataDisplayType","ex1y2p");
tags.setTagBool("style.manualStacking",false);
tags.setTagBool("style.autoStackLegend",true);
double yVetoLeft = 0.70;
double yVetoRight = 0.70;
if (tags.getTagBoolDefault ("style.logScale",false )) {
yVetoLeft -= 0.15;
yVetoRight -= 0.15;
}
tags.setTagDouble("blocks.x.0",0.5); tags.setTagDouble("blocks.y.0",yVetoLeft);
tags.setTagDouble("blocks.x.1",1.0); tags.setTagDouble("blocks.y.1",yVetoRight);
}
void TQHWWPlotter::setStyle(TQTaggable& tags){
double padScaling = 1.;
double ratioPadScaling = 1.;
double additionalTopMargin = 0.;
bool showSub = tags.getTagBoolDefault("style.showSub",false);
double ratioPadRatio = tags.getTagDoubleDefault("geometry.sub.height",0.35);
if(tags.getTagBoolDefault("style.topLegend",false)){
tags.setTagDouble("geometry.main.margins.top",0.25);
tags.setTagInteger("style.legend.fillColor",kWhite);
tags.setTagInteger("style.legend.fillStyle",1001);
tags.setTagDouble("labels.info.yPos",0.9);
tags.setTagDouble("style.labels.yPos",0.9);
tags.setTagBool("style.showMissing",false);
tags.setTagDouble("legend.yMin",0.75);
tags.setTagDouble("legend.yMax",0.95);
} else {
tags.setTagDouble("geometry.main.margins.top", 0.05);
tags.setTagDouble("geometry.legend.margins.top", 0.05);
}
if((tags.hasTag("style.heatmap") || tags.hasTag("style.migration"))&& tags.getTagIntegerDefault("style.nDim",1) == 2){
tags.setTagDouble("geometry.main.margins.right", 0.12);
} else {
tags.setTagDouble("geometry.main.margins.right", 0.05);
}
tags.setTagDouble("geometry.main.margins.left", 0.16);
tags.setTagDouble("geometry.main.xMin",0.);
tags.setTagDouble("geometry.main.xMax",1.);
tags.setTagDouble("geometry.main.yMax",1.);
tags.setTagInteger("geometry.canvas.height",600);
if (showSub){
tags.setTagDouble("geometry.sub.margins.top", tags.getTagDoubleDefault("style.ratioTopMargin",0.015));
tags.setTagDouble("geometry.sub.margins.bottom",0.16);
tags.setTagDouble("geometry.sub.margins.left", 0.16);
tags.setTagDouble("geometry.sub.margins.right", 0.05);
tags.setTagInteger("geometry.canvas.width",600);
double height = tags.getTagDoubleDefault("geometry.canvas.height",0);
double width = tags.getTagDoubleDefault("geometry.canvas.width",0);
padScaling = width / height;
ratioPadScaling = (height > width ? padScaling : 1.) / ratioPadRatio;
additionalTopMargin = 0.1 * (padScaling - 1);
tags.setTagDouble("geometry.main.additionalTopMargin",additionalTopMargin);
tags.setTagDouble("geometry.main.scaling",padScaling);
tags.setTagDouble("geometry.sub.scaling",ratioPadScaling);
tags.setTagDouble("geometry.sub.xMin",0.);
tags.setTagDouble("geometry.sub.yMin",0.);
tags.setTagDouble("geometry.sub.xMax",1.);
tags.setTagDouble("geometry.sub.yMax",ratioPadRatio);
tags.setTagDouble("geometry.main.yMin",0);
tags.setTagDouble("geometry.main.margins.bottom",ratioPadRatio);
tags.setTagDouble("geometry.legend.margins.bottom",ratioPadRatio);
tags.setTagBool("style.main.xAxis.showLabels",false);
tags.setTagBool("style.main.xAxis.showTitle",false);
} else {
tags.setTagDouble("geometry.main.margins.bottom",0.16);
tags.setTagDouble("geometry.legend.margins.bottom",0.16);
tags.setTagDouble("geometry.main.yMin",0.);
tags.setTagInteger("geometry.canvas.width",800);
}
tags.setTagInteger("style.text.font",42);
tags.setTagDouble("style.textSize",DEFAULTTEXTSIZE);
tags.setTagInteger("style.markerType",20);
tags.setTagInteger("style.main.lineColor",0);
tags.setTagInteger("style.main.markerColor",0);
tags.setTagInteger("style.main.fillColor",0);
tags.setTagInteger("style.main.fillStyle",0);
tags.setTagInteger("style.main.totalStack.lineColor",kBlue);
tags.setTagInteger("style.main.totalStack.lineWidth",1);
tags.setTagInteger("style.main.totalStack.fillColor",0);
tags.setTagInteger("style.main.totalStack.fillStyle",0);
tags.setTagInteger("style.main.totalStackError.fillColor",14);
tags.setTagInteger("style.main.totalStackError.fillStyle",3254);
tags.setTagInteger("style.main.totalStackError.lineStyle",0);
tags.setTagInteger("style.ratio.mcErrorBand.fillColor",kOrange -2);
tags.setTagInteger("style.ratio.mcErrorBand.fillStyle",1001);
tags.setTagInteger("style.optScan.default.fillColor",kOrange -2);
tags.setTagInteger("style.optScan.default.fillStyle",1001);
tags.setTagInteger("style.optScan.left.fillColor",kRed);
tags.setTagInteger("style.optScan.left.fillStyle",1001);
tags.setTagInteger("style.optScan.right.fillColor",kBlue);
tags.setTagInteger("style.optScan.right.fillStyle",1001);
tags.setTagInteger("style.main.data.lineWidth",2);
tags.setTagDouble ("style.main.data.markerStyle",20);
if (tags.hasTag("style.markerSize") && !tags.hasTag("style.main.data.markerSize")) {
tags.setTagDouble("style.main.data.markerSize",tags.getTagDoubleDefault("style.markerSize", 1.));
}
tags.setTagInteger("style.significance.fillColor",kRed);
tags.setTagInteger("style.significance.fillStyle",1001);
tags.setTagInteger("style.significance.lineColor",0);
tags.setTagInteger("style.significance.lineStyle",0);
double tickLength = tags.getTagDoubleDefault("style.tickLength",0.03);
tags.setTagDouble("geometry.main.yAxis.tickLength",tickLength);
tags.setTagDouble("geometry.main.xAxis.tickLength",tickLength);
tags.setTagDouble("geometry.sub.yAxis.tickLength", tickLength);
tags.setTagDouble("geometry.sub.xAxis.tickLength",tickLength);
tags.setTagInteger("style.sub.yAxis.nDiv",tags.getTagIntegerDefault("style.ratio.nYdiv",510));
tags.setTagInteger("style.sub.xAxis.nDiv", tags.getTagIntegerDefault("style.ratio.nXdiv", 510));
tags.setTagDouble("legend.xMin",0.59);
tags.setTagDouble("legend.xMax",0.90);
tags.setTagDouble("legend.yMin",0.70);
tags.setTagDouble("legend.yMax",0.92);
tags.setTagBool("errors.showX",true);
tags.setTagDouble("erros.widthX",0.5);
tags.setTagDouble("blocks.x.0",0.5);
tags.setTagDouble("blocks.x.1",1.0);
if(tags.getTagBoolDefault("style.showLabels",true)){
double yVetoLeft = 0.84;
TList* labels = tags.getTagList("labels");
if (labels) yVetoLeft -= (showSub ? 0.08 : 0.09) * (double)labels->GetEntries() * tags.getTagDoubleDefault("geometry.main.scaling",1.);
delete labels;
tags.setTagDouble("blocks.y.0",yVetoLeft);
} else {
tags.setTagDouble("blocks.y.0",1);
}
if(!tags.getTagBoolDefault("style.useLegendPad",false)){
double yVetoRight = tags.getTagDoubleDefault("legend.yMin",0.5) - tags.getTagDoubleDefault("legend.margin.right",0.05);
tags.setTagDouble("blocks.y.1",yVetoRight);
} else {
tags.setTagDouble("blocks.y.1",1);
}
}
bool TQHWWPlotter::includeSystematicsLegacy(TQTaggable& tags,TQTaggable& aliases){
bool verbose = tags.getTagBoolDefault("verbose",false);
if(verbose) VERBOSEclass("collecting uncertainty band data");
TH1 * hTotalStackSys = 0;
bool sysMcErrors = tags.getTagBoolDefault("errors.drawSysMC",false );
bool asymmSysMcErrors = tags.getTagBoolDefault("errors.drawAsymmSysMC", false);
if (sysMcErrors && !asymmSysMcErrors) {
TObjArray * histoSystematics = getHistograms(this->fProcesses,"isTotalBkgSys", tags.getTagStringDefault("input.bkg", "bkg"),".systematics/", aliases, tags);
if (histoSystematics && histoSystematics->GetEntries() > 0){
hTotalStackSys = (TH1*)histoSystematics->First();
this->addObject(hTotalStackSys,"totalStackSys");
}
} else {
TObjArray * histoSystematicsAsymm = 0;
if (asymmSysMcErrors) {
TObjArray * procSystematicsAsymm = new TObjArray();
procSystematicsAsymm->SetOwner(true);
TQTaggableIterator sysItr(this->fProcesses);
TObjArray* processes = NULL;
TObjArray* systList = (tags.getTagStringDefault("errors.drawAsymmSysList", "")).Tokenize(",");
while(!processes && sysItr.hasNext()){
TQTaggable* process = sysItr.readNext();
if(!process) continue;
if(!process->getTagBoolDefault("isTotalBkgSys")) continue;
processes = process->getTagStringDefault(".path").Tokenize("+");
}
for (int iSys = 0; iSys < systList->GetEntries(); iSys++) {
TString entry = "";
for (int iProc = 0; iProc < processes->GetEntries(); iProc++) {
TString process = TQStringUtils::trim(processes->At(iProc)->GetName());
TString syst = TQStringUtils::trim(systList->At(iSys)->GetName());
if (iProc)
entry += "+" + process + "/" + syst;
else
entry = process + "/" + syst;
}
TQNamedTaggable* tmp = new TQNamedTaggable();
tmp->setTagString(".path",entry);
tmp->setTagBool("isBkgSys",true);
procSystematicsAsymm->Add(tmp);
}
histoSystematicsAsymm = getHistograms(processes, "isBkgSys", tags.getTagStringDefault("input.bkg", "bkg"), ".asymmsystematics/", aliases, tags);
delete procSystematicsAsymm;
delete processes;
delete systList;
}
this->addObject(histoSystematicsAsymm,"asymmSys");
}
return true;
}
bool TQHWWPlotter::setTotalBkgSystematics(const TString& path) {
TQNamedTaggable* totalStackSys = new TQNamedTaggable("totalStackSys");
totalStackSys->setTagBool("isTotalBkgSys",true);
totalStackSys->setTagString(".path",path);
this->fProcesses->Add(totalStackSys);
return true;
}
TObjArray* TQHWWPlotter::collectHistograms(TQTaggable& tags){
bool showUnderflow = tags.getTagBoolDefault ("style.showUnderflow",false);
bool showOverflow = tags.getTagBoolDefault ("style.showOverflow",false );
tags.setTagBool("includeOverflow",showOverflow);
tags.setTagBool("includeUnderflow",showUnderflow);
int mh = tags.getTagIntegerDefault ("input.mh", 125);
bool verbose = tags.getTagBoolDefault("verbose",false );
TQTaggable aliases;
aliases.setTagString("lepch",tags.getTagStringDefault("input.lepch","?"));
aliases.setTagString("channel",tags.getTagStringDefault("input.channel","?"));
aliases.setTagString("datachannel",tags.getTagStringDefault("input.datachannel","?"));
aliases.setTagInteger("mh",mh);
aliases.importTagsWithoutPrefix(tags,"alias.");
aliases.importTagsWithoutPrefix(tags,"input.");
if(verbose) VERBOSEclass("getting data histograms");
TObjArray* histosData = getHistograms(this->fProcesses,".isData", tags.getTagStringDefault("input.data", "histogram"), "", aliases, tags);
if(verbose) VERBOSEclass("getting background histograms");
TObjArray* histosBkg = getHistograms(this->fProcesses,".isBackground", tags.getTagStringDefault("input.bkg", "histogram"), "", aliases, tags);
if(verbose) VERBOSEclass("getting signal histograms");
TObjArray* histosSig = getHistograms(this->fProcesses,".isSignal", tags.getTagStringDefault("input.sig", "histogram"), "", aliases, tags);
TObjArray* histos = new TObjArray();
histos->AddAll(histosData);
histos->AddAll(histosBkg);
histos->AddAll(histosSig);
if(histos->GetEntries() < 1){
delete histos;
ERRORclass("no histograms found: "+tags.exportTagsAsString("input.*"));
return NULL;
}
if(!histosData || histosData->GetEntries() < 1){
if(verbose) VERBOSEclass("no data histograms found, disabling data");
tags.setTagBool("style.drawData",false);
} else {
if(verbose) VERBOSEclass("found %d data histograms",histosData->GetEntries());
}
this->applyBlinding(tags,histosSig, histosBkg, histosData);
if(histosData) delete histosData;
if(histosBkg) delete histosBkg;
if(histosSig) delete histosSig;
TQTH1Iterator itr(histos);
double maxint = 0;
while(itr.hasNext()){
TH1* hist = itr.readNext();
double integral = hist->Integral();
maxint = std::max(integral,maxint);
}
if(verbose) VERBOSEclass("highest integral of histogram set is %g",maxint);
if( maxint < tags.getTagDoubleDefault("skipEmptyHistograms",1e-5) && !tags.getTagDoubleDefault("skipEmptyHistograms",1e-5) == 0 ){
delete histos;
return NULL;
}
if(verbose) VERBOSEclass("checking histogram consistency");
bool consistent = (histos->GetEntries() > 0);
TH1* hMaster = NULL;
consistent = checkConsistency(hMaster, histos) && consistent;
if (!consistent){
if(verbose) VERBOSEclass("consistency check failed");
delete histos;
return NULL;
}
hMaster->Reset();
this->addObject(histos,"histos");
tags.setTagInteger("style.nDim",TQHistogramUtils::getDimension(hMaster));
if(verbose) VERBOSEclass("preparing total background histogram");
TH1* hTotalStack = TQHistogramUtils::copyHistogram(hMaster,"totalStack");
hTotalStack->SetTitle(tags.getTagStringDefault ("labels.totalStack", "SM"));
TH1* hTotalSig = TQHistogramUtils::copyHistogram(hMaster,"totalSig");
hTotalSig->SetTitle(tags.getTagStringDefault ("labels.totalSig", "H#rightarrowWW#rightarrowl#nul#nu"));
hTotalStack->Reset();
hTotalSig->Reset();
bool hasTotalBkg = false;
TString stackFilter = tags.getTagStringDefault ("style.stackFilter","" );
TQTaggableIterator itr_bkg(this->fProcesses);
while(itr_bkg.hasNext()){
TQNamedTaggable* process = itr_bkg.readNext();
if(!process) continue;
if(!process->getTagBoolDefault(".isBackground",false)) continue;
TH1 * h = this->getObject<TH1>(this->makeHistogramIdentifier(process));
if(!h) continue;
if (!stackFilter.IsNull()) {
TString title = h->GetTitle();
if (!stackFilter.Contains(title))
continue;
}
hTotalStack->Add(h);
hasTotalBkg = true;
}
TH1* hTotalBkg = NULL;
if(hTotalStack){
hTotalBkg = TQHistogramUtils::copyHistogram(hTotalStack,"totalBkg");
hTotalBkg->SetDirectory(NULL);
this->addObject(hTotalBkg);
}
bool hasTotalSig = false;
bool stackSignal = tags.getTagBoolDefault ("style.stackSignal",false);
if (hTotalStack) {
TQTaggableIterator itr_sig(this->fProcesses);
while(itr_sig.hasNext()){
TQNamedTaggable* process = itr_sig.readNext();
if(!process) continue;
if(!process->getTagBoolDefault(".isSignal",false)) continue;
TH1 * h = this->getObject<TH1>(this->makeHistogramIdentifier(process));
if(!h) continue;
if(process->getTagBoolDefault("stack",stackSignal)){
hTotalStack->Add(h);
hasTotalSig = true;
} else {
hTotalSig->Add(h);
hasTotalSig = true;
}
}
}
if(hTotalStack && !hasTotalBkg){
this->removeObject("totalStack",true);
}
if(hTotalSig && !hasTotalSig){
this->removeObject("totalSig",true);
}
if(tags.hasTag("errors.totalBkgSys")){
tags.setTagString("errors.showSys",tags.getTagStringDefault("errors.totalBkgSys",""));
}
if(tags.getTagBoolDefault("errors.drawSysMC",false ) || tags.getTagBoolDefault("errors.drawAsymmSysMC", false)){
this->includeSystematicsLegacy(tags,aliases);
}
if(tags.hasTag("errors.showSys")){
this->sysOk = this->includeSystematics(tags);
}
if(this->getNProcesses(".isData") == 0 || !hasTotalBkg) tags.setTagBool("style.showSub",false);
return histos;
}
void TQHWWPlotter::stackHistograms(TQTaggable& tags, const TString& stackname){
bool normalize = tags.getTagBoolDefault("normalize",false );
bool normalizeWithoutOverUnderflow = !tags.getTagBoolDefault("normalizeWithoutOverUnderflow",false );
TString stackFilter = tags.getTagStringDefault ("style.stackFilter","");
TH1* hTotalStack = this->getObject<TH1>("totalStack");
double totalStackScale = TQHistogramUtils::getIntegral(hTotalStack, normalizeWithoutOverUnderflow);
if (hTotalStack && normalize) {
if (totalStackScale != 0.)
hTotalStack->Scale(1. / totalStackScale);
}
TObjArray * histStackList = new TObjArray();
TObjArray * processStackList = new TObjArray();
TQTaggableIterator itr(this->fProcesses);
while(itr.hasNext()){
TQNamedTaggable* process = itr.readNext();
if(!process) continue;
if( (process->getTagBoolDefault(".isBackground",false) && process->getTagBoolDefault("stack", true))
|| (process->getTagBoolDefault(".isSignal",false) && tags.getTagBoolDefault ("style.autoStackSignal",false))
){
TH1 * h = this->getObject<TH1>(this->makeHistogramIdentifier(process));
if (!h) continue;
if (!stackFilter.IsNull()) {
TString title = h->GetTitle();
if (!stackFilter.Contains(title))
continue;
}
if(totalStackScale > 0 && normalize){
h->Scale(1. / totalStackScale);
}
histStackList->Add(h);
processStackList->Add(process);
} else if (totalStackScale > 0 && normalize) {
TH1 * h = this->getObject<TH1>(this->makeHistogramIdentifier(process));
if (TQHistogramUtils::getIntegral(h, normalizeWithoutOverUnderflow) > 0) h->Scale(1/TQHistogramUtils::getIntegral(h, normalizeWithoutOverUnderflow));
}
}
if (!tags.getTagBoolDefault("style.manualStacking",false) && tags.getTagBoolDefault("style.autoStack",tags.getTagBoolDefault("style.logScale",false))){
for (int iHist = 0; iHist < histStackList->GetEntries(); iHist++) {
int iHistMin = iHist;
double intMin = ((TH1*)histStackList->At(iHistMin))->GetSumOfWeights();
for (int iHist2 = iHist + 1; iHist2 < histStackList->GetEntries(); iHist2++) {
double intMin2 = ((TH1*)histStackList->At(iHist2))->GetSumOfWeights();
if (intMin2 < intMin) {
iHistMin = iHist2;
intMin = intMin2;
}
}
if (iHistMin != iHist) {
TH1 * temp = (TH1*)(*histStackList)[iHist];
(*histStackList)[iHist] = (*histStackList)[iHistMin];
(*histStackList)[iHistMin] = temp;
TQNamedTaggable * temptag = (TQNamedTaggable*)(*processStackList)[iHist];
(*processStackList)[iHist] = (*processStackList)[iHistMin];
(*processStackList)[iHistMin] = temptag;
}
}
}
THStack * stack = new THStack(stackname, tags.getTagBoolDefault("style.stackSignal",false) ? "Signal+Background Stack" : "Background Stack");
if (tags.getTagBoolDefault ("style.reverseStacking",false )) {
for (int iHist = histStackList->GetEntries(); iHist >= 0 ; iHist--){
TH1* h = dynamic_cast<TH1*>(histStackList->At(iHist));
stack->Add(h);
}
} else {
for (int iHist = 0; iHist < histStackList->GetEntries(); iHist++){
TH1* h = dynamic_cast<TH1*>(histStackList->At(iHist));
stack->Add(h);
}
}
delete histStackList;
delete processStackList;
TQTaggableIterator sitr(this->fProcesses);
bool stackSignal = tags.getTagBoolDefault ("style.stackSignal",false);
if (tags.getTagBoolDefault ("style.autoStackSignal",false)) stackSignal = false;
if(hTotalStack){
while(sitr.hasNext()){
TQNamedTaggable* process = sitr.readNext();
if(!process) continue;
if(!process->getTagBoolDefault(".isSignal",false)) continue;
TH1 * h = this->getObject<TH1>(this->makeHistogramIdentifier(process));
if(!h) continue;
if(totalStackScale > 0 && process->getTagBoolDefault("normalizeToTotalBkg",false) && !normalize){
h->Scale(totalStackScale / TQHistogramUtils::getIntegral(h));
}
if (process->getTagBoolDefault("stack", stackSignal)){
stack->Add(h);
}
}
}
this->addObject(stack,stackname);
}
TCanvas * TQHWWPlotter::makePlot(TQTaggable& tags) {
bool verbose = tags.getTagBoolDefault("verbose",false);
if(verbose) VERBOSEclass("entering function");
TString lepch;
TString histogram = tags.getTagStringDefault("input.histogram");
TString histname_data = "";
TString histname_bkg = "";
TString histname_sig = "";
if(histogram.First('=') != kNPOS){
TQTaggable names(histogram);
names.getTagString("bkg",histname_bkg);
names.getTagString("sig",histname_sig);
names.getTagString("data",histname_data);
if(histname_bkg.IsNull()) getTagString("sig" ,histname_bkg);
if(histname_bkg.IsNull()) getTagString("data",histname_bkg);
if(histname_bkg.IsNull()) return NULL;
if(histname_data.IsNull()) histname_data = histname_bkg;
if(histname_sig.IsNull()) histname_sig = histname_bkg;
names.getTagString("lepch",lepch);
names.getTagString("channel",lepch);
histogram = "";
if(this->getNProcesses(".isSignal") > 0) histogram+="sig:"+histname_sig+",";
if(this->getNProcesses(".isBackground") > 0) histogram+="bkg:"+histname_bkg+",";
if(this->getNProcesses(".isData") > 0) histogram+="data:"+histname_data+",";
TQStringUtils::removeTrailing(histogram,",");
} else {
lepch = TQStringUtils::readPrefix(histogram, ":", "?");
histname_bkg = histogram;
histname_sig = histogram;
histname_data = histogram;
}
gStyle->SetOptStat(false);
gStyle->SetOptFit(false);
gStyle->SetOptTitle(false);
tags.getTagString("input.lepch", lepch);
tags.getTagString("input.channel", lepch);
tags.setTagString("input.channel", lepch);
tags.setTagString("input.chname",lepch == "?" ? "all" : lepch);
tags.setTagString("input.name",histogram);
tags.setTagString("input.bkg", histname_bkg);
tags.setTagString("input.data",histname_data);
tags.setTagString("input.sig", histname_sig);
tags.setTagString("input.sys", histname_bkg);
if(verbose) VERBOSEclass("bkg: %s",histname_bkg.Data());
if(verbose) VERBOSEclass("sig: %s",histname_sig.Data());
if(verbose) VERBOSEclass("data: %s",histname_data.Data());
if(verbose) VERBOSEclass("sys: %s",histname_data.Data());
if(verbose) VERBOSEclass("collecting histograms");
TObjArray* histos = this->collectHistograms(tags);
if(!histos) return NULL;
bool drawData = tags.getTagBoolDefault ("style.drawData",true);
std::vector<TString> showDataAtCuts;
if (drawData) {
tags.getTag("showDataAtCuts", showDataAtCuts);
}
if (!drawData) {
tags.setGlobalOverwrite(true);
tags.setTagBool("style.showKS",false);
tags.setTagBool("style.showRatio",false);
tags.setTagBool("style.showDoverB",false);
tags.setTagBool("style.showDminusB",false);
tags.setTagBool("style.showSignificance",false);
tags.setGlobalOverwrite(false);
}
TQTH1Iterator histitr(histos);
int nEntries = 0;
bool is2D = false;
bool isTProfile = false;
while(histitr.hasNext()){
TH1* hist = histitr.readNext();
nEntries += hist->GetEntries();
if(dynamic_cast<TH2*>(hist)) is2D=true;
if(dynamic_cast<TProfile*>(hist)) isTProfile=true;
}
if(nEntries < 1){
WARNclass("refusing to plot histogram '%s' - no entries!",histogram.Data());
return NULL;
}
if(verbose) VERBOSEclass("sanitizing tags");
bool overrideTotalBkgRequirement = tags.getTagBoolDefault("style.overrideTotalBkgRequirement", is2D);
TH1* hTotalStack = this->getObject<TH1>("totalStack");
if ((!hTotalStack || hTotalStack->GetEntries() <= 0) && !overrideTotalBkgRequirement){
if(verbose) VERBOSEclass("no total background histogram found, quitting");
return NULL;
}
TH1* hMaster = this->getObject<TH1>("Graph_master");
if (!hMaster){
if(verbose) VERBOSEclass("no master histogram found, quitting");
return NULL;
}
bool showPull = tags.getTagBoolDefault ("style.showPull",false);
bool showMultiRatio = tags.getTagBoolDefault ("style.showMultiRatio",false);
bool showSignificance = tags.getTagBoolDefault ("style.showSignificance",false);
bool showDoverB = tags.getTagBoolDefault ("style.showDoverB",false) || tags.getTagBoolDefault ("style.showRatio",false);
bool showDminusB = tags.getTagBoolDefault ("style.showDminusB",false);
bool showDminusBoverD = tags.getTagBoolDefault ("style.showDminusBoverD",false);
bool showOptScan = tags.getTagBoolDefault ("style.showOptScan",false);
bool showCustom = tags.getTagBoolDefault ("style.showCustom",false) && tags.hasTagString("style.ratioFormula") ;
bool showUnitNorm = tags.getTagBoolDefault ("style.showUnitNorm", false);
int nDim = tags.getTagIntegerDefault("style.nDim",1);
if(nDim != 1){
showPull = false;
showMultiRatio = false;
showDoverB = false;
showSignificance = false;
showDminusB = false;
showDminusBoverD = false;
showOptScan = false;
showCustom = false;
tags.setTagBool("style.showTotalBkg",false);
}
if(showSignificance || showDoverB || showOptScan || showDminusB || showDminusBoverD || showCustom || showMultiRatio || showPull || showUnitNorm){
tags.setGlobalOverwrite(true);
tags.setTagBool("style.showSub",true);
tags.setGlobalOverwrite(false);
} else {
tags.setTagBool("style.showSub",false);
}
if(verbose) VERBOSEclass("applying style");
bool newPlotStyle = tags.getTagBoolDefault ("style.newPlotStyle", false);
tags.setGlobalOverwrite(false);
if (newPlotStyle){
this->setStyleIllinois(tags);
} else {
this->setStyle(tags);
}
double xscaling = tags.getTagDoubleDefault("geometry.xscaling",1.);
this->applyGeometry(tags,hMaster, "main", xscaling,tags.getTagDoubleDefault("geometry.main.scaling",1.));
this->applyStyle (tags,hMaster, "main", xscaling,tags.getTagDoubleDefault("geometry.main.scaling",1.));
this->applyStyle (tags,hTotalStack,"main.totalStack",xscaling,tags.getTagDoubleDefault("geometry.main.scaling",1.));
if(verbose) VERBOSEclass("creating canvas");
TCanvas * canvas = this->createCanvas(tags);
if(!canvas) return NULL;
canvas->Draw();
TPad* pad = this->getPad("main");
if(!pad){
delete canvas;
return NULL;
}
canvas->cd();
if(verbose) VERBOSEclass("creating legend");
if(tags.getTagBoolDefault("style.useLegendPad",false)){
canvas->cd();
TPad * legendPad = this->createPad(tags,"legend");
legendPad->Draw();
this->getPad("legend");
if(!legendPad) return NULL;
this->makeLegend(tags,histos);
} else {
this->makeLegend(tags,histos);
}
if(hTotalStack && nDim == 1){
if(verbose) VERBOSEclass("stacking histograms");
this->stackHistograms(tags,"stack");
}
if(verbose) VERBOSEclass("setting labels");
TString label;
tags.setGlobalOverwrite(true);
int labelidx = 0;
if (tags.getTagString("labels.lumi", label)){
labelidx++;
tags.setTagString(TString::Format("labels.%d",labelidx), label);
}
if (tags.getTagString("labels.process", label)){
labelidx++;
tags.setTagString(TString::Format("labels.%d",labelidx), label);
}
if(verbose) VERBOSEclass("calculating tests and other labels");
if(hTotalStack){
if(tags.getTagBoolDefault("style.showBkgRMS",false)){
if(verbose) VERBOSEclass("calculating total background RMS");
double RMS = hTotalStack->GetRMS();
tags.setTagString(TString::Format("labels.%d",labelidx),TString::Format("#font[72]{RMS(%s) = %g}", hTotalStack->GetTitle(), RMS));
labelidx++;
}
TQTaggableIterator itr(fProcesses);
while(itr.hasNext()){
TQNamedTaggable* process = itr.readNext();
if(!process) continue;
if(!process->getTagBoolDefault(".isData",false)) continue;
TH1 * h_data = this->getObject<TH1>(this->makeHistogramIdentifier(process));
if(!h_data || h_data->GetEntries() == 0) continue;
if(tags.getTagBoolDefault ("style.showKS",false)){
if(verbose) VERBOSEclass("calculating KS test for '%s'",h_data->GetTitle());
float ks = std::numeric_limits<double>::quiet_NaN();
if(h_data->GetEntries() > 0 && hTotalStack->GetEntries() > 0 && h_data->Integral() > 0 && hTotalStack->Integral() > 0){
ks = hTotalStack->KolmogorovTest(h_data);
}
TString id = TString::Format("labels.%d",labelidx);
if(TQUtils::isNum(ks)){
float roundedKS = (float) int(ks*10000.+0.5)/10000.;
tags.setTagString(id,TString::Format("#color[2]{#font[72]{KS Prob = %2.1f%%}}", roundedKS*100.));
} else {
tags.setTagString(id,"#color[2]{#font[72]{KS Prob = N.A.}}");
}
labelidx++;
}
if(tags.getTagBoolDefault ("style.showChi2",false)){
if(verbose) VERBOSEclass("calculating Chi2 test for '$s'",h_data->GetTitle());
Double_t chi2 = 0;
Int_t ndf = 0, igood = 0;
TH1F* h_data_tmp = (TH1F*) h_data->Clone("h_data_tmp");
TH1F* hTotalStack_tmp = (TH1F*) hTotalStack->Clone("hTotalStack_tmp");
double maxSanitization = 0.;
if (tags.getTagDouble("style.chi2.maxSanitization",maxSanitization)) {
for(int i_tmp=1;i_tmp<=h_data_tmp->GetNbinsX()+1;i_tmp++){
if( h_data_tmp->GetBinContent(i_tmp)==0 && hTotalStack_tmp->GetBinContent(i_tmp)<maxSanitization ){
hTotalStack_tmp->SetBinContent(i_tmp, 0);
hTotalStack_tmp->SetBinError(i_tmp, 0);
}
if( hTotalStack_tmp->GetBinContent(i_tmp)==0 && h_data_tmp->GetBinContent(i_tmp)<maxSanitization ){
h_data_tmp->SetBinContent(i_tmp, 0);
h_data_tmp->SetBinError(i_tmp, 0);
}
}
}
double prob = h_data_tmp->Chi2TestX(hTotalStack_tmp,chi2,ndf,igood,"UW UF OF");
float roundedChi2Prob = (float) int(prob*10000.+0.5)/10000.;
tags.setTagString(TString::Format("labels.%d",labelidx),TString::Format("#color[2]{#font[72]{Chi2 Prob = %2.1f%%}}", roundedChi2Prob*100.));
labelidx++;
delete h_data_tmp;
delete hTotalStack_tmp;
}
if(tags.getTagBoolDefault ("style.showChi2P",false)){
TH1F* h_data_tmp = (TH1F*) h_data->Clone("h_data_tmp");
TH1F* hTotalStack_tmp = (TH1F*) hTotalStack->Clone("hTotalStack_tmp");
double maxSanitization = 0.;
if (tags.getTagDouble("style.chi2.maxSanitization",maxSanitization)) {
for(int i_tmp=1;i_tmp<=h_data_tmp->GetNbinsX()+1;i_tmp++){
if( h_data_tmp->GetBinContent(i_tmp)==0 && hTotalStack_tmp->GetBinContent(i_tmp)<maxSanitization ){
hTotalStack_tmp->SetBinContent(i_tmp, 0);
hTotalStack_tmp->SetBinError(i_tmp, 0);
}
if( hTotalStack_tmp->GetBinContent(i_tmp)==0 && h_data_tmp->GetBinContent(i_tmp)<maxSanitization ){
h_data_tmp->SetBinContent(i_tmp, 0);
h_data_tmp->SetBinError(i_tmp, 0);
}
}
}
double p_value = h_data_tmp->Chi2Test(hTotalStack_tmp,"UW UF OF");
tags.setTagString(TString::Format("labels.%d",labelidx),TString::Format("#color[2]{#font[72]{#chi^{2} p-value = %f}}", p_value));
labelidx++;
delete h_data_tmp;
delete hTotalStack_tmp;
}
if(tags.getTagBoolDefault ("style.showDataRMS",false)){
if(verbose) VERBOSEclass("calculating RMS for '$s'",h_data->GetTitle());
double RMS = h_data->GetRMS();
tags.setTagString(TString::Format("labels.%d",labelidx),TString::Format("#color[2]{#font[72]{RMS(%s) = %2.1f%%}}", h_data->GetTitle(),RMS));
labelidx++;
}
}
} else {
if(verbose) VERBOSEclass("no total background histogram found!");
}
this->setErrors(tags,"totalBkg");
tags.setGlobalOverwrite(false);
if(verbose) VERBOSEclass("drawing main pad");
if(isTProfile){
this->drawProfiles(tags);
this->drawLegend(tags);
} else if(nDim == 1){
if(!tags.getTagBoolDefault("allow1D",true)) return NULL;
bool ok = this->drawStack(tags);
if(!ok){
return NULL;
}
this->drawLegend(tags);
if(verbose) VERBOSEclass("drawing cut lines");
this->drawCutLines1D(tags);
} else if(nDim == 2){
if(!tags.getTagBoolDefault("allow2D",true)) return NULL;
if(tags.hasTagString("style.heatmap")){
this->drawHeatmap(tags);
} else if (tags.hasTagString("style.migration")){
this->drawMigration(tags);
} else if (tags.hasTagString("style.scatter")) {
this->drawScatter(tags);
this->drawLegend(tags);
} else {
this->drawContours(tags);
this->drawLegend(tags);
}
if(verbose) VERBOSEclass("drawing decorations");
this->drawAdditionalAxes(tags);
this->drawHeightLines(tags);
} else {
ERRORclass("unsupported dimensionality (nDim=%d)!",nDim);
return NULL;
}
TString fit;
if(hTotalStack && nDim == 1 && tags.getTagString("totalStackFit.function",fit)){
TFitResultPtr p = hTotalStack->Fit(fit,"Q");
TF1* func = dynamic_cast<TF1*>(hTotalStack->GetListOfFunctions()->Last());
if(func){
func->SetLineColor(tags.getTagIntegerDefault("totalStackFit.color",kRed));
func->SetLineStyle(tags.getTagIntegerDefault("totalStackFit.style",1));
func->Draw("SAME");
if(tags.getTagBoolDefault("totalStackFit.showResults",true)){
TString info = "";
for(Int_t i=0; i<func->GetNpar(); ++i){
TString name = func->GetParName(i);
tags.getTagString(TString::Format("totalStackFit.parameter.%d.name",i),name);
double val = func->GetParameter(i);
double uncertainty = func->GetParError(i);
tags.setTagString(TString::Format("labels.%d",labelidx),TString::Format("%s = %g #pm %g",name.Data(),val,uncertainty));
labelidx++;
}
}
}
}
TString histogramTag = tags.getTagStringDefault("input.histogram", "");
TString cutName(histogramTag(0, histogramTag.First('/')));
bool drawDataThisCut = (showDataAtCuts.size() == 0);
if (std::find(showDataAtCuts.begin(), showDataAtCuts.end(), cutName) != showDataAtCuts.end()) {
drawDataThisCut = true;
}
if (drawData && drawDataThisCut) {
if(verbose) VERBOSEclass("fitting data slopes");
TQTaggableIterator itr_data(fProcesses);
while(itr_data.hasNext()){
TQNamedTaggable* process = itr_data.readNext();
if(!process) continue;
if(!process->getTagBoolDefault(".isData",false)) continue;
TH1 * h = this->getObject<TH1>(this->makeHistogramIdentifier(process));
if(!h) continue;
if(tags.getTagBoolDefault("style.data.fitSlope",false)){
double fitSlopeXmin = tags.getTagDoubleDefault("style.data.fitSlope.xmin",hMaster->GetXaxis()->GetXmin());
double fitSlopeXmax = tags.getTagDoubleDefault("style.data.fitSlope.xmax",hMaster->GetXaxis()->GetXmax());
h->Fit("pol1","QG","", fitSlopeXmin, fitSlopeXmax);
TF1* f = h->GetFunction("pol1");
f->SetName(TString::Format("%s_fit",h->GetName()));
f->SetLineColor(h->GetMarkerColor());
f->SetLineWidth(tags.getTagIntegerDefault("style.data.fitSlope.lineWidth",1));
f->SetLineStyle(tags.getTagIntegerDefault("style.data.fitSlope.lineStyle",2));
if (tags.getTagBoolDefault("style.data.fitSlope.exportResults",false)) {
this->setTagDouble(TString::Format("export.fitSlope.%s.slope",h->GetName()),f->GetParameter(1));
this->setTagDouble(TString::Format("export.fitSlope.%s.slopeError",h->GetName()),f->GetParError(1));
this->setTagDouble(TString::Format("export.fitSlope.%s.chi2",h->GetName()),f->GetChisquare());
}
if (tags.getTagBoolDefault("style.data.fitSlope.printResults",true)) {
double slope = TQUtils::roundAuto(f->GetParameter(1));
double slopeErr = TQUtils::roundAuto(f->GetParError(1));
double chi2 = TQUtils::roundAuto(f->GetChisquare());
h->SetTitle(TString::Format("%s (slope #approx %g #pm %g with #chi^{2}/NDF#approx%g)",h->GetTitle(),slope,slopeErr,chi2/f->GetNDF()));
}
}
}
}
if(verbose) VERBOSEclass("drawing labels");
this->setAxisLabels(tags);
this->drawLabels(tags);
if(verbose) VERBOSEclass("refreshing drawing area");
pad->RedrawAxis();
pad->Update();
pad->cd();
if(tags.getTagBoolDefault("style.showSub",false)){
if(verbose) VERBOSEclass("drawing subplot");
canvas->cd();
TPad* subPad = this->getPad("sub");
if(!subPad){
throw std::runtime_error("unable to obtain sub pad!");
}
subPad->cd();
if (showDoverB){
if(verbose) VERBOSEclass("drawing ratio");
this->drawRatio(tags);
} else if(showPull){
if(verbose) VERBOSEclass("drawing pull");
this->drawPull(tags);
} else if(showMultiRatio){
if(verbose) VERBOSEclass("drawing multi ratio");
this->drawMultiRatio(tags);
} else if(showSignificance){
if(verbose) VERBOSEclass("drawing significance");
this->drawSignificance(tags);
} else if(showOptScan){
if(verbose) VERBOSEclass("drawing optimization scan");
this->drawOptScan(tags);
} else if(showDminusB){
if(verbose) VERBOSEclass("drawing data minus background");
this->drawDataMinusBackground(tags);
} else if(showDminusBoverD){
if(verbose) VERBOSEclass("drawing data minus background over data");
this->drawDataMinusBackgroundOverData(tags);
} else if(showCustom) {
if(verbose) VERBOSEclass("drawing custom subplot");
this->drawCustomSubPlot(tags);
} else if(showUnitNorm) {
if(verbose) VERBOSEclass("drawing unit norm subplot");
this->drawUnitNormSubPlot(tags);
}
subPad->RedrawAxis();
subPad->Update();
subPad->cd();
}
if(verbose) VERBOSEclass("all done!");
return canvas;
}
void TQHWWPlotter::drawLabels(TQTaggable& tags){
bool drawlabels = tags.getTagBoolDefault("style.showLabels",true);
double scaling = tags.getTagDoubleDefault("geometry.main.scaling",1.);
double textsize = tags.getTagDoubleDefault("style.textSize",DEFAULTTEXTSIZE);
int font = tags.getTagDoubleDefault("style.text.font",42);
int color = tags.getTagDoubleDefault("style.text.color",1);
double xscaling = tags.getTagDoubleDefault("geometry.xscaling",1.);
double x = tags.getTagDoubleDefault("style.labels.xOffset",0.2)*xscaling;
double y = tags.getTagDoubleDefault("style.labels.yPos",0.86 - tags.getTagDoubleDefault("geometry.main.additionalTopMargin",0.));
bool drawATLAS = tags.getTagBoolDefault ("labels.drawATLAS",drawlabels);
TString nfLabel = "";
if(tags.getTagBoolDefault ("labels.drawNFInfo",false)){
TString tmpLabel = tags.getTagStringDefault("labels.nfInfo","#color[2]{(NF applied for %s)}");
if(TQStringUtils::countText(tmpLabel,"%s") == 1){
TString nflist = this->getScaleFactorList(tags.getTagStringDefault("input.bkg",""));
if(!nflist.IsNull()){
nfLabel = TString::Format(tmpLabel.Data(),TQStringUtils::convertLaTeX2ROOTTeX(nflist).Data());
}
}
}
TString infoLabel = tags.getTagBoolDefault ("labels.drawInfo",drawlabels) ? tags.getTagStringDefault ("labels.info",TString::Format("Plot: \"%s\"", tags.getTagStringDefault("input.name","histogram").Data())) : "";
TString atlasLabel = tags.getTagStringDefault ("labels.atlas","Private");
TString stickerLabel = tags.getTagStringDefault ("labels.sticker","");
if (drawATLAS) {
TLatex l;
l.SetNDC();
l.SetTextFont(72);
l.SetTextSize(textsize * tags.getTagDoubleDefault("labels.drawATLAS.scale",tags.getTagDoubleDefault("labels.atlas.scale",1.25)) * scaling);
l.SetTextColor(1);
l.DrawLatex(x, y, tags.getTagStringDefault("labels.drawATLAS.text","ATLAS"));
}
if (drawATLAS && !atlasLabel.IsNull()){
TLatex p;
p.SetNDC();
p.SetTextFont(font);
p.SetTextColor(color);
p.SetTextSize(textsize * tags.getTagDoubleDefault("labels.atlas.scale",tags.getTagDoubleDefault("labels.drawATLAS.scale",1.25)) * scaling);
p.DrawLatex(x + tags.getTagDoubleDefault("labels.atlas.xOffset",0.16)*xscaling, y, atlasLabel.Data());
}
if (!infoLabel.IsNull()){
if(!nfLabel.IsNull()){
infoLabel.Prepend(" ");
infoLabel.Prepend(nfLabel);
}
TLatex l0;
l0.SetNDC();
l0.SetTextFont(font);
bool newPlotStyle = tags.getTagBoolDefault ("style.newPlotStyle", false);
if (newPlotStyle)
l0.SetTextSize(textsize * tags.getTagDoubleDefault("labels.info.size",0.6) * scaling * 0.7);
else
l0.SetTextSize(textsize * tags.getTagDoubleDefault("labels.info.size",0.6) * scaling);
l0.SetTextColor(color);
double xpos = tags.getTagDoubleDefault("geometry.main.margins.left",0.16) + tags.getTagDoubleDefault("labels.info.xPos",1.)*(1. - tags.getTagDoubleDefault("geometry.main.margins.right",0.05) - tags.getTagDoubleDefault("geometry.main.margins.left",0.16));
double ypos = 1. - scaling*(1.-tags.getTagDoubleDefault("labels.info.yPos",0.2))*tags.getTagDoubleDefault("geometry.main.margins.top",0.05);
l0.SetTextAlign(tags.getTagIntegerDefault("labels.info.align",31));
l0.DrawLatex(xpos, ypos, infoLabel.Data());
}
double marginStep = tags.getTagDoubleDefault("style.labels.marginStep",0.045);
double labelTextScale = tags.getTagDoubleDefault("style.labels.scale",0.85);
if(drawlabels){
TQIterator itr(tags.getTagList("labels"),true);
size_t index = 1;
while(itr.hasNext()){
TObject* obj = itr.readNext();
if(!obj) break;
TLatex latex;
latex.SetNDC();
latex.SetTextFont(font);
latex.SetTextSize(textsize * labelTextScale * scaling);
latex.SetTextColor(color);
latex.DrawLatex(x, y - marginStep * index * scaling,obj->GetName());
index++;
}
}
if(true){
int index = 0;
while(true){
TString key = TString::Format("extralabels.%d",index);
TString labeltext;
if(!tags.getTagString(key,labeltext)){
break;
}
TLatex latex;
latex.SetNDC();
latex.SetTextFont(font);
latex.SetTextSize(textsize * labelTextScale * scaling);
latex.SetTextColor(color);
latex.DrawLatex(tags.getTagDoubleDefault(key+".x",x),
tags.getTagDoubleDefault(key+".y", y - marginStep * index * scaling),
labeltext);
index++;
}
}
}
void TQHWWPlotter::drawSignificance(TQTaggable& tags){
TString totalStackLabel = tags.getTagStringDefault ("labels.totalStack", "SM");
TH1* hMaster = this->getObject<TH1>("Graph_master");
TH1* hTotalStack = this->getObject<TH1>("totalStack");
if(!hTotalStack) return;
int nBins = hMaster->GetNbinsX();
TQTaggableIterator itr(fProcesses);
while(itr.hasNext()){
TQNamedTaggable* process = itr.readNext();
if(!process) continue;
if(!process->getTagBoolDefault(".isData",false)) continue;
TH1 * h_data = this->getObject<TH1>(this->makeHistogramIdentifier(process));
if (!h_data) continue;
int nPoints = 0;
int nRatioPoints = 0;
for (int i = 1; i <= nBins; i++) {
if (hTotalStack->GetBinContent(i) != 0.) {
nPoints++;
if (h_data->GetBinContent(i) > 0)
nRatioPoints++;
}
}
if(nRatioPoints < 1){
continue;
}
TGraphAsymmErrors * significanceGraph = new TGraphAsymmErrors(nPoints);
this->addObject(significanceGraph,TString::Format("significanceGraph_%s",h_data->GetName()));
int iPoint = 0;
double actualSigMin = 0.;
double actualSigMax = 0.;
bool first = true;
for (int iBin = 1; iBin <= nBins; iBin++) {
double data = h_data ->GetBinContent(iBin);
double MC = hTotalStack->GetBinContent(iBin);
if (MC == 0.)
continue;
double sig = 0.;
double pValue = 0.;
significanceGraph->SetPoint(iPoint, hTotalStack->GetBinCenter(iBin), 0.);
pValue = TQHistogramUtils::pValuePoisson((unsigned)data, MC);
if (pValue < 0.5)
sig = TQHistogramUtils::pValueToSignificance(pValue, (data > MC));
if (sig < 0.) {
significanceGraph->SetPointError(
iPoint, hTotalStack->GetBinWidth(iBin) / 2.,
hTotalStack->GetBinWidth(iBin) / 2., -sig, 0.);
} else {
significanceGraph->SetPointError(
iPoint, hTotalStack->GetBinWidth(iBin) / 2.,
hTotalStack->GetBinWidth(iBin) / 2., 0., sig);
}
if (sig < actualSigMin){
actualSigMin = sig;
}
if (sig > actualSigMax){
actualSigMax = sig;
}
significanceGraph->SetPoint(iPoint, hTotalStack->GetBinCenter(iBin), 0.);
pValue = TQHistogramUtils::pValuePoisson((unsigned)data, MC);
if (pValue < 0.5)
sig = TQHistogramUtils::pValueToSignificance(pValue, (data > MC));
if (sig < 0.) {
significanceGraph->SetPointError(
iPoint, hTotalStack->GetBinWidth(iBin) / 2.,
hTotalStack->GetBinWidth(iBin) / 2., -sig, 0.);
} else {
significanceGraph->SetPointError(
iPoint, hTotalStack->GetBinWidth(iBin) / 2.,
hTotalStack->GetBinWidth(iBin) / 2., 0., sig);
}
if (sig < actualSigMin){
actualSigMin = sig;
}
if (sig > actualSigMax){
actualSigMax = sig;
}
iPoint++;
}
double xscaling = tags.getTagDoubleDefault("geometry.xscaling",1.);
double sigPadScaling = tags.getTagDoubleDefault("geometry.sub.scaling",1.);
this->applyStyle(tags,significanceGraph,"significance",xscaling,sigPadScaling);
this->applyGeometry(tags,significanceGraph,"main" ,xscaling,sigPadScaling);
this->applyGeometry(tags,significanceGraph,"sub" ,xscaling,sigPadScaling);
double xLowerLimit = hTotalStack->GetBinLowEdge(1);
double xUpperLimit = hTotalStack->GetBinLowEdge(nBins) + hTotalStack->GetBinWidth(nBins);
significanceGraph->GetXaxis()->SetLimits(xLowerLimit, xUpperLimit);
significanceGraph->GetXaxis()->SetTitle(hTotalStack->GetXaxis()->GetTitle());
significanceGraph->GetYaxis()->SetTitle("Significance");
actualSigMin = TMath::Abs(actualSigMin);
int y1 = TMath::Nint(actualSigMin);
if (y1 < actualSigMin)
actualSigMin = y1 + 0.5;
else
actualSigMin = y1;
if (fmod(actualSigMin, 1) == 0)
actualSigMin += 0.5;
int y2 = TMath::Nint(actualSigMax);
if (y2 < actualSigMax)
actualSigMax = y2 + 0.5;
else
actualSigMax = y2;
if (fmod(actualSigMax, 1) == 0)
actualSigMax += 0.5;
significanceGraph->GetHistogram()->SetMinimum(-actualSigMin);
significanceGraph->GetHistogram()->SetMaximum(actualSigMax);
if (first)
significanceGraph->Draw("A2");
else
significanceGraph->Draw("2");
if ((significanceGraph->GetHistogram()->GetMinimum() <= 0.) && (significanceGraph->GetHistogram()->GetMaximum() >= 0.)) {
TLine * line = new TLine(xLowerLimit, 0, xUpperLimit, 0);
line->SetLineColor(kRed);
line->Draw();
}
first = false;
}
}
void TQHWWPlotter::drawRatio(TQTaggable& tags){
double ratioMax = tags.getTagDoubleDefault ("style.ratioMax",1000.);
double ratioMin = tags.getTagDoubleDefault ("style.ratioMin",0.);
double ratioMaxQerr = tags.getTagDoubleDefault ("style.ratioMaxQerr",std::numeric_limits<double>::infinity());
bool forceRatioLimits = tags.getTagBoolDefault ("style.forceRatioLimits",false );
bool asymmStatErrorData = tags.getTagBoolDefault("style.data.asymErrors", false);
bool verbose = tags.getTagBoolDefault("verbose",false);
TString ratioDenominator = tags.getTagStringDefault("style.ratio.denominator","totalStack");
TH1* denominator = this->getObject<TH1>(ratioDenominator);
if(!denominator) return;
int nBins = denominator->GetNbinsX();
if(verbose) VERBOSEclass("generating ratio error graphs");
bool invertRatio = tags.getTagBoolDefault("style.invertRatio",false);
TGraphAsymmErrors * ratioErrorGraph = getRatioErrorGraph(denominator);
this->addObject(ratioErrorGraph);
if(verbose) VERBOSEclass("calculating geometry and axis ranges");
double xLowerLimit;
double xUpperLimit;
if (tags.getTagDouble("style.xmin", xLowerLimit) && tags.getTagDouble("style.xmax", xUpperLimit)) {
ratioErrorGraph->GetXaxis()->SetLimits(xLowerLimit, xUpperLimit);
}
else {
xLowerLimit = denominator->GetBinLowEdge(1);
xUpperLimit = denominator->GetBinLowEdge(nBins) + denominator->GetBinWidth(nBins);
ratioErrorGraph->GetXaxis()->SetLimits(xLowerLimit, xUpperLimit);
}
double ratioPadScaling = tags.getTagDoubleDefault("geometry.sub.scaling",1.);
double xscaling = tags.getTagDoubleDefault("geometry.xscaling",1);
this->applyStyle (tags,ratioErrorGraph,"ratio.mcErrorBand",xscaling,ratioPadScaling);
this->applyGeometry(tags,ratioErrorGraph,"main" ,xscaling,ratioPadScaling);
this->applyGeometry(tags,ratioErrorGraph,"sub" ,xscaling,ratioPadScaling);
if(verbose) VERBOSEclass("drawing ratio error graph");
ratioErrorGraph->Draw("A2");
TH1* hMaster = this->getObject<TH1>("Graph_master");
ratioErrorGraph->GetHistogram()->GetXaxis()->SetTitle(hMaster->GetXaxis()->GetTitle());
TString dataLabel("");
tags.getTagString("labels.numerator",dataLabel);
TList* graphs = new TList();
double actualRatioMin = 1.;
double actualRatioMax = 1.;
if(verbose) VERBOSEclass("generating ratio graphs");
TQTaggableIterator itr(fProcesses);
double ratioContentThreshold = tags.getTagDoubleDefault("style.ratio.dropYieldsBelow",0.0001);
double ratioMinAllowed = tags.getTagDoubleDefault ("style.ratioMinAllowed",ratioMin);
double ratioMaxAllowed = tags.getTagDoubleDefault ("style.ratioMaxAllowed",ratioMax);
actualRatioMin=ratioMinAllowed;
actualRatioMax=ratioMaxAllowed;
if(verbose) VERBOSEclass("drawRatio: allowed range of ratio graph: %f -- %f",actualRatioMin,actualRatioMax);
while(itr.hasNext()){
DEBUGclass("next process...");
TQNamedTaggable* process = itr.readNext();
if(!process) continue;
if(!process->getTagBoolDefault(".isData",false)) continue;
TH1 * h_data = this->getObject<TH1>(this->makeHistogramIdentifier(process));
if(!h_data) continue;
if(dataLabel.IsNull()) dataLabel = h_data->GetTitle();
if (asymmStatErrorData) {
h_data->Sumw2(false);
h_data->SetBinErrorOption(TH1::kPoisson);
}
TGraphAsymmErrors* ratioGraph = getRatioGraph(h_data,denominator,invertRatio,ratioContentThreshold,verbose);
if(!ratioGraph) continue;
this->addObject(ratioGraph,TString::Format("ratioGraph_%s",h_data->GetName()));
this->applyStyle(tags ,ratioGraph,"sub.data",1.,ratioPadScaling);
this->estimateRangeY(ratioGraph,actualRatioMin,actualRatioMax,ratioMaxQerr);
if(verbose) VERBOSEclass("drawRatio: estimated range of ratio graph: %f -- %f (ratioMaxQerr=%f)",actualRatioMin,actualRatioMax,ratioMaxQerr);
graphs->Add(ratioGraph);
}
if(actualRatioMin == actualRatioMax){
if(verbose) VERBOSEclass("expanding ratio to not be empty");
actualRatioMin *= 0.9;
actualRatioMax *= 1.1;
}
if (forceRatioLimits) actualRatioMin = ratioMin;
else actualRatioMin = actualRatioMin-0.1*(actualRatioMax-actualRatioMin);
if (forceRatioLimits) actualRatioMax = ratioMax;
else actualRatioMax = actualRatioMax+0.1*(actualRatioMax-actualRatioMin);
if(verbose) VERBOSEclass("drawRatio: final of ratio graph: %f -- %f",actualRatioMin,actualRatioMax);
ratioErrorGraph->GetHistogram()->SetMaximum(actualRatioMax);
ratioErrorGraph->GetHistogram()->SetMinimum(actualRatioMin);
TString totalStackLabel = tags.getTagStringDefault ("labels.totalStack", "SM");
tags.getTagString("labels.data",dataLabel);
ratioErrorGraph->GetHistogram()->GetXaxis()->SetTitle(hMaster->GetXaxis()->GetTitle());
TString subXName = tags.getTagStringDefault("labels.axes.subX", "");
if (subXName.Length()>0) {
ratioErrorGraph->GetXaxis()->SetTitle(subXName);
}
ratioErrorGraph->GetYaxis()->SetTitle(tags.getTagStringDefault("labels.ratio",dataLabel + " / "+ tags.getTagStringDefault ("labels.totalStack", "SM") +" "));
gStyle->SetEndErrorSize(0);
if(verbose) VERBOSEclass("drawing lines");
this->applyStyle(tags,ratioErrorGraph->GetHistogram()->GetXaxis(),"sub.xAxis");
this->applyStyle(tags,ratioErrorGraph->GetHistogram()->GetYaxis(),"sub.yAxis");
this->applyStyle(tags,ratioErrorGraph->GetHistogram()->GetXaxis(),"sub.xAxis");
if ((ratioErrorGraph->GetHistogram()->GetMinimum() <= 1) && (ratioErrorGraph->GetHistogram()->GetMaximum() >= 1.)) {
TLine * line = new TLine(xLowerLimit, 1., xUpperLimit, 1.);
line->SetLineColor(kRed);
line->Draw();
}
double textsize = tags.getTagDoubleDefault("style.textSize",DEFAULTTEXTSIZE)* ratioPadScaling * tags.getTagDoubleDefault("style.ratio.fitSlope.printResults.textSize",0.5);
TLatex l;
l.SetNDC();
l.SetTextSize(textsize);
double fitResultPrintPosX = tags.getTagDoubleDefault("style.ratio.fitSlope.printResults.posX",0.2);
double fitResultPrintPosY = tags.getTagDoubleDefault("style.ratio.fitSlope.printResults.posY",0.85);
double fitResultPrintStepY = tags.getTagDoubleDefault("style.ratio.fitSlope.printResults.stepY",1.);
TString ratioDrawStyle("SAME ");
ratioDrawStyle.Append(tags.getTagStringDefault("style.ratio.drawOption","P e0"));
TQGraphIterator itr2(graphs);
while(itr2.hasNext()){
TGraph* ratioGraph = itr2.readNext();
if(!ratioGraph) continue;
if(tags.getTagBoolDefault("style.ratio.fitSlope",false) && ratioGraph->GetN() > 1){
if(verbose) VERBOSEclass("running fit on %s",ratioGraph->GetName());
double fitSlopeXmin = tags.getTagDoubleDefault("style.ratio.fitSlope.xmin",xLowerLimit);
double fitSlopeXmax = tags.getTagDoubleDefault("style.ratio.fitSlope.xmax",xUpperLimit);
ratioGraph->Fit("pol1","EQF","", fitSlopeXmin, fitSlopeXmax);
TF1* f = ratioGraph->GetFunction("pol1");
f->SetName(TString::Format("%s_fit",ratioGraph->GetName()));
f->SetLineColor(ratioGraph->GetLineColor());
f->SetLineWidth(tags.getTagIntegerDefault("style.ratio.fitSlope.lineWidth",1));
f->SetLineStyle(tags.getTagIntegerDefault("style.ratio.fitSlope.lineStyle",2));
if (tags.getTagBoolDefault("style.ratio.fitSlope.printResults",false)) {
l.SetTextColor(ratioGraph->GetLineColor());
double offset = TQUtils::roundAuto(f->GetParameter(0), 3);
double slope = TQUtils::roundAuto(f->GetParameter(1), 3);
double slopeErr = TQUtils::roundAuto(f->GetParError(1), 3);
double chi2 = TQUtils::roundAuto(f->GetChisquare());
TString s = TString::Format("line #approx %g + %g * x #pm %g (#chi^{2}#approx%g)",offset, slope,slopeErr,chi2);
l.DrawLatex(fitResultPrintPosX,fitResultPrintPosY,s);
fitResultPrintPosY -= fitResultPrintStepY * textsize;
}
if (tags.getTagBoolDefault("style.ratio.fitSlope.exportResults",false)) {
this->setTagDouble(TString::Format("export.fitSlope.%s.slope",ratioGraph->GetName()),f->GetParameter(1));
this->setTagDouble(TString::Format("export.fitSlope.%s.slopeError",ratioGraph->GetName()),f->GetParError(1));
this->setTagDouble(TString::Format("export.fitSlope.%s.chi2",ratioGraph->GetName()),f->GetChisquare());
}
}
ratioGraph->Draw(ratioDrawStyle);
if(verbose) VERBOSEclass("drawing additional markers");
this->drawArrows(tags,ratioGraph, actualRatioMin,actualRatioMax);
}
}
void TQHWWPlotter::drawMultiRatio(TQTaggable& tags){
double ratioMax = tags.getTagDoubleDefault ("style.ratioMax",1000.);
double ratioMin = tags.getTagDoubleDefault ("style.ratioMin",0.);
double ratioMaxQerr = tags.getTagDoubleDefault ("style.ratioMaxQerr",std::numeric_limits<double>::infinity());
bool forceRatioLimits = tags.getTagBoolDefault ("style.forceRatioLimits",false );
bool verbose = tags.getTagBoolDefault("verbose",false);
double ratioPadScaling = tags.getTagDoubleDefault("geometry.sub.scaling",1.);
double xscaling = tags.getTagDoubleDefault("geometry.xscaling",1.);
if(verbose) VERBOSEclass("calculating geometry and axis ranges");
TString dataLabel("");
TList* graphs = new TList();
double actualRatioMin = 1.;
double actualRatioMax = 1.;
if(verbose) VERBOSEclass("generating ratio graphs");
TQTaggableIterator numerator_processes(fProcesses);
TQTaggableIterator denominator_processes(fProcesses);
TString axtitle;
double xmin = 0;
double xmax = 0;
int nbins = 0;
while(numerator_processes.hasNext() && denominator_processes.hasNext()){
DEBUGclass(" in the loop");
TQNamedTaggable* denominator = NULL;
TQNamedTaggable* numerator = NULL;
while(!numerator && numerator_processes.hasNext()){
DEBUGclass("Numinator");
TQNamedTaggable* next = numerator_processes.readNext();
if(next->getTagBoolDefault(".isNumerator",false)) numerator = next;
}
while(!denominator && denominator_processes.hasNext()){
DEBUGclass(" Denominator ");
TQNamedTaggable* next = denominator_processes.readNext();
if(next->getTagBoolDefault(".isDenominator",false)) denominator = next;
}
if(!numerator || !denominator) continue;
if(verbose) VERBOSEclass("drawing comparsion between %s and %s",numerator->GetName(), denominator->GetName());
TH1 * h_numerator = this->getObject<TH1>(this->makeHistogramIdentifier(numerator));
TH1 * h_denominator = this->getObject<TH1>(this->makeHistogramIdentifier(denominator));
if(!h_numerator) continue;
if(!h_denominator) continue;
if(axtitle.IsNull()){
axtitle = h_numerator->GetXaxis()->GetTitle();
xmin = h_numerator->GetXaxis()->GetXmin();
xmax = h_numerator->GetXaxis()->GetXmax();
nbins = h_numerator->GetNbinsX();
}
int nRatioPoints = 0;
for (int i = 1; i <= h_numerator->GetNbinsX(); i++) {
double denVal = h_denominator->GetBinContent(i);
double numVal = h_numerator->GetBinContent(i);
if(denVal == 0) continue;
if(numVal == 0) continue;
if(!TQUtils::isNum(denVal)){
WARNclass("encountered non-numeric denominator value: %f",denVal);
continue;
}
if(!TQUtils::isNum(numVal)){
WARNclass("encountered non-numeric numerator value: %f",numVal);
continue;
}
nRatioPoints++;
}
if(nRatioPoints < 1){
continue;
}
TGraphErrors * ratioGraph = new TGraphErrors(nRatioPoints);
this->addObject(ratioGraph,TString::Format("ratioGraph_%s",h_numerator->GetName()));
ratioGraph->SetTitle(TString::Format("%s (ratio)",h_numerator->GetTitle()));
ratioGraph->SetLineColor(h_numerator->GetLineColor());
ratioGraph->SetMarkerSize(h_numerator->GetMarkerSize());
ratioGraph->SetMarkerStyle(h_numerator->GetMarkerStyle());
ratioGraph->SetMarkerColor(h_numerator->GetMarkerColor());
int iRatioPoint = 0;
for (int iBin = 1; iBin <= h_numerator->GetNbinsX(); iBin++) {
double x = h_denominator->GetBinCenter(iBin);
double num = h_numerator ->GetBinContent(iBin);
double numErr = h_numerator ->GetBinError (iBin);
double den = h_denominator->GetBinContent(iBin);
if (den == 0. || num <= 0.) continue;
double ratio = num / den;
double ratioError = ratio * numErr / num;
if(verbose) VERBOSEclass("adding ratio point with x=%f, y=%f (numerator=%f, denominator=%f)",x,ratio,num,den);
ratioGraph->SetPoint(iRatioPoint, x, ratio);
ratioGraph->SetPointError(iRatioPoint, 0., ratioError);
iRatioPoint++;
}
this->applyStyle(tags ,ratioGraph,"sub.data",1.,ratioPadScaling);
double ratioMinAllowed = tags.getTagDoubleDefault ("style.ratioMinAllowed",ratioMin);
double ratioMaxAllowed = tags.getTagDoubleDefault ("style.ratioMaxAllowed",ratioMax);
actualRatioMin=ratioMinAllowed;
actualRatioMax=ratioMaxAllowed;
if(verbose) VERBOSEclass("drawMultiRatio: allowed range of ratio graph: %f -- %f",actualRatioMin,actualRatioMax);
this->estimateRangeY(ratioGraph,actualRatioMin,actualRatioMax,ratioMaxQerr);
if(verbose) VERBOSEclass("drawMultiRatio: estimated range of ratio graph: %f -- %f (ratioMaxQerr=%f)",actualRatioMin,actualRatioMax,ratioMaxQerr);
if(actualRatioMin == actualRatioMax){
if(verbose) VERBOSEclass("expanding multi ratio to not be empty");
actualRatioMin *= 0.9;
actualRatioMax *= 1.1;
}
if (forceRatioLimits)
actualRatioMin = ratioMin;
else
actualRatioMin = actualRatioMin-0.1*(actualRatioMax-actualRatioMin);
if (forceRatioLimits)
actualRatioMax = ratioMax;
else
actualRatioMax = actualRatioMax+0.1*(actualRatioMax-actualRatioMin);
if(verbose) VERBOSEclass("drawMultiRatio: final of ratio graph: %f -- %f",actualRatioMin,actualRatioMax);
DEBUGclass(" ratio ");
graphs->Add(ratioGraph);
}
if(verbose) VERBOSEclass("built %d ratio graphs",graphs->GetEntries());
TString label = tags.getTagStringDefault("labels.ratio","ratio");
gStyle->SetEndErrorSize(0);
if(verbose) VERBOSEclass("drawing graphs, range is %g < x %g",xmin,xmax);
TQGraphErrorsIterator itr2(graphs);
bool first = true;
while(itr2.hasNext()){
TGraphErrors* ratioGraph = itr2.readNext();
if(!ratioGraph) continue;
ratioGraph->SetMinimum(actualRatioMin);
ratioGraph->SetMaximum(actualRatioMax);
DEBUGclass(" in the loop iiter next");
ratioGraph->Draw(first ? "AP" : "P SAME");
if(first){
ratioGraph->GetYaxis()->SetTitle(label);
ratioGraph->GetXaxis()->SetTitle(axtitle);
ratioGraph->GetXaxis()->Set(nbins,xmin,xmax);
this->applyGeometry(tags,ratioGraph,"main" ,xscaling,ratioPadScaling);
this->applyGeometry(tags,ratioGraph,"sub" ,xscaling,ratioPadScaling);
}
first = false;
this->drawArrows(tags,ratioGraph, actualRatioMin,actualRatioMax);
}
}
void TQHWWPlotter::drawOptScan(TQTaggable& tags){
double xscaling = tags.getTagDoubleDefault("geometry.xscaling",1.);
double subPadScaling = tags.getTagDoubleDefault("geometry.sub.scaling",1.);
bool verbose = tags.getTagBoolDefault("verbose",false);
TH1* hTotalStack = this->getObject<TH1>("totalStack");
TQTaggableIterator itr(this->fProcesses);
TH1* hSig = NULL;
while(itr.hasNext() && !hSig){
TQNamedTaggable* process = itr.readNext();
if(!process) continue;
if(process->getTagBoolDefault(".isSignal",false)){
hSig = this->getObject<TH1>(this->makeHistogramIdentifier(process));
}
}
if(!hTotalStack){
return;
}
if(!hSig){
return;
}
TPad* optscanPad = this->getPad("sub");
optscanPad->SetGridy(0);
TH1* hFOMl = 0;
TH1* hFOMr = 0;
TH1* hFOM = 0;
TString fommodestr = tags.getTagStringDefault("optScan.FOMmode",tags.getTagStringDefault ("style.FOMmode","s/sqrt(b)"));
TQHistogramUtils::FOM FOMmode = TQHistogramUtils::readFOM(fommodestr);
if(FOMmode == TQHistogramUtils::kUndefined){
WARNclass("unknown figure of merit '%s'!",fommodestr.Data());
return;
}
bool binByBin = tags.getTagBoolDefault("optScan.FOMbbb",tags.getTagBoolDefault ("style.FOMbbb",false));
bool drawLegend = !binByBin;
std::vector<TH1*> bkgSystHistos;
collectOptScanSimplifiedSystHistograms(bkgSystHistos, tags);
double actualmax = 0;
if(binByBin){
if(verbose){
VERBOSEclass("drawing bin-by-bin significances with FOM=%s for S=%s and B=%s",TQHistogramUtils::getFOMTitleROOT(FOMmode).Data(),hSig->GetTitle(),hTotalStack->GetTitle());
}
hFOM = TQHistogramUtils::getFOMHistogram(FOMmode,hSig, hTotalStack, 0, bkgSystHistos);
actualmax = hFOM->GetMaximum() * tags.getTagDoubleDefault("optScan.enlargeY",1.3);
this->addObject(hFOM,"hist_FOM_bbb");
} else {
if(verbose){
VERBOSEclass("drawing optimization scan with FOM=%s for S=%s and B=%s",TQHistogramUtils::getFOMTitleROOT(FOMmode).Data(),hSig->GetTitle(),hTotalStack->GetTitle());
}
hFOMl = TQHistogramUtils::getFOMScan(FOMmode,hSig, hTotalStack, true,0.05,verbose, bkgSystHistos);
hFOMr = TQHistogramUtils::getFOMScan(FOMmode,hSig, hTotalStack, false,0.05,verbose, bkgSystHistos);
if(tags.getTagBoolDefault("optScan.autoselect",false)){
if(verbose) VERBOSEclass("autoselecting opt scan");
if(TQHistogramUtils::hasGreaterMaximumThan(hFOMr,hFOMl)){
if(verbose) VERBOSEclass("removing left-hand FOM histogram");
this->addObject(hFOMr,"hist_FOM");
delete hFOMl;
hFOMl = NULL;
actualmax = hFOMr->GetMaximum() * tags.getTagDoubleDefault("optScan.enlargeY",1.3);
} else {
if(verbose) VERBOSEclass("removing right-hand FOM histogram");
this->addObject(hFOMl,"hist_FOM");
delete hFOMr;
hFOMr = NULL;
actualmax = hFOMl->GetMaximum() * tags.getTagDoubleDefault("optScan.enlargeY",1.3);
}
} else {
if(verbose) VERBOSEclass("using all opt scans");
this->addObject(hFOMl,"hist_FOM_left");
this->addObject(hFOMr,"hist_FOM_right");
actualmax = std::max(hFOMl->GetMaximum(),hFOMr->GetMaximum()) * tags.getTagDoubleDefault("optScan.enlargeY",1.3);
}
}
for (TH1* toDel : bkgSystHistos) {
delete toDel;
}
bkgSystHistos.clear();
bool first = true;
if (hFOM) {
if(verbose) VERBOSEclass("drawing FOM histogram");
this->applyStyle (tags,hFOM,"optScan.default",xscaling,subPadScaling);
this->applyGeometry(tags,hFOM,"main" ,xscaling,subPadScaling);
this->applyGeometry(tags,hFOM,"sub" ,xscaling,subPadScaling);
hFOM->SetMaximum(actualmax);
hFOM->SetMinimum(0);
hFOM->SetNdivisions(50008);
hFOM->GetYaxis()->SetNdivisions(50004);
hFOM->Draw(first ? "HIST" : "HIST SAME");
first = false;
}
if (hFOMl) {
if(verbose) VERBOSEclass("drawing FOM histogram (lhs)");
this->applyStyle (tags,hFOMl,"optScan.left",xscaling,subPadScaling);
this->applyGeometry(tags,hFOMl,"main" ,xscaling,subPadScaling);
this->applyGeometry(tags,hFOMl,"sub" ,xscaling,subPadScaling);
hFOMl->SetFillStyle(0);
hFOMl->SetMaximum(actualmax);
hFOMl->SetNdivisions(50008);
hFOMl->GetYaxis()->SetNdivisions(50004);
hFOMl->SetMinimum(0);
hFOMl->Draw(first ? "HIST" : "HIST SAME");
first = false;
}
if (hFOMr) {
if(verbose) VERBOSEclass("drawing FOM histogram (rhs)");
this->applyStyle (tags,hFOMr,"optScan.right",xscaling,subPadScaling);
this->applyGeometry(tags,hFOMr,"main" ,xscaling,subPadScaling);
this->applyGeometry(tags,hFOMr,"sub" ,xscaling,subPadScaling);
hFOMr->SetFillStyle(0);
hFOMr->SetMaximum(actualmax);
hFOMr->SetNdivisions(50008);
hFOMr->GetYaxis()->SetNdivisions(50004);
hFOMr->SetMinimum(0);
hFOMr->Draw(first ? "HIST" : "HIST SAME");
first = false;
}
if(drawLegend){
TLegend * leg = new TLegend(0.21,0.85,0.93,0.95);
leg->SetNColumns(2);
leg->SetFillColor(0);
leg->SetFillStyle(0);
leg->SetLineColor(0);
leg->SetLineWidth(0);
if (FOMmode == TQHistogramUtils::kSoSqB){
if(hFOMr){
double rmax = hFOMr->GetBinContent(hFOMr->GetMaximumBin());
double rmaxxval = hFOMr->GetBinLowEdge(hFOMr->GetMaximumBin()) + hFOMr->GetBinWidth(hFOMr->GetMaximumBin());
leg->AddEntry(hFOMr,TString::Format("#leftarrow cut Max=%.2f (%.2f)",rmax,rmaxxval), "l");
}
if(hFOMl){
double lmax = hFOMl->GetBinContent(hFOMl->GetMaximumBin());
double lmaxxval = hFOMl->GetBinLowEdge(hFOMl->GetMaximumBin());
leg->AddEntry(hFOMl,TString::Format("#rightarrow cut Max=%.2f (%.2f)",lmax,lmaxxval), "l");
}
} else {
if(hFOMl) leg->AddEntry(hFOMl,"#rightarrow cut", "l");
if(hFOMr) leg->AddEntry(hFOMr,"#leftarrow cut" , "l");
}
leg->Draw("SAME");
}
}
void TQHWWPlotter::drawDataMinusBackground(TQTaggable& tags){
TString subtractionName = tags.getTagStringDefault("style.DminusB.subtraction","totalBkg");
TH1* subtraction = this->getObject<TH1>(subtractionName);
if(!subtraction) return;
TString errorSourceName = tags.getTagStringDefault("style.DminusB.errors","totalBkg");
TH1* errorSource = this->getObject<TH1>(errorSourceName);
if(!errorSource) return;
double dmbPadScaling = tags.getTagDoubleDefault("geometry.sub.scaling",1.);
TString dataLabel("");
double max = 0;
double min = 0;
std::vector<TH1*> v_signal;
std::vector<TH1*> v_data;
TQTaggableIterator itrSig(fProcesses);
while(itrSig.hasNext()){
TQNamedTaggable* process = itrSig.readNext();
if(!process) continue;
if(!process->getTagBoolDefault(".isSignal",false)) continue;
TH1* h_sig = this->getObject<TH1>(this->makeHistogramIdentifier(process));
h_sig = TQHistogramUtils::copyHistogram(h_sig,TString::Format("%s_dminusb",h_sig->GetName()));
this->applyStyle(tags,h_sig,"sub.sig",1.,dmbPadScaling);
max = std::max(max,TQHistogramUtils::getMax(h_sig,false));
min = std::min(min,TQHistogramUtils::getMin(h_sig,false));
if(!h_sig) continue;
v_signal.push_back(h_sig);
}
TQTaggableIterator itr(fProcesses);
while(itr.hasNext()){
TQNamedTaggable* process = itr.readNext();
if(!process) continue;
if(!process->getTagBoolDefault(".isData",false)) continue;
TH1 * h_data = this->getObject<TH1>(this->makeHistogramIdentifier(process));
h_data = TQHistogramUtils::copyHistogram(h_data,TString::Format("%s_minus_bkg",h_data->GetName()));
if(!h_data) continue;
this->applyStyle(tags,h_data,"sub.data",1.,dmbPadScaling);
TQHistogramUtils::addHistogramWithoutError(h_data,subtraction,-1.);
max = std::max(max,TQHistogramUtils::getMax(h_data,true));
min = std::min(min,TQHistogramUtils::getMin(h_data,true));
v_data.push_back(h_data);
}
gStyle->SetEndErrorSize(0);
TGraphErrors* errorGraph = new TGraphErrors(errorSource->GetNbinsX());
for(int i=1; i<errorSource->GetNbinsX(); ++i){
double val = errorSource->GetBinError(i);
max = std::max(max,1.1*val);
min = std::min(min,-1.1*val);
errorGraph->SetPoint(i,errorSource->GetBinCenter(i),errorSource->GetBinContent(i)-subtraction->GetBinContent(i));
errorGraph->SetPointError(i,errorSource->GetBinCenter(i)-errorSource->GetBinLowEdge(i),val);
}
double margin = tags.getTagDoubleDefault("style.sub.margin",1.1);
TH1* frame = TQHistogramUtils::copyHistogram(subtraction,"Graph_subFrame");
frame->Reset();
frame->SetMaximum(margin*max);
frame->SetMinimum(margin*min);
this->applyStyle (tags,frame,"sub");
this->applyGeometry(tags,frame,"main",1.,dmbPadScaling);
this->applyGeometry(tags,frame,"sub",1.,dmbPadScaling);
frame->GetYaxis()->SetTitle(tags.getTagStringDefault("labels.axes.subY", "Data-Bkg."));
frame->Draw("HIST");
std::sort(v_signal.begin(),v_signal.end(),[&](TH1* a, TH1* b){ return a->GetSumOfWeights() >= b->GetSumOfWeights();});
for(auto h:v_signal){
h->Draw("HISTSAME");
}
errorGraph->SetTitle("mc error band");
this->applyStyle(tags,errorGraph,"main.totalStackError",1.,dmbPadScaling);
errorGraph->Draw("E2SAME");
for(auto h:v_data){
h->Draw("EPSAME");
}
if (min <= 0. && max >= 0.){
TLine* line = new TLine();
line->SetLineColor(kBlack);
line->DrawLine(TQHistogramUtils::getAxisXmin(subtraction), 0., TQHistogramUtils::getAxisXmax(subtraction), 0.);
delete line;
}
}
void TQHWWPlotter::drawDataMinusBackgroundOverData(TQTaggable& tags){
TString subtractionName = tags.getTagStringDefault("style.DminusB.subtraction","totalBkg");
TH1* subtraction = this->getObject<TH1>(subtractionName);
if(!subtraction) return;
TString errorSourceName = tags.getTagStringDefault("style.DminusB.errors","totalBkg");
TH1* errorSource = this->getObject<TH1>(errorSourceName);
if(!errorSource) return;
double dmbPadScaling = tags.getTagDoubleDefault("geometry.sub.scaling",1.);
TString dataLabel("");
double max = 0;
double min = 0;
std::vector<TH1*> v_signal;
std::vector<TH1*> v_data;
TQTaggableIterator itr(fProcesses);
while(itr.hasNext()){
TQNamedTaggable* process = itr.readNext();
if(!process) continue;
if(!process->getTagBoolDefault(".isData",false)) continue;
TH1 * h_data = this->getObject<TH1>(this->makeHistogramIdentifier(process));
h_data = TQHistogramUtils::copyHistogram(h_data,TString::Format("%s_minus_bkg_over_d",h_data->GetName()));
if(!h_data) continue;
this->applyStyle(tags,h_data,"sub.data",1.,dmbPadScaling);
v_data.push_back(h_data);
}
if(v_data.size() != 1){
ERRORclass("cannot plot data minus background over data when the number of datasets is != 1");
}
TH1* data = v_data[0];
TQTaggableIterator itrSig(fProcesses);
while(itrSig.hasNext()){
TQNamedTaggable* process = itrSig.readNext();
if(!process) continue;
if(!process->getTagBoolDefault(".isSignal",false)) continue;
TH1* h_sig = this->getObject<TH1>(this->makeHistogramIdentifier(process));
h_sig = TQHistogramUtils::copyHistogram(h_sig,TString::Format("%s_dminusboverd",h_sig->GetName()));
TQHistogramUtils::divideHistogramWithoutError(h_sig,data);
this->applyStyle(tags,h_sig,"sub.sig",1.,dmbPadScaling);
max = std::max(max,TQHistogramUtils::getMax(h_sig,false));
min = std::min(min,TQHistogramUtils::getMin(h_sig,false));
if(!h_sig) continue;
v_signal.push_back(h_sig);
}
gStyle->SetEndErrorSize(0);
TGraphErrors* errorGraph = new TGraphErrors(errorSource->GetNbinsX());
for(int i=1; i<=errorSource->GetNbinsX(); ++i){
double val = 1000;
if (data->GetBinContent(i) != 0){
val = errorSource->GetBinError(i)/data->GetBinContent(i);
}
double point = (data->GetBinContent(i)-subtraction->GetBinContent(i))/data->GetBinContent(i);
if (val < 1000){
max = std::max(max, 1.1*(abs(point)+val));
min = std::min(min, -1.1*(abs(point)+val));
}
else {
max = std::max(max, 1.1*(abs(point)));
min = std::min(min, -1.1*(abs(point)));
}
errorGraph->SetPoint(i,errorSource->GetBinCenter(i),(errorSource->GetBinContent(i)-subtraction->GetBinContent(i))/data->GetBinContent(i));
errorGraph->SetPointError(i,errorSource->GetBinCenter(i)-errorSource->GetBinLowEdge(i),val);
}
tags.getTagDouble("sub.yMin", min);
tags.getTagDouble("sub.yMax", max);
double margin = tags.getTagDoubleDefault("style.sub.margin",1.1);
TH1* frame = TQHistogramUtils::copyHistogram(subtraction,"Graph_subFrame");
frame->Reset();
frame->SetMaximum(margin*max);
frame->SetMinimum(margin*min);
this->applyStyle (tags,frame,"sub");
this->applyGeometry(tags,frame,"main",1.,dmbPadScaling);
this->applyGeometry(tags,frame,"sub",1.,dmbPadScaling);
TString subXName = tags.getTagStringDefault("labels.axes.subX", "");
frame->GetYaxis()->SetTitle(tags.getTagStringDefault("labels.axes.subY", "(Data-Bkg.)/Data"));
if (subXName.Length()>0) {
frame->GetXaxis()->SetTitle(subXName);
}
frame->Draw("HIST");
std::sort(v_signal.begin(),v_signal.end(),[&](TH1* a, TH1* b){ return a->GetSumOfWeights() >= b->GetSumOfWeights();});
for(auto h:v_signal){
h->Draw("HISTSAME");
}
errorGraph->SetTitle("mc error band");
this->applyStyle(tags,errorGraph,"main.totalStackError",1.,dmbPadScaling);
errorGraph->Draw("E2SAME");
TH1* copydata = TQHistogramUtils::copyHistogram(data);
TQHistogramUtils::addHistogramWithoutError(data,subtraction,-1.);
TQHistogramUtils::divideHistogramWithoutError(data,copydata);
delete copydata;
data->Draw("E P SAME X0");
TH1* dataClone = (TH1*) data->Clone();
dataClone->SetMarkerSize(0);
dataClone->Draw("SAME P e0 X0");
if (min <= 1. && max >= 1.){
TLine* line = new TLine();
line->SetLineColor(kBlack);
line->DrawLine(TQHistogramUtils::getAxisXmin(subtraction), 0., TQHistogramUtils::getAxisXmax(subtraction), 0.);
delete line;
}
this->drawArrows(tags, data, frame->GetMinimum(), frame->GetMaximum());
}
void TQHWWPlotter::drawUnitNormSubPlot(TQTaggable& tags){
gPad->SetGridy(0);
double unitNormPadScaling = tags.getTagDoubleDefault("geometry.sub.scaling",1.);
double margin = tags.getTagDoubleDefault("style.sub.margin",1.1);
double max = 0;
double min = 0;
std::vector<TH1*> v_Sig;
std::vector<TH1*> v_Bkg;
std::vector<TH1*> v_SigBkg;
std::vector<TH1*> v_SigBkg_bkwds;
TQTaggableIterator itrSig(fProcesses);
while(itrSig.hasNext()){
TQNamedTaggable* process = itrSig.readNext();
if(!process) continue;
if(!process->getTagBoolDefault(".isSignal",false)) continue;
TH1 * histo = this->getObject<TH1>(this->makeHistogramIdentifier(process));
histo = TQHistogramUtils::copyHistogram(histo,TString::Format("%s_unitNorm",histo->GetName()));
histo->Scale(1./histo->Integral());
this->applyStyle(tags,histo,"sub",1.,unitNormPadScaling);
this->applyGeometry(tags,histo,"sub",1.,unitNormPadScaling);
v_Sig.push_back(histo);
if (!histo) continue;
}
TQTaggableIterator itrBkg(fProcesses);
while(itrBkg.hasNext()){
TQNamedTaggable* process = itrBkg.readNext();
if(!process) continue;
if(!process->getTagBoolDefault(".isBackground",false)) continue;
TH1 * histo = this->getObject<TH1>(this->makeHistogramIdentifier(process));
histo = TQHistogramUtils::copyHistogram(histo,TString::Format("%s_unitNorm",histo->GetName()));
histo->Scale(1./histo->Integral());
this->applyStyle(tags,histo,"sub",1.,unitNormPadScaling);
this->applyGeometry(tags,histo,"sub",1.,unitNormPadScaling);
v_Bkg.push_back(histo);
if (!histo) continue;
}
for(auto h:v_Sig){
v_SigBkg.push_back(h);
}
for (Int_t i = v_Bkg.size() - 1; i >= 0; --i ){
v_SigBkg.push_back(v_Bkg[i]);
v_SigBkg_bkwds.push_back(v_Bkg[i]);
}
for (auto h:v_Sig){
v_SigBkg_bkwds.push_back(h);
}
bool unitnormreverse = tags.getTagBoolDefault("style.unitnormreverse", false);
if(unitnormreverse){
std::reverse(v_SigBkg.begin(),v_SigBkg.end());
std::reverse(v_SigBkg_bkwds.begin(),v_SigBkg_bkwds.end());
}
TH1* hMain = TQHistogramUtils::copyHistogram(v_SigBkg[0],"Graph_subFrame");
hMain->Reset();
hMain->SetMaximum(margin*max);
hMain->SetMinimum(margin*min);
this->applyStyle(tags,hMain,"sub");
this->applyGeometry(tags,hMain,"main",1.,unitNormPadScaling);
this->applyGeometry(tags,hMain,"sub",1.,unitNormPadScaling);
hMain->GetYaxis()->SetTitle(tags.getTagStringDefault("labels.axes.subY", "Unit norm."));
hMain->GetXaxis()->SetTitle(tags.getTagStringDefault("labels.axes.subX", ""));
hMain->Draw("HIST");
double leg_xmin = tags.getTagDoubleDefault("subLegend.xMin",0.65);
double leg_xmax = tags.getTagDoubleDefault("subLegend.xMax",0.95);
double leg_ymin = tags.getTagDoubleDefault("subLegend.yMin",0.58);
double leg_ymax = tags.getTagDoubleDefault("subLegend.yMax",0.90);
double leg_textSize = tags.getTagDoubleDefault("subLegend.textSize", 0.065);
TLegend* fLegend_sub = new TLegend(leg_xmin, leg_ymin, leg_xmax, leg_ymax);
int nColumnsSubLegend=tags.getTagIntegerDefault("subLegend.nColumns",2);
fLegend_sub->SetNColumns(nColumnsSubLegend);
fLegend_sub->SetFillColor(0);
fLegend_sub->SetFillStyle(0);
fLegend_sub->SetBorderSize(0);
fLegend_sub->SetTextFont(42);
fLegend_sub->SetTextSize(leg_textSize);
fLegend_sub->SetShadowColor(kWhite);
double maxVal = 0.;
double max_t = 0.;
bool fillSignal = tags.getTagBoolDefault("style.fillSignal", false);
TString fillSignalName = tags.getTagStringDefault("style.fillSignalName", "sigGGF");
if (fillSignal) {
for(auto h:v_SigBkg){
max_t = h->GetBinContent(h->GetMaximumBin());
if (max_t > maxVal) {
maxVal = max_t;
}
TString title = h->GetTitle();
title = TQStringUtils::convertLaTeX2ROOTTeX(title);
TString histoName = h->GetName();
h->SetLineColor(h->GetFillColor());
if (fillSignal && histoName.Contains(fillSignalName)) {
h->SetFillColor(h->GetFillColor());
fLegend_sub->AddEntry(h, title, "FL");
}
else{
h->SetFillColor(0);
fLegend_sub->AddEntry(h, title, "L");
}
h->SetLineWidth(3);
h->Draw("HISTSAME");
}
}
else {
for(auto h:v_SigBkg_bkwds) {
max_t = h->GetBinContent(h->GetMaximumBin());
if (max_t > maxVal) {
maxVal = max_t;
}
h->SetLineColor(h->GetFillColor());
h->SetFillColor(0);
h->SetLineWidth(3);
h->Draw("HISTSAME");
}
for(auto h:v_SigBkg) {
TString title = h->GetTitle();
title = TQStringUtils::convertLaTeX2ROOTTeX(title);
TString histoName = h->GetName();
fLegend_sub->AddEntry(h, title, "L");
}
}
fLegend_sub->Draw();
double yMaxSubPlot = tags.getTagDoubleDefault("sub.yMax",maxVal*1.25);
double yMinSubPlot = tags.getTagDoubleDefault("sub.yMin",0.0);
hMain->GetYaxis()->SetRangeUser(yMinSubPlot, yMaxSubPlot);
bool cutLineSubPlot = tags.getTagBoolDefault("style.cutLineSubPlot", false);
if (cutLineSubPlot) {
double cutVal = 0.;
int it= 0.;
while (tags.getTagDouble(TString::Format("cuts.%d", it++), cutVal)) {
TLine * line_sub = new TLine(cutVal, yMinSubPlot, cutVal, yMaxSubPlot);
line_sub->SetLineStyle(tags.getTagIntegerDefault("style.cutLineStyle",7));
line_sub->SetLineWidth(tags.getTagIntegerDefault("style.cutLineWidth",2));
line_sub->SetLineColor(tags.getTagIntegerDefault("style.cutLineColor",kRed));
line_sub->Draw();
}
}
}
void TQHWWPlotter::drawCustomSubPlot(TQTaggable& tags){
TString totalStackLabesl = tags.getTagStringDefault ("labels.totalStack", "SM");
TString formulaString = tags.getTagStringDefault ("style.ratioFormula","d/b");
TString formulaName = tags.getTagStringDefault ("style.ratioName",formulaString);
double min = tags.getTagDoubleDefault("style.customSubMin",0.);
double max = tags.getTagDoubleDefault("style.customSubMax",0.);
TH1* hMaster = this->getObject<TH1>("Graph_master");
TH1* hTotalStack = this->getObject<TH1>("totalStack");
TH1* hTotalSig = this->getObject<TH1>("totalSig");
if(!hTotalStack) return;
int nBins = hMaster->GetNbinsX();
TQTaggableIterator itr(fProcesses);
while(itr.hasNext()){
TQNamedTaggable* process = itr.readNext();
if(!process) continue;
if(!process->getTagBoolDefault(".isData",false)) continue;
TH1 * hdata = this->getObject<TH1>(this->makeHistogramIdentifier(process));
if (!hdata) continue;
TGraph * customGraph = new TGraph(nBins);
customGraph->SetLineColor(hdata->GetLineColor());
customGraph->SetMarkerSize(hdata->GetMarkerSize());
customGraph->SetMarkerStyle(hdata->GetMarkerStyle());
customGraph->SetMarkerColor(hdata->GetMarkerColor());
this->addObject(customGraph,TString::Format("custom_%s",hdata->GetName()));
int iPoint = 0;
double actualSigMin = 0.;
double actualSigMax = 0.;
bool first = true;
for (int iBin = 1; iBin <= nBins; iBin++) {
TString localFormula = formulaString;
localFormula = TQStringUtils::replace(localFormula,"sLowXbinWidth",std::to_string(hTotalSig->Integral(0,iBin,"width")));
localFormula = TQStringUtils::replace(localFormula,"sHighXbinWidth",std::to_string(hTotalSig->Integral(iBin,nBins+1,"width")));
localFormula = TQStringUtils::replace(localFormula,"sLow",std::to_string(hTotalSig->Integral(0,iBin)));
localFormula = TQStringUtils::replace(localFormula,"sHigh",std::to_string(hTotalSig->Integral(iBin,nBins+1)));
localFormula = TQStringUtils::replace(localFormula,"sig",std::to_string(hTotalSig->GetBinContent(iBin)));
localFormula = TQStringUtils::replace(localFormula,"bLowXbinWidth",std::to_string(hTotalStack->Integral(0,iBin,"width")));
localFormula = TQStringUtils::replace(localFormula,"bHighXbinWidth",std::to_string(hTotalStack->Integral(iBin,nBins+1,"width")));
localFormula = TQStringUtils::replace(localFormula,"bLow",std::to_string(hTotalStack->Integral(0,iBin)));
localFormula = TQStringUtils::replace(localFormula,"bHigh",std::to_string(hTotalStack->Integral(iBin,nBins+1)));
localFormula = TQStringUtils::replace(localFormula,"bkg",std::to_string(hTotalStack->GetBinContent(iBin)));
localFormula = TQStringUtils::replace(localFormula,"dLowXbinWidth",std::to_string(hdata->Integral(0,iBin,"width")));
localFormula = TQStringUtils::replace(localFormula,"dHighXbinWidth",std::to_string(hdata->Integral(iBin,nBins+1,"width")));
localFormula = TQStringUtils::replace(localFormula,"dLow",std::to_string(hdata->Integral(0,iBin)));
localFormula = TQStringUtils::replace(localFormula,"dHigh",std::to_string(hdata->Integral(iBin,nBins+1)));
localFormula = TQStringUtils::replace(localFormula,"data",std::to_string(hdata->GetBinContent(iBin)));
localFormula = TQStringUtils::replace(localFormula,"binN",std::to_string(iBin));
localFormula = TQStringUtils::replace(localFormula,"binX",std::to_string(hTotalStack->GetBinCenter(iBin)));
localFormula = TQStringUtils::replace(localFormula,"binWidth",std::to_string(hTotalStack->GetBinWidth(iBin)));
TFormula frml(formulaName,localFormula);
if (0 != frml.Compile()) {
WARNclass("failed to compile formula %s (raw: %s)",localFormula.Data(),formulaString.Data());
continue;
}
double value = frml.Eval(0.);
customGraph->SetPoint(iPoint, hTotalStack->GetBinCenter(iBin), value);
if (value < actualSigMin){
actualSigMin = value;
}
if (value > actualSigMax){
actualSigMax = value;
}
iPoint++;
}
if (min < max) {
actualSigMin = std::max(actualSigMin,min);
actualSigMax = std::min(actualSigMax,max);
}
double xscaling = tags.getTagDoubleDefault("geometry.xscaling",1.);
double sigPadScaling = tags.getTagDoubleDefault("geometry.sub.scaling",1.);
this->applyStyle(tags,customGraph,formulaName,xscaling,sigPadScaling);
this->applyGeometry(tags,customGraph,"main" ,xscaling,sigPadScaling);
this->applyGeometry(tags,customGraph,"sub" ,xscaling,sigPadScaling);
double xLowerLimit = hTotalStack->GetBinLowEdge(1);
double xUpperLimit = hTotalStack->GetBinLowEdge(nBins) + hTotalStack->GetBinWidth(nBins);
customGraph->GetXaxis()->SetLimits(xLowerLimit, xUpperLimit);
customGraph->GetXaxis()->SetTitle(hTotalStack->GetXaxis()->GetTitle());
customGraph->GetYaxis()->SetTitle(formulaName);
actualSigMin = TMath::Abs(actualSigMin);
int y1 = TMath::Nint(actualSigMin);
if (y1 < actualSigMin)
actualSigMin = y1 + 0.5;
else
actualSigMin = y1;
if (fmod(actualSigMin, 1) == 0)
actualSigMin += 0.5;
int y2 = TMath::Nint(actualSigMax);
if (y2 < actualSigMax)
actualSigMax = y2 + 0.5;
else
actualSigMax = y2;
if (fmod(actualSigMax, 1) == 0)
actualSigMax += 0.5;
customGraph->GetHistogram()->SetMinimum(actualSigMin);
customGraph->GetHistogram()->SetMaximum(actualSigMax);
if (first)
customGraph->Draw("AP2");
else
customGraph->Draw("P2");
first = false;
}
}
void TQHWWPlotter::drawPull(TQTaggable& tags){
double pullMax = tags.getTagDoubleDefault ("style.pullMax",1000.);
double pullMin = tags.getTagDoubleDefault ("style.pullMin",0.);
double pullMaxQerr = tags.getTagDoubleDefault ("style.pullMaxQerr",std::numeric_limits<double>::infinity());
bool forcePullLimits = tags.getTagBoolDefault ("style.forcePullLimits",false );
bool verbose = tags.getTagBoolDefault("verbose",false);
TH1* hTotalStack = this->getObject<TH1>("totalStack");
if(!hTotalStack) return;
int nBins = hTotalStack->GetNbinsX();
int nPoints = 0;
for (int i = 1; i <= nBins; i++) {
if (hTotalStack->GetBinContent(i) != 0.) {
nPoints++;
}
}
if(verbose) VERBOSEclass("calculating geometry and axis ranges");
double xLowerLimit = hTotalStack->GetBinLowEdge(1);
double xUpperLimit = hTotalStack->GetBinLowEdge(nBins) + hTotalStack->GetBinWidth(nBins);
double pullPadScaling = tags.getTagDoubleDefault("geometry.sub.scaling",1.);
TString dataLabel("");
TList* graphs = new TList();
double actualPullMin = 1.;
double actualPullMax = 1.;
if(verbose) VERBOSEclass("generating pull graphs");
TQTaggableIterator itr(fProcesses);
while(itr.hasNext()){
TQNamedTaggable* process = itr.readNext();
if(!process) continue;
if(!process->getTagBoolDefault(".isData",false)) continue;
TH1 * h_data = this->getObject<TH1>(this->makeHistogramIdentifier(process));
if(!h_data) continue;
if(dataLabel.IsNull()) dataLabel = h_data->GetTitle();
int nPullPoints = 0;
for (int i = 1; i <= nBins; i++) {
double mcErr = hTotalStack->GetBinError(i);
double dataErr = h_data->GetBinError(i);
if(mcErr == 0) continue;
if(dataErr == 0) continue;
if(!TQUtils::isNum(hTotalStack->GetBinContent(i))){
WARNclass("encountered non-numeric MC value: %f",mcErr);
continue;
}
if(!TQUtils::isNum(h_data->GetBinContent(i))){
WARNclass("encountered non-numeric data value: %f",dataErr);
continue;
}
nPullPoints++;
}
if(nPullPoints < 1){
continue;
}
TGraphErrors * pullGraph = new TGraphErrors(nPullPoints);
this->addObject(pullGraph,TString::Format("pullGraph_%s",h_data->GetName()));
pullGraph->SetTitle(TString::Format("%s (pull)",h_data->GetTitle()));
pullGraph->SetLineColor(h_data->GetLineColor());
pullGraph->SetMarkerSize(h_data->GetMarkerSize());
pullGraph->SetMarkerStyle(h_data->GetMarkerStyle());
pullGraph->SetMarkerColor(h_data->GetMarkerColor());
int iPullPoint = 0;
for (int iBin = 1; iBin <= nBins; iBin++) {
double x = hTotalStack->GetBinCenter(iBin);
double data = h_data ->GetBinContent(iBin);
double mc = hTotalStack->GetBinContent(iBin);
double value = data - mc;
double error2 = pow(h_data->GetBinContent(iBin),2) + pow(hTotalStack->GetBinContent(iBin),2);
if(verbose) VERBOSEclass("adding pull point with x=%f, v=%f, e=%f (data=%f, MC=%f)",x,value,sqrt(error2),data,mc);
pullGraph->SetPoint(iPullPoint, x, value/sqrt(error2));
iPullPoint++;
}
this->applyStyle(tags ,pullGraph,"sub.data",1.,pullPadScaling);
double pullMinAllowed = tags.getTagDoubleDefault ("style.pullMinAllowed",pullMin);
double pullMaxAllowed = tags.getTagDoubleDefault ("style.pullMaxAllowed",pullMax);
actualPullMin=pullMinAllowed;
actualPullMax=pullMaxAllowed;
if(verbose) VERBOSEclass("drawPull: allowed range of pull graph: %f -- %f",actualPullMin,actualPullMax);
this->estimateRangeY(pullGraph,actualPullMin,actualPullMax,pullMaxQerr);
if(verbose) VERBOSEclass("drawPull: estimated range of pull graph: %f -- %f (pullMaxQerr=%f)",actualPullMin,actualPullMax,pullMaxQerr);
if(actualPullMin == actualPullMax){
if(verbose) VERBOSEclass("expanding pull to not be empty");
actualPullMin *= 1.1;
actualPullMax *= 1.1;
}
if (forcePullLimits)
actualPullMin = pullMin;
else
actualPullMin = actualPullMin-0.1*(actualPullMax-actualPullMin);
if (forcePullLimits)
actualPullMax = pullMax;
else
actualPullMax = actualPullMax+0.1*(actualPullMax-actualPullMin);
if(verbose) VERBOSEclass("drawPull: final of pull graph: %f -- %f",actualPullMin,actualPullMax);
graphs->Add(pullGraph);
}
TString totalStackLabel = tags.getTagStringDefault ("labels.totalStack", "SM");
tags.getTagString("labels.data",dataLabel);
gStyle->SetEndErrorSize(0);
if(verbose) VERBOSEclass("drawing line");
TLine * line = new TLine(xLowerLimit, 0., xUpperLimit, 0.);
line->SetLineColor(kRed);
line->Draw();
if(verbose) VERBOSEclass("drawing additional markers");
TQGraphErrorsIterator itr2(graphs);
bool first = true;
while(itr2.hasNext()){
TGraphErrors* pullGraph = itr2.readNext();
if(!pullGraph) continue;
if(first){
pullGraph->Draw("AP");
pullGraph->GetXaxis()->SetRangeUser(hTotalStack->GetXaxis()->GetXmin(),hTotalStack->GetXaxis()->GetXmax());
} else {
pullGraph->Draw("P SAME");
}
this->drawArrows(tags,pullGraph, actualPullMin,actualPullMax);
}
}