ATLAS Offline Software
Loading...
Searching...
No Matches
LArG4PlottingScript.py
Go to the documentation of this file.
1# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
2
3
4__author__ = 'Radist Morse radist.morse@gmail.com'
5
6class RootFile :
7 def __init__(self) :
8 self.filename = ""
9 self.color = 0
10 self.thickness = 1
11 self.markerstyle = 1
12 self.markersize = 1
13 self.legendname = ""
14 self.drawopt = "HIST"
15 self.restricts = []
16
17def parseRoots(filename) :
18 inputfile=open(filename)
19 parsedRoots = []
20 parsedRestricts = []
21 for line in inputfile :
22 line = line.expandtabs(1)
23 line = line.rstrip("\n")
24 line = line.split("#")[0] #everything after "#" is a comment. just like here :)
25 line = line.split()
26 line[:] = [x for x in line if (len(x) > 0) ] #remove empty elements
27 if len(line) == 0 : #the whole line is a comment, empty, or just spaces
28 continue
29 rf = RootFile()
30 if line[0] == "file" :
31 rf.filename = line[1]
32 rf.color = int(line[2])
33 rf.thickness = int(line[3])
34 rf.markerstyle = int(line[4])
35 if (rf.markerstyle > 1) :
36 rf.drawopt = "E"
37 rf.markersize = float(line[5])
38 rf.legendname = " ".join(line[6:])
39 parsedRoots.append(rf)
40 print ("Found rootfile '"+rf.filename+"' added as '"+rf.legendname+"'")
41 if line[0] == "restrict" :
42 re = RestrictEntry()
43 abs = False
44 if line[1].startswith("+") :
45 abs = True
46 line[1] = line[1][1:]
47 re.var = line[1]
48 for rang in line[2:] :
49 if abs :
50 re.addRangeAbs(rang)
51 else :
52 re.addRange(rang)
53 if (len(parsedRoots) > 0) : #there already was a rootfile, adding restriction to it
54 rstrict = parsedRoots[-1].restricts #the last parsed rootfile
55 else : #no roots yet. this is a global restriction
56 rstrict = parsedRestricts
57 for rech in rstrict :
58 if (rech.var == re.var) : #there is already a restriction on a given variable. just add ranges
59 rech.rangeList += re.rangeList
60 re.rangeList = []
61 if (len(re.rangeList) > 0) : #no restriction for this variable yet. add it.
62 print ("A restriction found for variable",str(re))
63 rstrict.append(re)
64 else :
65 print ("WARNING: unknown key:", line[0])
66 continue
67 for pr in parsedRoots : #apply global restrictions on every plot
68 for re in parsedRestricts :
69 for rech in pr.restricts :
70 if (rech.var == re.var) :
71 rech.rangeList += re.rangeList
72 re.rangeList = []
73 if (len(re.rangeList) > 0) :
74 pr.restricts.append(re)
75 return parsedRoots
76
77def defaultRoots(args) :
78 parsed = []
79 colors = [2,4,7,6,3,1]
80 thickness = [1,1,1,1,1,1]
81 markerstyle = [20,1,0,1,1,1]
82 markersize = [0.6,1,1,1,1,1]
83 for fn,col,thick,mark1,mark2,legname in zip(args,colors,thickness,markerstyle,markersize,args) :
84 rf = RootFile()
85 rf.filename = fn
86 rf.color = col
87 rf.thickness = thick
88 rf.markerstyle = mark1
89 if (rf.markerstyle > 1) :
90 rf.drawopt = "E"
91 rf.markersize = mark2
92 rf.legendname = legname
93 parsed.append(rf)
94 return parsed
95
96class PlotEntry :
97 def __init__(self) :
98 self.vars_to_draw = []
99 self.axis_captions = {} #var is the key
100 self.givenmin = 0
101 self.givenmax = 0
102 self.nbins = 100
103 self.logy = 0
104 self.display_name = ""
105 self.profile = False
106 self.i2d = False
107 self.restricts = []
108
110 def __init__(self) :
111 self.var = ""
112 self.rangeList = []
113 def checkVar(self,value) :
114 for rang in self.rangeList :
115 if (value >= rang[0]) and (value <= rang[1]) :
116 return True
117 return False
118 def __str__(self) :
119 outstr = self.var+" :"
120 for rang in self.rangeList :
121 outstr+=" ["+str(rang[0])+".."+str(rang[1])+"]"
122 return outstr
123 def addRange(self,rang) :
124 parsed = rang.split("..")
125 try :
126 parsed[0] = float(parsed[0])
127 except ValueError:
128 parsed[0] = -999999.9
129 try :
130 parsed[1] = float(parsed[1])
131 except ValueError:
132 parsed[1] = 9999999.9
133 self.rangeList.append(parsed[0:2])
134 def addRangeAbs(self,rang) :
135 parsed = rang.split("..")
136 try :
137 parsed[0] = float(parsed[0])
138 except ValueError:
139 parsed[0] = 0.0
140 try :
141 parsed[1] = float(parsed[1])
142 except ValueError:
143 parsed[1] = 9999999.9
144 if (parsed[0] < 0) or (parsed[1] <= 0) :
145 print ("WARNING: The absolute range is not valid: less then zero. Ignore.")
146 return
147 rang = str(parsed[0])+".."+str(parsed[1])
148 rang2 = str(-parsed[1])+".."+str(-parsed[0])
149 self.addRange(rang)
150 self.addRange(rang2)
151
152def parsePlots(filename,varCaption) :
153 inputfile=open(filename)
154 parsedPlots = []
155 parsedRestricts = []
156 for line in inputfile :
157 line = line.expandtabs(1)
158 line = line.rstrip("\n")
159 line = line.split("#")[0] #everything after "#" is a comment. just like here :)
160 line = line.split(" ")
161 line[:] = [x for x in line if (len(x) > 0) ] #remove empty elements
162 if len(line) == 0 : #the whole line is a comment, empty, or just spaces
163 continue
164 pe = PlotEntry()
165 if line[0] == "hist" :
166 pe.vars_to_draw.append(line[1])
167 pe.givenmin = float(line[2])
168 pe.givenmax = float(line[3])
169 pe.nbins = int(line[4])
170 pe.logy = int(line[5])
171 pe.display_name = " ".join(line[6:])
172 for var in pe.vars_to_draw :
173 varcap = varCaption(var.lstrip("+"))
174 if (varcap == "") :
175 varcap = var.lstrip("+")
176 pe.axis_captions[var.lstrip("+")]=varcap
177 if (pe.vars_to_draw[0].startswith("+")) and ((pe.givenmin < 0) or (pe.givenmax < 0)) :
178 print ("WARNING: Boundaries are less the zero, while the variable is absolute. Ignore.")
179 pe.givenmin = 0.0
180 pe.givenmax = 0.0
181 print ("Found 1D histogram:",pe.vars_to_draw[0],[pe.givenmin,pe.givenmax])
182 parsedPlots.append(pe)
183 elif line[0] == "prof" :
184 pe.vars_to_draw.extend(line[1:3])
185 pe.givenmin = float(line[3])
186 pe.givenmax = float(line[4])
187 pe.nbins = int(line[5])
188 pe.logy = int(line[6])
189 pe.display_name = " ".join(line[7:])
190 pe.profile = True
191 for var in pe.vars_to_draw :
192 varcap = varCaption(var.lstrip("+"))
193 if (varcap == "") :
194 varcap = var.lstrip("+")
195 pe.axis_captions[var.lstrip("+")]=varcap
196 if (pe.vars_to_draw[0].startswith("+")) and ((pe.givenmin < 0) or (pe.givenmax < 0)) :
197 print ("WARNING: Boundaries are less the zero, while the variable is absolute. Ignore.")
198 pe.givenmin = 0.0
199 pe.givenmax = 0.0
200 print ("Found 1D profile:",pe.vars_to_draw[1],"vs",pe.vars_to_draw[0],[pe.givenmin,pe.givenmax])
201 parsedPlots.append(pe)
202 elif line[0] == "hist2d" :
203 pe = PlotEntry()
204 pe.vars_to_draw.extend(line[1:3])
205 pe.givenmin = 0
206 pe.givenmax = 0
207 pe.nbins = [int(line[3]), int(line[4])]
208 pe.logy = 0
209 pe.display_name = " ".join(line[5:])
210 pe.i2d = True
211 for var in pe.vars_to_draw :
212 varcap = varCaption(var.lstrip("+"))
213 if (varcap == "") :
214 varcap = var.lstrip("+")
215 pe.axis_captions[var.lstrip("+")]=varcap
216 print ("Found 2D histogram:",pe.vars_to_draw)
217 parsedPlots.append(pe)
218 elif line[0] == "prof2d" :
219 pe.vars_to_draw.extend(line[1:4])
220 pe.givenmin = 0
221 pe.givenmax = 0
222 pe.nbins = [int(line[4]), int(line[5])]
223 pe.logy = 0
224 pe.display_name = " ".join(line[6:])
225 pe.profile = True
226 pe.i2d = True
227 for var in pe.vars_to_draw :
228 varcap = varCaption(var.lstrip("+"))
229 if (varcap == "") :
230 varcap = var.lstrip("+")
231 pe.axis_captions[var.lstrip("+")]=varcap
232 print ("Found 2D profile:",pe.vars_to_draw[2],"vs",pe.vars_to_draw[0:2])
233 parsedPlots.append(pe)
234 elif line[0] == "restrict" :
235 re = RestrictEntry()
236 abs = False
237 if line[1].startswith("+") :
238 abs = True
239 line[1] = line[1][1:]
240 re.var = line[1]
241 for rang in line[2:] :
242 if abs :
243 re.addRangeAbs(rang)
244 else :
245 re.addRange(rang)
246 if (len(parsedPlots) > 0) : #there already was a plot, adding restriction to it
247 rstrict = parsedPlots[-1].restricts #the last parsed plot
248 else : #no plots yet. this is a global restriction
249 rstrict = parsedRestricts
250 for rech in rstrict :
251 if (rech.var == re.var) : #there is already a restriction on a given variable. just add ranges
252 rech.rangeList += re.rangeList
253 re.rangeList = []
254 if (len(re.rangeList) > 0) : #no restriction for this variable yet. add it.
255 print ("A restriction found for variable",str(re))
256 rstrict.append(re)
257 elif line[0] == "axisname" :
258 if (len(parsedPlots) == 0) : #no plots yet. drop the name
259 print ("WARNING: axisname shouldn't be before plots")
260 continue
261 parsedPlots[-1].axis_captions[line[1].lstrip("+")] = " ".join(line[2:]).replace("%","#")
262 else :
263 print ("WARNING: unknown key:", line[0])
264 continue
265 for pe in parsedPlots : #apply global restrictions on every plot
266 for re in parsedRestricts :
267 for rech in pe.restricts :
268 if (rech.var == re.var) :
269 rech.rangeList += re.rangeList
270 re.rangeList = []
271 if (len(re.rangeList) > 0) :
272 pe.restricts.append(re)
273 return parsedPlots
274
275def createPlots(plotopts,rootopts) :
276 from ROOT import TH1D, TProfile,TH2D,TProfile2D
277 plots = {}
278 #creating histos
279 for plotopt in plotopts :
280 plots[plotopt] = {}
281 for rootopt in rootopts :
282 if (plotopt.profile) :
283 if (plotopt.i2d) :
284 plot = TProfile2D(str(hash(plotopt))+str(hash(rootopt)),plotopt.display_name,plotopt.nbins[0], 0,0,plotopt.nbins[1], 0,0)
285 else:
286 plot = TProfile(str(hash(plotopt))+str(hash(rootopt)),plotopt.display_name,plotopt.nbins, 0,0)
287 else :
288 if (plotopt.i2d) :
289 plot = TH2D(str(hash(plotopt))+str(hash(rootopt)),plotopt.display_name,plotopt.nbins[0], 0,0,plotopt.nbins[1], 0,0)
290 else :
291 plot = TH1D(str(hash(plotopt))+str(hash(rootopt)),plotopt.display_name,plotopt.nbins, 0,0)
292 plot.SetBuffer(1000000)
293 plots[plotopt][rootopt] = plot
294 return plots
295
296def fillPlots(plots,plotopts,rootopts,eventVal) :
297 listmin = {}
298 listmax = {}
299 listmin2 = {}
300 listmax2 = {}
301 for plotopt in plotopts :
302 listmin[plotopt] = 99999.9
303 listmax[plotopt] = -99999.9
304 listmin2[plotopt] = 99999.9
305 listmax2[plotopt] = -99999.9
306 for rootopt in rootopts :
307 for event in rootopt.tree :
308 for plotopt in plotopts :
309 inrange = True
310 # deal with restrictions
311 if (len(plotopt.restricts) > 0) : #there are restricts for this plot
312 for rest in plotopt.restricts :
313 eventval = eventVal(event,rest.var) #first try to find in the provided aliases
314 if (eventval == "False") :
315 try: #then try the event itself
316 eventval = event.__getattr__(rest.var)
317 except AttributeError: #nothing found
318 print ("ERROR: Non-existent variable in plot restrict:", rest.var)
319 import sys
320 sys.exit(1)
321 if not rest.checkVar(eventval) : #variable is not in the range list
322 inrange = False
323 break
324 if (len(rootopt.restricts) > 0) : #there are restricts for this rootfile
325 for rest in rootopt.restricts :
326 eventval = eventVal(event,rest.var) #first try to find in the provided aliases
327 if (eventval == "False") :
328 try: #then try the event itself
329 eventval = event.__getattr__(rest.var)
330 except Exception: #nothing found
331 print ("ERROR: Non-existent variable in rootfile restrict:", rest.var)
332 import sys
333 sys.exit(1)
334 if not rest.checkVar(eventval) : #variable is not in the range list
335 inrange = False
336 break
337 if (not inrange) :
338 continue #this event in this plot is outside restriction
339 plot = plots[plotopt][rootopt]
340 plotvars = plotopt.vars_to_draw
341 eventvals = []
342 # extracting values from root
343 for plotvar in plotvars : # one for hist1D, two for hist2D and prof1D, three for prof2D
344 sign = 1
345 locvar = plotvar
346 if plotvar.startswith("+") :
347 locvar = plotvar.lstrip("+")
348 sign = -1
349 eventval = eventVal(event,locvar) #first try to find in the provided aliases
350 if (eventval == "False") :
351 try: #then try the event itself
352 eventval = event.__getattr__(locvar)
353 except AttributeError: #nothing found
354 print ("ERROR: Non-existent variable:", locvar)
355 import sys
356 sys.exit(1)
357 if (eventval < 0) :
358 eventval *= sign
359 eventvals.append(eventval)
360 if (plotopt.profile) : #profile
361 if (plotopt.i2d) :
362 plot.Fill(eventvals[0],eventvals[1],eventvals[2])
363 else :
364 plot.Fill(eventvals[0],eventvals[1])
365 else : #hist
366 if (plotopt.i2d) :
367 plot.Fill(eventvals[0],eventvals[1])
368 else :
369 plot.Fill(eventvals[0])
370 # set limits. we pick the limits closest to the given (if provided)
371 if (eventvals[0] < plotopt.givenmax) or (plotopt.givenmin == plotopt.givenmax) :
372 listmax[plotopt] = max(listmax[plotopt], eventvals[0])
373 if (eventvals[0] > plotopt.givenmin) or (plotopt.givenmin == plotopt.givenmax) :
374 listmin[plotopt] = min(listmin[plotopt], eventvals[0])
375 if (plotopt.i2d) :
376 if (eventvals[1] < plotopt.givenmax) or (plotopt.givenmin == plotopt.givenmax) :
377 listmax2[plotopt] = max(listmax2[plotopt], eventvals[1])
378 if (eventvals[1] > plotopt.givenmin) or (plotopt.givenmin == plotopt.givenmax) :
379 listmin2[plotopt] = min(listmin2[plotopt], eventvals[1])
380 #eye candy
381 for plotopt in plotopts :
382 if (plotopt.i2d) :
383 pass #no "markers" for 2d stuff
384 else :
385 plot = plots[plotopt][rootopt]
386 plot.SetLineColor(rootopt.color)
387 plot.SetLineWidth(rootopt.thickness)
388 if rootopt.markerstyle > 0 :
389 plot.SetMarkerStyle(rootopt.markerstyle)
390 else :
391 plot.SetMarkerStyle(1)
392 plot.SetFillColor(rootopt.color)
393 #fillers[hname] = n
394 plot.SetMarkerSize(rootopt.markersize)
395 plot.SetMarkerColor(rootopt.color)
396 #setting limits & emptying buffer
397 for plotopt in plotopts :
398 for plot in plots[plotopt].itervalues() :
399 plot.GetXaxis().SetLimits(listmin[plotopt],listmax[plotopt])
400 if (plotopt.i2d) :
401 plot.GetYaxis().SetLimits(listmin2[plotopt],listmax2[plotopt])
402 plot.BufferEmpty(1)
403
404def dividePlots(plots,rootopt1) :
405 for singplot in plots.itervalues() :
406 plot1 = singplot.pop(rootopt1)
407 plot1.Sumw2()
408 for plot in singplot.itervalues() :
409 plot.Sumw2()
410 plot.Divide(plot1)
411 del plot1
412
413def savePlots(plots,output):
414 from ROOT import TFile
415
416 rootfile = TFile(output,"RECREATE")
417
418 for plotopt, pls in plots.iteritems() :
419 rootfile.cd(output+":/")
420 rootfile.mkdir("_".join(plotopt.vars_to_draw)+"/")
421 rootfile.cd(output+":/"+"_".join(plotopt.vars_to_draw)+"/")
422 for rootopt, plot in pls.iteritems() :
423 plot.Write("_".join(plotopt.vars_to_draw))
424 rootfile.Close
425
426def drawPlots(plots,plotopts,rootopts,output,optzero,optmean,opth,optw) :
427 from ROOT import TPostScript, TCanvas, TLegend
428 from ROOT import gROOT, gStyle, gPad
429
430 gROOT.Reset()
431 gROOT.SetStyle("Plain")
432 gStyle.SetOptStat(0)
433 gStyle.SetPalette(1)
434
435 leg = TLegend(0.54,0.71,0.9,0.9)
436
437 leg.SetLineColor(1)
438 leg.SetLineStyle(1)
439 leg.SetLineWidth(1)
440 leg.SetFillColor(10)
441 leg.SetFillStyle(0)
442 leg.SetBorderSize(0)
443
444
445 if output != "DISPLAY" :
446 ps = TPostScript(output,111)
447 ps.NewPage()
448 canv = TCanvas( 'c1', "Validation Plot Viewer",600,800)
449 canv.Divide(opth, optw)
450 maxperlist = opth * optw
451
452 #current pad
453 num = 0
454 #for stupid drawing system
455 legends = []
456
457 #drawing hists
458 for plotopt in plotopts :
459 print ("Drawing",plotopt.display_name)
460 num += 1
461 if (num > maxperlist and output != "DISPLAY") : #end of a current PS page
462 ps.NewPage()
463 print ("new page")
464 num = 1
465 canv.cd(num)
466 gPad.SetLogy(plotopt.logy)
467 leg.Clear()
468
469 entries = {}
470 valuemax = -999999.9
471 entryZ = 0
472
473 for rootopt in rootopts : #get the max entries
474 entries[rootopt] = plots[plotopt][rootopt].GetEntries()
475 if (plots[plotopt][rootopt].GetEntries() > entryZ) :
476 entryZ = plots[plotopt][rootopt].GetEntries()
477
478 for rootopt in rootopts : #get the max entries
479 plot = plots[plotopt][rootopt]
480 if (plotopt.profile) :
481 print (rootopt.legendname,"is a profile: no need to scale")
482 else :
483 if not (entries[rootopt] == 0) :
484 print ("scaling",rootopt.legendname,"to",entryZ/entries[rootopt])
485 plot.Scale(entryZ/entries[rootopt])
486 else :
487 print (rootopt.legendname,"is an empty hist, no scale")
488
489 for rootopt in rootopts : #get the highest peak
490 if (plots[plotopt][rootopt].GetMaximum() > valuemax) :
491 valuemax = plots[plotopt][rootopt].GetMaximum()
492 entryZ = plots[plotopt][rootopt].GetEntries()
493
494 sameDrawOpt = ""
495 #now we plot all fillers, as otherwise they will render invisible everything behind them
496 for rootopt in rootopts :
497 if (rootopt.markerstyle > 0) : #not filler
498 continue
499 plot = plots[plotopt][rootopt]
500 print ("Drawing filler from",rootopt.legendname)
501 if optzero :
502 if (plotopt.logy == 1) :
503 plot.SetMinimum(1.0)
504 else :
505 plot.SetMinimum(0.0)
506 plot.SetMaximum(valuemax * 1.1)
507 plot.GetXaxis().SetTitle(plotopt.axis_captions[plotopt.vars_to_draw[0].lstrip("+")])
508 if len(plotopt.vars_to_draw) > 1 :
509 plot.GetYaxis().SetTitle(plotopt.axis_captions[plotopt.vars_to_draw[1].lstrip("+")])
510 if (plotopt.i2d) :
511 plot.Draw("CONT4Z "+sameDrawOpt)
512 else :
513 plot.Draw(rootopt.drawopt+sameDrawOpt)
514 sameDrawOpt = " SAME"
515 #plot the rest & fill the legend in the normal order
516 for rootopt in rootopts :
517 plot = plots[plotopt][rootopt]
518 prname = rootopt.legendname
519 if optmean and (not plotopt.profile):
520 prname += " (mean: "+("%.4f" %plot.GetMean())+")"
521 leg.AddEntry(plot,prname,"L")
522 if (rootopt.markerstyle == 0) : #filler
523 continue #fillers are already drawn
524 print ("Drawing plot from",rootopt.legendname)
525 if optzero :
526 if (plotopt.logy == 1) :
527 plot.SetMinimum(1.0)
528 else :
529 plot.SetMinimum(0.0)
530 plot.SetMaximum(valuemax * 1.1)
531 plot.GetXaxis().SetTitle(plotopt.axis_captions[plotopt.vars_to_draw[0].lstrip("+")])
532 if len(plotopt.vars_to_draw) > 1 :
533 plot.GetYaxis().SetTitle(plotopt.axis_captions[plotopt.vars_to_draw[1].lstrip("+")])
534 if (plotopt.i2d) :
535 plot.Draw("CONT4Z "+sameDrawOpt)
536 else :
537 plot.Draw(rootopt.drawopt+sameDrawOpt)
538 sameDrawOpt = " SAME"
539 if not plotopt.i2d:
540 legends.append(leg.Clone())
541 legends[len(legends)-1].Draw()
542 canv.Update()
543 if output != "DISPLAY" :
544 canv.Close()
545 ps.Close()
546 return canv,legends
TGraphErrors * GetEntries(TH2F *histo)
#define min(a, b)
Definition cfImp.cxx:40
#define max(a, b)
Definition cfImp.cxx:41
std::string replace(std::string s, const std::string &s2, const std::string &s3)
Definition hcg.cxx:310
drawPlots(plots, plotopts, rootopts, output, optzero, optmean, opth, optw)
createPlots(plotopts, rootopts)
fillPlots(plots, plotopts, rootopts, eventVal)
dividePlots(plots, rootopt1)
parsePlots(filename, varCaption)