11 ROOT.gROOT.SetBatch(
True)
12 ROOT.PyConfig.IgnoreCommandLineOptions =
True 17 _ratioYTitle =
"Ratio" 32 ROOT.gROOT.SetStyle(
"Plain")
33 ROOT.gStyle.SetPadRightMargin(0.07)
34 ROOT.gStyle.SetPadLeftMargin(0.13)
35 ROOT.gStyle.SetTitleFont(font,
"XYZ")
36 ROOT.gStyle.SetTitleSize(titleSize,
"XYZ")
37 ROOT.gStyle.SetTitleOffset(1.2,
"Y")
39 ROOT.gStyle.SetLabelFont(font,
"XYZ")
40 ROOT.gStyle.SetLabelSize(labelSize,
"XYZ")
41 ROOT.gStyle.SetTextSize(labelSize)
42 ROOT.gStyle.SetStatFont(font)
43 ROOT.gStyle.SetStatFontSize(statSize)
45 ROOT.TGaxis.SetMaxDigits(4)
48 obj = tdirectory.Get(name)
51 print "Did not find {obj} from {dir}".
format(obj=name, dir=tdirectory.GetPath())
56 if hasattr(nameOrCreator,
"create"):
57 return nameOrCreator.create(tdirectory)
72 """Get TDirectory from TFile.""" 75 for pdf
in possibleDirs:
78 if subDir
is not None:
85 print "Did not find subdirectory '%s' from directory '%s' in file %s" % (subDir, pdf, tfile.GetName())
92 print "Did not find any of directories '%s' from file %s" % (
",".
join(possibleDirs), tfile.GetName())
99 values = collections.OrderedDict()
100 for i
in xrange(1, th1.GetNbinsX()+1):
101 binLabel = th1.GetXaxis().GetBinLabel(i)
102 if renameBin
is not None:
103 binLabel = renameBin(binLabel)
104 values[binLabel] = (th1.GetBinContent(i), th1.GetBinError(i))
110 backup = ROOT.gErrorIgnoreLevel
111 ROOT.gErrorIgnoreLevel = ROOT.kError
112 canvas = ROOT.TCanvas(name, name, width, height)
114 ROOT.gErrorIgnoreLevel = backup
120 divisionPoint = 1-1/ratioFactor
122 topMargin = pad.GetTopMargin()
123 bottomMargin = pad.GetBottomMargin()
124 divisionPoint += (1-divisionPoint)*bottomMargin
125 divisionPointForPad1 = 1-( (1-divisionPoint) / (1-0.02) )
130 ylow = divisionPointForPad1
133 pad1.SetPad(xlow, ylow, xup, yup)
134 pad1.SetFillStyle(4000)
135 pad1.SetBottomMargin(0.02)
141 pad2.SetPad(xlow, ylow, xup, yup)
142 pad2.SetFillStyle(4000)
143 pad2.SetTopMargin(0.0)
144 pad2.SetBottomMargin(bottomMargin/(ratioFactor*divisionPoint))
147 """Calculate the ratios for a list of histograms""" 149 def _divideOrZero(numerator, denominator):
152 return numerator/denominator
155 if a == 0.
and b == 0.:
159 def findBins(wrap, bins_xvalues):
161 currBin = wrap.begin()
163 while i < len(bins_xvalues)
and currBin < wrap.end():
164 (xcenter, xlow, xhigh) = bins_xvalues[i]
165 xlowEdge = xcenter-xlow
166 xupEdge = xcenter+xhigh
168 (curr_center, curr_low, curr_high) = wrap.xvalues(currBin)
169 curr_lowEdge = curr_center-curr_low
170 curr_upEdge = curr_center+curr_high
172 if equal(xlowEdge, curr_lowEdge)
and equal(xupEdge, curr_upEdge):
176 elif curr_upEdge <= xlowEdge:
178 elif curr_lowEdge >= xupEdge:
185 if len(ret) != len(bins_xvalues):
186 ret.extend([
None]*( len(bins_xvalues) - len(ret) ))
192 def __init__(self, th1, uncertainty):
194 self._uncertainty = uncertainty
196 xaxis = th1.GetXaxis()
197 xaxis_arr = xaxis.GetXbins()
198 if xaxis_arr.GetSize() > 0:
199 lst = [xaxis_arr[i]
for i
in xrange(0, xaxis_arr.GetSize())]
200 arr = array.array(
"d", lst)
201 self._ratio = ROOT.TH1F(
"foo",
"foo", xaxis.GetNbins(), arr)
203 self._ratio = ROOT.TH1F(
"foo",
"foo", xaxis.GetNbins(), xaxis.GetXmin(), xaxis.GetXmax())
205 self._ratio.SetStats(0)
206 self._ratio.SetLineColor(ROOT.kBlack)
207 self._ratio.SetLineWidth(1)
208 def draw(self, style=None):
211 if self._uncertainty:
215 self._ratio.Draw(
"same "+st)
219 return self._th1.GetNbinsX()+1
220 def xvalues(self, bin):
221 xval = self._th1.GetBinCenter(bin)
222 xlow = xval-self._th1.GetXaxis().GetBinLowEdge(bin)
223 xhigh = self._th1.GetXaxis().GetBinUpEdge(bin)-xval
224 return (xval, xlow, xhigh)
225 def yvalues(self, bin):
226 yval = self._th1.GetBinContent(bin)
227 yerr = self._th1.GetBinError(bin)
228 return (yval, yerr, yerr)
230 return self._th1.GetBinContent(bin)
231 def divide(self, bin, scale):
232 self._ratio.SetBinContent(bin, _divideOrZero(self._th1.GetBinContent(bin), scale))
233 self._ratio.SetBinError(bin, _divideOrZero(self._th1.GetBinError(bin), scale))
240 def __init__(self, gr, uncertainty):
242 self._uncertainty = uncertainty
249 def draw(self, style=None):
250 if self._ratio
is None:
254 if self._uncertainty:
258 self._ratio.Draw(
"same "+st)
262 return self._gr.GetN()
263 def xvalues(self, bin):
264 return (self._gr.GetX()[bin], self._gr.GetErrorXlow(bin), self._gr.GetErrorXhigh(bin))
265 def yvalues(self, bin):
266 return (self._gr.GetY()[bin], self._gr.GetErrorYlow(bin), self._gr.GetErrorYhigh(bin))
268 return self._gr.GetY()[bin]
269 def divide(self, bin, scale):
274 if bin >= self._gr.GetN():
277 xvals = self.xvalues(bin)
280 self._xvalues.append(xval)
281 self._xerrslow.append(xvals[1])
282 self._xerrshigh.append(xvals[2])
283 yvals = self.yvalues(bin)
284 self._yvalues.append(yvals[0] / scale)
285 if self._uncertainty:
286 self._yerrslow.append(yvals[1] / scale)
287 self._yerrshigh.append(yvals[2] / scale)
289 self._yerrslow.append(0)
290 self._yerrshigh.append(0)
292 if len(self._xvalues) == 0:
295 self._ratio = ROOT.TGraphAsymmErrors(len(self._xvalues), array.array(
"d", self._xvalues), array.array(
"d", self._yvalues),
296 array.array(
"d", self._xerrslow), array.array(
"d", self._xerrshigh),
297 array.array(
"d", self._yerrslow), array.array(
"d", self._yerrshigh))
301 class WrapTGraph2D(WrapTGraph):
302 def __init__(self, gr, uncertainty):
303 WrapTGraph.__init__(self, gr, uncertainty)
304 def xvalues(self, bin):
305 return (self._gr.GetX()[bin], self._gr.GetErrorX(bin), self._gr.GetErrorX(bin))
306 def yvalues(self, bin):
307 return (self._gr.GetY()[bin], self._gr.GetErrorY(bin), self._gr.GetErrorY(bin))
310 if isinstance(o, ROOT.TH1):
311 return WrapTH1(o, ratioUncertainty)
312 elif isinstance(o, ROOT.TGraph):
313 return WrapTGraph(o, ratioUncertainty)
314 elif isinstance(o, ROOT.TGraph2D):
315 return WrapTGraph2D(o, ratioUncertainty)
317 wrappers = [
wrap(h)
for h
in histos]
321 ref_bins = [ref.xvalues(b)
for b
in xrange(ref.begin(), ref.end())]
323 wrappers_bins.append(findBins(w, ref_bins))
325 for i, bin
in enumerate(xrange(ref.begin(), ref.end())):
326 (scale, ylow, yhigh) = ref.yvalues(bin)
327 for w, bins
in zip(wrappers, wrappers_bins):
330 w.divide(bins[i], scale)
339 if isinstance(obj, ROOT.TH1):
340 xaxis = obj.GetXaxis()
341 if limitToNonZeroContent:
342 for i
in xrange(1, obj.GetNbinsX()+1):
343 if obj.GetBinContent(i) != 0:
344 return xaxis.GetBinLowEdge(i)
348 return xaxis.GetBinLowEdge(xaxis.GetFirst())
349 elif isinstance(obj, ROOT.TGraph)
or isinstance(obj, ROOT.TGraph2D):
350 m =
min([obj.GetX()[i]
for i
in xrange(0, obj.GetN())])
351 return m*0.9
if m > 0
else m*1.1
355 if isinstance(obj, ROOT.TH1):
356 xaxis = obj.GetXaxis()
357 if limitToNonZeroContent:
358 for i
in xrange(obj.GetNbinsX(), 0, -1):
359 if obj.GetBinContent(i) != 0:
360 return xaxis.GetBinUpEdge(i)
364 return xaxis.GetBinUpEdge(xaxis.GetLast())
365 elif isinstance(obj, ROOT.TGraph)
or isinstance(obj, ROOT.TGraph2D):
366 m =
max([obj.GetX()[i]
for i
in xrange(0, obj.GetN())])
367 return m*1.1
if m > 0
else m*0.9
371 if isinstance(obj, ROOT.TH2):
372 yaxis = obj.GetYaxis()
373 return yaxis.GetBinLowEdge(yaxis.GetFirst())
374 elif isinstance(obj, ROOT.TH1):
375 if limitToNonZeroContent:
376 lst = [obj.GetBinContent(i)
for i
in xrange(1, obj.GetNbinsX()+1)
if obj.GetBinContent(i) != 0 ]
377 return min(lst)
if len(lst) != 0
else 0
379 return obj.GetMinimum()
380 elif isinstance(obj, ROOT.TGraph)
or isinstance(obj, ROOT.TGraph2D):
381 m =
min([obj.GetY()[i]
for i
in xrange(0, obj.GetN())])
382 return m*0.9
if m > 0
else m*1.1
386 if isinstance(obj, ROOT.TH2):
387 yaxis = obj.GetYaxis()
388 return yaxis.GetBinUpEdge(yaxis.GetLast())
389 elif isinstance(obj, ROOT.TH1):
390 if limitToNonZeroContent:
391 lst = [obj.GetBinContent(i)
for i
in xrange(1, obj.GetNbinsX()+1)
if obj.GetBinContent(i) != 0 ]
392 return max(lst)
if len(lst) != 0
else 0
394 return obj.GetMaximum()
395 elif isinstance(obj, ROOT.TGraph)
or isinstance(obj, ROOT.TGraph2D):
396 m =
max([obj.GetY()[i]
for i
in xrange(0, obj.GetN())])
397 return m*1.1
if m > 0
else m*0.9
401 return max([th1.GetBinContent(i)+th1.GetBinError(i)
for i
in xrange(1, th1.GetNbinsX()+1)])
404 yvals = sorted([n
for n
in [th1.GetBinContent(i)
for i
in xrange(1, th1.GetNbinsX()+1)]
if n>0])
406 return th1.GetMinimum()
411 ind_min = len(yvals)-1 -
int(len(yvals)*0.95)
412 min_val = yvals[ind_min]
413 for i
in xrange(0, ind_min):
414 if yvals[i] > 0.1*min_val:
420 inRange =
lambda x:
True 421 inRange2 =
lambda xmin,xmax:
True 423 inRange =
lambda x: coverageRange[0] <= x <= coverageRange[1]
424 inRange2 =
lambda xmin,xmax: coverageRange[0] <= xmin
and xmax <= coverageRange[1]
426 if isinstance(obj, ROOT.TH1):
427 yvals = [obj.GetBinContent(i)
for i
in xrange(1, obj.GetNbinsX()+1)
if inRange2(obj.GetXaxis().GetBinLowEdge(i), obj.GetXaxis().GetBinUpEdge(i))]
428 yvals = [x
for x
in yvals
if x != 0]
429 elif isinstance(obj, ROOT.TGraph)
or isinstance(obj, ROOT.TGraph2D):
430 yvals = [obj.GetY()[i]
for i
in xrange(0, obj.GetN())
if inRange(obj.GetX()[i])]
436 return (yvals[0], yvals[0])
438 return (yvals[0], yvals[1])
441 nvals =
int(len(yvals)*coverage)
444 if len(yvals) % 2 == 0:
446 return ( yvals[half-1], yvals[half] )
448 middle = len(yvals)/2
449 return ( yvals[middle-1], yvals[middle+1] )
450 ind_min = (len(yvals)-nvals)/2
451 ind_max = len(yvals)-1 - ind_min
453 return (yvals[ind_min], yvals[ind_max])
455 def _findBounds(th1s, ylog, xmin=None, xmax=None, ymin=None, ymax=None):
456 """Find x-y axis boundaries encompassing a list of TH1s if the bounds are not given in arguments. 460 ylog -- Boolean indicating if y axis is in log scale or not (affects the automatic ymax) 463 xmin -- Minimum x value; if None, take the minimum of TH1s 464 xmax -- Maximum x value; if None, take the maximum of TH1s 465 ymin -- Minimum y value; if None, take the minimum of TH1s 466 ymax -- Maximum y value; if None, take the maximum of TH1s 471 if xmin
is None or xmax
is None or isinstance(xmin, list)
or isinstance(max, list):
475 xmins.append(
_getXmin(th1, limitToNonZeroContent=isinstance(xmin, list)))
476 xmaxs.append(
_getXmax(th1, limitToNonZeroContent=isinstance(xmax, list)))
479 xmins = [h
for h
in xmins
if h
is not None]
480 xmaxs = [h
for h
in xmaxs
if h
is not None]
484 elif isinstance(xmin, list):
488 print "Histogram is zero, using the smallest given value for xmin from",
str(xmin)
491 xmins_below = [x
for x
in xmin
if x<=xm]
492 if len(xmins_below) == 0:
496 print "Histogram minimum x %f is below all given xmin values %s, using the smallest one" % (xm,
str(xmin))
498 xmin =
max(xmins_below)
502 elif isinstance(xmax, list):
506 print "Histogram is zero, using the smallest given value for xmax from",
str(xmin)
509 xmaxs_above = [x
for x
in xmax
if x>xm]
510 if len(xmaxs_above) == 0:
514 print "Histogram maximum x %f is above all given xmax values %s, using the maximum one" % (xm,
str(xmax))
516 xmax =
min(xmaxs_above)
519 th1.GetXaxis().SetRangeUser(xmin, xmax)
521 return (xmin, ymin, xmax, ymax)
523 def _findBoundsY(th1s, ylog, ymin=None, ymax=None, coverage=None, coverageRange=None):
524 """Find y axis boundaries encompassing a list of TH1s if the bounds are not given in arguments. 528 ylog -- Boolean indicating if y axis is in log scale or not (affects the automatic ymax) 531 ymin -- Minimum y value; if None, take the minimum of TH1s 532 ymax -- Maximum y value; if None, take the maximum of TH1s 533 coverage -- If set, use only values within the 'coverage' part around the median are used for min/max (useful for ratio) 534 coverageRange -- If coverage and this are set, use only the x axis specified by an (xmin,xmax) pair for the coverage 536 if coverage
is not None or isinstance(th1s[0], ROOT.TH2):
542 y_scale_max =
lambda y: y
543 y_scale_min =
lambda y: y
546 y_scale_max =
lambda y: y*1.5
548 y_scale_max =
lambda y: y*1.05
549 y_scale_min =
lambda y: y*0.9
551 if ymin
is None or ymax
is None or isinstance(ymin, list)
or isinstance(ymax, list):
555 if coverage
is not None:
558 if ylog
and isinstance(ymin, list):
561 _ymin =
_getYmin(th1, limitToNonZeroContent=isinstance(ymin, list))
562 _ymax =
_getYmax(th1, limitToNonZeroContent=isinstance(ymax, list))
570 elif isinstance(ymin, list):
571 ym_unscaled =
min(ymins)
572 ym = y_scale_min(ym_unscaled)
573 ymins_below = [y
for y
in ymin
if y<=ym]
574 if len(ymins_below) == 0:
576 if ym_unscaled < ymin:
578 print "Histogram minimum y %f is below all given ymin values %s, using the smallest one" % (ym,
str(ymin))
580 ymin =
max(ymins_below)
585 ymax = y_scale_max(
max(ymaxs+[ymin]))
586 elif isinstance(ymax, list):
587 ym_unscaled =
max(ymaxs)
588 ym = y_scale_max(ym_unscaled)
589 ymaxs_above = [y
for y
in ymax
if y>ym]
590 if len(ymaxs_above) == 0:
592 if ym_unscaled > ymax:
594 print "Histogram maximum y %f is above all given ymax values %s, using the maximum one" % (ym_unscaled,
str(ymax))
596 ymax =
min(ymaxs_above)
599 th1.GetYaxis().SetRangeUser(ymin, ymax)
605 for b
in xrange(1, histos[0].GetNbinsX()+1):
608 if h.GetBinContent(b) > 0:
614 if len(binsToRemove) > 0:
617 for i
in xrange(len(xbinlabels)):
618 if (i+1)
not in binsToRemove:
619 xbinlab_new.append(xbinlabels[i])
620 xbinlabels = xbinlab_new
626 for b
in xrange(1, h.GetNbinsX()+1):
627 if b
not in binsToRemove:
628 values.append( (h.GetXaxis().GetBinLabel(b), h.GetBinContent(b), h.GetBinError(b)) )
631 h_new = h.Clone(h.GetName()+
"_empty")
632 h_new.SetBins(len(values), h.GetBinLowEdge(1), h.GetBinLowEdge(1)+len(values))
633 for b, (l, v, e)
in enumerate(values):
634 h_new.GetXaxis().SetBinLabel(b+1, l)
635 h_new.SetBinContent(b+1, v)
636 h_new.SetBinError(b+1, e)
638 histos_new.append(h_new)
641 return (histos, xbinlabels)
644 xbinsToRemove = set()
645 ybinsToRemove = set()
646 for ih, h
in enumerate(histos):
647 for bx
in xrange(1, h.GetNbinsX()+1):
649 for by
in xrange(1, h.GetNbinsY()+1):
650 if h.GetBinContent(bx, by) > 0:
654 xbinsToRemove.add(bx)
656 xbinsToRemove.discard(bx)
658 for by
in xrange(1, h.GetNbinsY()+1):
660 for bx
in xrange(1, h.GetNbinsX()+1):
661 if h.GetBinContent(bx, by) > 0:
665 ybinsToRemove.add(by)
667 ybinsToRemove.discard(by)
669 if len(xbinsToRemove) > 0
or len(ybinsToRemove) > 0:
672 for b
in xrange(1, len(xbinlabels)+1):
673 if b
not in xbinsToRemove:
674 xbinlabels_new.append(histos[0].GetXaxis().GetBinLabel(b))
676 xbinlabels = xbinlabels_new
679 for b
in xrange(1, len(ybinlabels)+1):
680 if b
not in ybinsToRemove:
681 ybinlabels.append(histos[0].GetYaxis().GetBinLabel(b))
683 ybinlabels = xbinlabels_new
686 if len(xbinlabels) == 0
or len(ybinlabels) == 0:
687 return (histos_new, xbinlabels, ybinlabels)
689 h_new = ROOT.TH2F(h.GetName()+
"_empty", h.GetTitle(), len(xbinlabels),0,len(xbinlabels), len(ybinlabels),0,len(ybinlabels))
690 for b, l
in enumerate(xbinlabels):
691 h_new.GetXaxis().SetBinLabel(b+1, l)
692 for b, l
in enumerate(ybinlabels):
693 h_new.GetYaxis().SetBinLabel(b+1, l)
695 for ix, bx
in enumerate(xbins):
696 for iy, by
in enumerate(ybins):
697 h_new.SetBinContent(ix+1, iy+1, h.GetBinContent(bx, by))
698 h_new.SetBinError(ix+1, iy+1, h.GetBinError(bx, by))
699 histos_new.append(h_new)
701 return (histos, xbinlabels, ybinlabels)
704 return _mergeBinLabels([[h.GetXaxis().GetBinLabel(i)
for i
in xrange(1, h.GetNbinsX()+1)]
for h
in histos])
707 return _mergeBinLabels([[h.GetYaxis().GetBinLabel(i)
for i
in xrange(1, h.GetNbinsY()+1)]
for h
in histos])
710 labels_merged = labelsAll[0]
711 for labels
in labelsAll[1:]:
712 diff = difflib.unified_diff(labels_merged, labels, n=
max(len(labels_merged), len(labels)))
719 operation.append(item[0])
721 if lab
in labels_merged:
723 ind = labels_merged.index(lab)
724 if operation[ind] ==
"-" and operation[-1] ==
"+":
725 labels_merged.remove(lab)
727 elif operation[ind] ==
"+" and operation[-1] ==
"-":
731 raise Exception(
"This should never happen")
732 labels_merged.append(lab)
735 if len(labels_merged) == 0:
736 labels_merged = labels
743 h_new = h.Clone(h.GetName()+
"_xbinlabels")
744 h_new.SetBins(len(xbinlabels), h.GetBinLowEdge(1), h.GetBinLowEdge(1)+len(xbinlabels))
745 for i, label
in enumerate(xbinlabels):
746 bin = h.GetXaxis().FindFixBin(label)
748 h_new.SetBinContent(i+1, h.GetBinContent(bin))
749 h_new.SetBinError(i+1, h.GetBinError(bin))
751 h_new.SetBinContent(i+1, 0)
752 h_new.SetBinError(i+1, 0)
753 histos_new.append(h_new)
758 """Class for subtracting two histograms""" 763 name -- String for name of the resulting histogram (A-B) 764 nameA -- String for A histogram 765 nameB -- String for B histogram 768 title -- String for a title of the resulting histogram (default "") 770 Uncertainties are calculated with the assumption that B is a 771 subset of A, and the histograms contain event counts. 779 """String representation, returns the name""" 783 """Create and return the fake+duplicate histogram from a TDirectory""" 787 if not histoA
or not histoB:
790 ret = histoA.Clone(self.
_name)
796 ret.SetCanExtend(
False)
798 for i
in xrange(0, histoA.GetNbinsX()+2):
799 val = histoA.GetBinContent(i)-histoB.GetBinContent(i)
800 ret.SetBinContent(i, val)
801 ret.SetBinError(i, math.sqrt(val))
806 """Class to transform bin contents in an arbitrary way.""" 811 name -- String for name of the resulting histogram 812 histo -- String for a source histogram (needs to be cumulative) 813 func -- Function to operate on the bin content 821 """String representation, returns the name""" 825 """Create and return the transformed histogram from a TDirectory""" 830 ret = histo.Clone(self.
_name)
836 ret.SetCanExtend(
False)
838 for i
in xrange(0, histo.GetNbinsX()+2):
839 ret.SetBinContent(i, self.
_func(histo.GetBinContent(i)))
843 """Class to calculate the fake+duplicate rate""" 844 def __init__(self, name, assoc, dup, reco, title=""):
848 name -- String for the name of the resulting efficiency histogram 849 assoc -- String for the name of the "associated" histogram 850 dup -- String for the name of the "duplicates" histogram 851 reco -- String for the name of the "reco" (denominator) histogram 854 title -- String for a title of the resulting histogram (default "") 856 The result is calculated as 1 - (assoc - dup) / reco 865 """String representation, returns the name""" 869 """Create and return the fake+duplicate histogram from a TDirectory""" 876 if not hassoc
or not hdup
or not hreco:
879 hfakedup = hreco.Clone(self.
_name)
880 hfakedup.SetTitle(self.
_title)
882 for i
in xrange(1, hassoc.GetNbinsX()+1):
883 numerVal = hassoc.GetBinContent(i) - hdup.GetBinContent(i)
884 denomVal = hreco.GetBinContent(i)
886 fakedupVal = (1 - numerVal / denomVal)
if denomVal != 0.0
else 0.0
887 errVal = math.sqrt(fakedupVal*(1-fakedupVal)/denomVal)
if (denomVal != 0.0
and fakedupVal <= 1)
else 0.0
889 hfakedup.SetBinContent(i, fakedupVal)
890 hfakedup.SetBinError(i, errVal)
895 """Class for making a cut efficiency histograms. 905 name -- String for name of the resulting histogram 906 histo -- String for a source histogram (needs to be cumulative) 913 """String representation, returns the name""" 917 """Create and return the cut efficiency histogram from a TDirectory""" 923 ascending = histo.GetBinContent(0) < histo.GetBinContent(histo.GetNbinsX())
925 n_tot = histo.GetBinContent(histo.GetNbinsX())
927 n_tot = histo.GetBinContent(0)
932 ret = histo.Clone(self.
_name)
936 for i
in xrange(1, histo.GetNbinsX()+1):
937 n = histo.GetBinContent(i)
939 errVal = math.sqrt(val*(1-val)/n_tot)
940 ret.SetBinContent(i, val)
941 ret.SetBinError(i, errVal)
945 """Class to create a histogram by aggregating bins of another histogram to a bin of the resulting histogram.""" 946 def __init__(self, name, histoName, mapping, normalizeTo=None, scale=None, renameBin=None, ignoreMissingBins=False, minExistingBins=None, originalOrder=False, reorder=None):
950 name -- String for the name of the resulting histogram 951 histoName -- String for the name of the source histogram 952 mapping -- Dictionary for mapping the bins (see below) 955 normalizeTo -- Optional string of a bin label in the source histogram. If given, all bins of the resulting histogram are divided by the value of this bin. 956 scale -- Optional number for scaling the histogram (passed to ROOT.TH1.Scale()) 957 renameBin -- Optional function (string -> string) to rename the bins of the input histogram 958 originalOrder -- Boolean for using the order of bins in the histogram (default False) 959 reorder -- Optional function to reorder the bins 961 Mapping structure (mapping): 963 Dictionary (you probably want to use collections.OrderedDict) 964 should be a mapping from the destination bin label to a list 965 of source bin labels ("dst -> [src]"). 978 raise Exception(
"reorder is not None and originalOrder is True, please set only one of them")
981 """String representation, returns the name""" 985 """Create and return the histogram from a TDirectory""" 991 binValues = [
None]*len(self.
_mapping)
997 for i, (key, labels)
in enumerate(six.iteritems(self.
_mapping)):
1003 sumTime += values[l][0]
1004 sumErrorSq += values[l][1]**2
1010 binValues[i] = (sumTime, math.sqrt(sumErrorSq))
1013 ivalue = len(values)+1
1019 ivalue = values.keys().
index(lab)
1021 binIndexOrder.append( (ivalue, i) )
1024 binIndexOrder.sort(key=
lambda t: t[0])
1027 for i
in xrange(0, len(binValues)):
1028 fromIndex = binIndexOrder[i][1]
1029 tmpVal.append(binValues[fromIndex])
1030 tmpLab.append(binLabels[fromIndex])
1034 order = self.
_reorder(tdirectory, binLabels)
1035 binValues = [binValues[i]
for i
in order]
1036 binLabels = [binLabels[i]
for i
in order]
1042 for i, val
in enumerate(binValues):
1045 binValues = [v
for v
in binValues
if v
is not None]
1046 binLabels = [v
for v
in binLabels
if v
is not None]
1047 if len(binValues) == 0:
1050 result = ROOT.TH1F(self.
_name, self.
_name, len(binValues), 0, len(binValues))
1051 for i, (value, label)
in enumerate(
zip(binValues, binLabels)):
1052 if value
is not None:
1053 result.SetBinContent(i+1, value[0])
1054 result.SetBinError(i+1, value[1])
1055 result.GetXaxis().SetBinLabel(i+1, label)
1060 print "Trying to normalize {name} to {binlabel}, which does not exist".
format(name=self.
_name, binlabel=self.
_normalizeTo)
1062 value = th1.GetBinContent(bin)
1064 result.Scale(1/value)
1066 if self.
_scale is not None:
1067 result.Scale(self.
_scale)
1072 """Class to create a histogram by aggregaging integrals of another histoggrams.""" 1077 name -- String for the name of the resulting histogram 1078 mapping -- Dictionary for mapping the bin label to a histogram name 1081 normalizeTo -- Optional string for a histogram. If given, all bins of the resulting histograqm are divided by the integral of this histogram. 1088 """String representation, returns the name""" 1092 """Create and return the histogram from a TDirectory""" 1094 for key, histoName
in six.iteritems(self.
_mapping):
1098 result.append( (key, th1.Integral(0, th1.GetNbinsX()+1)) )
1099 if len(result) == 0:
1102 res = ROOT.TH1F(self.
_name, self.
_name, len(result), 0, len(result))
1104 for i, (name, count)
in enumerate(result):
1105 res.SetBinContent(i+1, count)
1106 res.GetXaxis().SetBinLabel(i+1, name)
1112 scale = th1.Integral(0, th1.GetNbinsX()+1)
1118 """Class to construct a ROC curve (e.g. efficiency vs. fake rate) from two histograms""" 1119 def __init__(self, name, xhistoName, yhistoName, zaxis=False):
1123 name -- String for the name of the resulting histogram 1124 xhistoName -- String for the name of the x-axis histogram (or another "creator" object) 1125 yhistoName -- String for the name of the y-axis histogram (or another "creator" object) 1128 zaxis -- If set to True (default False), create a TGraph2D with z axis showing the cut value (recommended drawStyle 'pcolz') 1136 """String representation, returns the name""" 1140 """Create and return the histogram from a TDirectory""" 1143 if xhisto
is None or yhisto
is None:
1154 for i
in xrange(1, xhisto.GetNbinsX()+1):
1155 x.append(xhisto.GetBinContent(i))
1156 xerrup.append(xhisto.GetBinError(i))
1157 xerrdown.append(xhisto.GetBinError(i))
1159 y.append(yhisto.GetBinContent(i))
1160 yerrup.append(yhisto.GetBinError(i))
1161 yerrdown.append(yhisto.GetBinError(i))
1163 z.append(xhisto.GetXaxis().GetBinUpEdge(i))
1166 if x.count(0.0) == len(x)
or y.count(0.0) == len(y):
1169 arr =
lambda v: array.array(
"d", v)
1172 gr = ROOT.TGraph2D(len(x), arr(x), arr(y), arr(z))
1174 gr = ROOT.TGraphAsymmErrors(len(x), arr(x), arr(y), arr(xerrdown), arr(xerrup), arr(yerrdown), arr(yerrup))
1180 _plotStylesColor = [4, 2, ROOT.kBlack, ROOT.kOrange+7, ROOT.kMagenta-3]
1181 _plotStylesMarker = [21, 20, 22, 34, 33]
1183 def _drawFrame(pad, bounds, zmax=None, xbinlabels=None, xbinlabelsize=None, xbinlabeloption=None, ybinlabels=None, suffix=""):
1184 """Function to draw a frame 1187 pad -- TPad to where the frame is drawn 1188 bounds -- List or 4-tuple for (xmin, ymin, xmax, ymax) 1191 zmax -- Maximum Z, needed for TH2 histograms 1192 xbinlabels -- Optional list of strings for x axis bin labels 1193 xbinlabelsize -- Optional number for the x axis bin label size 1194 xbinlabeloption -- Optional string for the x axis bin options (passed to ROOT.TH1.LabelsOption()) 1195 suffix -- Optional string for a postfix of the frame name 1197 if xbinlabels
is None and ybinlabels
is None:
1198 frame = pad.DrawFrame(*bounds)
1201 nbins = len(xbinlabels)
1202 if ybinlabels
is None:
1203 frame = ROOT.TH1F(
"hframe"+suffix,
"", nbins, bounds[0], bounds[2])
1204 frame.SetMinimum(bounds[1])
1205 frame.SetMaximum(bounds[3])
1206 frame.GetYaxis().SetLimits(bounds[1], bounds[3])
1208 ybins = len(ybinlabels)
1209 frame = ROOT.TH2F(
"hframe"+suffix,
"", nbins,bounds[0],bounds[2], ybins,bounds[1],bounds[3])
1210 frame.SetMaximum(zmax)
1212 frame.SetBit(ROOT.TH1.kNoStats)
1213 frame.SetBit(ROOT.kCanDelete)
1216 xaxis = frame.GetXaxis()
1217 for i
in xrange(nbins):
1218 xaxis.SetBinLabel(i+1, xbinlabels[i])
1219 if xbinlabelsize
is not None:
1220 xaxis.SetLabelSize(xbinlabelsize)
1221 if xbinlabeloption
is not None:
1222 frame.LabelsOption(xbinlabeloption)
1224 if ybinlabels
is not None:
1225 yaxis = frame.GetYaxis()
1226 for i, lab
in enumerate(ybinlabels):
1227 yaxis.SetBinLabel(i+1, lab)
1228 if xbinlabelsize
is not None:
1229 yaxis.SetLabelSize(xbinlabelsize)
1230 if xbinlabeloption
is not None:
1231 frame.LabelsOption(xbinlabeloption,
"Y")
1236 """Class for creating and managing a frame for a simple, one-pad plot""" 1237 def __init__(self, pad, bounds, zmax, nrows, xbinlabels=None, xbinlabelsize=None, xbinlabeloption=None, ybinlabels=None):
1239 self.
_frame =
_drawFrame(pad, bounds, zmax, xbinlabels, xbinlabelsize, xbinlabeloption, ybinlabels)
1247 yoffsetFactor *= 1.5
1248 xoffsetFactor *= 1.5
1253 self._frame.GetYaxis().SetTitleOffset(self._frame.GetYaxis().GetTitleOffset()*yoffsetFactor)
1254 self._frame.GetXaxis().SetTitleOffset(self._frame.GetXaxis().GetTitleOffset()*xoffsetFactor)
1258 self._pad.SetLogx(log)
1261 self._pad.SetLogy(log)
1264 self._pad.SetGridx(grid)
1267 self._pad.SetGridy(grid)
1270 self._pad.SetLeftMargin(self._pad.GetLeftMargin()+adjust)
1273 self._frame.Draw(
"")
1276 self._pad.SetRightMargin(self._pad.GetRightMargin()+adjust)
1279 self._frame.Draw(
"")
1282 self._frame.SetTitle(title)
1285 self._frame.GetXaxis().SetTitle(title)
1288 self._frame.GetXaxis().SetTitleSize(size)
1291 self._frame.GetXaxis().SetTitleOffset(offset)
1294 self._frame.GetXaxis().SetLabelSize(size)
1297 self._frame.GetYaxis().SetTitle(title)
1300 self._frame.GetYaxis().SetTitleSize(size)
1303 self._frame.GetYaxis().SetTitleOffset(offset)
1306 self._pad.RedrawAxis()
1309 """Class for creating and managing a frame for a ratio plot with two subpads""" 1310 def __init__(self, pad, bounds, zmax, ratioBounds, ratioFactor, nrows, xbinlabels=None, xbinlabelsize=None, xbinlabeloption=None, ratioYTitle=_ratioYTitle):
1313 if xbinlabels
is not None:
1320 self._frame.GetXaxis().SetLabelSize(0)
1321 self._frame.GetXaxis().SetTitleSize(0)
1323 yoffsetFactor = ratioFactor
1324 divisionPoint = 1-1/ratioFactor
1325 xoffsetFactor = 1/divisionPoint
1328 xoffsetFactor *= 0.6
1331 xoffsetFactor *= 1.5
1334 xoffsetFactor *= 2.3
1339 self._frame.GetYaxis().SetTitleOffset(self._frameRatio.GetYaxis().GetTitleOffset()*yoffsetFactor)
1340 self._frameRatio.GetYaxis().SetLabelSize(
int(self._frameRatio.GetYaxis().GetLabelSize()*0.8))
1341 self._frameRatio.GetYaxis().SetTitleOffset(self._frameRatio.GetYaxis().GetTitleOffset()*yoffsetFactor)
1342 self._frameRatio.GetXaxis().SetTitleOffset(self._frameRatio.GetXaxis().GetTitleOffset()*xoffsetFactor)
1344 self._frameRatio.GetYaxis().SetNdivisions(4, 5, 0)
1346 self._frameRatio.GetYaxis().SetTitle(ratioYTitle)
1349 self._pad.SetLogx(log)
1350 self._padRatio.SetLogx(log)
1353 self._pad.SetLogy(log)
1356 self._pad.SetGridx(grid)
1357 self._padRatio.SetGridx(grid)
1360 self._pad.SetGridy(grid)
1361 self._padRatio.SetGridy(grid)
1364 self._pad.SetLeftMargin(self._pad.GetLeftMargin()+adjust)
1365 self._padRatio.SetLeftMargin(self._padRatio.GetLeftMargin()+adjust)
1368 self._frame.Draw(
"")
1370 self._frameRatio.Draw(
"")
1373 self._pad.SetRightMargin(self._pad.GetRightMargin()+adjust)
1374 self._padRatio.SetRightMargin(self._padRatio.GetRightMargin()+adjust)
1377 self._frame.Draw(
"")
1379 self._frameRatio.Draw(
"")
1382 self._frame.SetTitle(title)
1385 self._frameRatio.GetXaxis().SetTitle(title)
1388 self._frameRatio.GetXaxis().SetTitleSize(size)
1391 self._frameRatio.GetXaxis().SetTitleOffset(offset)
1394 self._frameRatio.GetXaxis().SetLabelSize(size)
1397 self._frame.GetYaxis().SetTitle(title)
1400 self._frameRatio.GetYaxis().SetTitle(title)
1403 self._frame.GetYaxis().SetTitleSize(size)
1404 self._frameRatio.GetYaxis().SetTitleSize(size)
1407 self._frame.GetYaxis().SetTitleOffset(offset)
1408 self._frameRatio.GetYaxis().SetTitleOffset(offset)
1411 self._padRatio.RedrawAxis()
1412 self._pad.RedrawAxis()
1414 self._parentPad.cd()
1421 self.
_coverPad = ROOT.TPad(
"coverpad",
"coverpad", xmin, ymin, xmax, ymax)
1422 self._coverPad.SetBorderMode(0)
1423 self._coverPad.Draw()
1429 """Class for creating and managing a frame for a plot from TGraph2D""" 1430 def __init__(self, pad, bounds, histos, ratioOrig, ratioFactor):
1433 self.
_pad = pad.cd(1)
1437 (xlow, ylow, width, height) = (self._pad.GetXlowNDC(), self._pad.GetYlowNDC(), self._pad.GetWNDC(), self._pad.GetHNDC())
1441 bottomMargin = self._pad.GetBottomMargin()
1442 bottomMarginNew = ROOT.gStyle.GetPadBottomMargin()
1444 ylowNew = yup - (1-bottomMargin)/(1-bottomMarginNew) * (yup-ylow)
1445 topMarginNew = self._pad.GetTopMargin() * (yup-ylow)/(yup-ylowNew)
1447 self._pad.SetPad(xlow, ylowNew, xup, yup)
1448 self._pad.SetTopMargin(topMarginNew)
1449 self._pad.SetBottomMargin(bottomMarginNew)
1469 self._pad.SetLeftMargin(self._pad.GetLeftMargin()+adjust)
1473 self._pad.SetRightMargin(self._pad.GetRightMargin()+adjust)
1501 self._firstHisto.GetZaxis().SetTitle(title)
1504 self._firstHisto.GetZaxis().SetTitleOffset(offset)
1509 self._pad.SetPhi(epsilon)
1510 self._pad.SetTheta(90+epsilon)
1512 self._firstHisto.GetXaxis().SetTitleOffset(self.
_xtitleoffset)
1513 self._firstHisto.GetYaxis().SetTitleOffset(self.
_ytitleoffset)
1515 if hasattr(self,
"_xtitle"):
1516 self._firstHisto.GetXaxis().SetTitle(self.
_xtitle)
1517 if hasattr(self,
"_xtitlesize"):
1518 self._firstHisto.GetXaxis().SetTitleSize(self.
_xtitlesize)
1519 if hasattr(self,
"_xlabelsize"):
1520 self._firstHisto.GetXaxis().SetLabelSize(self._labelsize)
1521 if hasattr(self,
"_ytitle"):
1522 self._firstHisto.GetYaxis().SetTitle(self.
_ytitle)
1523 if hasattr(self,
"_ytitlesize"):
1524 self._firstHisto.GetYaxis().SetTitleSize(self.
_ytitlesize)
1525 if hasattr(self,
"_ytitleoffset"):
1526 self._firstHisto.GetYaxis().SetTitleOffset(self.
_ytitleoffset)
1529 """Abstraction on top of TLatex""" 1530 def __init__(self, x, y, text, size=None, bold=True, align="left", color=ROOT.kBlack, font=None):
1534 x -- X coordinate of the text (in NDC) 1535 y -- Y coordinate of the text (in NDC) 1536 text -- String to draw 1537 size -- Size of text (None for the default value, taken from gStyle) 1538 bold -- Should the text be bold? 1539 align -- Alignment of text (left, center, right) 1540 color -- Color of the text 1541 font -- Specify font explicitly 1550 self._l.SetTextFont(self._l.GetTextFont()-20)
1551 if font
is not None:
1552 self._l.SetTextFont(font)
1553 if size
is not None:
1554 self._l.SetTextSize(size)
1555 if isinstance(align, str):
1556 if align.lower() ==
"left":
1557 self._l.SetTextAlign(11)
1558 elif align.lower() ==
"center":
1559 self._l.SetTextAlign(21)
1560 elif align.lower() ==
"right":
1561 self._l.SetTextAlign(31)
1563 raise Exception(
"Error: Invalid option '%s' for text alignment! Options are: 'left', 'center', 'right'."%align)
1565 self._l.SetTextAlign(align)
1566 self._l.SetTextColor(color)
1569 """Draw the text to the current TPad. 1572 options -- For interface compatibility, ignored 1574 Provides interface compatible with ROOT's drawable objects. 1576 self._l.DrawLatex(self.
_x, self.
_y, self.
_text)
1580 """Class for drawing text and a background box.""" 1581 def __init__(self, xmin, ymin, xmax, ymax, lineheight=0.04, fillColor=ROOT.kWhite, transparent=True, **kwargs):
1585 xmin -- X min coordinate of the box (NDC) 1586 ymin -- Y min coordinate of the box (NDC) (if None, deduced automatically) 1587 xmax -- X max coordinate of the box (NDC) 1588 ymax -- Y max coordinate of the box (NDC) 1589 lineheight -- Line height 1590 fillColor -- Fill color of the box 1591 transparent -- Should the box be transparent? (in practive the TPave is not created) 1593 Keyword arguments are forwarded to constructor of PlotText 1605 self._textArgs.update(kwargs)
1610 """Add text to current position""" 1617 def move(self, dx=0, dy=0, dw=0, dh=0):
1618 """Move the box and the contained text objects 1621 dx -- Movement in x (positive is to right) 1622 dy -- Movement in y (positive is to up) 1623 dw -- Increment of width (negative to decrease width) 1624 dh -- Increment of height (negative to decrease height) 1626 dx and dy affect to both box and text objects, dw and dh 1627 affect the box only. 1631 if self.
_ymin is not None:
1636 if self.
_ymin is not None:
1644 """Draw the box and the text to the current TPad. 1647 options -- Forwarded to ROOT.TPave.Draw(), and the Draw() of the contained objects 1652 ymin = self.currenty - 0.01
1653 self.
_pave = ROOT.TPave(self.xmin, self.ymin, self.xmax, self.ymax, 0,
"NDC")
1654 self._pave.SetFillColor(self.fillColor)
1655 self._pave.Draw(options)
1661 if hasattr(src,
"GetLineColor")
and hasattr(dst,
"SetLineColor"):
1662 properties.extend([
"LineColor",
"LineStyle",
"LineWidth"])
1663 if hasattr(src,
"GetFillColor")
and hasattr(dst,
"SetFillColor"):
1664 properties.extend([
"FillColor",
"FillStyle"])
1665 if hasattr(src,
"GetMarkerColor")
and hasattr(dst,
"SetMarkerColor"):
1666 properties.extend([
"MarkerColor",
"MarkerSize",
"MarkerStyle"])
1668 for prop
in properties:
1669 getattr(dst,
"Set"+prop)(getattr(src,
"Get"+prop)())
1672 """Denotes an empty place in a group.""" 1692 """Represents one plot, comparing one or more histograms.""" 1697 name -- String for name of the plot, or Efficiency object 1700 fallback -- Dictionary for specifying fallback (default None) 1701 outname -- String for an output name of the plot (default None for the same as 'name') 1702 title -- String for a title of the plot (default None) 1703 xtitle -- String for x axis title (default None) 1704 xtitlesize -- Float for x axis title size (default None) 1705 xtitleoffset -- Float for x axis title offset (default None) 1706 xlabelsize -- Float for x axis label size (default None) 1707 ytitle -- String for y axis title (default None) 1708 ytitlesize -- Float for y axis title size (default None) 1709 ytitleoffset -- Float for y axis title offset (default None) 1710 ztitle -- String for z axis title (default None) 1711 ztitleoffset -- Float for z axis title offset (default None) 1712 xmin -- Float for x axis minimum (default None, i.e. automatic) 1713 xmax -- Float for x axis maximum (default None, i.e. automatic) 1714 ymin -- Float for y axis minimum (default 0) 1715 ymax -- Float for y axis maximum (default None, i.e. automatic) 1716 xlog -- Bool for x axis log status (default False) 1717 ylog -- Bool for y axis log status (default False) 1718 xgrid -- Bool for x axis grid status (default True) 1719 ygrid -- Bool for y axis grid status (default True) 1720 stat -- Draw stat box? (default False) 1721 fit -- Do gaussian fit? (default False) 1722 statx -- Stat box x coordinate (default 0.65) 1723 staty -- Stat box y coordinate (default 0.8) 1724 statyadjust -- List of floats for stat box y coordinate adjustments (default None) 1725 normalizeToUnitArea -- Normalize histograms to unit area? (default False) 1726 normalizeToNumberOfEvents -- Normalize histograms to number of events? If yes, the PlotFolder needs 'numberOfEventsHistogram' set to a histogram filled once per event (default False) 1727 profileX -- Take histograms via ProfileX()? (default False) 1728 fitSlicesY -- Take histograms via FitSlicesY() (default False) 1729 rebinX -- rebin x axis (default None) 1730 scale -- Scale histograms by a number (default None) 1731 xbinlabels -- List of x axis bin labels (if given, default None) 1732 xbinlabelsize -- Size of x axis bin labels (default None) 1733 xbinlabeloption -- Option string for x axis bin labels (default None) 1734 removeEmptyBins -- Bool for removing empty bins, but only if histogram has bin labels (default False) 1735 printBins -- Bool for printing bin values, but only if histogram has bin labels (default False) 1736 drawStyle -- If "hist", draw as line instead of points (default None) 1737 drawCommand -- Deliver this to Draw() (default: None for same as drawStyle) 1738 lineWidth -- If drawStyle=="hist", the width of line (default 2) 1739 legendDx -- Float for moving TLegend in x direction for separate=True (default None) 1740 legendDy -- Float for moving TLegend in y direction for separate=True (default None) 1741 legendDw -- Float for changing TLegend width for separate=True (default None) 1742 legendDh -- Float for changing TLegend height for separate=True (default None) 1743 legend -- Bool to enable/disable legend (default True) 1744 adjustMarginLeft -- Float for adjusting left margin (default None) 1745 adjustMarginRight -- Float for adjusting right margin (default None) 1746 ratio -- Possibility to disable ratio for this particular plot (default None) 1747 ratioYmin -- Float for y axis minimum in ratio pad (default: list of values) 1748 ratioYmax -- Float for y axis maximum in ratio pad (default: list of values) 1749 ratioFit -- Fit straight line in ratio? (default None) 1750 ratioUncertainty -- Plot uncertainties on ratio? (default True) 1751 ratioCoverageXrange -- Range of x axis values (xmin,xmax) to limit the automatic ratio y axis range calculation to (default None for disabled) 1752 histogramModifier -- Function to be called in create() to modify the histograms (default None) 1756 def _set(attr, default):
1757 setattr(self,
"_"+attr, kwargs.get(attr, default))
1759 _set(
"fallback",
None)
1760 _set(
"outname",
None)
1763 _set(
"xtitle",
None)
1764 _set(
"xtitlesize",
None)
1765 _set(
"xtitleoffset",
None)
1766 _set(
"xlabelsize",
None)
1767 _set(
"ytitle",
None)
1768 _set(
"ytitlesize",
None)
1769 _set(
"ytitleoffset",
None)
1770 _set(
"ztitle",
None)
1771 _set(
"ztitleoffset",
None)
1788 _set(
"statyadjust",
None)
1790 _set(
"normalizeToUnitArea",
False)
1791 _set(
"normalizeToNumberOfEvents",
False)
1792 _set(
"profileX",
False)
1793 _set(
"fitSlicesY",
False)
1794 _set(
"rebinX",
None)
1797 _set(
"xbinlabels",
None)
1798 _set(
"xbinlabelsize",
None)
1799 _set(
"xbinlabeloption",
None)
1800 _set(
"removeEmptyBins",
False)
1801 _set(
"printBins",
False)
1803 _set(
"drawStyle",
"EP")
1804 _set(
"drawCommand",
None)
1805 _set(
"lineWidth", 2)
1807 _set(
"legendDx",
None)
1808 _set(
"legendDy",
None)
1809 _set(
"legendDw",
None)
1810 _set(
"legendDh",
None)
1811 _set(
"legend",
True)
1813 _set(
"adjustMarginLeft",
None)
1814 _set(
"adjustMarginRight",
None)
1817 _set(
"ratioYmin", [0, 0.2, 0.5, 0.7, 0.8, 0.9, 0.95])
1818 _set(
"ratioYmax", [1.05, 1.1, 1.2, 1.3, 1.5, 1.8, 2, 2.5, 3, 4, 5])
1819 _set(
"ratioFit",
None)
1820 _set(
"ratioUncertainty",
True)
1821 _set(
"ratioCoverageXrange",
None)
1823 _set(
"histogramModifier",
None)
1828 for name, value
in six.iteritems(kwargs):
1829 if not hasattr(self,
"_"+name):
1830 raise Exception(
"No attribute '%s'" % name)
1831 setattr(self,
"_"+name, value)
1835 raise Exception(
"Plot can be cloned only before histograms have been created")
1836 cl = copy.copy(self)
1837 cl.setProperties(**kwargs)
1841 """Return number of existing histograms.""" 1842 return len([h
for h
in self.
_histograms if h
is not None])
1845 """Return true if there are no histograms created for the plot""" 1850 if isinstance(h, ROOT.TGraph2D):
1855 if self._ratio
is None:
1857 return ratio
and self._ratio
1860 if self._outname
is not None:
1861 return self._outname
1862 if isinstance(self.
_name, list):
1868 """Return true if the ratio uncertainty should be drawn""" 1869 return self._ratioUncertainty
1872 """Create one histogram from a TDirectory.""" 1877 if isinstance(name, list):
1881 if h
is not None and self._normalizeToNumberOfEvents
and nevents
is not None and nevents != 0:
1882 h.Scale(1.0/nevents)
1885 def create(self, tdirNEvents, requireAllHistograms=False):
1886 """Create histograms from list of TDirectories""" 1887 self.
_histograms = [self.
_createOne(self.
_name, i, tdirNEvent[0], tdirNEvent[1])
for i, tdirNEvent
in enumerate(tdirNEvents)]
1889 if self._fallback
is not None:
1893 self.
_histograms[i] = self.
_createOne(self._fallback[
"name"], i, tdirNEvents[i][0], tdirNEvents[i][1])
1894 profileX[i] = self._fallback.get(
"profileX", self._profileX)
1896 if self._histogramModifier
is not None:
1900 raise Exception(
"More histograms (%d) than there are plot styles (%d) defined. Please define more plot styles in this file" % (len(self.
_histograms), len(_plotStylesColor)))
1905 def _modifyHisto(th1, profileX):
1910 th1 = th1.ProfileX()
1912 if self._fitSlicesY:
1913 ROOT.TH1.AddDirectory(
True)
1915 th1 = ROOT.gDirectory.Get(th1.GetName()+
"_2")
1916 th1.SetDirectory(
None)
1918 ROOT.TH1.AddDirectory(
False)
1920 if self._title
is not None:
1921 th1.SetTitle(self._title)
1923 if self._scale
is not None:
1924 th1.Scale(self._scale)
1928 if self._fallback
is not None:
1932 if requireAllHistograms
and None in self.
_histograms:
1936 """Set stats box.""" 1939 if h
is not None and hasattr(h,
"SetStats"):
1943 def _doStats(h, col, dy):
1948 if self._fit
and h.GetEntries() > 0.5:
1950 f = h.GetListOfFunctions().FindObject(
"gaus")
1958 st = h.GetListOfFunctions().FindObject(
"stats")
1962 st.SetX1NDC(startingX)
1963 st.SetX2NDC(startingX+0.3)
1964 st.SetY1NDC(startingY+dy)
1965 st.SetY2NDC(startingY+dy+0.15)
1966 st.SetTextColor(col)
1969 for i, h
in enumerate(histos):
1970 if self._statyadjust
is not None and i < len(self._statyadjust):
1971 dy += self._statyadjust[i]
1973 _doStats(h, _plotStylesColor[i], dy)
1977 """Normalise histograms to unit area""" 1985 if h.GetSumw2().fN <= 0:
1989 def draw(self, pad, ratio, ratioFactor, nrows):
1990 """Draw the histograms using values for a given algorithm.""" 2001 if self._normalizeToUnitArea:
2004 if self._rebinX
is not None:
2006 h.Rebin(self._rebinX)
2008 def _styleMarker(h, msty, col):
2009 h.SetMarkerStyle(msty)
2010 h.SetMarkerColor(col)
2011 h.SetMarkerSize(0.7)
2015 def _styleHist(h, msty, col):
2016 _styleMarker(h, msty, col)
2018 h.SetLineWidth(self._lineWidth)
2021 style = _styleMarker
2022 if "hist" in self._drawStyle.lower():
2025 if "l" in self._drawStyle.lower():
2033 style(h, _plotStylesMarker[i], _plotStylesColor[i])
2035 if len(histos) == 0:
2037 print "No histograms for plot {name}".
format(name=self.
getName())
2042 histosHaveBinLabels = len(histos[0].GetXaxis().GetBinLabel(1)) > 0
2043 xbinlabels = self._xbinlabels
2045 if xbinlabels
is None:
2046 if histosHaveBinLabels:
2048 if isinstance(histos[0], ROOT.TH2):
2057 if self._removeEmptyBins
and histosHaveBinLabels:
2060 if isinstance(histos[0], ROOT.TH2):
2065 if len(histos) == 0:
2067 print "No histograms with non-empty bins for plot {name}".
format(name=self.
getName())
2070 if self._printBins
and histosHaveBinLabels:
2071 print "####################" 2073 width =
max([len(l)
for l
in xbinlabels])
2074 tmp =
"%%-%ds " % width
2075 for b
in xrange(1, histos[0].GetNbinsX()+1):
2076 s = tmp % xbinlabels[b-1]
2078 s +=
"%.3f " % h.GetBinContent(b)
2083 xmin=self._xmin, xmax=self._xmax,
2084 ymin=self._ymin, ymax=self._ymax)
2086 if isinstance(histos[0], ROOT.TH2):
2087 zmax =
max([h.GetMaximum()
for h
in histos])
2095 ratioHistos = [h
for h
in [r.getRatio()
for r
in self.
_ratios[1:]]
if h
is not None]
2097 if len(ratioHistos) > 0:
2098 ratioBoundsY =
_findBoundsY(ratioHistos, ylog=
False, ymin=self._ratioYmin, ymax=self._ratioYmax, coverage=0.68, coverageRange=self._ratioCoverageXrange)
2100 ratioBoundsY = (0.9, 1,1)
2102 if self._ratioFit
is not None:
2103 for i, rh
in enumerate(ratioHistos):
2104 tf_line = ROOT.TF1(
"line%d"%i,
"[0]+x*[1]")
2105 tf_line.SetRange(self._ratioFit[
"rangemin"], self._ratioFit[
"rangemax"])
2106 fitres = rh.Fit(tf_line,
"RINSQ")
2107 tf_line.SetLineColor(rh.GetMarkerColor())
2108 tf_line.SetLineWidth(2)
2109 self._ratioAdditional.append(tf_line)
2110 box =
PlotTextBox(xmin=self._ratioFit.get(
"boxXmin", 0.14), ymin=
None,
2111 xmax=self._ratioFit.get(
"boxXmax", 0.35), ymax=self._ratioFit.get(
"boxYmax", 0.09),
2112 color=rh.GetMarkerColor(), font=43, size=11, lineheight=0.02)
2113 box.move(dx=(box.width()+0.01)*i)
2116 box.addText(
"Const: %.4f#pm%.4f" % (fitres.Parameter(0), fitres.ParError(0)))
2117 box.addText(
"Slope: %.4f#pm%.4f" % (fitres.Parameter(1), fitres.ParError(1)))
2118 self._mainAdditional.append(box)
2128 self.
_setStats(histos, self._statx, self._staty)
2132 frame =
FrameTGraph2D(pad, bounds, histos, ratioOrig, ratioFactor)
2135 ratioBounds = (bounds[0], ratioBoundsY[0], bounds[2], ratioBoundsY[1])
2136 frame =
FrameRatio(pad, bounds, zmax, ratioBounds, ratioFactor, nrows, xbinlabels, self._xbinlabelsize, self._xbinlabeloption)
2138 frame =
Frame(pad, bounds, zmax, nrows, xbinlabels, self._xbinlabelsize, self._xbinlabeloption, ybinlabels=ybinlabels)
2141 frame.setLogx(self._xlog)
2142 frame.setLogy(self._ylog)
2143 frame.setGridx(self._xgrid)
2144 frame.setGridy(self._ygrid)
2149 if self._drawStyle
is not None:
2150 ds = self._drawStyle
2151 if self._drawCommand
is not None:
2152 ds = self._drawCommand
2157 frame.setTitle(histos[0].GetTitle())
2158 if self._xtitle
is not None:
2159 frame.setXTitle(self._xtitle)
2160 if self._xtitlesize
is not None:
2161 frame.setXTitleSize(self._xtitlesize)
2162 if self._xtitleoffset
is not None:
2163 frame.setXTitleOffset(self._xtitleoffset)
2164 if self._xlabelsize
is not None:
2165 frame.setXLabelSize(self._xlabelsize)
2166 if self._ytitle
is not None:
2167 frame.setYTitle(self._ytitle)
2168 if self._ytitlesize
is not None:
2169 frame.setYTitleSize(self._ytitlesize)
2170 if self._ytitleoffset
is not None:
2171 frame.setYTitleOffset(self._ytitleoffset)
2172 if self._ztitle
is not None:
2173 frame.setZTitle(self._ztitle)
2174 if self._ztitleoffset
is not None:
2175 frame.setZTitleOffset(self._ztitleoffset)
2176 if self._adjustMarginLeft
is not None:
2177 frame.adjustMarginLeft(self._adjustMarginLeft)
2178 if self._adjustMarginRight
is not None:
2179 frame.adjustMarginRight(self._adjustMarginRight)
2181 frame.adjustMarginLeft(0.03)
2182 frame.adjustMarginRight(0.08)
2188 for i, h
in enumerate(histos):
2190 if isTGraph2D
and i == 0:
2191 o = o.replace(
"sames",
"")
2198 if ratio
and len(histos) > 0:
2199 frame._padRatio.cd()
2200 firstRatio = self.
_ratios[0].getRatio()
2201 if self._ratioUncertainty
and firstRatio
is not None:
2202 firstRatio.SetFillStyle(1001)
2203 firstRatio.SetFillColor(ROOT.kGray)
2204 firstRatio.SetLineColor(ROOT.kGray)
2205 firstRatio.SetMarkerColor(ROOT.kGray)
2206 firstRatio.SetMarkerSize(0)
2208 frame._padRatio.RedrawAxis(
"G")
2219 """Add histograms to a legend. 2223 legendLabels -- List of strings for the legend labels 2225 first = denomUncertainty
2232 self._forLegend.SetFillStyle(1001)
2233 self._forLegend.SetFillColor(ROOT.kGray)
2234 entry = legend.AddEntry(self.
_forLegend, label,
"lpf")
2237 legend.AddEntry(h, label,
"LP")
2240 """Group of plots, results a TCanvas""" 2245 name -- String for name of the TCanvas, used also as the basename of the picture files 2246 plots -- List of Plot objects 2249 ncols -- Number of columns (default 2) 2250 legendDx -- Float for moving TLegend in x direction (default None) 2251 legendDy -- Float for moving TLegend in y direction (default None) 2252 legendDw -- Float for changing TLegend width (default None) 2253 legendDh -- Float for changing TLegend height (default None) 2254 legend -- Bool for disabling legend (default True for legend being enabled) 2255 overrideLegendLabels -- List of strings for legend labels, if given, these are used instead of the ones coming from Plotter (default None) 2256 onlyForPileup -- Plots this group only for pileup samples 2263 def _set(attr, default):
2264 setattr(self,
"_"+attr, kwargs.get(attr, default))
2268 _set(
"legendDx",
None)
2269 _set(
"legendDy",
None)
2270 _set(
"legendDw",
None)
2271 _set(
"legendDh",
None)
2272 _set(
"legend",
True)
2274 _set(
"overrideLegendLabels",
None)
2276 _set(
"onlyForPileup",
False)
2281 for name, value
in six.iteritems(kwargs):
2282 if not hasattr(self,
"_"+name):
2283 raise Exception(
"No attribute '%s'" % name)
2284 setattr(self,
"_"+name, value)
2293 for i, plot
in enumerate(self.
_plots):
2294 if plot.getName() == name:
2297 raise Exception(
"Did not find Plot '%s' from PlotGroup '%s'" % (name, self.
_name))
2303 self._plots.append(plot)
2307 if plot.getName() == name:
2309 raise Exception(
"No Plot named '%s'" % name)
2312 """Return True if the PlotGroup is intended only for pileup samples""" 2313 return self._onlyForPileup
2315 def create(self, tdirectoryNEvents, requireAllHistograms=False):
2316 """Create histograms from a list of TDirectories. 2319 tdirectoryNEvents -- List of (TDirectory, nevents) pairs 2320 requireAllHistograms -- If True, a plot is produced if histograms from all files are present (default: False) 2323 plot.create(tdirectoryNEvents, requireAllHistograms)
2325 def draw(self, legendLabels, prefix=None, separate=False, saveFormat=".pdf", ratio=True, directory=""):
2326 """Draw the histograms using values for a given algorithm. 2329 legendLabels -- List of strings for legend labels (corresponding to the tdirectories in create()) 2330 prefix -- Optional string for file name prefix (default None) 2331 separate -- Save the plots of a group to separate files instead of a file per group (default False) 2332 saveFormat -- String specifying the plot format (default '.pdf') 2333 ratio -- Add ratio to the plot (default True) 2334 directory -- Directory where to save the file (default "") 2337 if self._overrideLegendLabels
is not None:
2338 legendLabels = self._overrideLegendLabels
2341 onlyEmptyPlots =
True 2343 if not plot.isEmpty():
2344 onlyEmptyPlots =
False 2350 return self.
_drawSeparate(legendLabels, prefix, saveFormat, ratio, directory)
2352 cwidth = 500*self._ncols
2353 nrows =
int((len(self.
_plots)+self._ncols-1)/self._ncols)
2354 cheight = 500 * nrows
2361 canvas.Divide(self._ncols, nrows)
2363 for i, plot
in enumerate(self.
_plots):
2364 pad = canvas.cd(i+1)
2368 for i, plot
in enumerate(self.
_plots):
2369 pad = canvas.cd(i+1)
2370 if not plot.isEmpty():
2375 if len(self.
_plots) <= 4:
2385 if self._legendDx
is not None:
2386 lx1 += self._legendDx
2387 lx2 += self._legendDx
2388 if self._legendDy
is not None:
2389 ly1 += self._legendDy
2390 ly2 += self._legendDy
2391 if self._legendDw
is not None:
2392 lx2 += self._legendDw
2393 if self._legendDh
is not None:
2394 ly1 -= self._legendDh
2395 plot =
max(self.
_plots, key=
lambda p: p.getNumberOfHistograms())
2396 denomUnc = sum([p.drawRatioUncertainty()
for p
in self.
_plots]) > 0
2397 legend = self.
_createLegend(plot, legendLabels, lx1, ly1, lx2, ly2,
2398 denomUncertainty=(ratio
and denomUnc))
2400 return self.
_save(canvas, saveFormat, prefix=prefix, directory=directory)
2403 """Internal method to do the drawing to separate files per Plot instead of a file per PlotGroup""" 2411 for c
in [canvas, canvasRatio]:
2412 c.SetTopMargin(0.05)
2413 c.SetBottomMargin(0.13)
2414 c.SetLeftMargin(0.16)
2415 c.SetRightMargin(0.05)
2428 ratioForThisPlot = plot.isRatio(ratio)
2430 if ratioForThisPlot:
2446 if plot._legendDx
is not None:
2447 lx1 += plot._legendDx
2448 lx2 += plot._legendDx
2449 if plot._legendDy
is not None:
2450 ly1 += plot._legendDy
2451 ly2 += plot._legendDy
2452 if plot._legendDw
is not None:
2453 lx2 += plot._legendDw
2454 if plot._legendDh
is not None:
2455 ly1 -= plot._legendDh
2458 legend = self.
_createLegend(plot, legendLabels, lx1, ly1, lx2, ly2, textSize=0.03,
2459 denomUncertainty=(ratioForThisPlot
and plot.drawRatioUncertainty))
2461 ret.extend(self.
_save(c, saveFormat, prefix=prefix, postfix=
"_"+plot.getName(), single=
True, directory=directory))
2465 """Internal method to set divide a pad to two for ratio plots""" 2468 def _createLegend(self, plot, legendLabels, lx1, ly1, lx2, ly2, textSize=0.016, denomUncertainty=True):
2469 if not self._legend:
2472 l = ROOT.TLegend(lx1, ly1, lx2, ly2)
2473 l.SetTextSize(textSize)
2480 plot.addToLegend(l, legendLabels, denomUncertainty)
2484 def _save(self, canvas, saveFormat, prefix=None, postfix=None, single=False, directory=""):
2487 if prefix
is not None:
2489 if postfix
is not None:
2491 name = os.path.join(directory, name)
2494 backup = ROOT.gErrorIgnoreLevel
2495 ROOT.gErrorIgnoreLevel = ROOT.kWarning
2496 canvas.SaveAs(name+saveFormat)
2498 ROOT.gErrorIgnoreLevel = backup
2502 canvas.SetLogx(
False)
2503 canvas.SetLogy(
False)
2507 return [name+saveFormat]
2510 """Resembles DQM GUI's "On side" layout. 2512 Like PlotGroup, but has only a description of a single plot. The 2513 plot is drawn separately for each file. Useful for 2D histograms.""" 2515 def __init__(self, name, plot, ncols=2, onlyForPileup=False):
2516 super(PlotOnSideGroup, self).
__init__(name, [], ncols=ncols, legend=
False, onlyForPileup=onlyForPileup)
2518 self._plot.setProperties(ratio=
False)
2521 raise Exception(
"PlotOnSideGroup.append() is not implemented")
2523 def create(self, tdirectoryNEvents, requireAllHistograms=False):
2525 for element
in tdirectoryNEvents:
2526 pl = self._plot.clone()
2527 pl.create([element], requireAllHistograms)
2528 self._plots.append(pl)
2531 kargs = copy.copy(kwargs)
2532 kargs[
"ratio"] =
False 2533 return super(PlotOnSideGroup, self).
draw(*args, **kargs)
2537 """Represents a collection of PlotGroups, produced from a single folder in a DQM file""" 2542 plotGroups -- List of PlotGroup objects 2545 loopSubFolders -- Should the subfolders be looped over? (default: True) 2546 onlyForPileup -- Plots this folder only for pileup samples 2547 onlyForElectron -- Plots this folder only for electron samples 2548 onlyForConversion -- Plots this folder only for conversion samples 2549 onlyForBHadron -- Plots this folder only for B-hadron samples 2550 purpose -- html.PlotPurpose member class for the purpose of the folder, used for grouping of the plots to the HTML pages 2551 page -- Optional string for the page in HTML generatin 2552 section -- Optional string for the section within a page in HTML generation 2553 numberOfEventsHistogram -- Optional path to histogram filled once per event. Needed if there are any plots normalized by number of events. Path is relative to "possibleDqmFolders". 2566 raise Exception(
"Got unexpected keyword arguments: "+
",".
join(kwargs.keys()))
2569 """Return True if the PlotGroups of this folder should be applied to the all subfolders""" 2573 """Return True if the folder is intended only for pileup samples""" 2598 self._plotGroups.append(plotGroup)
2608 if pg.getName() == name:
2610 raise Exception(
"No PlotGroup named '%s'" % name)
2612 def create(self, dirsNEvents, labels, isPileupSample=True, requireAllHistograms=False):
2613 """Create histograms from a list of TFiles. 2616 dirsNEvents -- List of (TDirectory, nevents) pairs 2617 labels -- List of strings for legend labels corresponding the files 2618 isPileupSample -- Is sample pileup (some PlotGroups may limit themselves to pileup) 2619 requireAllHistograms -- If True, a plot is produced if histograms from all files are present (default: False) 2622 if len(dirsNEvents) != len(labels):
2623 raise Exception(
"len(dirsNEvents) should be len(labels), now they are %d and %d" % (len(dirsNEvents), len(labels)))
2628 if pg.onlyForPileup()
and not isPileupSample:
2630 pg.create(dirsNEvents, requireAllHistograms)
2632 def draw(self, prefix=None, separate=False, saveFormat=".pdf", ratio=True, directory=""):
2633 """Draw and save all plots using settings of a given algorithm. 2636 prefix -- Optional string for file name prefix (default None) 2637 separate -- Save the plots of a group to separate files instead of a file per group (default False) 2638 saveFormat -- String specifying the plot format (default '.pdf') 2639 ratio -- Add ratio to the plot (default True) 2640 directory -- Directory where to save the file (default "") 2645 ret.extend(pg.draw(self.
_labels, prefix=prefix, separate=separate, saveFormat=saveFormat, ratio=ratio, directory=directory))
2651 """Method called to (possibly) translate a subfolder name to more 'readable' form 2653 The implementation in this (base) class just returns the 2654 argument. The idea is that a deriving class might want to do 2655 something more complex (like trackingPlots.TrackingPlotFolder 2658 return dqmSubFolderName
2661 """Iterate over possible selections name (used in output directory name and legend) from the name of PlotterFolder, and a return value of translateSubFolder""" 2663 if plotFolderName !=
"":
2664 ret +=
"_"+plotFolderName
2665 if translatedDqmSubFolder
is not None:
2666 ret +=
"_"+translatedDqmSubFolder
2670 """Return True if this subfolder should be processed 2673 limitOnlyTo -- List/set/similar containing the translatedDqmSubFolder 2674 translatedDqmSubFolder -- Return value of translateSubFolder 2676 return translatedDqmSubFolder
in limitOnlyTo
2679 """Class to hold the original name and a 'translated' name of a subfolder in the DQM ROOT file""" 2685 """Equality is defined by the 'translated' name""" 2689 """Plotter for one DQM folder. 2691 This class is supposed to be instantiated by the Plotter class (or 2692 PlotterItem, to be more specific), and not used directly by the 2695 def __init__(self, name, possibleDqmFolders, dqmSubFolders, plotFolder, fallbackNames, fallbackDqmSubFolders, tableCreators):
2700 name -- Name of the folder (is used in the output directory naming) 2701 possibleDqmFolders -- List of strings for possible directories of histograms in TFiles 2702 dqmSubFolders -- List of lists of strings for list of subfolders per input file, or None if no subfolders 2703 plotFolder -- PlotFolder object 2704 fallbackNames -- List of names for backward compatibility (can be empty). These are used only by validation.Validation (class responsible of the release validation workflow) in case the reference file pointed by 'name' does not exist. 2705 fallbackDqmSubFolders -- List of dicts of (string->string) for mapping the subfolder names found in the first file to another names. Use case is comparing files that have different iteration naming convention. 2706 tableCreators -- List of PlotterTableItem objects for tables to be created from this folder 2712 if dqmSubFolders
is None:
2718 for sf_list
in dqmSubFolders:
2720 sf_translated = self._plotFolder.translateSubFolder(sf)
2721 if sf_translated
is not None and not sf_translated
in subfolders:
2722 subfolders[sf_translated] =
DQMSubFolder(sf, sf_translated)
2725 self._dqmSubFolders.sort(key=
lambda sf: sf.subfolder)
2735 return self._plotFolder.getPurpose()
2738 return self._plotFolder.getPage()
2741 return self._plotFolder.getSection()
2744 return self._plotFolder.onlyForPileup()
2747 return self._plotFolder.onlyForElectron()
2750 return self._plotFolder.onlyForConversion()
2753 return self._plotFolder.onlyForBHadron()
2759 """Get list of subfolders, possibly limiting to some of them. 2762 limitOnlyTo -- Object depending on the PlotFolder type for limiting the set of subfolders to be processed 2768 if limitOnlyTo
is None:
2771 return [s
for s
in self.
_dqmSubFolders if self._plotFolder.limitSubFolder(limitOnlyTo, s.translated)]
2777 """Get a generator for the 'selection name', looping over the name and fallbackNames""" 2779 for selname
in self._plotFolder.iterSelectionName(name, dqmSubFolder.translated
if dqmSubFolder
is not None else None):
2785 def create(self, files, labels, dqmSubFolder, isPileupSample=True, requireAllHistograms=False):
2786 """Create histograms from a list of TFiles. 2788 files -- List of TFiles 2789 labels -- List of strings for legend labels corresponding the files 2790 dqmSubFolder -- DQMSubFolder object for a subfolder (or None for no subfolder) 2791 isPileupSample -- Is sample pileup (some PlotGroups may limit themselves to pileup) 2792 requireAllHistograms -- If True, a plot is produced if histograms from all files are present (default: False) 2795 subfolder = dqmSubFolder.subfolder
if dqmSubFolder
is not None else None 2796 neventsHisto = self._plotFolder.getNumberOfEventsHistogram()
2804 fallback = fallbackFunc(subfolder)
2805 if fallback
is not None:
2809 d = GetDirectoryCode.codesToNone(ret)
2811 if neventsHisto
is not None and tfile
is not None:
2813 if hnev
is not None:
2814 nev = hnev.GetEntries()
2815 dirsNEvents.append( (d, nev) )
2817 self._plotFolder.create(dirsNEvents, labels, isPileupSample, requireAllHistograms)
2820 """Draw and save all plots using settings of a given algorithm.""" 2821 return self._plotFolder.draw(*args, **kwargs)
2825 """Instance of plotter that knows the directory content, holds many folders.""" 2832 if limitSubFoldersOnlyTo
is not None:
2833 limitOnlyTo = limitSubFoldersOnlyTo.get(plotterFolder.getName(),
None)
2835 for dqmSubFolder
in plotterFolder.getDQMSubFolders(limitOnlyTo=limitOnlyTo):
2836 yield plotterFolder, dqmSubFolder
2840 def __init__(self, name, possibleDirs, plotFolder, fallbackNames=[], fallbackDqmSubFolders=[]):
2844 name -- Name of the folder (is used in the output directory naming) 2845 possibleDirs -- List of strings for possible directories of histograms in TFiles 2846 plotFolder -- PlotFolder object 2849 fallbackNames -- Optional list of names for backward compatibility. These are used only by validation.Validation (class responsible of the release validation workflow) in case the reference file pointed by 'name' does not exist. 2850 fallbackDqmSubFolders -- Optional list of functions for (string->string) mapping the subfolder names found in the first file to another names (function should return None for no mapping). Use case is comparing files that have different iteration naming convention. 2866 self._tableCreators.append(tc)
2869 """Read available subfolders from the files 2872 files -- List of strings for paths to files, or list of TFiles 2874 For each file, loop over 'possibleDirs', and read the 2875 subfolders of first one that exists. 2877 Returns a PlotterFolder if at least one file for which one of 2878 'possibleDirs' exists. Otherwise, return None to signal that 2879 there is nothing available for this PlotFolder. 2882 if self._plotFolder.loopSubFolders():
2884 possibleDirFound =
False 2889 isOpenFile = isinstance(fname, ROOT.TFile)
2893 tfile = ROOT.TFile.Open(fname)
2897 possibleDirFound =
True 2898 if subFolders
is not None:
2900 for key
in d.GetListOfKeys():
2901 if isinstance(key.ReadObj(), ROOT.TDirectory):
2902 subf.append(key.GetName())
2903 subFolders.append(subf)
2909 if not possibleDirFound:
2919 def create(self, openFiles, legendLabels, dqmSubFolder):
2920 if isinstance(dqmSubFolder, list):
2921 if len(dqmSubFolder) != len(openFiles):
2922 raise Exception(
"When dqmSubFolder is a list, len(dqmSubFolder) should be len(openFiles), now they are %d and %d" % (len(dqmSubFolder), len(openFiles)))
2924 dqmSubFolder = [dqmSubFolder]*len(openFiles)
2925 dqmSubFolder = [sf.subfolder
if sf
is not None else None for sf
in dqmSubFolder]
2928 for f, sf
in zip(openFiles, dqmSubFolder):
2931 if tdir
is not None:
2932 data = self._tableCreator.create(tdir)
2947 for i
in xrange(len(tbl)):
2949 tbl[i] = [
None]*colLen
2951 return html.Table(columnHeaders=legendLabels, rowHeaders=self._tableCreator.headers(), table=tbl,
2952 purpose=self._tableCreator.getPurpose(), page=self._tableCreator.getPage(), section=self._tableCreator.getSection(dqmSubFolder[0]))
2955 """Contains PlotFolders, i.e. the information what plots to do, and creates a helper object to actually produce the plots.""" 2959 ROOT.TH1.AddDirectory(
False)
2962 """Append a plot folder to the plotter. 2964 All arguments are forwarded to the constructor of PlotterItem. 2969 for plotterItem
in self.
_plots:
2970 if plotterItem.getName() == attachToFolder:
2973 raise Exception(
"Did not find plot folder '%s' when trying to attach a table creator to it" % attachToFolder)
2976 """Remove all plot folders and tables""" 2980 return [item.getName()
for item
in self.
_plots]
2983 return [item.getPlotFolder()
for item
in self.
_plots]
2987 if item.getName() == name:
2988 return item.getPlotFolder()
2989 raise Exception(
"No PlotFolder named '%s'" % name)
2992 """Returns PlotterInstance object, which knows how exactly to produce the plots for these files"""
def create(self, tdirectory)
def iterSelectionName(self, plotFolderName, translatedDqmSubFolder)
def __init__(self, x, y, text, size=None, bold=True, align="left", color=ROOT.kBlack, font=None)
def append(self, plotGroup)
def _getYmax(obj, limitToNonZeroContent=False)
def __init__(self, name, plots, kwargs)
def __init__(self, name, nameA, nameB, title="")
def getPossibleDQMFolders(self)
def adjustMarginLeft(self, adjust)
def _findBoundsY(th1s, ylog, ymin=None, ymax=None, coverage=None, coverageRange=None)
def set(self, plotGroups)
def setXTitle(self, title)
def readDirs(self, files)
def draw(self, legendLabels, prefix=None, separate=False, saveFormat=".pdf", ratio=True, directory="")
def setXLabelSize(self, size)
def _drawFrame(pad, bounds, zmax=None, xbinlabels=None, xbinlabelsize=None, xbinlabeloption=None, ybinlabels=None, suffix="")
def _getOrCreateObject(tdirectory, nameOrCreator)
def iterFolders(self, limitSubFoldersOnlyTo=None)
def setYTitleSize(self, size)
def setXLabelSize(self, size)
def _findBounds(th1s, ylog, xmin=None, xmax=None, ymin=None, ymax=None)
def _modifyPadForRatio(self, pad)
def Draw(self, options="")
def __init__(self, name, xhistoName, yhistoName, zaxis=False)
def adjustMarginRight(self, adjust)
def __init__(self, possibleDirs, tableCreator)
def getTableCreators(self)
def __init__(self, xmin, ymin, xmax, ymax, lineheight=0.04, fillColor=ROOT.kWhite, transparent=True, kwargs)
def _getYmin(obj, limitToNonZeroContent=False)
def create(self, args, kwargs)
def setXTitleSize(self, size)
def create(self, tdirectory)
def adjustMarginLeft(self, adjust)
def setXLabelSize(self, size)
def _getYminIgnoreOutlier(th1)
def append(self, args, kwargs)
def getDQMSubFolders(self, limitOnlyTo=None)
def _getXmax(obj, limitToNonZeroContent=False)
def __init__(self, pad, bounds, zmax, nrows, xbinlabels=None, xbinlabelsize=None, xbinlabeloption=None, ybinlabels=None)
def drawRatioUncertainty(self)
def setZTitle(self, title)
def __init__(self, pad, bounds, histos, ratioOrig, ratioFactor)
def setZTitleOffset(self, offset)
def setXTitleSize(self, size)
def __init__(self, pad, bounds, zmax, ratioBounds, ratioFactor, nrows, xbinlabels=None, xbinlabelsize=None, xbinlabeloption=None, ratioYTitle=_ratioYTitle)
def getNumberOfHistograms(self)
def create(self, tdirectoryNEvents, requireAllHistograms=False)
bool equal(const T &first, const T &second)
def move(self, dx=0, dy=0, dw=0, dh=0)
def __init__(self, name, kwargs)
def create(self, openFiles, legendLabels, dqmSubFolder)
def _calculateRatios(histos, ratioUncertainty=False)
def appendTable(self, attachToFolder, args, kwargs)
def setYTitleOffset(self, offset)
def setYTitle(self, title)
def _save(self, canvas, saveFormat, prefix=None, postfix=None, single=False, directory="")
def setYTitleSize(self, size)
def onlyForElectron(self)
def draw(name, histos, styles=_defaultStyles, legendLabels=[], kwargs)
def _setStats(self, histos, startingX, startingY)
def getSelectionName(self, dqmSubFolder)
def _getDirectory(args, kwargs)
def setYTitle(self, title)
def Draw(self, options=None)
def draw(self, pad, ratio, ratioFactor, nrows)
OutputIterator zip(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result, Compare comp)
def setTitle(self, title)
def setXTitle(self, title)
def create(self, tdirectory)
def readDirs(self, files)
def _mergeBinLabelsY(histos)
Abs< T >::type abs(const T &t)
def adjustMarginRight(self, adjust)
def adjustMarginLeft(self, adjust)
def setProperties(self, kwargs)
def addToLegend(self, legend, legendLabels, denomUncertainty)
def _getYmaxWithError(th1)
def setXTitleOffset(self, offset)
def _getDirectoryDetailed(tfile, possibleDirs, subDir=None)
def setXTitleOffset(self, size)
def draw(self, args, kwargs)
def create(self, tdirectory)
def onlyForConversion(self)
def _getYminMaxAroundMedian(obj, coverage, coverageRange=None)
def getPlotFolder(self, name)
def setYTitleOffset(self, offset)
def __init__(self, name, histo, title="")
def onlyForConversion(self)
def limitSubFolder(self, limitOnlyTo, translatedDqmSubFolder)
def setXTitleSize(self, size)
def setYTitleRatio(self, title)
def drawRatioUncertainty(self)
static std::string join(char **cmd)
def create(self, dirsNEvents, labels, isPileupSample=True, requireAllHistograms=False)
def getNumberOfHistograms(self)
def __init__(self, name, assoc, dup, reco, title="")
void divide(MonitorElement *eff, const MonitorElement *numerator, const MonitorElement *denominator)
Function to fill an efficiency histograms with binomial errors.
def adjustMarginRight(self, adjust)
def __init__(self, subfolder, translated)
def create(self, tdirectory)
def setXTitleOffset(self, offset)
def __init__(self, name, histoName, mapping, normalizeTo=None, scale=None, renameBin=None, ignoreMissingBins=False, minExistingBins=None, originalOrder=False, reorder=None)
def __init__(self, name, mapping, normalizeTo=None)
def _createLegend(self, plot, legendLabels, lx1, ly1, lx2, ly2, textSize=0.016, denomUncertainty=True)
def translateSubFolder(self, dqmSubFolderName)
def _drawSeparate(self, legendLabels, prefix, saveFormat, ratio, directory)
def __init__(self, folders)
def setTitle(self, title)
def __init__(self, name, possibleDqmFolders, dqmSubFolders, plotFolder, fallbackNames, fallbackDqmSubFolders, tableCreators)
def setXTitle(self, title)
def setYTitleSize(self, size)
def setYTitle(self, title)
def _th1RemoveEmptyBins(histos, xbinlabels)
def _getXmin(obj, limitToNonZeroContent=False)
def onlyForElectron(self)
def append(self, args, kwargs)
def create(self, tdirNEvents, requireAllHistograms=False)
def getPlotGroup(self, name)
def appendTableCreator(self, tc)
def _modifyPadForRatio(pad, ratioFactor)
def create(self, files, labels, dqmSubFolder, isPileupSample=True, requireAllHistograms=False)
def create(self, tdirectoryNEvents, requireAllHistograms=False)
def _createCanvas(name, width, height)
def setYTitleOffset(self, offset)
auto wrap(F iFunc) -> decltype(iFunc())
def __init__(self, name, plot, ncols=2, onlyForPileup=False)
def getPlotFolderNames(self)
def getNumberOfEventsHistogram(self)
def _mergeBinLabels(labelsAll)
def __init__(self, plotGroups, kwargs)
def draw(self, args, kwargs)
def _th1ToOrderedDict(th1, renameBin=None)
def _th2RemoveEmptyBins(histos, xbinlabels, ybinlabels)
def getSelectionNameIterator(self, dqmSubFolder)
def create(self, tdirectory)
def setProperties(self, kwargs)
def _mergeBinLabelsX(histos)
def _createOne(self, name, index, tdir, nevents)
def draw(self, prefix=None, separate=False, saveFormat=".pdf", ratio=True, directory="")
How EventSelector::AcceptEvent() decides whether to accept an event for output otherwise it is excluding the probing of A single or multiple positive and the trigger will pass if any such matching triggers are PASS or EXCEPTION[A criterion thatmatches no triggers at all is detected and causes a throw.] A single negative with an expectation of appropriate bit checking in the decision and the trigger will pass if any such matching triggers are FAIL or EXCEPTION A wildcarded negative criterion that matches more than one trigger in the trigger list("!*","!HLTx*"if it matches 2 triggers or more) will accept the event if all the matching triggers are FAIL.It will reject the event if any of the triggers are PASS or EXCEPTION(this matches the behavior of"!*"before the partial wildcard feature was incorporated).Triggers which are in the READY state are completely ignored.(READY should never be returned since the trigger paths have been run
def setTitle(self, title)
def _th1IncludeOnlyBins(histos, xbinlabels)
def __init__(self, name, possibleDirs, plotFolder, fallbackNames=[], fallbackDqmSubFolders=[])
def _getObject(tdirectory, name)