ATLAS Offline Software
validator.py
Go to the documentation of this file.
1 # Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
2 
3 """This script compares two given root files and saves plots where they differ
4 as pdfs.
5 
6 author: Felix Socher <Felix.Socher@cern.ch>"""
7 
8 
9 import ROOT
10 from ROOT import *
11 import sys
12 import argparse
13 import re
14 import os
15 import math
16 
17 LABELS = []
18 
19 def GoToDirectory(directory):
20  cwd = os.getcwd()
21  print os.getcwd()
22  newdir = cwd + "/" + directory
23  if not os.path.isdir( newdir ):
24  print "Creating folder " + newdir
25  os.makedirs( newdir )
26  os.chdir(newdir)
27 
28 
29 def SameHist(refHist, testHist):
30  chi2 = 0
31  for x in range(refHist.GetNbinsX()):
32  for y in range(refHist.GetNbinsY()):
33  for z in range(refHist.GetNbinsZ()):
34  if refHist.GetBinContent(x,y,z) != testHist.GetBinContent(x,y,z): return False
35  return True
36 
37 def SimilarHist(refHist, testHist):
38  for x in range(refHist.GetNbinsX()):
39  for y in range(refHist.GetNbinsY()):
40  for z in range(refHist.GetNbinsZ()):
41  if abs(refHist.GetBinContent(x,y,z) - testHist.GetBinContent(x,y,z)) > 0.01: return False
42  return True
43 
44 
45 
46 
48  """docstring for Validator"""
49  def __init__(self, structDirs, exclude, compareFunc, normalization):
50  super(Validator, self).__init__()
51  self.structDirs = structDirs
52  #self.excludedStrings = exclude.split("|")
53  #print self.excludedStrings
54  self.CompareFunc = compareFunc
55  self.DoNormalization = normalization
56 
57  def CompareFiles(self, fileNames, dirName):
58  openedFiles = [ TFile.Open(f) for f in fileNames ]
59  self.CompareDirectories(openedFiles, dirName)
60 
61  def CompareDirectories(self, dirs, dirName):
62  if (self.structDirs): GoToDirectory(dirName)
63  refDir = dirs[0]
64  newRefDir = refDir.GetDirectory(dirName)
65  for testDir in dirs:
66  if testDir == refDir: continue
67  if not testDir:
68  print 'ERROR --------- test dir not found: ', dirName, testDir
69  return
70 
71  newTestDirs = [ testDir.GetDirectory(dirName) for testDir in dirs ]
72 
73  theDir = newRefDir
74  # if not newRefDir:
75  # print 'ERROR --------- reference dir not found: ', dirName
76  # theDir = newTestDir
77 
78  for key in theDir.GetListOfKeys():
79 
80  obj = key.ReadObj()
81 
82  #2D histograms cannot be compared; skip
83  if obj.IsA().InheritsFrom(ROOT.TH2.Class()):
84  continue
85 
86  if obj.IsA().InheritsFrom(ROOT.TH1.Class()):
87  print key.GetName()
88  #testHist = newTestDir.Get(key.GetName())
89  testHists = [ newTestDir.Get(key.GetName()) for newTestDir in newTestDirs ]
90  self.CompareHistograms( testHists, newRefDir.GetPath())
91  elif obj.IsA().InheritsFrom(ROOT.TDirectory.Class()):
92  self.CompareDirectories( newTestDirs, obj.GetName())
93  if (self.structDirs): os.chdir("..")
94 
95  def CompareHistograms(self, hists, path):
96  # print self.excludedStrings, refHist.GetName()
97  # if any(exString in refHist.GetName() for exString in self.excludedStrings):
98  # print "Skipped " + path + "/" + refHist.GetName()
99  # return
100  #@@@if self.CompareFunc(refHist, testHist): print path + refHist.GetName() + " looks ok"
101  #else:
102  #self.MakeComparisonPlot(refHist, testHist, path)
103  self.MakeComparisonPlot(hists, path)
104 
105  #def MakeComparisonPlot(self,refHist, testHist, path):
106  def MakeComparisonPlot(self, hists, path):
107  def SetBounds(hists, ymin=0, ymax=0):
108  if (ymin==0 and ymax==0):
109  ymin = min( [ h.GetMinimum() for h in hists ] )
110  ymax = min( [ h.GetMaximum() for h in hists ] )
111  if ymin>0 and ymax>0:
112  ymin = 0
113  else:
114  ymin = ymin - 0.15*abs(ymin)
115  ymax = ymax+ 0.15*ymax
116  # if ymin<0 and ymax>0:
117  # if ymax>0 and abs(minimum)>ymax:
118  # ymax = -minimum
119  hists[0].SetMinimum(ymin)
120  hists[0].SetMaximum(ymax)
121  return hists[0]
122 
123 
124  # try:
125  # refHist.Scale(1.0/refHist.Integral())
126  # testHist.Scale(1.0/testHist.Integral())
127  # except:
128  # return
129  canvas = ROOT.TCanvas( "", "", 900, 900 )
130  padMain = ROOT.TPad( 'padMain', 'padMain', 0, 0.3, 1, 1 )
131  padMain.SetBottomMargin( 0.02 )
132  padMain.Draw()
133  #padMain.SetLogy(1) #@@@
134  padRatio = ROOT.TPad( 'padRatio', 'padRatio', 0, 0, 1, 0.3 )
135  padRatio.SetTopMargin( 0.01 )
136  padRatio.SetBottomMargin( 0.25 )
137  padRatio.Draw()
138  ROOT.TLine()
139  padMain.cd()
140 
141  leg = ROOT.TLegend(0.82,0.78,0.96,0.94)
142  #leg = ROOT.TLegend(0.52,0.76,0.96,0.94)
143  #leg.SetFillColor(ROOT.kWhite)
144  leg.SetFillStyle(0)
145  leg.SetBorderSize(0)
146  leg.SetTextFont(43)
147  leg.SetTextSizePixels(32)
148 
149  refHist = hists[0]
150  refHist.SetLineColor(17)
151  #refHist.SetFillColor(30)
152 
153 
159  for i in range(0,len(hists)):
160  leg.AddEntry(hists[i], LABELS[i], 'lp')
161 
162  if self.DoNormalization and not "_Eff_" in refHist.GetName() and not "_eff" in refHist.GetName() and not "_Eff" in refHist.GetName():
163  for h in hists:
164  n = h.Integral()
165  if n>0:
166  h.Scale(1./n)
167 
168  refHist = SetBounds(hists)
169 
170  ref_textsize = 32./(padMain.GetWh()*padMain.GetAbsHNDC())
171  refHist.GetYaxis().SetLabelSize( ref_textsize )
172  refHist.GetXaxis().SetLabelSize( 0 )
173  refHist.GetXaxis().SetTitleSize( 0 )
174  refHist.GetYaxis().SetTitleSize( 1.3*ref_textsize )
175  refHist.GetYaxis().SetTitleOffset(1)
176  refHist.GetYaxis().SetTitleColor( kAzure )
177 
178  # testHist.GetYaxis().SetTextFont(43)
179  # testHist.GetYaxis().SetTextSizePixels(20)
180  refHist.SetMarkerSize(0)
181  refHist.SetLineColor(ROOT.kRed)
182  #refHist.GetYaxis().SetRangeUser(0.00001,refHist.GetMaximum()*5) ##@@@
183 
184  #testHist.Rebin(2)
185  #refHist.Rebin(2);
186  histmax = refHist
187  histmax.DrawCopy('e')
188  # for h in hists:
189  # if h.GetMaximum() > refHist.GetMaximum():
190  # histmax = h
191  # if histmax == refHist:
192  # histmax.DrawCopy("e")
193  # else:
194  # histmax.DrawCopy("ehist")
195  nh=0
196  for h in hists:
197  if h is not histmax:
198  if h==refHist:
199  h.DrawCopy('histsame')
200  else:
201  nh=nh+1
202  if nh>1:
203  h.SetMarkerStyle(0)
204  h.SetMarkerColor(0)
205  h.SetLineColor(8) # green
206  h.SetLineStyle(ROOT.kDashed)
207  h.DrawCopy('ehistsame')
208  # if refHist.GetMaximum()>histmax.GetMaximum():
209  # refHist.DrawCopy("e")
210  # testHist.DrawCopy("ehistsame")
211  # refHist.DrawCopy("ehistsame")
212  # else:
213  # testHist.DrawCopy("ehist")
214  # refHist.DrawCopy("ehistsame")
215 
216  leg.Draw()
217  padRatio.cd()
218 
219  for h in hists:
220  if h is refHist: continue
221  ratioHist = h.Clone()
222  ratioHist.Divide(refHist)
223  ratioHist = SetBounds( [ratioHist, ratioHist], 0.84,1.16) # 0.941,1.059
224  for i in range(ratioHist.GetNbinsX()):
225  nref = refHist.GetBinContent(i)
226  ntest = h.GetBinContent(i)
227  if nref == 0 or ntest == 0:
228  ratioHist.SetBinError(i, 0)
229  else:
230  #error = nref/ntest*math.sqrt((refHist.GetBinError(i)/nref)**2 + (testHist.GetBinError(i)/ntest)**2)
231  error = nref/ntest* max(refHist.GetBinError(i)/nref, h.GetBinError(i)/ntest)
232  ratioHist.SetBinError(i, error)
233 
234  ratioHist_textsize = 32./(padRatio.GetWh()*padRatio.GetAbsHNDC())
235  ratioHist.GetYaxis().SetLabelSize( ratioHist_textsize )
236  ratioHist.GetXaxis().SetLabelSize( ratioHist_textsize )
237  ratioHist.GetXaxis().SetTitleSize( 1.2*ratioHist_textsize )
238  ratioHist.GetXaxis().SetTitleOffset(0.75)
239  ratioHist.GetXaxis().SetTitleColor(kAzure)
240  ratioHist.GetYaxis().SetTitleSize( ratioHist_textsize )
241  ratioHist.GetYaxis().SetTitleOffset(0.6)
242 
243 
244  ratioHist.SetLineColor(ROOT.kBlack)
245  ratioHist.SetMarkerStyle(24)
246  ratioHist.SetYTitle("test / ref")
247  if h == hists[1]:
248  ratioHist.DrawCopy("p")
249  lineRatio = ROOT.TLine( ratioHist.GetXaxis().GetXmin(), 1,
250  ratioHist.GetXaxis().GetXmax(), 1 )
251  lineRatio.SetLineColor( ROOT.kRed )
252  lineRatio.SetLineWidth( 2 )
253  lineRatio.Draw("same")
254  else:
255  ratioHist.SetMarkerStyle(25)
256  ratioHist.SetMarkerColor(8)
257  ratioHist.SetLineColor(8)
258  ratioHist.DrawCopy("psame")
259 
260  npath = ""
261  if not self.structDirs:
262  npath = path[path.find(":/")+2:] + "/"
263  npath = re.sub(r"[:,./]", "_", npath+"/")
264 
265  canvas.cd()
266  t = ROOT.TLatex();
267  t.SetNDC()
268  t.SetTextColor(1)
269  t.SetTextSize(0.03);
270  t.DrawLatex(0.,0.97,refHist.GetName()) #@@@
271 
272  canvas.SaveAs(npath + refHist.GetName() + ".pdf")
273  canvas.Close()
274 
275 #======================================================================
276 def main( argv ):
277  """
278  Main function to be executed when starting the code.
279  """
280 
281  parser = argparse.ArgumentParser( description = 'Distribution Plotter' )
282  parser.add_argument( '-s', '--structDirs', default = True, action = "store_true", help = ' if true, it creates directories following the same structure as in the root file to store the pdf plots')
283  parser.add_argument( '-r', '--reference', help = 'The reference' )
284  parser.add_argument( '-t', '--test', help = 'The test' )
285  parser.add_argument( '-t2', '--test2', default ='', help = 'The additional test' )
286  parser.add_argument( '-d', '--directory', default = "/", help = 'Print cutflow fror systematic variations' )
287  parser.add_argument( '-e', '--exclude', default = "_bin_", help = 'histograms whose names contain the provided strings are not examined')
288  parser.add_argument( '-n', '--normalize', default = False, action = "store_true", help = 'normalize histograms with larger stats for better comparison')
289  parser.add_argument( '-l', '--labels', default ='', help = 'Add text to legend for ref/test/test2, split with commas' )
290 
291  args = parser.parse_args()
292 
293 
294  #ROOT.gROOT.Macro("rootlogon.C")
295  ROOT.gROOT.SetBatch()
296  #ROOT.gROOT.LoadMacro("./AtlasUtils.C")
297  ROOT.gROOT.LoadMacro("./AtlasStyle.C")
298  ROOT.TH1.SetDefaultSumw2(ROOT.kTRUE)
299 
300  SetAtlasStyle()
301 
302  LABELS = []
303  if args.labels is '':
304  LABELS = [ 'Ref','Test' ]
305  if args.test2 is not '':
306  LABELS.append( 'Test2' )
307  else:
308  LABELS = args.labels.split(",")
309  #print LABELS
310 
311  # if you want to pass labels to legend directly from the file name...:
312  #LABELS.append( args.test.split('.')[2]+' '+args.test.split('.')[3] )
313  #
314 
315  validator = Validator( args.structDirs, args.exclude, SameHist, args.normalize )
316  if args.test2 == '':
317  allFiles = [ os.path.abspath(args.reference), os.path.abspath(args.test) ]
318  else:
319  allFiles = [ os.path.abspath(args.reference), os.path.abspath(args.test), os.path.abspath(args.test2) ]
320  #======================================================================
321 
322 if __name__ == "__main__":
323  """
324  Here the code should appear that is executed when running the plotter directly
325  (and not import it in another python file via 'import Plotter')
326  """
327 
328  # start main program
329  main( sys.argv[1:] )
330 
validator.Validator.CompareFunc
CompareFunc
Definition: validator.py:54
validator.Validator.__init__
def __init__(self, structDirs, exclude, compareFunc, normalization)
Definition: validator.py:49
SetAtlasStyle
void SetAtlasStyle()
Definition: InnerDetector/InDetCalibAlgs/PixelCalibAlgs/Macro/AtlasStyle.h:17
max
#define max(a, b)
Definition: cfImp.cxx:41
validator.GoToDirectory
def GoToDirectory(directory)
Definition: validator.py:19
MuonValidation_CreateSlides.SetBounds
def SetBounds(refHist, testHist)
Definition: MuonValidation_CreateSlides.py:21
validator.SameHist
def SameHist(refHist, testHist)
Definition: validator.py:29
validator.Validator.MakeComparisonPlot
def MakeComparisonPlot(self, hists, path)
Definition: validator.py:106
validator.Validator.DoNormalization
DoNormalization
Definition: validator.py:55
validator.main
def main(argv)
Definition: validator.py:276
plotBeamSpotVxVal.range
range
Definition: plotBeamSpotVxVal.py:195
min
#define min(a, b)
Definition: cfImp.cxx:40
validator.Validator
Definition: validator.py:47
validator.Validator.CompareHistograms
def CompareHistograms(self, hists, path)
Definition: validator.py:95
validator.SimilarHist
def SimilarHist(refHist, testHist)
Definition: validator.py:37
pickleTool.object
object
Definition: pickleTool.py:30
validator.Validator.CompareDirectories
def CompareDirectories(self, dirs, dirName)
Definition: validator.py:61
validator.Validator.structDirs
structDirs
Definition: validator.py:51
validator.Validator.CompareFiles
def CompareFiles(self, fileNames, dirName)
Definition: validator.py:57