3 from __future__
import print_function
4 from builtins
import range
5 import FWCore.ParameterSet.Config
as cms
11 from optparse
import OptionParser
12 from ROOT
import gStyle, TDirectory, TDirectoryFile, TLatex, TH1F, TLegend, TPaveText, TPad
14 __author__ =
"Mauro Verzetti (mauro.verzetti@cern.ch) and Lucia Perrini (lucia.perrini@cern.ch)" 15 __doc__ =
"""Script to plot the content of a Validation .root file and compare it to a different file:\n\n 16 Usage: MultipleCompare.py -T testFile -R refFile [options] [search strings that you want to apply '*' is supported as special character]""" 20 parser = OptionParser(description=__doc__)
21 parser.add_option(
'--myhelp',metavar=
'', action=
"store_true",help=
'prints this output message',dest=
'help',default =
False)
22 parser.add_option(
'--TestFile',
'-T',metavar=
'testFile', type=str,help=
'Sets the test file',dest=
'test',default =
'')
23 parser.add_option(
'--RefFile',
'-R',metavar=
'refFile', type=str,help=
'Sets the reference file',dest=
'ref',default =
None)
24 parser.add_option(
'--output',
'-o',metavar=
'outputFile', type=str,help=
'Sets the output file',dest=
'out',default =
'MultipleCompare.png')
25 parser.add_option(
'--logScaleY',action=
"store_true", dest=
"logScaleY", default=
False, help=
"Sets the log scale in the plot (Y axis)")
26 parser.add_option(
'--logScaleX',action=
"store_true", dest=
"logScaleX", default=
False, help=
"Sets the log scale in the plot (X axis)")
27 parser.add_option(
'--fakeRate',
'-f',action=
"store_true", dest=
"fakeRate", default=
False, help=
"Sets the fake rate options and put the correct label (implies --logScale)")
28 parser.add_option(
'--testLabel',
'-t',metavar=
'testLabel', type=str,help=
'Sets the label to put in the plots for test file',dest=
'testLabel',default =
None)
29 parser.add_option(
'--refLabel',
'-r',metavar=
'refLabel', type=str,help=
'Sets the label to put in the plots for ref file',dest=
'refLabel',default =
None)
30 parser.add_option(
'--sampleLabel',
'-s',metavar=
'sampleLabel', type=str,help=
'Sets the label to indicate the sample used',dest=
'sampleLabel',default =
None)
31 parser.add_option(
'--maxLogX',metavar=
'number', type=float,help=
'Sets the maximum of the scale in log scale both in the main and in the sub pad (requires --logScale or -f to work)',dest=
'maxLogX',default = 100)
32 parser.add_option(
'--minLogX',metavar=
'number', type=float,help=
'Sets the minimum of the scale in log scale (requires --logScale or -f to work)',dest=
'minLogX',default = 0.001)
33 parser.add_option(
'--minLogY',metavar=
'number', type=float,help=
'Sets the minimum of the scale in log scale (requires --logScale or -f to work)',dest=
'minLogY',default = 0.0001)
34 parser.add_option(
'--maxLogY',metavar=
'number', type=float,help=
'Sets the maximum of the scale in log scale (requires --logScale or -f to work)',dest=
'maxLogY',default = 3)
35 parser.add_option(
'--minYR',metavar=
'number', type=float,help=
'Sets the minimum of the scale in sub pad',dest=
'minYR',default = 0)
36 parser.add_option(
'--maxYR',metavar=
'number', type=float,help=
'Sets the maximum of the scale in sub pad',dest=
'maxYR',default = 1.2)
41 parser.add_option(
'--logDiv',action=
"store_true", dest=
"logDiv", default=
False, help=
"Sets the log scale in the plot")
42 parser.add_option(
'--normalize',action=
"store_true", dest=
"normalize", default=
False, help=
"plot normalized")
43 parser.add_option(
'--maxRange',metavar=
'number',type=float, dest=
"maxRange", default=1.6, help=
"Sets the maximum range in linear plots")
44 parser.add_option(
'--maxXaxis',metavar=
'number',type=float, dest=
"maxXaxis", default=800, help=
"Sets the maximum range on x axis in the main pad")
45 parser.add_option(
'--minXaxis',metavar=
'number',type=float,help=
"Sets the minimum range on x axis in the main pad",dest=
"minXaxis", default=-3)
46 parser.add_option(
'--maxYaxis',metavar=
'number',type=float, dest=
"maxYaxis", default=2, help=
"Sets the maximum range on Y axis in the main pad")
47 parser.add_option(
'--minYaxis',metavar=
'number',type=float, dest=
"minYaxis", default=0, help=
"Sets the minimum range on Y axis in the main pad")
48 parser.add_option(
'--rebin', dest=
"rebin", type=int, default=-1, help=
"Sets the rebinning scale")
49 parser.add_option(
'--branding',
'-b',metavar=
'branding', type=str,help=
'Define a branding to label the plots (in the top right corner)',dest=
'branding',default =
None)
52 (options,toPlot) = parser.parse_args()
56 return [options, toPlot]
59 tempList = dir.GetListOfKeys()
61 for it
in range(0,tempList.GetSize()):
62 retList.append(tempList.At(it).ReadObj())
67 for entry
in dirContent:
68 if isinstance(entry, TDirectory)
or isinstance(entry, TDirectoryFile):
69 subdirName = os.path.join(dirName,entry.GetName())
72 pathname = os.path.join(dirName,entry.GetName())
73 objectList.append(pathname)
76 for part
in required.split(
'*'):
77 if got.find(part) == -1:
82 ret = hNum.Clone(
'Division')
83 ret.GetYaxis().SetTitle(
'Ratio')
84 for binI
in range(hNum.GetNbinsX()+1):
85 denVal = hDen.GetBinContent(binI)
86 denErr = hDen.GetBinError(binI)
87 numErr = hNum.GetBinError(binI)
88 numVal = hNum.GetBinContent(binI)
90 ret.SetBinContent(binI,0)
91 ret.SetBinError(binI,0)
93 ret.SetBinContent(binI,numVal/denVal)
95 ret.SetBinError(binI,1)
97 ret.SetBinError(binI,(numVal/denVal)*math.sqrt(math.pow(numErr/numVal,2) + math.pow(denErr/denVal,2) ) )
106 matches = re.match(
r'.*/(.*)_(.*)_(.*)', name)
108 prefix = matches.group(1)
109 label = matches.group(3)
110 knowntypes = ([
'pTRatio',
'SumPt',
'Size'])
111 for knowntype
in knowntypes:
112 if matches.group(2) == knowntype:
119 prefixParts = prefix.partition(
'Discrimination')
120 if prefixParts[2] !=
'':
121 prefix = prefixParts[2]
122 prefixParts = prefix.partition(
'By')
123 if prefixParts[2] !=
'':
124 prefix = prefixParts[2]
127 return [type, label, prefix]
132 title.SetTextAlign(12)
133 title.SetTextSize(.035)
134 leftMargin = gStyle.GetPadLeftMargin()
135 topMargin = 1 - 0.5*gStyle.GetPadTopMargin()
136 title.DrawLatex(leftMargin, topMargin, text)
139 if options.branding !=
None or label !=
'':
142 text.SetTextAlign(11)
143 text.SetTextSize(.025)
144 text.SetTextColor(13)
145 if options.out.find(
".eps")!=-1:
146 text.SetTextAngle(-91.0)
148 text.SetTextAngle(-90.0)
149 rightMargin = 1 - gStyle.GetPadRightMargin()
150 topMargin = 1 - gStyle.GetPadTopMargin()
153 text.DrawLatex(rightMargin+.01, topMargin+0.025, label+options.branding);
157 root = histoPath[:histoPath.find(
'_')]
158 par = histoPath[histoPath.find(
'Eff')+3:]
159 validationPlots = validation.proc.efficiencies.plots._Parameterizable__parameterNames
163 for efficiency
in validationPlots:
164 effpset = getattr(validation.proc.efficiencies.plots,efficiency)
165 effName = effpset.efficiency.value()
166 effNameCut = effName[effName.find(
'_'):effName.find(
'#')]
167 if effNameCut
in histoPath:
169 print(
'More than one pair of parents found for ' + histopath +
':')
171 num = root + effpset.numerator.value()[effName.find(
'_'):].
replace(
'#PAR#',par)
172 den = root + effpset.denominator.value()[effName.find(
'_'):].
replace(
'#PAR#',par)
176 def Rebin(tfile, histoPath, rebinVal):
178 num = tfile.Get(parents[0])
179 if not isinstance(num, TH1F):
180 print(
'Looking for ' + num)
181 print(
'Plot now found! What the hell are you doing? Exiting...')
183 denSingle = tfile.Get(parents[1])
184 if not isinstance(denSingle, TH1F):
185 print(
'Looking for '+denSingle)
186 print(
'Plot now found! What the hell are you doing? Exiting...')
189 den = denSingle.Rebin(rebinVal,
'denClone')
190 retVal = num.Clone(histoPath+
'Rebin%s'%rebinVal)
194 retVal.Divide(num,den,1,1,
'B')
203 if min0 == -1
or max0 == -1:
208 if minTmp < min
or min == -1:
212 if maxTmp > max
or max == -1:
223 minY, maxY =
findRange(hists, -1, maxLogY)
225 minY, maxY =
findRange(hists, minY_, maxY_)
233 if maxY <= 1.1
and maxY > 0.7:
235 hists[0].SetAxisRange(minY, maxY,
"Y")
242 minX, maxX =
findRange(hists, -1, maxLogX)
244 minX, maxX =
findRange(hists, minX_, maxX_)
252 if maxX <= 1.1
and maxX > 0.7:
254 hists[0].SetAxisRange(minX, maxX,
"X")
263 minX, maxX =
findRange(hists, -1, maxLogX)
265 minX, maxX =
findRange(hists, minX_, maxX_)
272 if maxX <= 1.1
and maxX > 0.7:
274 hists[0].SetAxisRange(minX, maxX,
"X")
285 hists[0].SetAxisRange(min, max,
"Y")
292 for i
in range(1, hist.GetNbinsX()):
293 if hist.GetBinContent(i) > max:
294 max = hist.GetBinContent(i)
296 return max + distance*hist.GetBinError(pos)
304 for i
in range(1, hist.GetNbinsX()):
305 if hist.GetBinContent(i)<=0.:
307 if hist.GetBinContent(i) < min
or min==-1:
308 min = hist.GetBinContent(i)
312 return min - distance*hist.GetBinError(pos)
321 gROOT.SetStyle(
'Plain')
325 gStyle.SetPadGridX(
True)
326 gStyle.SetPadGridY(
True)
327 gStyle.SetOptTitle(0)
328 gStyle.SetPadTopMargin(0.1)
329 gStyle.SetPadBottomMargin(0.1)
330 gStyle.SetPadLeftMargin(0.13)
331 gStyle.SetPadRightMargin(0.07)
334 testFile = TFile(options.test)
336 if options.ref !=
None:
337 refFile = TFile(options.ref)
345 for path
in plotList:
346 if Match(plot.lower(),path.lower()):
347 histoList.append(path)
354 print(
'\tError: Please specify at least one histogram.')
356 print(
'Check your plot list:', toPlot)
364 scaleToIntegral =
False 365 if options.normalize:
366 scaleToIntegral =
True 368 ylabel =
'Efficiency' 374 if histType==
'pTRatio' and len(histoList)<3:
379 x2 = 1-gStyle.GetPadRightMargin()
380 y2 = 1-gStyle.GetPadTopMargin()
382 if len(histoList) == 1:
384 y1 = y2 - lineHeight*len(histoList)
385 legend = TLegend(x1,y1,x2,y2)
386 legend.SetHeader(label)
387 legend.SetFillColor(0)
388 legend.SetTextSize(0.032)
391 y1 = y2 - .07*len(histoList)
392 statsBox = TPaveText(x1,y1,x2,y2,
"NDC")
393 statsBox.SetFillColor(0)
394 statsBox.SetTextAlign(12)
395 statsBox.SetMargin(0.05)
396 statsBox.SetBorderSize(1)
399 canvas = TCanvas(
'MultiPlot',
'MultiPlot',validation.standardDrawingStuff.canvasSizeX.value(),832)
400 effPad = TPad(
'effPad',
'effPad',0.01,0.35,0.99,0.99)
401 effPad.SetBottomMargin(0.0)
407 if options.sampleLabel !=
None:
408 header +=
'Sample: '+options.sampleLabel
409 if options.testLabel !=
None:
410 header +=
' Dots: '+options.testLabel
411 if options.refLabel !=
None:
412 header +=
' Line: '+options.refLabel
415 diffPad = TPad(
'diffPad',
'diffPad',0.01,0.01,0.99,0.32)
416 diffPad.SetTopMargin(0.00);
417 diffPad.SetBottomMargin(0.30);
419 colors = [2,3,4,6,5,7,28,1,2,3,4,6,5,7,28,1,2,3,4,6,5,7,28,1,2,3,4,6,5,7,28,1,2,3,4,6,5,7,28,1]
422 statTemplate =
'%s Mean: %.3f RMS: %.3f' 425 for histoPath,color
in zip(histoList,colors):
426 if(options.rebin == -1):
427 testH = testFile.Get(histoPath)
429 testH =
Rebin(testFile,histoPath,options.rebin)
430 if not isinstance(testH, TH1F):
431 print(
'Looking for '+histoPath)
432 print(
'Test plot now found! What the hell are you doing? Exiting...')
435 xAx = histoPath[histoPath.find(
'Eff')+len(
'Eff'):]
437 if not testH.GetXaxis().GetTitle():
438 if hasattr(validation.standardDrawingStuff.xAxes,xAx):
439 testH.GetXaxis().SetTitle( getattr(validation.standardDrawingStuff.xAxes,xAx).xAxisTitle.value())
440 if not testH.GetYaxis().GetTitle():
441 testH.GetYaxis().SetTitle(ylabel)
443 testH.GetXaxis().SetTitle(label+
': '+testH.GetXaxis().GetTitle())
444 testH.GetXaxis().SetTitleOffset(1.1)
445 testH.GetXaxis().SetRangeUser(options.minXaxis,options.maxXaxis)
446 testH.GetYaxis().SetTitleOffset(1.1)
449 testH.SetMarkerSize(1)
450 testH.SetMarkerStyle(20)
451 testH.SetMarkerColor(color)
452 if histType ==
'Eff':
453 legend.AddEntry(testH,histoPath[histoPath.rfind(
'/')+1:histoPath.find(histType)],
'p')
457 text = statsBox.AddText(statTemplate % (
'Dots',testH.GetMean(), testH.GetRMS()) )
458 text.SetTextColor(color)
461 if options.logScaleY:
463 if options.logScaleX:
467 if testH.GetEntries() > 0:
468 if not testH.GetSumw2N():
470 testH.DrawNormalized(
'ex0 P')
472 print(
"--> Warning! You tried to normalize a histogram which seems to be already scaled properly. Draw it unscaled.")
473 scaleToIntegral =
False 479 if testH.GetEntries() > 0:
480 testH.DrawNormalized(
'same p')
482 testH.Draw(
'same ex0 l')
485 if(options.rebin == -1):
486 refH = refFile.Get(histoPath)
488 refH =
Rebin(refFile,histoPath,options.rebin)
489 if not isinstance(refH, TH1F):
492 refH.SetLineColor(color)
495 if testH.GetEntries() > 0:
496 refH.DrawNormalized(
'same hist')
498 refH.DrawCopy(
'same hist')
500 text = statsBox.AddText(statTemplate % (
'Line',refH.GetMean(), refH.GetRMS()) )
501 text.SetTextColor(color)
505 entries = testH.GetEntries()
507 testH.Scale(1./entries)
508 entries = refH.GetEntries()
511 refH.Scale(1./entries)
512 refH.Draw(
'same hist')
513 divHistos.append(
Divide(testH,refH))
515 if options.maxLogY > 0:
516 maxlY=options.maxLogY
517 if options.maxLogX > 0:
518 maxlX=options.maxLogX
521 tmpHists.extend(testHs)
522 tmpHists.extend(refHs)
523 optimizeRangeMainPad(argv, effPad, tmpHists, maxlX, options.minXaxis, options.maxXaxis, maxlY, options.minYaxis, options.maxYaxis)
527 for histo,color
in zip(divHistos,colors):
529 histo.SetMarkerSize(1)
530 histo.SetMarkerStyle(20)
531 histo.SetMarkerColor(color)
532 histo.GetYaxis().SetLabelSize(0.07)
533 histo.GetYaxis().SetTitleOffset(0.75)
534 histo.GetYaxis().SetTitleSize(0.08)
535 histo.GetXaxis().SetLabelSize(0.08)
536 histo.GetXaxis().SetTitleSize(0.08)
544 histo.Draw(
'same ex0')
547 if options.maxLogX > 0:
548 maxlX=options.maxLogX
549 optimizeRangeSubPad(argv, diffPad, divHistos, maxlX, options.minXaxis, options.maxXaxis, options.minYR, options.maxYR)
557 canvas.Print(options.out)
560 if __name__ ==
'__main__':
def LoadCommandlineOptions(argv)
ALPAKA_FN_HOST_ACC ALPAKA_FN_INLINE constexpr float zip(ConstView const &tracks, int32_t i)
def DetermineHistType(name)
def replace(string, replacements)
def Rebin(tfile, histoPath, rebinVal)
def optimizeRangeMainPad(argv, pad, hists, maxLogX_, minX_, maxX_, maxLogY_, minY_, maxY_)
def optimizeRangeSubPad(argv, pad, hists, maxLogX_, minX_, maxX_, minYRatio_, maxYRatio_)
def MapDirStructure(directory, dirName, objectList)
void print(TMatrixD &m, const char *label=nullptr, bool mathematicaFormat=false)
def DrawBranding(options, label='')
def getMaximumIncludingErrors(hist)
def findRange(hists, min0=-1, max0=-1)
def getMinimumIncludingErrors(hist)
def FindParents(histoPath)
if(threadIdxLocalY==0 &&threadIdxLocalX==0)