3 from __future__
import print_function
4 import FWCore.ParameterSet.Config
as cms
10 from optparse
import OptionParser
13 __author__ =
"Mauro Verzetti (mauro.verzetti@cern.ch) and Lucia Perrini (lucia.perrini@cern.ch)" 14 __doc__ =
"""Script to plot the content of a Validation .root file and compare it to a different file:\n\n 15 Usage: MultipleCompare.py -T testFile -R refFile [options] [search strings that you want to apply '*' is supported as special character]""" 19 parser = OptionParser(description=__doc__)
20 parser.add_option(
'--myhelp',metavar=
'', action=
"store_true",help=
'prints this output message',dest=
'help',default =
False)
21 parser.add_option(
'--TestFile',
'-T',metavar=
'testFile', type=str,help=
'Sets the test file',dest=
'test',default =
'')
22 parser.add_option(
'--RefFile',
'-R',metavar=
'refFile', type=str,help=
'Sets the reference file',dest=
'ref',default =
None)
23 parser.add_option(
'--output',
'-o',metavar=
'outputFile', type=str,help=
'Sets the output file',dest=
'out',default =
'MultipleCompare.png')
24 parser.add_option(
'--logScaleY',action=
"store_true", dest=
"logScaleY", default=
False, help=
"Sets the log scale in the plot (Y axis)")
25 parser.add_option(
'--logScaleX',action=
"store_true", dest=
"logScaleX", default=
False, help=
"Sets the log scale in the plot (X axis)")
26 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)")
27 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)
28 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)
29 parser.add_option(
'--sampleLabel',
'-s',metavar=
'sampleLabel', type=str,help=
'Sets the label to indicate the sample used',dest=
'sampleLabel',default =
None)
30 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)
31 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)
32 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)
33 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)
34 parser.add_option(
'--minYR',metavar=
'number', type=float,help=
'Sets the minimum of the scale in sub pad',dest=
'minYR',default = 0)
35 parser.add_option(
'--maxYR',metavar=
'number', type=float,help=
'Sets the maximum of the scale in sub pad',dest=
'maxYR',default = 1.2)
40 parser.add_option(
'--logDiv',action=
"store_true", dest=
"logDiv", default=
False, help=
"Sets the log scale in the plot")
41 parser.add_option(
'--normalize',action=
"store_true", dest=
"normalize", default=
False, help=
"plot normalized")
42 parser.add_option(
'--maxRange',metavar=
'number',type=float, dest=
"maxRange", default=1.6, help=
"Sets the maximum range in linear plots")
43 parser.add_option(
'--maxXaxis',metavar=
'number',type=float, dest=
"maxXaxis", default=800, help=
"Sets the maximum range on x axis in the main pad")
44 parser.add_option(
'--minXaxis',metavar=
'number',type=float,help=
"Sets the minimum range on x axis in the main pad",dest=
"minXaxis", default=-3)
45 parser.add_option(
'--maxYaxis',metavar=
'number',type=float, dest=
"maxYaxis", default=2, help=
"Sets the maximum range on Y axis in the main pad")
46 parser.add_option(
'--minYaxis',metavar=
'number',type=float, dest=
"minYaxis", default=0, help=
"Sets the minimum range on Y axis in the main pad")
47 parser.add_option(
'--rebin', dest=
"rebin", type=int, default=-1, help=
"Sets the rebinning scale")
48 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)
51 (options,toPlot) = parser.parse_args()
55 return [options, toPlot]
58 tempList = dir.GetListOfKeys()
60 for it
in range(0,tempList.GetSize()):
61 retList.append(tempList.At(it).ReadObj())
66 for entry
in dirContent:
67 if isinstance(entry, TDirectory)
or isinstance(entry, TDirectoryFile):
68 subdirName = os.path.join(dirName,entry.GetName())
71 pathname = os.path.join(dirName,entry.GetName())
72 objectList.append(pathname)
75 for part
in required.split(
'*'):
76 if got.find(part) == -1:
81 ret = hNum.Clone(
'Division')
82 ret.GetYaxis().SetTitle(
'Ratio')
83 for binI
in range(hNum.GetNbinsX()+1):
84 denVal = hDen.GetBinContent(binI)
85 denErr = hDen.GetBinError(binI)
86 numErr = hNum.GetBinError(binI)
87 numVal = hNum.GetBinContent(binI)
89 ret.SetBinContent(binI,0)
90 ret.SetBinError(binI,0)
92 ret.SetBinContent(binI,numVal/denVal)
94 ret.SetBinError(binI,1)
96 ret.SetBinError(binI,(numVal/denVal)*math.sqrt(math.pow(numErr/numVal,2) + math.pow(denErr/denVal,2) ) )
105 matches = re.match(
r'.*/(.*)_(.*)_(.*)', name)
107 prefix = matches.group(1)
108 label = matches.group(3)
109 knowntypes = ([
'pTRatio',
'SumPt',
'Size'])
110 for knowntype
in knowntypes:
111 if matches.group(2) == knowntype:
118 prefixParts = prefix.partition(
'Discrimination')
119 if prefixParts[2] !=
'':
120 prefix = prefixParts[2]
121 prefixParts = prefix.partition(
'By')
122 if prefixParts[2] !=
'':
123 prefix = prefixParts[2]
126 return [type, label, prefix]
131 title.SetTextAlign(12)
132 title.SetTextSize(.035)
133 leftMargin = gStyle.GetPadLeftMargin()
134 topMargin = 1 - 0.5*gStyle.GetPadTopMargin()
135 title.DrawLatex(leftMargin, topMargin, text)
138 if options.branding !=
None or label !=
'':
141 text.SetTextAlign(11)
142 text.SetTextSize(.025)
143 text.SetTextColor(13)
144 if options.out.find(
".eps")!=-1:
145 text.SetTextAngle(-91.0)
147 text.SetTextAngle(-90.0)
148 rightMargin = 1 - gStyle.GetPadRightMargin()
149 topMargin = 1 - gStyle.GetPadTopMargin()
152 text.DrawLatex(rightMargin+.01, topMargin+0.025, label+options.branding);
156 root = histoPath[:histoPath.find(
'_')]
157 par = histoPath[histoPath.find(
'Eff')+3:]
158 validationPlots = validation.proc.efficiencies.plots._Parameterizable__parameterNames
162 for efficiency
in validationPlots:
163 effpset = getattr(validation.proc.efficiencies.plots,efficiency)
164 effName = effpset.efficiency.value()
165 effNameCut = effName[effName.find(
'_'):effName.find(
'#')]
166 if effNameCut
in histoPath:
168 print(
'More than one pair of parents found for ' + histopath +
':')
170 num = root + effpset.numerator.value()[effName.find(
'_'):].
replace(
'#PAR#',par)
171 den = root + effpset.denominator.value()[effName.find(
'_'):].
replace(
'#PAR#',par)
175 def Rebin(tfile, histoPath, rebinVal):
177 num = tfile.Get(parents[0])
178 if not isinstance(num, TH1F):
179 print(
'Looking for ' + num)
180 print(
'Plot now found! What the hell are you doing? Exiting...')
182 denSingle = tfile.Get(parents[1])
183 if not isinstance(denSingle, TH1F):
184 print(
'Looking for '+denSingle)
185 print(
'Plot now found! What the hell are you doing? Exiting...')
188 den = denSingle.Rebin(rebinVal,
'denClone')
189 retVal = num.Clone(histoPath+
'Rebin%s'%rebinVal)
193 retVal.Divide(num,den,1,1,
'B')
202 if min0 == -1
or max0 == -1:
207 if minTmp < min
or min == -1:
211 if maxTmp > max
or max == -1:
222 minY, maxY =
findRange(hists, -1, maxLogY)
224 minY, maxY =
findRange(hists, minY_, maxY_)
232 if maxY <= 1.1
and maxY > 0.7:
234 hists[0].SetAxisRange(minY, maxY,
"Y")
241 minX, maxX =
findRange(hists, -1, maxLogX)
243 minX, maxX =
findRange(hists, minX_, maxX_)
251 if maxX <= 1.1
and maxX > 0.7:
253 hists[0].SetAxisRange(minX, maxX,
"X")
262 minX, maxX =
findRange(hists, -1, maxLogX)
264 minX, maxX =
findRange(hists, minX_, maxX_)
271 if maxX <= 1.1
and maxX > 0.7:
273 hists[0].SetAxisRange(minX, maxX,
"X")
284 hists[0].SetAxisRange(min, max,
"Y")
291 for i
in range(1, hist.GetNbinsX()):
292 if hist.GetBinContent(i) > max:
293 max = hist.GetBinContent(i)
295 return max + distance*hist.GetBinError(pos)
303 for i
in range(1, hist.GetNbinsX()):
304 if hist.GetBinContent(i)<=0.:
306 if hist.GetBinContent(i) < min
or min==-1:
307 min = hist.GetBinContent(i)
311 return min - distance*hist.GetBinError(pos)
320 gROOT.SetStyle(
'Plain')
324 gStyle.SetPadGridX(
True)
325 gStyle.SetPadGridY(
True)
326 gStyle.SetOptTitle(0)
327 gStyle.SetPadTopMargin(0.1)
328 gStyle.SetPadBottomMargin(0.1)
329 gStyle.SetPadLeftMargin(0.13)
330 gStyle.SetPadRightMargin(0.07)
333 testFile = TFile(options.test)
335 if options.ref !=
None:
336 refFile = TFile(options.ref)
344 for path
in plotList:
345 if Match(plot.lower(),path.lower()):
346 histoList.append(path)
353 print(
'\tError: Please specify at least one histogram.')
355 print(
'Check your plot list:', toPlot)
363 scaleToIntegral =
False 364 if options.normalize:
365 scaleToIntegral =
True 367 ylabel =
'Efficiency' 373 if histType==
'pTRatio' and len(histoList)<3:
378 x2 = 1-gStyle.GetPadRightMargin()
379 y2 = 1-gStyle.GetPadTopMargin()
381 if len(histoList) == 1:
383 y1 = y2 - lineHeight*len(histoList)
384 legend = TLegend(x1,y1,x2,y2)
385 legend.SetHeader(label)
386 legend.SetFillColor(0)
387 legend.SetTextSize(0.032)
390 y1 = y2 - .07*len(histoList)
391 statsBox = TPaveText(x1,y1,x2,y2,
"NDC")
392 statsBox.SetFillColor(0)
393 statsBox.SetTextAlign(12)
394 statsBox.SetMargin(0.05)
395 statsBox.SetBorderSize(1)
398 canvas = TCanvas(
'MultiPlot',
'MultiPlot',validation.standardDrawingStuff.canvasSizeX.value(),832)
399 effPad = TPad(
'effPad',
'effPad',0.01,0.35,0.99,0.99)
400 effPad.SetBottomMargin(0.0)
406 if options.sampleLabel !=
None:
407 header +=
'Sample: '+options.sampleLabel
408 if options.testLabel !=
None:
409 header +=
' Dots: '+options.testLabel
410 if options.refLabel !=
None:
411 header +=
' Line: '+options.refLabel
414 diffPad = TPad(
'diffPad',
'diffPad',0.01,0.01,0.99,0.32)
415 diffPad.SetTopMargin(0.00);
416 diffPad.SetBottomMargin(0.30);
418 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]
421 statTemplate =
'%s Mean: %.3f RMS: %.3f' 424 for histoPath,color
in zip(histoList,colors):
425 if(options.rebin == -1):
426 testH = testFile.Get(histoPath)
428 testH =
Rebin(testFile,histoPath,options.rebin)
429 if not isinstance(testH, TH1F):
430 print(
'Looking for '+histoPath)
431 print(
'Test plot now found! What the hell are you doing? Exiting...')
434 xAx = histoPath[histoPath.find(
'Eff')+len(
'Eff'):]
436 if not testH.GetXaxis().GetTitle():
437 if hasattr(validation.standardDrawingStuff.xAxes,xAx):
438 testH.GetXaxis().SetTitle( getattr(validation.standardDrawingStuff.xAxes,xAx).xAxisTitle.value())
439 if not testH.GetYaxis().GetTitle():
440 testH.GetYaxis().SetTitle(ylabel)
442 testH.GetXaxis().SetTitle(label+
': '+testH.GetXaxis().GetTitle())
443 testH.GetXaxis().SetTitleOffset(1.1)
444 testH.GetXaxis().SetRangeUser(options.minXaxis,options.maxXaxis)
445 testH.GetYaxis().SetTitleOffset(1.1)
448 testH.SetMarkerSize(1)
449 testH.SetMarkerStyle(20)
450 testH.SetMarkerColor(color)
451 if histType ==
'Eff':
452 legend.AddEntry(testH,histoPath[histoPath.rfind(
'/')+1:histoPath.find(histType)],
'p')
456 text = statsBox.AddText(statTemplate % (
'Dots',testH.GetMean(), testH.GetRMS()) )
457 text.SetTextColor(color)
460 if options.logScaleY:
462 if options.logScaleX:
466 if testH.GetEntries() > 0:
467 if not testH.GetSumw2N():
469 testH.DrawNormalized(
'ex0 P')
471 print(
"--> Warning! You tried to normalize a histogram which seems to be already scaled properly. Draw it unscaled.")
472 scaleToIntegral =
False 478 if testH.GetEntries() > 0:
479 testH.DrawNormalized(
'same p')
481 testH.Draw(
'same ex0 l')
484 if(options.rebin == -1):
485 refH = refFile.Get(histoPath)
487 refH =
Rebin(refFile,histoPath,options.rebin)
488 if not isinstance(refH, TH1F):
491 refH.SetLineColor(color)
494 if testH.GetEntries() > 0:
495 refH.DrawNormalized(
'same hist')
497 refH.DrawCopy(
'same hist')
499 text = statsBox.AddText(statTemplate % (
'Line',refH.GetMean(), refH.GetRMS()) )
500 text.SetTextColor(color)
504 entries = testH.GetEntries()
506 testH.Scale(1./entries)
507 entries = refH.GetEntries()
510 refH.Scale(1./entries)
511 refH.Draw(
'same hist')
512 divHistos.append(
Divide(testH,refH))
514 if options.maxLogY > 0:
515 maxlY=options.maxLogY
516 if options.maxLogX > 0:
517 maxlX=options.maxLogX
520 tmpHists.extend(testHs)
521 tmpHists.extend(refHs)
522 optimizeRangeMainPad(argv, effPad, tmpHists, maxlX, options.minXaxis, options.maxXaxis, maxlY, options.minYaxis, options.maxYaxis)
526 for histo,color
in zip(divHistos,colors):
528 histo.SetMarkerSize(1)
529 histo.SetMarkerStyle(20)
530 histo.SetMarkerColor(color)
531 histo.GetYaxis().SetLabelSize(0.07)
532 histo.GetYaxis().SetTitleOffset(0.75)
533 histo.GetYaxis().SetTitleSize(0.08)
534 histo.GetXaxis().SetLabelSize(0.08)
535 histo.GetXaxis().SetTitleSize(0.08)
543 histo.Draw(
'same ex0')
546 if options.maxLogX > 0:
547 maxlX=options.maxLogX
548 optimizeRangeSubPad(argv, diffPad, divHistos, maxlX, options.minXaxis, options.maxXaxis, options.minYR, options.maxYR)
556 canvas.Print(options.out)
559 if __name__ ==
'__main__':
def LoadCommandlineOptions(argv)
def DetermineHistType(name)
def replace(string, replacements)
def Rebin(tfile, histoPath, rebinVal)
def optimizeRangeMainPad(argv, pad, hists, maxLogX_, minX_, maxX_, maxLogY_, minY_, maxY_)
S & print(S &os, JobReport::InputFile const &f)
def optimizeRangeSubPad(argv, pad, hists, maxLogX_, minX_, maxX_, minYRatio_, maxYRatio_)
OutputIterator zip(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result, Compare comp)
def MapDirStructure(directory, dirName, objectList)
def DrawBranding(options, label='')
def getMaximumIncludingErrors(hist)
def findRange(hists, min0=-1, max0=-1)
def getMinimumIncludingErrors(hist)
def FindParents(histoPath)