1 from __future__
import print_function
2 from __future__
import absolute_import
3 from builtins
import range
13 ROOT.gROOT.SetBatch(
True)
14 ROOT.PyConfig.IgnoreCommandLineOptions =
True 19 _ratioYTitle =
"Ratio" 34 ROOT.gROOT.SetStyle(
"Plain")
35 ROOT.gStyle.SetPadRightMargin(0.07)
36 ROOT.gStyle.SetPadLeftMargin(0.13)
37 ROOT.gStyle.SetTitleFont(font,
"XYZ")
38 ROOT.gStyle.SetTitleSize(titleSize,
"XYZ")
39 ROOT.gStyle.SetTitleOffset(1.2,
"Y")
41 ROOT.gStyle.SetLabelFont(font,
"XYZ")
42 ROOT.gStyle.SetLabelSize(labelSize,
"XYZ")
43 ROOT.gStyle.SetTextSize(labelSize)
44 ROOT.gStyle.SetStatFont(font)
45 ROOT.gStyle.SetStatFontSize(statSize)
47 ROOT.TGaxis.SetMaxDigits(4)
50 obj = tdirectory.Get(name)
53 print(
"Did not find {obj} from {dir}".
format(obj=name, dir=tdirectory.GetPath()))
58 if hasattr(nameOrCreator,
"create"):
59 return nameOrCreator.create(tdirectory)
74 """Get TDirectory from TFile.""" 77 for pdf
in possibleDirs:
80 if subDir
is not None:
87 print(
"Did not find subdirectory '%s' from directory '%s' in file %s" % (subDir, pdf, tfile.GetName()))
94 print(
"Did not find any of directories '%s' from file %s" % (
",".
join(possibleDirs), tfile.GetName()))
101 values = collections.OrderedDict()
102 for i
in range(1, th1.GetNbinsX()+1):
103 binLabel = th1.GetXaxis().GetBinLabel(i)
104 if renameBin
is not None:
105 binLabel = renameBin(binLabel)
106 values[binLabel] = (th1.GetBinContent(i), th1.GetBinError(i))
112 backup = ROOT.gErrorIgnoreLevel
113 ROOT.gErrorIgnoreLevel = ROOT.kError
114 canvas = ROOT.TCanvas(name, name, width, height)
116 ROOT.gErrorIgnoreLevel = backup
122 divisionPoint = 1-1/ratioFactor
124 topMargin = pad.GetTopMargin()
125 bottomMargin = pad.GetBottomMargin()
126 divisionPoint += (1-divisionPoint)*bottomMargin
127 divisionPointForPad1 = 1-( (1-divisionPoint) / (1-0.02) )
132 ylow = divisionPointForPad1
135 pad1.SetPad(xlow, ylow, xup, yup)
136 pad1.SetFillStyle(4000)
137 pad1.SetBottomMargin(0.02)
143 pad2.SetPad(xlow, ylow, xup, yup)
144 pad2.SetFillStyle(4000)
145 pad2.SetTopMargin(0.0)
146 pad2.SetBottomMargin(bottomMargin/(ratioFactor*divisionPoint))
149 """Calculate the ratios for a list of histograms""" 151 def _divideOrZero(numerator, denominator):
154 return numerator/denominator
157 if a == 0.
and b == 0.:
161 def findBins(wrap, bins_xvalues):
163 currBin = wrap.begin()
165 while i < len(bins_xvalues)
and currBin < wrap.end():
166 (xcenter, xlow, xhigh) = bins_xvalues[i]
167 xlowEdge = xcenter-xlow
168 xupEdge = xcenter+xhigh
170 (curr_center, curr_low, curr_high) = wrap.xvalues(currBin)
171 curr_lowEdge = curr_center-curr_low
172 curr_upEdge = curr_center+curr_high
174 if equal(xlowEdge, curr_lowEdge)
and equal(xupEdge, curr_upEdge):
178 elif curr_upEdge <= xlowEdge:
180 elif curr_lowEdge >= xupEdge:
187 if len(ret) != len(bins_xvalues):
188 ret.extend([
None]*( len(bins_xvalues) - len(ret) ))
194 def __init__(self, th1, uncertainty):
196 self._uncertainty = uncertainty
198 xaxis = th1.GetXaxis()
199 xaxis_arr = xaxis.GetXbins()
200 if xaxis_arr.GetSize() > 0:
201 lst = [xaxis_arr[i]
for i
in range(0, xaxis_arr.GetSize())]
202 arr = array.array(
"d", lst)
203 self._ratio = ROOT.TH1F(
"foo",
"foo", xaxis.GetNbins(), arr)
205 self._ratio = ROOT.TH1F(
"foo",
"foo", xaxis.GetNbins(), xaxis.GetXmin(), xaxis.GetXmax())
207 self._ratio.SetStats(0)
208 self._ratio.SetLineColor(ROOT.kBlack)
209 self._ratio.SetLineWidth(1)
210 def draw(self, style=None):
213 if self._uncertainty:
217 self._ratio.Draw(
"same "+st)
221 return self._th1.GetNbinsX()+1
222 def xvalues(self, bin):
223 xval = self._th1.GetBinCenter(bin)
224 xlow = xval-self._th1.GetXaxis().GetBinLowEdge(bin)
225 xhigh = self._th1.GetXaxis().GetBinUpEdge(bin)-xval
226 return (xval, xlow, xhigh)
227 def yvalues(self, bin):
228 yval = self._th1.GetBinContent(bin)
229 yerr = self._th1.GetBinError(bin)
230 return (yval, yerr, yerr)
232 return self._th1.GetBinContent(bin)
233 def divide(self, bin, scale):
234 self._ratio.SetBinContent(bin, _divideOrZero(self._th1.GetBinContent(bin), scale))
235 self._ratio.SetBinError(bin, _divideOrZero(self._th1.GetBinError(bin), scale))
242 def __init__(self, gr, uncertainty):
244 self._uncertainty = uncertainty
251 def draw(self, style=None):
252 if self._ratio
is None:
256 if self._uncertainty:
260 self._ratio.Draw(
"same "+st)
264 return self._gr.GetN()
265 def xvalues(self, bin):
266 return (self._gr.GetX()[bin], self._gr.GetErrorXlow(bin), self._gr.GetErrorXhigh(bin))
267 def yvalues(self, bin):
268 return (self._gr.GetY()[bin], self._gr.GetErrorYlow(bin), self._gr.GetErrorYhigh(bin))
270 return self._gr.GetY()[bin]
271 def divide(self, bin, scale):
276 if bin >= self._gr.GetN():
279 xvals = self.xvalues(bin)
282 self._xvalues.
append(xval)
283 self._xerrslow.
append(xvals[1])
284 self._xerrshigh.
append(xvals[2])
285 yvals = self.yvalues(bin)
286 self._yvalues.
append(yvals[0] / scale)
287 if self._uncertainty:
288 self._yerrslow.
append(yvals[1] / scale)
289 self._yerrshigh.
append(yvals[2] / scale)
294 if len(self._xvalues) == 0:
297 self._ratio = ROOT.TGraphAsymmErrors(len(self._xvalues), array.array(
"d", self._xvalues), array.array(
"d", self._yvalues),
298 array.array(
"d", self._xerrslow), array.array(
"d", self._xerrshigh),
299 array.array(
"d", self._yerrslow), array.array(
"d", self._yerrshigh))
303 class WrapTGraph2D(WrapTGraph):
304 def __init__(self, gr, uncertainty):
305 WrapTGraph.__init__(self, gr, uncertainty)
306 def xvalues(self, bin):
307 return (self._gr.GetX()[bin], self._gr.GetErrorX(bin), self._gr.GetErrorX(bin))
308 def yvalues(self, bin):
309 return (self._gr.GetY()[bin], self._gr.GetErrorY(bin), self._gr.GetErrorY(bin))
312 if isinstance(o, ROOT.TH1)
and not isinstance(o, ROOT.TH2):
313 return WrapTH1(o, ratioUncertainty)
314 elif isinstance(o, ROOT.TGraph):
315 return WrapTGraph(o, ratioUncertainty)
316 elif isinstance(o, ROOT.TGraph2D):
317 return WrapTGraph2D(o, ratioUncertainty)
319 wrappers = [
wrap(h)
for h
in histos
if wrap(h)
is not None]
320 if len(wrappers) < 1:
325 ref_bins = [ref.xvalues(b)
for b
in range(ref.begin(), ref.end())]
327 wrappers_bins.append(findBins(w, ref_bins))
329 for i, bin
in enumerate(
range(ref.begin(), ref.end())):
330 (scale, ylow, yhigh) = ref.yvalues(bin)
331 for w, bins
in zip(wrappers, wrappers_bins):
334 w.divide(bins[i], scale)
343 if isinstance(obj, ROOT.TH1):
344 xaxis = obj.GetXaxis()
345 if limitToNonZeroContent:
346 for i
in range(1, obj.GetNbinsX()+1):
347 if obj.GetBinContent(i) != 0:
348 return xaxis.GetBinLowEdge(i)
352 return xaxis.GetBinLowEdge(xaxis.GetFirst())
353 elif isinstance(obj, ROOT.TGraph)
or isinstance(obj, ROOT.TGraph2D):
354 m =
min([obj.GetX()[i]
for i
in range(0, obj.GetN())])
355 return m*0.9
if m > 0
else m*1.1
359 if isinstance(obj, ROOT.TH1):
360 xaxis = obj.GetXaxis()
361 if limitToNonZeroContent:
362 for i
in range(obj.GetNbinsX(), 0, -1):
363 if obj.GetBinContent(i) != 0:
364 return xaxis.GetBinUpEdge(i)
368 return xaxis.GetBinUpEdge(xaxis.GetLast())
369 elif isinstance(obj, ROOT.TGraph)
or isinstance(obj, ROOT.TGraph2D):
370 m =
max([obj.GetX()[i]
for i
in range(0, obj.GetN())])
371 return m*1.1
if m > 0
else m*0.9
375 if isinstance(obj, ROOT.TH2):
376 yaxis = obj.GetYaxis()
377 return yaxis.GetBinLowEdge(yaxis.GetFirst())
378 elif isinstance(obj, ROOT.TH1):
379 if limitToNonZeroContent:
380 lst = [obj.GetBinContent(i)
for i
in range(1, obj.GetNbinsX()+1)
if obj.GetBinContent(i) != 0 ]
381 return min(lst)
if len(lst) != 0
else 0
383 return obj.GetMinimum()
384 elif isinstance(obj, ROOT.TGraph)
or isinstance(obj, ROOT.TGraph2D):
385 m =
min([obj.GetY()[i]
for i
in range(0, obj.GetN())])
386 return m*0.9
if m > 0
else m*1.1
390 if isinstance(obj, ROOT.TH2):
391 yaxis = obj.GetYaxis()
392 return yaxis.GetBinUpEdge(yaxis.GetLast())
393 elif isinstance(obj, ROOT.TH1):
394 if limitToNonZeroContent:
395 lst = [obj.GetBinContent(i)
for i
in range(1, obj.GetNbinsX()+1)
if obj.GetBinContent(i) != 0 ]
396 return max(lst)
if len(lst) != 0
else 0
398 return obj.GetMaximum()
399 elif isinstance(obj, ROOT.TGraph)
or isinstance(obj, ROOT.TGraph2D):
400 m =
max([obj.GetY()[i]
for i
in range(0, obj.GetN())])
401 return m*1.1
if m > 0
else m*0.9
405 return max([th1.GetBinContent(i)+th1.GetBinError(i)
for i
in range(1, th1.GetNbinsX()+1)])
408 yvals = sorted([n
for n
in [th1.GetBinContent(i)
for i
in range(1, th1.GetNbinsX()+1)]
if n>0])
410 return th1.GetMinimum()
415 ind_min = len(yvals)-1 -
int(len(yvals)*0.95)
416 min_val = yvals[ind_min]
417 for i
in range(0, ind_min):
418 if yvals[i] > 0.1*min_val:
424 inRange =
lambda x:
True 425 inRange2 =
lambda xmin,xmax:
True 427 inRange =
lambda x: coverageRange[0] <= x <= coverageRange[1]
428 inRange2 =
lambda xmin,xmax: coverageRange[0] <= xmin
and xmax <= coverageRange[1]
430 if isinstance(obj, ROOT.TH1):
431 yvals = [obj.GetBinContent(i)
for i
in range(1, obj.GetNbinsX()+1)
if inRange2(obj.GetXaxis().GetBinLowEdge(i), obj.GetXaxis().GetBinUpEdge(i))]
432 yvals = [x
for x
in yvals
if x != 0]
433 elif isinstance(obj, ROOT.TGraph)
or isinstance(obj, ROOT.TGraph2D):
434 yvals = [obj.GetY()[i]
for i
in range(0, obj.GetN())
if inRange(obj.GetX()[i])]
440 return (yvals[0], yvals[0])
442 return (yvals[0], yvals[1])
445 nvals =
int(len(yvals)*coverage)
448 if len(yvals) % 2 == 0:
450 return ( yvals[half-1], yvals[half] )
452 middle = len(yvals)//2
453 return ( yvals[middle-1], yvals[middle+1] )
454 ind_min = (len(yvals)-nvals)//2
455 ind_max = len(yvals)-1 - ind_min
457 return (yvals[ind_min], yvals[ind_max])
459 def _findBounds(th1s, ylog, xmin=None, xmax=None, ymin=None, ymax=None):
460 """Find x-y axis boundaries encompassing a list of TH1s if the bounds are not given in arguments. 464 ylog -- Boolean indicating if y axis is in log scale or not (affects the automatic ymax) 467 xmin -- Minimum x value; if None, take the minimum of TH1s 468 xmax -- Maximum x value; if None, take the maximum of TH1s 469 ymin -- Minimum y value; if None, take the minimum of TH1s 470 ymax -- Maximum y value; if None, take the maximum of TH1s 475 if xmin
is None or xmax
is None or isinstance(xmin, list)
or isinstance(max, list):
479 xmins.append(
_getXmin(th1, limitToNonZeroContent=isinstance(xmin, list)))
480 xmaxs.append(
_getXmax(th1, limitToNonZeroContent=isinstance(xmax, list)))
483 xmins = [h
for h
in xmins
if h
is not None]
484 xmaxs = [h
for h
in xmaxs
if h
is not None]
488 elif isinstance(xmin, list):
492 print(
"Histogram is zero, using the smallest given value for xmin from",
str(xmin))
495 xmins_below = [x
for x
in xmin
if x<=xm]
496 if len(xmins_below) == 0:
500 print(
"Histogram minimum x %f is below all given xmin values %s, using the smallest one" % (xm,
str(xmin)))
502 xmin =
max(xmins_below)
506 elif isinstance(xmax, list):
510 print(
"Histogram is zero, using the smallest given value for xmax from",
str(xmin))
513 xmaxs_above = [x
for x
in xmax
if x>xm]
514 if len(xmaxs_above) == 0:
518 print(
"Histogram maximum x %f is above all given xmax values %s, using the maximum one" % (xm,
str(xmax)))
520 xmax =
min(xmaxs_above)
523 th1.GetXaxis().SetRangeUser(xmin, xmax)
525 return (xmin, ymin, xmax, ymax)
527 def _findBoundsY(th1s, ylog, ymin=None, ymax=None, coverage=None, coverageRange=None):
528 """Find y axis boundaries encompassing a list of TH1s if the bounds are not given in arguments. 532 ylog -- Boolean indicating if y axis is in log scale or not (affects the automatic ymax) 535 ymin -- Minimum y value; if None, take the minimum of TH1s 536 ymax -- Maximum y value; if None, take the maximum of TH1s 537 coverage -- If set, use only values within the 'coverage' part around the median are used for min/max (useful for ratio) 538 coverageRange -- If coverage and this are set, use only the x axis specified by an (xmin,xmax) pair for the coverage 540 if coverage
is not None or isinstance(th1s[0], ROOT.TH2):
546 y_scale_max =
lambda y: y
547 y_scale_min =
lambda y: y
550 y_scale_max =
lambda y: y*1.5
552 y_scale_max =
lambda y: y*1.05
553 y_scale_min =
lambda y: y*0.9
555 if ymin
is None or ymax
is None or isinstance(ymin, list)
or isinstance(ymax, list):
559 if coverage
is not None:
562 if ylog
and isinstance(ymin, list):
565 _ymin =
_getYmin(th1, limitToNonZeroContent=isinstance(ymin, list))
566 _ymax =
_getYmax(th1, limitToNonZeroContent=isinstance(ymax, list))
574 elif isinstance(ymin, list):
575 ym_unscaled =
min(ymins)
576 ym = y_scale_min(ym_unscaled)
577 ymins_below = [y
for y
in ymin
if y<=ym]
578 if len(ymins_below) == 0:
580 if ym_unscaled < ymin:
582 print(
"Histogram minimum y %f is below all given ymin values %s, using the smallest one" % (ym,
str(ymin)))
584 ymin =
max(ymins_below)
589 ymax = y_scale_max(
max(ymaxs+[ymin]))
590 elif isinstance(ymax, list):
591 ym_unscaled =
max(ymaxs)
592 ym = y_scale_max(ym_unscaled)
593 ymaxs_above = [y
for y
in ymax
if y>ym]
594 if len(ymaxs_above) == 0:
596 if ym_unscaled > ymax:
598 print(
"Histogram maximum y %f is above all given ymax values %s, using the maximum one" % (ym_unscaled,
str(ymax)))
600 ymax =
min(ymaxs_above)
603 th1.GetYaxis().SetRangeUser(ymin, ymax)
609 for b
in range(1, histos[0].GetNbinsX()+1):
612 if h.GetBinContent(b) > 0:
618 if len(binsToRemove) > 0:
621 for i
in range(len(xbinlabels)):
622 if (i+1)
not in binsToRemove:
623 xbinlab_new.append(xbinlabels[i])
624 xbinlabels = xbinlab_new
630 for b
in range(1, h.GetNbinsX()+1):
631 if b
not in binsToRemove:
632 values.append( (h.GetXaxis().GetBinLabel(b), h.GetBinContent(b), h.GetBinError(b)) )
635 h_new = h.Clone(h.GetName()+
"_empty")
636 h_new.SetBins(len(values), h.GetBinLowEdge(1), h.GetBinLowEdge(1)+len(values))
637 for b, (l, v, e)
in enumerate(values):
638 h_new.GetXaxis().SetBinLabel(b+1, l)
639 h_new.SetBinContent(b+1, v)
640 h_new.SetBinError(b+1, e)
642 histos_new.append(h_new)
645 return (histos, xbinlabels)
648 xbinsToRemove = set()
649 ybinsToRemove = set()
650 for ih, h
in enumerate(histos):
651 for bx
in range(1, h.GetNbinsX()+1):
653 for by
in range(1, h.GetNbinsY()+1):
654 if h.GetBinContent(bx, by) > 0:
658 xbinsToRemove.add(bx)
660 xbinsToRemove.discard(bx)
662 for by
in range(1, h.GetNbinsY()+1):
664 for bx
in range(1, h.GetNbinsX()+1):
665 if h.GetBinContent(bx, by) > 0:
669 ybinsToRemove.add(by)
671 ybinsToRemove.discard(by)
673 if len(xbinsToRemove) > 0
or len(ybinsToRemove) > 0:
676 for b
in range(1, len(xbinlabels)+1):
677 if b
not in xbinsToRemove:
678 xbinlabels_new.append(histos[0].GetXaxis().GetBinLabel(b))
680 xbinlabels = xbinlabels_new
683 for b
in range(1, len(ybinlabels)+1):
684 if b
not in ybinsToRemove:
685 ybinlabels.append(histos[0].GetYaxis().GetBinLabel(b))
687 ybinlabels = xbinlabels_new
690 if len(xbinlabels) == 0
or len(ybinlabels) == 0:
691 return (histos_new, xbinlabels, ybinlabels)
693 h_new = ROOT.TH2F(h.GetName()+
"_empty", h.GetTitle(), len(xbinlabels),0,len(xbinlabels), len(ybinlabels),0,len(ybinlabels))
694 for b, l
in enumerate(xbinlabels):
695 h_new.GetXaxis().SetBinLabel(b+1, l)
696 for b, l
in enumerate(ybinlabels):
697 h_new.GetYaxis().SetBinLabel(b+1, l)
699 for ix, bx
in enumerate(xbins):
700 for iy, by
in enumerate(ybins):
701 h_new.SetBinContent(ix+1, iy+1, h.GetBinContent(bx, by))
702 h_new.SetBinError(ix+1, iy+1, h.GetBinError(bx, by))
703 histos_new.append(h_new)
705 return (histos, xbinlabels, ybinlabels)
708 return _mergeBinLabels([[h.GetXaxis().GetBinLabel(i)
for i
in range(1, h.GetNbinsX()+1)]
for h
in histos])
711 return _mergeBinLabels([[h.GetYaxis().GetBinLabel(i)
for i
in range(1, h.GetNbinsY()+1)]
for h
in histos])
714 labels_merged = labelsAll[0]
715 for labels
in labelsAll[1:]:
716 diff = difflib.unified_diff(labels_merged, labels, n=
max(len(labels_merged), len(labels)))
723 operation.append(item[0])
725 if lab
in labels_merged:
727 ind = labels_merged.index(lab)
728 if operation[ind] ==
"-" and operation[-1] ==
"+":
729 labels_merged.remove(lab)
731 elif operation[ind] ==
"+" and operation[-1] ==
"-":
735 raise Exception(
"This should never happen")
736 labels_merged.append(lab)
739 if len(labels_merged) == 0:
740 labels_merged = labels
747 h_new = h.Clone(h.GetName()+
"_xbinlabels")
748 h_new.SetBins(len(xbinlabels), h.GetBinLowEdge(1), h.GetBinLowEdge(1)+len(xbinlabels))
749 for i, label
in enumerate(xbinlabels):
750 bin = h.GetXaxis().FindFixBin(label)
752 h_new.SetBinContent(i+1, h.GetBinContent(bin))
753 h_new.SetBinError(i+1, h.GetBinError(bin))
755 h_new.SetBinContent(i+1, 0)
756 h_new.SetBinError(i+1, 0)
757 histos_new.append(h_new)
762 """Class for subtracting two histograms""" 767 name -- String for name of the resulting histogram (A-B) 768 nameA -- String for A histogram 769 nameB -- String for B histogram 772 title -- String for a title of the resulting histogram (default "") 774 Uncertainties are calculated with the assumption that B is a 775 subset of A, and the histograms contain event counts. 783 """String representation, returns the name""" 787 """Create and return the fake+duplicate histogram from a TDirectory""" 791 if not histoA
or not histoB:
794 ret = histoA.Clone(self.
_name)
800 ret.SetCanExtend(
False)
802 for i
in range(0, histoA.GetNbinsX()+2):
803 val = histoA.GetBinContent(i)-histoB.GetBinContent(i)
804 ret.SetBinContent(i, val)
805 ret.SetBinError(i, math.sqrt(val))
810 """Class to transform bin contents in an arbitrary way.""" 815 name -- String for name of the resulting histogram 816 histo -- String for a source histogram (needs to be cumulative) 817 func -- Function to operate on the bin content 825 """String representation, returns the name""" 829 """Create and return the transformed histogram from a TDirectory""" 834 ret = histo.Clone(self.
_name)
840 ret.SetCanExtend(
False)
842 for i
in range(0, histo.GetNbinsX()+2):
843 ret.SetBinContent(i, self.
_func(histo.GetBinContent(i)))
847 """Class to calculate the fake+duplicate rate""" 848 def __init__(self, name, assoc, dup, reco, title=""):
852 name -- String for the name of the resulting efficiency histogram 853 assoc -- String for the name of the "associated" histogram 854 dup -- String for the name of the "duplicates" histogram 855 reco -- String for the name of the "reco" (denominator) histogram 858 title -- String for a title of the resulting histogram (default "") 860 The result is calculated as 1 - (assoc - dup) / reco 869 """String representation, returns the name""" 873 """Create and return the fake+duplicate histogram from a TDirectory""" 880 if not hassoc
or not hdup
or not hreco:
883 hfakedup = hreco.Clone(self.
_name)
884 hfakedup.SetTitle(self.
_title)
886 for i
in range(1, hassoc.GetNbinsX()+1):
887 numerVal = hassoc.GetBinContent(i) - hdup.GetBinContent(i)
888 denomVal = hreco.GetBinContent(i)
890 fakedupVal = (1 - numerVal / denomVal)
if denomVal != 0.0
else 0.0
891 errVal = math.sqrt(fakedupVal*(1-fakedupVal)/denomVal)
if (denomVal != 0.0
and fakedupVal <= 1)
else 0.0
893 hfakedup.SetBinContent(i, fakedupVal)
894 hfakedup.SetBinError(i, errVal)
899 """Class for making a cut efficiency histograms. 909 name -- String for name of the resulting histogram 910 histo -- String for a source histogram (needs to be cumulative) 917 """String representation, returns the name""" 921 """Create and return the cut efficiency histogram from a TDirectory""" 927 ascending = histo.GetBinContent(0) < histo.GetBinContent(histo.GetNbinsX())
929 n_tot = histo.GetBinContent(histo.GetNbinsX())
931 n_tot = histo.GetBinContent(0)
936 ret = histo.Clone(self.
_name)
940 for i
in range(1, histo.GetNbinsX()+1):
941 n = histo.GetBinContent(i)
943 errVal = math.sqrt(val*(1-val)/n_tot)
944 ret.SetBinContent(i, val)
945 ret.SetBinError(i, errVal)
949 """Class to create a histogram by aggregating bins of another histogram to a bin of the resulting histogram.""" 950 def __init__(self, name, histoName, mapping, normalizeTo=None, scale=None, renameBin=None, ignoreMissingBins=False, minExistingBins=None, originalOrder=False, reorder=None):
954 name -- String for the name of the resulting histogram 955 histoName -- String for the name of the source histogram 956 mapping -- Dictionary for mapping the bins (see below) 959 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. 960 scale -- Optional number for scaling the histogram (passed to ROOT.TH1.Scale()) 961 renameBin -- Optional function (string -> string) to rename the bins of the input histogram 962 originalOrder -- Boolean for using the order of bins in the histogram (default False) 963 reorder -- Optional function to reorder the bins 965 Mapping structure (mapping): 967 Dictionary (you probably want to use collections.OrderedDict) 968 should be a mapping from the destination bin label to a list 969 of source bin labels ("dst -> [src]"). 982 raise Exception(
"reorder is not None and originalOrder is True, please set only one of them")
985 """String representation, returns the name""" 989 """Create and return the histogram from a TDirectory""" 995 binValues = [
None]*len(self.
_mapping)
1007 sumTime += values[l][0]
1008 sumErrorSq += values[l][1]**2
1014 binValues[i] = (sumTime, math.sqrt(sumErrorSq))
1017 ivalue = len(values)+1
1023 ivalue = list(values.keys()).
index(lab)
1025 binIndexOrder.append( (ivalue, i) )
1028 binIndexOrder.sort(key=
lambda t: t[0])
1031 for i
in range(0, len(binValues)):
1032 fromIndex = binIndexOrder[i][1]
1033 tmpVal.append(binValues[fromIndex])
1034 tmpLab.append(binLabels[fromIndex])
1038 order = self.
_reorder(tdirectory, binLabels)
1039 binValues = [binValues[i]
for i
in order]
1040 binLabels = [binLabels[i]
for i
in order]
1046 for i, val
in enumerate(binValues):
1049 binValues = [v
for v
in binValues
if v
is not None]
1050 binLabels = [v
for v
in binLabels
if v
is not None]
1051 if len(binValues) == 0:
1054 result = ROOT.TH1F(self.
_name, self.
_name, len(binValues), 0, len(binValues))
1055 for i, (value, label)
in enumerate(
zip(binValues, binLabels)):
1056 if value
is not None:
1057 result.SetBinContent(i+1, value[0])
1058 result.SetBinError(i+1, value[1])
1059 result.GetXaxis().SetBinLabel(i+1, label)
1066 value = th1.GetBinContent(bin)
1068 result.Scale(1/value)
1070 if self.
_scale is not None:
1071 result.Scale(self.
_scale)
1076 """Class to create a histogram by aggregating integrals of another histogram.""" 1081 name -- String for the name of the resulting histogram 1082 mapping -- Dictionary for mapping the bin label to a histogram name 1085 normalizeTo -- Optional string for a histogram. If given, all bins of the resulting histograqm are divided by the integral of this histogram. 1092 """String representation, returns the name""" 1096 """Create and return the histogram from a TDirectory""" 1102 result.append( (key, th1.Integral(0, th1.GetNbinsX()+1)) )
1103 if len(result) == 0:
1106 res = ROOT.TH1F(self.
_name, self.
_name, len(result), 0, len(result))
1108 for i, (name, count)
in enumerate(result):
1109 res.SetBinContent(i+1, count)
1110 res.GetXaxis().SetBinLabel(i+1, name)
1116 scale = th1.Integral(0, th1.GetNbinsX()+1)
1122 """Class to construct a ROC curve (e.g. efficiency vs. fake rate) from two histograms""" 1123 def __init__(self, name, xhistoName, yhistoName, zaxis=False):
1127 name -- String for the name of the resulting histogram 1128 xhistoName -- String for the name of the x-axis histogram (or another "creator" object) 1129 yhistoName -- String for the name of the y-axis histogram (or another "creator" object) 1132 zaxis -- If set to True (default False), create a TGraph2D with z axis showing the cut value (recommended drawStyle 'pcolz') 1140 """String representation, returns the name""" 1144 """Create and return the histogram from a TDirectory""" 1147 if xhisto
is None or yhisto
is None:
1158 for i
in range(1, xhisto.GetNbinsX()+1):
1159 x.append(xhisto.GetBinContent(i))
1160 xerrup.append(xhisto.GetBinError(i))
1161 xerrdown.append(xhisto.GetBinError(i))
1163 y.append(yhisto.GetBinContent(i))
1164 yerrup.append(yhisto.GetBinError(i))
1165 yerrdown.append(yhisto.GetBinError(i))
1167 z.append(xhisto.GetXaxis().GetBinUpEdge(i))
1170 if x.count(0.0) == len(x)
or y.count(0.0) == len(y):
1173 arr =
lambda v: array.array(
"d", v)
1176 gr = ROOT.TGraph2D(len(x), arr(x), arr(y), arr(z))
1178 gr = ROOT.TGraphAsymmErrors(len(x), arr(x), arr(y), arr(xerrdown), arr(xerrup), arr(yerrdown), arr(yerrup))
1184 _plotStylesColor = [4, 2, ROOT.kBlack, ROOT.kOrange+7, ROOT.kMagenta-3, ROOT.kGreen+2]
1185 _plotStylesMarker = [21, 20, 22, 34, 33, 23]
1187 def _drawFrame(pad, bounds, zmax=None, xbinlabels=None, xbinlabelsize=None, xbinlabeloption=None, ybinlabels=None, suffix=""):
1188 """Function to draw a frame 1191 pad -- TPad to where the frame is drawn 1192 bounds -- List or 4-tuple for (xmin, ymin, xmax, ymax) 1195 zmax -- Maximum Z, needed for TH2 histograms 1196 xbinlabels -- Optional list of strings for x axis bin labels 1197 xbinlabelsize -- Optional number for the x axis bin label size 1198 xbinlabeloption -- Optional string for the x axis bin options (passed to ROOT.TH1.LabelsOption()) 1199 suffix -- Optional string for a postfix of the frame name 1201 if xbinlabels
is None and ybinlabels
is None:
1202 frame = pad.DrawFrame(*bounds)
1205 nbins = len(xbinlabels)
1206 if ybinlabels
is None:
1207 frame = ROOT.TH1F(
"hframe"+suffix,
"", nbins, bounds[0], bounds[2])
1208 frame.SetMinimum(bounds[1])
1209 frame.SetMaximum(bounds[3])
1210 frame.GetYaxis().SetLimits(bounds[1], bounds[3])
1212 ybins = len(ybinlabels)
1213 frame = ROOT.TH2F(
"hframe"+suffix,
"", nbins,bounds[0],bounds[2], ybins,bounds[1],bounds[3])
1214 frame.SetMaximum(zmax)
1216 frame.SetBit(ROOT.TH1.kNoStats)
1217 frame.SetBit(ROOT.kCanDelete)
1220 xaxis = frame.GetXaxis()
1221 for i
in range(nbins):
1222 xaxis.SetBinLabel(i+1, xbinlabels[i])
1223 if xbinlabelsize
is not None:
1224 xaxis.SetLabelSize(xbinlabelsize)
1225 if xbinlabeloption
is not None:
1226 frame.LabelsOption(xbinlabeloption)
1228 if ybinlabels
is not None:
1229 yaxis = frame.GetYaxis()
1230 for i, lab
in enumerate(ybinlabels):
1231 yaxis.SetBinLabel(i+1, lab)
1232 if xbinlabelsize
is not None:
1233 yaxis.SetLabelSize(xbinlabelsize)
1234 if xbinlabeloption
is not None:
1235 frame.LabelsOption(xbinlabeloption,
"Y")
1240 """Class for creating and managing a frame for a simple, one-pad plot""" 1241 def __init__(self, pad, bounds, zmax, nrows, xbinlabels=None, xbinlabelsize=None, xbinlabeloption=None, ybinlabels=None):
1243 self.
_frame =
_drawFrame(pad, bounds, zmax, xbinlabels, xbinlabelsize, xbinlabeloption, ybinlabels)
1248 self.
_frame.GetYaxis().SetTitleOffset(self.
_frame.GetYaxis().GetTitleOffset()*yoffsetFactor)
1249 self.
_frame.GetXaxis().SetTitleOffset(self.
_frame.GetXaxis().GetTitleOffset()*xoffsetFactor)
1253 self.
_pad.SetLogx(log)
1256 self.
_pad.SetLogy(log)
1259 self.
_pad.SetGridx(grid)
1262 self.
_pad.SetGridy(grid)
1265 self.
_pad.SetLeftMargin(self.
_pad.GetLeftMargin()+adjust)
1271 self.
_pad.SetRightMargin(self.
_pad.GetRightMargin()+adjust)
1277 self.
_frame.SetTitle(title)
1280 self.
_frame.GetXaxis().SetTitle(title)
1283 self.
_frame.GetXaxis().SetTitleSize(size)
1286 self.
_frame.GetXaxis().SetTitleOffset(offset)
1289 self.
_frame.GetXaxis().SetLabelSize(size)
1292 self.
_frame.GetYaxis().SetTitle(title)
1295 self.
_frame.GetYaxis().SetTitleSize(size)
1298 self.
_frame.GetYaxis().SetTitleOffset(offset)
1301 self.
_pad.RedrawAxis()
1304 """Class for creating and managing a frame for a ratio plot with two subpads""" 1305 def __init__(self, pad, bounds, zmax, ratioBounds, ratioFactor, nrows, xbinlabels=None, xbinlabelsize=None, xbinlabeloption=None, ratioYTitle=_ratioYTitle):
1308 if xbinlabels
is not None:
1315 self.
_frame.GetXaxis().SetLabelSize(0)
1316 self.
_frame.GetXaxis().SetTitleSize(0)
1318 yoffsetFactor = ratioFactor
1321 self.
_frame.GetYaxis().SetTitleOffset(self.
_frameRatio.GetYaxis().GetTitleOffset()*yoffsetFactor)
1326 self.
_frameRatio.GetYaxis().SetNdivisions(4, 5, 0)
1331 self.
_pad.SetLogx(log)
1335 self.
_pad.SetLogy(log)
1338 self.
_pad.SetGridx(grid)
1342 self.
_pad.SetGridy(grid)
1346 self.
_pad.SetLeftMargin(self.
_pad.GetLeftMargin()+adjust)
1355 self.
_pad.SetRightMargin(self.
_pad.GetRightMargin()+adjust)
1364 self.
_frame.SetTitle(title)
1373 self.
_frameRatio.GetXaxis().SetTitleOffset(offset)
1379 self.
_frame.GetYaxis().SetTitle(title)
1385 self.
_frame.GetYaxis().SetTitleSize(size)
1389 self.
_frame.GetYaxis().SetTitleOffset(offset)
1390 self.
_frameRatio.GetYaxis().SetTitleOffset(offset)
1394 self.
_pad.RedrawAxis()
1403 self.
_coverPad = ROOT.TPad(
"coverpad",
"coverpad", xmin, ymin, xmax, ymax)
1411 """Class for creating and managing a frame for a plot from TGraph2D""" 1412 def __init__(self, pad, bounds, histos, ratioOrig, ratioFactor):
1415 self.
_pad = pad.cd(1)
1419 (xlow, ylow, width, height) = (self.
_pad.GetXlowNDC(), self.
_pad.GetYlowNDC(), self.
_pad.GetWNDC(), self.
_pad.GetHNDC())
1423 bottomMargin = self.
_pad.GetBottomMargin()
1424 bottomMarginNew = ROOT.gStyle.GetPadBottomMargin()
1426 ylowNew = yup - (1-bottomMargin)/(1-bottomMarginNew) * (yup-ylow)
1427 topMarginNew = self.
_pad.GetTopMargin() * (yup-ylow)/(yup-ylowNew)
1429 self.
_pad.SetPad(xlow, ylowNew, xup, yup)
1430 self.
_pad.SetTopMargin(topMarginNew)
1431 self.
_pad.SetBottomMargin(bottomMarginNew)
1451 self._pad.SetLeftMargin(self._pad.GetLeftMargin()+adjust)
1455 self.
_pad.SetRightMargin(self.
_pad.GetRightMargin()+adjust)
1486 self.
_firstHisto.GetZaxis().SetTitleOffset(offset)
1491 self.
_pad.SetPhi(epsilon)
1492 self.
_pad.SetTheta(90+epsilon)
1497 if hasattr(self,
"_xtitle"):
1499 if hasattr(self,
"_xtitlesize"):
1501 if hasattr(self,
"_xlabelsize"):
1502 self.
_firstHisto.GetXaxis().SetLabelSize(self._labelsize)
1503 if hasattr(self,
"_ytitle"):
1505 if hasattr(self,
"_ytitlesize"):
1507 if hasattr(self,
"_ytitleoffset"):
1511 """Abstraction on top of TLatex""" 1512 def __init__(self, x, y, text, size=None, bold=True, align="left", color=ROOT.kBlack, font=None):
1516 x -- X coordinate of the text (in NDC) 1517 y -- Y coordinate of the text (in NDC) 1518 text -- String to draw 1519 size -- Size of text (None for the default value, taken from gStyle) 1520 bold -- Should the text be bold? 1521 align -- Alignment of text (left, center, right) 1522 color -- Color of the text 1523 font -- Specify font explicitly 1532 self.
_l.SetTextFont(self.
_l.GetTextFont()-20)
1533 if font
is not None:
1534 self.
_l.SetTextFont(font)
1535 if size
is not None:
1536 self.
_l.SetTextSize(size)
1537 if isinstance(align, str):
1538 if align.lower() ==
"left":
1539 self.
_l.SetTextAlign(11)
1540 elif align.lower() ==
"center":
1541 self.
_l.SetTextAlign(21)
1542 elif align.lower() ==
"right":
1543 self.
_l.SetTextAlign(31)
1545 raise Exception(
"Error: Invalid option '%s' for text alignment! Options are: 'left', 'center', 'right'."%align)
1547 self.
_l.SetTextAlign(align)
1548 self.
_l.SetTextColor(color)
1551 """Draw the text to the current TPad. 1554 options -- For interface compatibility, ignored 1556 Provides interface compatible with ROOT's drawable objects. 1562 """Class for drawing text and a background box.""" 1563 def __init__(self, xmin, ymin, xmax, ymax, lineheight=0.04, fillColor=ROOT.kWhite, transparent=True, **kwargs):
1567 xmin -- X min coordinate of the box (NDC) 1568 ymin -- Y min coordinate of the box (NDC) (if None, deduced automatically) 1569 xmax -- X max coordinate of the box (NDC) 1570 ymax -- Y max coordinate of the box (NDC) 1571 lineheight -- Line height 1572 fillColor -- Fill color of the box 1573 transparent -- Should the box be transparent? (in practive the TPave is not created) 1575 Keyword arguments are forwarded to constructor of PlotText 1592 """Add text to current position""" 1599 def move(self, dx=0, dy=0, dw=0, dh=0):
1600 """Move the box and the contained text objects 1603 dx -- Movement in x (positive is to right) 1604 dy -- Movement in y (positive is to up) 1605 dw -- Increment of width (negative to decrease width) 1606 dh -- Increment of height (negative to decrease height) 1608 dx and dy affect to both box and text objects, dw and dh 1609 affect the box only. 1613 if self.
_ymin is not None:
1618 if self.
_ymin is not None:
1626 """Draw the box and the text to the current TPad. 1629 options -- Forwarded to ROOT.TPave.Draw(), and the Draw() of the contained objects 1634 ymin = self.currenty - 0.01
1635 self.
_pave = ROOT.TPave(self.xmin, self.ymin, self.xmax, self.ymax, 0,
"NDC")
1636 self.
_pave.SetFillColor(self.fillColor)
1643 if hasattr(src,
"GetLineColor")
and hasattr(dst,
"SetLineColor"):
1644 properties.extend([
"LineColor",
"LineStyle",
"LineWidth"])
1645 if hasattr(src,
"GetFillColor")
and hasattr(dst,
"SetFillColor"):
1646 properties.extend([
"FillColor",
"FillStyle"])
1647 if hasattr(src,
"GetMarkerColor")
and hasattr(dst,
"SetMarkerColor"):
1648 properties.extend([
"MarkerColor",
"MarkerSize",
"MarkerStyle"])
1650 for prop
in properties:
1651 getattr(dst,
"Set"+prop)(getattr(src,
"Get"+prop)())
1654 """Denotes an empty place in a group.""" 1674 """Represents one plot, comparing one or more histograms.""" 1679 name -- String for name of the plot, or Efficiency object 1682 fallback -- Dictionary for specifying fallback (default None) 1683 outname -- String for an output name of the plot (default None for the same as 'name') 1684 title -- String for a title of the plot (default None) 1685 xtitle -- String for x axis title (default None) 1686 xtitlesize -- Float for x axis title size (default None) 1687 xtitleoffset -- Float for x axis title offset (default None) 1688 xlabelsize -- Float for x axis label size (default None) 1689 ytitle -- String for y axis title (default None) 1690 ytitlesize -- Float for y axis title size (default None) 1691 ytitleoffset -- Float for y axis title offset (default None) 1692 ztitle -- String for z axis title (default None) 1693 ztitleoffset -- Float for z axis title offset (default None) 1694 xmin -- Float for x axis minimum (default None, i.e. automatic) 1695 xmax -- Float for x axis maximum (default None, i.e. automatic) 1696 ymin -- Float for y axis minimum (default 0) 1697 ymax -- Float for y axis maximum (default None, i.e. automatic) 1698 xlog -- Bool for x axis log status (default False) 1699 ylog -- Bool for y axis log status (default False) 1700 xgrid -- Bool for x axis grid status (default True) 1701 ygrid -- Bool for y axis grid status (default True) 1702 stat -- Draw stat box? (default False) 1703 fit -- Do gaussian fit? (default False) 1704 statx -- Stat box x coordinate (default 0.65) 1705 staty -- Stat box y coordinate (default 0.8) 1706 statyadjust -- List of floats for stat box y coordinate adjustments (default None) 1707 normalizeToUnitArea -- Normalize histograms to unit area? (default False) 1708 normalizeToNumberOfEvents -- Normalize histograms to number of events? If yes, the PlotFolder needs 'numberOfEventsHistogram' set to a histogram filled once per event (default False) 1709 profileX -- Take histograms via ProfileX()? (default False) 1710 fitSlicesY -- Take histograms via FitSlicesY() (default False) 1711 rebinX -- rebin x axis (default None) 1712 scale -- Scale histograms by a number (default None) 1713 xbinlabels -- List of x axis bin labels (if given, default None) 1714 xbinlabelsize -- Size of x axis bin labels (default None) 1715 xbinlabeloption -- Option string for x axis bin labels (default None) 1716 removeEmptyBins -- Bool for removing empty bins, but only if histogram has bin labels (default False) 1717 printBins -- Bool for printing bin values, but only if histogram has bin labels (default False) 1718 drawStyle -- If "hist", draw as line instead of points (default None) 1719 drawCommand -- Deliver this to Draw() (default: None for same as drawStyle) 1720 lineWidth -- If drawStyle=="hist", the width of line (default 2) 1721 legendDx -- Float for moving TLegend in x direction for separate=True (default None) 1722 legendDy -- Float for moving TLegend in y direction for separate=True (default None) 1723 legendDw -- Float for changing TLegend width for separate=True (default None) 1724 legendDh -- Float for changing TLegend height for separate=True (default None) 1725 legend -- Bool to enable/disable legend (default True) 1726 adjustMarginLeft -- Float for adjusting left margin (default None) 1727 adjustMarginRight -- Float for adjusting right margin (default None) 1728 ratio -- Possibility to disable ratio for this particular plot (default None) 1729 ratioYmin -- Float for y axis minimum in ratio pad (default: list of values) 1730 ratioYmax -- Float for y axis maximum in ratio pad (default: list of values) 1731 ratioFit -- Fit straight line in ratio? (default None) 1732 ratioUncertainty -- Plot uncertainties on ratio? (default True) 1733 ratioCoverageXrange -- Range of x axis values (xmin,xmax) to limit the automatic ratio y axis range calculation to (default None for disabled) 1734 histogramModifier -- Function to be called in create() to modify the histograms (default None) 1738 def _set(attr, default):
1739 setattr(self,
"_"+attr, kwargs.get(attr, default))
1741 _set(
"fallback",
None)
1742 _set(
"outname",
None)
1745 _set(
"xtitle",
None)
1746 _set(
"xtitlesize",
None)
1747 _set(
"xtitleoffset",
None)
1748 _set(
"xlabelsize",
None)
1749 _set(
"ytitle",
None)
1750 _set(
"ytitlesize",
None)
1751 _set(
"ytitleoffset",
None)
1752 _set(
"ztitle",
None)
1753 _set(
"ztitleoffset",
None)
1770 _set(
"statyadjust",
None)
1772 _set(
"normalizeToUnitArea",
False)
1773 _set(
"normalizeToNumberOfEvents",
False)
1774 _set(
"profileX",
False)
1775 _set(
"fitSlicesY",
False)
1776 _set(
"rebinX",
None)
1779 _set(
"xbinlabels",
None)
1780 _set(
"xbinlabelsize",
None)
1781 _set(
"xbinlabeloption",
None)
1782 _set(
"removeEmptyBins",
False)
1783 _set(
"printBins",
False)
1785 _set(
"drawStyle",
"EP")
1786 _set(
"drawCommand",
None)
1787 _set(
"lineWidth", 2)
1789 _set(
"legendDx",
None)
1790 _set(
"legendDy",
None)
1791 _set(
"legendDw",
None)
1792 _set(
"legendDh",
None)
1793 _set(
"legend",
True)
1795 _set(
"adjustMarginLeft",
None)
1796 _set(
"adjustMarginRight",
None)
1799 _set(
"ratioYmin", [0, 0.2, 0.5, 0.7, 0.8, 0.9, 0.95])
1800 _set(
"ratioYmax", [1.05, 1.1, 1.2, 1.3, 1.5, 1.8, 2, 2.5, 3, 4, 5])
1801 _set(
"ratioFit",
None)
1802 _set(
"ratioUncertainty",
True)
1803 _set(
"ratioCoverageXrange",
None)
1805 _set(
"histogramModifier",
None)
1810 for name, value
in kwargs.items():
1811 if not hasattr(self,
"_"+name):
1812 raise Exception(
"No attribute '%s'" % name)
1813 setattr(self,
"_"+name, value)
1817 raise Exception(
"Plot can be cloned only before histograms have been created")
1818 cl = copy.copy(self)
1819 cl.setProperties(**kwargs)
1823 """Return number of existing histograms.""" 1824 return len([h
for h
in self.
_histograms if h
is not None])
1827 """Return true if there are no histograms created for the plot""" 1832 if isinstance(h, ROOT.TGraph2D):
1837 if self._ratio
is None:
1839 return ratio
and self._ratio
1845 if self._outname
is not None:
1846 return self._outname
1847 if isinstance(self.
_name, list):
1853 """Return true if the ratio uncertainty should be drawn""" 1854 return self._ratioUncertainty
1857 """Create one histogram from a TDirectory.""" 1862 if isinstance(name, list):
1866 if h
is not None and self._normalizeToNumberOfEvents
and nevents
is not None and nevents != 0:
1867 h.Scale(1.0/nevents)
1870 def create(self, tdirNEvents, requireAllHistograms=False):
1871 """Create histograms from list of TDirectories""" 1872 self.
_histograms = [self.
_createOne(self.
_name, i, tdirNEvent[0], tdirNEvent[1])
for i, tdirNEvent
in enumerate(tdirNEvents)]
1874 if self._fallback
is not None:
1878 self.
_histograms[i] = self.
_createOne(self._fallback[
"name"], i, tdirNEvents[i][0], tdirNEvents[i][1])
1879 profileX[i] = self._fallback.get(
"profileX", self._profileX)
1881 if self._histogramModifier
is not None:
1885 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)))
1890 def _modifyHisto(th1, profileX):
1895 th1 = th1.ProfileX()
1897 if self._fitSlicesY:
1898 ROOT.TH1.AddDirectory(
True)
1900 th1 = ROOT.gDirectory.Get(th1.GetName()+
"_2")
1901 th1.SetDirectory(
None)
1903 ROOT.TH1.AddDirectory(
False)
1905 if self._title
is not None:
1906 th1.SetTitle(self._title)
1908 if self._scale
is not None:
1909 th1.Scale(self._scale)
1913 if self._fallback
is not None:
1917 if requireAllHistograms
and None in self.
_histograms:
1921 """Set stats box.""" 1924 if h
is not None and hasattr(h,
"SetStats"):
1928 def _doStats(h, col, dy):
1933 if self._fit
and h.GetEntries() > 0.5:
1935 f = h.GetListOfFunctions().FindObject(
"gaus")
1943 st = h.GetListOfFunctions().FindObject(
"stats")
1948 st.SetX1NDC(startingX)
1949 st.SetX2NDC(startingX+0.3)
1950 st.SetY1NDC(startingY+dy)
1951 st.SetY2NDC(startingY+dy+0.12)
1952 st.SetTextColor(col)
1955 for i, h
in enumerate(histos):
1956 if self._statyadjust
is not None and i < len(self._statyadjust):
1957 dy += self._statyadjust[i]
1959 _doStats(h, _plotStylesColor[i], dy)
1963 """Normalise histograms to unit area""" 1971 if h.GetSumw2().fN <= 0:
1975 def draw(self, pad, ratio, ratioFactor, nrows):
1976 """Draw the histograms using values for a given algorithm.""" 1987 if self._normalizeToUnitArea:
1990 if self._rebinX
is not None:
1992 h.Rebin(self._rebinX)
1994 def _styleMarker(h, msty, col):
1995 h.SetMarkerStyle(msty)
1996 h.SetMarkerColor(col)
1997 h.SetMarkerSize(0.7)
2001 def _styleHist(h, msty, col):
2002 _styleMarker(h, msty, col)
2004 h.SetLineWidth(self._lineWidth)
2007 style = _styleMarker
2008 if "hist" in self._drawStyle.lower():
2011 if "l" in self._drawStyle.lower():
2019 style(h, _plotStylesMarker[i], _plotStylesColor[i])
2021 if len(histos) == 0:
2028 histosHaveBinLabels = len(histos[0].GetXaxis().GetBinLabel(1)) > 0
2029 xbinlabels = self._xbinlabels
2031 if xbinlabels
is None:
2032 if histosHaveBinLabels:
2034 if isinstance(histos[0], ROOT.TH2):
2043 if self._removeEmptyBins
and histosHaveBinLabels:
2046 if isinstance(histos[0], ROOT.TH2):
2051 if len(histos) == 0:
2053 print(
"No histograms with non-empty bins for plot {name}".
format(name=self.
getName()))
2056 if self._printBins
and histosHaveBinLabels:
2057 print(
"####################")
2059 width =
max([len(l)
for l
in xbinlabels])
2060 tmp =
"%%-%ds " % width
2061 for b
in range(1, histos[0].GetNbinsX()+1):
2062 s = tmp % xbinlabels[b-1]
2064 s +=
"%.3f " % h.GetBinContent(b)
2069 xmin=self._xmin, xmax=self._xmax,
2070 ymin=self._ymin, ymax=self._ymax)
2072 if isinstance(histos[0], ROOT.TH2):
2073 zmax =
max([h.GetMaximum()
for h
in histos])
2081 ratioHistos = [h
for h
in [r.getRatio()
for r
in self.
_ratios[1:]]
if h
is not None]
2083 if len(ratioHistos) > 0:
2084 ratioBoundsY =
_findBoundsY(ratioHistos, ylog=
False, ymin=self._ratioYmin, ymax=self._ratioYmax, coverage=0.68, coverageRange=self._ratioCoverageXrange)
2086 ratioBoundsY = (0.9, 1,1)
2088 if self._ratioFit
is not None:
2089 for i, rh
in enumerate(ratioHistos):
2090 tf_line = ROOT.TF1(
"line%d"%i,
"[0]+x*[1]")
2091 tf_line.SetRange(self._ratioFit[
"rangemin"], self._ratioFit[
"rangemax"])
2092 fitres = rh.Fit(tf_line,
"RINSQ")
2093 tf_line.SetLineColor(rh.GetMarkerColor())
2094 tf_line.SetLineWidth(2)
2096 box =
PlotTextBox(xmin=self._ratioFit.get(
"boxXmin", 0.14), ymin=
None,
2097 xmax=self._ratioFit.get(
"boxXmax", 0.35), ymax=self._ratioFit.get(
"boxYmax", 0.09),
2098 color=rh.GetMarkerColor(), font=43, size=11, lineheight=0.02)
2099 box.move(dx=(box.width()+0.01)*i)
2102 box.addText(
"Const: %.4f#pm%.4f" % (fitres.Parameter(0), fitres.ParError(0)))
2103 box.addText(
"Slope: %.4f#pm%.4f" % (fitres.Parameter(1), fitres.ParError(1)))
2114 self.
_setStats(histos, self._statx, self._staty)
2118 frame =
FrameTGraph2D(pad, bounds, histos, ratioOrig, ratioFactor)
2121 ratioBounds = (bounds[0], ratioBoundsY[0], bounds[2], ratioBoundsY[1])
2122 frame =
FrameRatio(pad, bounds, zmax, ratioBounds, ratioFactor, nrows, xbinlabels, self._xbinlabelsize, self._xbinlabeloption)
2124 frame =
Frame(pad, bounds, zmax, nrows, xbinlabels, self._xbinlabelsize, self._xbinlabeloption, ybinlabels=ybinlabels)
2127 frame.setLogx(self._xlog)
2128 frame.setLogy(self._ylog)
2129 frame.setGridx(self._xgrid)
2130 frame.setGridy(self._ygrid)
2135 if self._drawStyle
is not None:
2136 ds = self._drawStyle
2137 if self._drawCommand
is not None:
2138 ds = self._drawCommand
2143 frame.setTitle(histos[0].GetTitle())
2145 frame.setXTitle( histos[0].GetXaxis().GetTitle() )
2146 elif self.
_xtitle is not None:
2148 if self._xtitlesize
is not None:
2149 frame.setXTitleSize(self._xtitlesize)
2150 if self._xtitleoffset
is not None:
2151 frame.setXTitleOffset(self._xtitleoffset)
2152 if self._xlabelsize
is not None:
2153 frame.setXLabelSize(self._xlabelsize)
2155 frame.setYTitle( histos[0].GetYaxis().GetTitle() )
2156 elif self.
_ytitle is not None:
2158 if self._ytitlesize
is not None:
2159 frame.setYTitleSize(self._ytitlesize)
2160 if self._ytitleoffset
is not None:
2161 frame.setYTitleOffset(self._ytitleoffset)
2162 if self._ztitle
is not None:
2163 frame.setZTitle(self._ztitle)
2164 if self._ztitleoffset
is not None:
2165 frame.setZTitleOffset(self._ztitleoffset)
2166 if self._adjustMarginLeft
is not None:
2167 frame.adjustMarginLeft(self._adjustMarginLeft)
2168 if self._adjustMarginRight
is not None:
2169 frame.adjustMarginRight(self._adjustMarginRight)
2171 frame.adjustMarginLeft(0.03)
2172 frame.adjustMarginRight(0.08)
2178 for i, h
in enumerate(histos):
2180 if isTGraph2D
and i == 0:
2181 o = o.replace(
"sames",
"")
2188 if ratio
and len(self.
_ratios) > 0:
2189 frame._padRatio.cd()
2190 firstRatio = self.
_ratios[0].getRatio()
2191 if self._ratioUncertainty
and firstRatio
is not None:
2192 firstRatio.SetFillStyle(1001)
2193 firstRatio.SetFillColor(ROOT.kGray)
2194 firstRatio.SetLineColor(ROOT.kGray)
2195 firstRatio.SetMarkerColor(ROOT.kGray)
2196 firstRatio.SetMarkerSize(0)
2198 frame._padRatio.RedrawAxis(
"G")
2209 """Add histograms to a legend. 2213 legendLabels -- List of strings for the legend labels 2215 first = denomUncertainty
2224 entry = legend.AddEntry(self.
_forLegend, label,
"lpf")
2227 legend.AddEntry(h, label,
"LP")
2230 """Group of plots, results a TCanvas""" 2235 name -- String for name of the TCanvas, used also as the basename of the picture files 2236 plots -- List of Plot objects 2239 ncols -- Number of columns (default 2) 2240 legendDx -- Float for moving TLegend in x direction (default None) 2241 legendDy -- Float for moving TLegend in y direction (default None) 2242 legendDw -- Float for changing TLegend width (default None) 2243 legendDh -- Float for changing TLegend height (default None) 2244 legend -- Bool for disabling legend (default True for legend being enabled) 2245 overrideLegendLabels -- List of strings for legend labels, if given, these are used instead of the ones coming from Plotter (default None) 2246 onlyForPileup -- Plots this group only for pileup samples 2253 def _set(attr, default):
2254 setattr(self,
"_"+attr, kwargs.get(attr, default))
2258 _set(
"legendDx",
None)
2259 _set(
"legendDy",
None)
2260 _set(
"legendDw",
None)
2261 _set(
"legendDh",
None)
2262 _set(
"legend",
True)
2264 _set(
"overrideLegendLabels",
None)
2266 _set(
"onlyForPileup",
False)
2271 for name, value
in kwargs.items():
2272 if not hasattr(self,
"_"+name):
2273 raise Exception(
"No attribute '%s'" % name)
2274 setattr(self,
"_"+name, value)
2283 for i, plot
in enumerate(self.
_plots):
2284 if plot.getName() == name:
2287 raise Exception(
"Did not find Plot '%s' from PlotGroup '%s'" % (name, self.
_name))
2297 if plot.getName() == name:
2299 raise Exception(
"No Plot named '%s'" % name)
2302 """Return True if the PlotGroup is intended only for pileup samples""" 2303 return self._onlyForPileup
2305 def create(self, tdirectoryNEvents, requireAllHistograms=False):
2306 """Create histograms from a list of TDirectories. 2309 tdirectoryNEvents -- List of (TDirectory, nevents) pairs 2310 requireAllHistograms -- If True, a plot is produced if histograms from all files are present (default: False) 2313 plot.create(tdirectoryNEvents, requireAllHistograms)
2315 def draw(self, legendLabels, prefix=None, separate=False, saveFormat=".pdf", ratio=True, directory=""):
2316 """Draw the histograms using values for a given algorithm. 2319 legendLabels -- List of strings for legend labels (corresponding to the tdirectories in create()) 2320 prefix -- Optional string for file name prefix (default None) 2321 separate -- Save the plots of a group to separate files instead of a file per group (default False) 2322 saveFormat -- String specifying the plot format (default '.pdf') 2323 ratio -- Add ratio to the plot (default True) 2324 directory -- Directory where to save the file (default "") 2327 if self._overrideLegendLabels
is not None:
2328 legendLabels = self._overrideLegendLabels
2331 onlyEmptyPlots =
True 2333 if not plot.isEmpty():
2334 onlyEmptyPlots =
False 2340 return self.
_drawSeparate(legendLabels, prefix, saveFormat, ratio, directory)
2342 cwidth = 500*self._ncols
2343 nrows =
int((len(self.
_plots)+self._ncols-1)/self._ncols)
2344 cheight = 500 * nrows
2351 canvas.Divide(self._ncols, nrows)
2353 for i, plot
in enumerate(self.
_plots):
2354 pad = canvas.cd(i+1)
2358 for i, plot
in enumerate(self.
_plots):
2359 pad = canvas.cd(i+1)
2360 if not plot.isEmpty():
2366 if len(self.
_plots) <= 4:
2376 if self._legendDx
is not None:
2377 lx1 += self._legendDx
2378 lx2 += self._legendDx
2379 if self._legendDy
is not None:
2380 ly1 += self._legendDy
2381 ly2 += self._legendDy
2382 if self._legendDw
is not None:
2383 lx2 += self._legendDw
2384 if self._legendDh
is not None:
2385 ly1 -= self._legendDh
2386 plot =
max(self.
_plots, key=
lambda p: p.getNumberOfHistograms())
2387 denomUnc = sum([p.drawRatioUncertainty()
for p
in self.
_plots]) > 0
2388 legend = self.
_createLegend(plot, legendLabels, lx1, ly1, lx2, ly2,
2389 denomUncertainty=(ratio
and denomUnc))
2391 return self.
_save(canvas, saveFormat, prefix=prefix, directory=directory)
2394 """Internal method to do the drawing to separate files per Plot instead of a file per PlotGroup""" 2413 for c
in [canvas, canvasRatio]:
2414 c.SetTopMargin(0.05)
2415 c.SetBottomMargin(0.13)
2416 c.SetLeftMargin(0.16)
2417 c.SetRightMargin(0.05)
2419 ratioForThisPlot = plot.isRatio(ratio)
2421 if ratioForThisPlot:
2437 if plot._legendDx
is not None:
2438 lx1 += plot._legendDx
2439 lx2 += plot._legendDx
2440 if plot._legendDy
is not None:
2441 ly1 += plot._legendDy
2442 ly2 += plot._legendDy
2443 if plot._legendDw
is not None:
2444 lx2 += plot._legendDw
2445 if plot._legendDh
is not None:
2446 ly1 -= plot._legendDh
2449 legend = self.
_createLegend(plot, legendLabels, lx1, ly1, lx2, ly2, textSize=0.03,
2450 denomUncertainty=(ratioForThisPlot
and plot.drawRatioUncertainty))
2452 ret.extend(self.
_save(c, saveFormat, prefix=prefix, postfix=
"/"+plot.getName(), single=
True, directory=directory))
2456 """Internal method to set divide a pad to two for ratio plots""" 2459 def _createLegend(self, plot, legendLabels, lx1, ly1, lx2, ly2, textSize=0.016, denomUncertainty=True):
2460 if not self._legend:
2463 l = ROOT.TLegend(lx1, ly1, lx2, ly2)
2464 l.SetTextSize(textSize)
2471 plot.addToLegend(l, legendLabels, denomUncertainty)
2475 def _save(self, canvas, saveFormat, prefix=None, postfix=None, single=False, directory=""):
2478 if not os.path.exists(directory+
'/'+name):
2479 os.makedirs(directory+
'/'+name, exist_ok=
True)
2480 if prefix
is not None:
2482 if postfix
is not None:
2484 name = os.path.join(directory, name)
2487 backup = ROOT.gErrorIgnoreLevel
2488 ROOT.gErrorIgnoreLevel = ROOT.kWarning
2489 canvas.SaveAs(name+saveFormat)
2491 ROOT.gErrorIgnoreLevel = backup
2495 canvas.SetLogx(
False)
2496 canvas.SetLogy(
False)
2500 return [name+saveFormat]
2503 """Resembles DQM GUI's "On side" layout. 2505 Like PlotGroup, but has only a description of a single plot. The 2506 plot is drawn separately for each file. Useful for 2D histograms.""" 2508 def __init__(self, name, plot, ncols=2, onlyForPileup=False):
2509 super(PlotOnSideGroup, self).
__init__(name, [], ncols=ncols, legend=
False, onlyForPileup=onlyForPileup)
2514 raise Exception(
"PlotOnSideGroup.append() is not implemented")
2516 def create(self, tdirectoryNEvents, requireAllHistograms=False):
2518 for i, element
in enumerate(tdirectoryNEvents):
2520 pl.create([element], requireAllHistograms)
2521 pl.setName(pl.getName()+
"_"+
str(i))
2525 kargs = copy.copy(kwargs)
2526 kargs[
"ratio"] =
False 2527 return super(PlotOnSideGroup, self).
draw(*args, **kargs)
2531 """Represents a collection of PlotGroups, produced from a single folder in a DQM file""" 2536 plotGroups -- List of PlotGroup objects 2539 loopSubFolders -- Should the subfolders be looped over? (default: True) 2540 onlyForPileup -- Plots this folder only for pileup samples 2541 onlyForElectron -- Plots this folder only for electron samples 2542 onlyForConversion -- Plots this folder only for conversion samples 2543 onlyForBHadron -- Plots this folder only for B-hadron samples 2544 purpose -- html.PlotPurpose member class for the purpose of the folder, used for grouping of the plots to the HTML pages 2545 page -- Optional string for the page in HTML generatin 2546 section -- Optional string for the section within a page in HTML generation 2547 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". 2560 raise Exception(
"Got unexpected keyword arguments: "+
",".
join(kwargs.keys()))
2563 """Return True if the PlotGroups of this folder should be applied to the all subfolders""" 2567 """Return True if the folder is intended only for pileup samples""" 2602 if pg.getName() == name:
2604 raise Exception(
"No PlotGroup named '%s'" % name)
2606 def create(self, dirsNEvents, labels, isPileupSample=True, requireAllHistograms=False):
2607 """Create histograms from a list of TFiles. 2610 dirsNEvents -- List of (TDirectory, nevents) pairs 2611 labels -- List of strings for legend labels corresponding the files 2612 isPileupSample -- Is sample pileup (some PlotGroups may limit themselves to pileup) 2613 requireAllHistograms -- If True, a plot is produced if histograms from all files are present (default: False) 2616 if len(dirsNEvents) != len(labels):
2617 raise Exception(
"len(dirsNEvents) should be len(labels), now they are %d and %d" % (len(dirsNEvents), len(labels)))
2622 if pg.onlyForPileup()
and not isPileupSample:
2624 pg.create(dirsNEvents, requireAllHistograms)
2626 def draw(self, prefix=None, separate=False, saveFormat=".pdf", ratio=True, directory=""):
2627 """Draw and save all plots using settings of a given algorithm. 2630 prefix -- Optional string for file name prefix (default None) 2631 separate -- Save the plots of a group to separate files instead of a file per group (default False) 2632 saveFormat -- String specifying the plot format (default '.pdf') 2633 ratio -- Add ratio to the plot (default True) 2634 directory -- Directory where to save the file (default "") 2639 ret.extend(pg.draw(self.
_labels, prefix=prefix, separate=separate, saveFormat=saveFormat, ratio=ratio, directory=directory))
2645 """Method called to (possibly) translate a subfolder name to more 'readable' form 2647 The implementation in this (base) class just returns the 2648 argument. The idea is that a deriving class might want to do 2649 something more complex (like trackingPlots.TrackingPlotFolder 2652 return dqmSubFolderName
2655 """Iterate over possible selections name (used in output directory name and legend) from the name of PlotterFolder, and a return value of translateSubFolder""" 2657 if plotFolderName !=
"":
2658 ret +=
"_"+plotFolderName
2659 if translatedDqmSubFolder
is not None:
2660 ret +=
"_"+translatedDqmSubFolder
2664 """Return True if this subfolder should be processed 2667 limitOnlyTo -- List/set/similar containing the translatedDqmSubFolder 2668 translatedDqmSubFolder -- Return value of translateSubFolder 2670 return translatedDqmSubFolder
in limitOnlyTo
2673 """Class to hold the original name and a 'translated' name of a subfolder in the DQM ROOT file""" 2679 """Equality is defined by the 'translated' name""" 2683 """Plotter for one DQM folder. 2685 This class is supposed to be instantiated by the Plotter class (or 2686 PlotterItem, to be more specific), and not used directly by the 2689 def __init__(self, name, possibleDqmFolders, dqmSubFolders, plotFolder, fallbackNames, fallbackDqmSubFolders, tableCreators):
2694 name -- Name of the folder (is used in the output directory naming) 2695 possibleDqmFolders -- List of strings for possible directories of histograms in TFiles 2696 dqmSubFolders -- List of lists of strings for list of subfolders per input file, or None if no subfolders 2697 plotFolder -- PlotFolder object 2698 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. 2699 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. 2700 tableCreators -- List of PlotterTableItem objects for tables to be created from this folder 2706 if dqmSubFolders
is None:
2712 for sf_list
in dqmSubFolders:
2714 sf_translated = self.
_plotFolder.translateSubFolder(sf)
2715 if sf_translated
is not None and not sf_translated
in subfolders:
2716 subfolders[sf_translated] =
DQMSubFolder(sf, sf_translated)
2718 self.
_dqmSubFolders = sorted(subfolders.values(), key=
lambda sf: sf.subfolder)
2752 """Get list of subfolders, possibly limiting to some of them. 2755 limitOnlyTo -- Object depending on the PlotFolder type for limiting the set of subfolders to be processed 2761 if limitOnlyTo
is None:
2770 """Get a generator for the 'selection name', looping over the name and fallbackNames""" 2772 for selname
in self.
_plotFolder.iterSelectionName(name, dqmSubFolder.translated
if dqmSubFolder
is not None else None):
2778 def create(self, files, labels, dqmSubFolder, isPileupSample=True, requireAllHistograms=False):
2779 """Create histograms from a list of TFiles. 2781 files -- List of TFiles 2782 labels -- List of strings for legend labels corresponding the files 2783 dqmSubFolder -- DQMSubFolder object for a subfolder (or None for no subfolder) 2784 isPileupSample -- Is sample pileup (some PlotGroups may limit themselves to pileup) 2785 requireAllHistograms -- If True, a plot is produced if histograms from all files are present (default: False) 2788 subfolder = dqmSubFolder.subfolder
if dqmSubFolder
is not None else None 2789 neventsHisto = self.
_plotFolder.getNumberOfEventsHistogram()
2797 fallback = fallbackFunc(subfolder)
2798 if fallback
is not None:
2802 d = GetDirectoryCode.codesToNone(ret)
2804 if neventsHisto
is not None and tfile
is not None:
2806 if hnev
is not None:
2807 nev = hnev.GetEntries()
2808 dirsNEvents.append( (d, nev) )
2810 self.
_plotFolder.
create(dirsNEvents, labels, isPileupSample, requireAllHistograms)
2813 """Draw and save all plots using settings of a given algorithm.""" 2818 """Instance of plotter that knows the directory content, holds many folders.""" 2825 if limitSubFoldersOnlyTo
is not None:
2826 limitOnlyTo = limitSubFoldersOnlyTo.get(plotterFolder.getName(),
None)
2828 for dqmSubFolder
in plotterFolder.getDQMSubFolders(limitOnlyTo=limitOnlyTo):
2829 yield plotterFolder, dqmSubFolder
2833 def __init__(self, name, possibleDirs, plotFolder, fallbackNames=[], fallbackDqmSubFolders=[]):
2837 name -- Name of the folder (is used in the output directory naming) 2838 possibleDirs -- List of strings for possible directories of histograms in TFiles 2839 plotFolder -- PlotFolder object 2842 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. 2843 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. 2862 """Read available subfolders from the files 2865 files -- List of strings for paths to files, or list of TFiles 2867 For each file, loop over 'possibleDirs', and read the 2868 subfolders of first one that exists. 2870 Returns a PlotterFolder if at least one file for which one of 2871 'possibleDirs' exists. Otherwise, return None to signal that 2872 there is nothing available for this PlotFolder. 2877 possibleDirFound =
False 2882 isOpenFile = isinstance(fname, ROOT.TFile)
2886 tfile = ROOT.TFile.Open(fname)
2890 possibleDirFound =
True 2891 if subFolders
is not None:
2893 for key
in d.GetListOfKeys():
2894 if isinstance(key.ReadObj(), ROOT.TDirectory):
2895 subf.append(key.GetName())
2896 subFolders.append(subf)
2899 print(
"Did not find directory '%s' from file %s" % (pd, tfile.GetName()))
2904 if not possibleDirFound:
2914 def create(self, openFiles, legendLabels, dqmSubFolder):
2915 if isinstance(dqmSubFolder, list):
2916 if len(dqmSubFolder) != len(openFiles):
2917 raise Exception(
"When dqmSubFolder is a list, len(dqmSubFolder) should be len(openFiles), now they are %d and %d" % (len(dqmSubFolder), len(openFiles)))
2919 dqmSubFolder = [dqmSubFolder]*len(openFiles)
2920 dqmSubFolder = [sf.subfolder
if sf
is not None else None for sf
in dqmSubFolder]
2923 for f, sf
in zip(openFiles, dqmSubFolder):
2926 if tdir
is not None:
2942 for i
in range(len(tbl)):
2944 tbl[i] = [
None]*colLen
2950 """Contains PlotFolders, i.e. the information what plots to do, and creates a helper object to actually produce the plots.""" 2954 ROOT.TH1.AddDirectory(
False)
2957 """Append a plot folder to the plotter. 2959 All arguments are forwarded to the constructor of PlotterItem. 2964 for plotterItem
in self.
_plots:
2965 if plotterItem.getName() == attachToFolder:
2968 raise Exception(
"Did not find plot folder '%s' when trying to attach a table creator to it" % attachToFolder)
2971 """Remove all plot folders and tables""" 2975 return [item.getName()
for item
in self.
_plots]
2978 return [item.getPlotFolder()
for item
in self.
_plots]
2982 if item.getName() == name:
2983 return item.getPlotFolder()
2984 raise Exception(
"No PlotFolder named '%s'" % name)
2987 """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)
ALPAKA_FN_HOST_ACC ALPAKA_FN_INLINE constexpr float zip(ConstView const &tracks, int32_t i)
def Draw(self, options="")
def __init__(self, dataset, job_number, job_id, job_name, isDA, isMC, applyBOWS, applyEXTRACOND, extraconditions, runboundary, lumilist, intlumi, maxevents, gt, allFromGT, alignmentDB, alignmentTAG, apeDB, apeTAG, bowDB, bowTAG, vertextype, tracktype, refittertype, ttrhtype, applyruncontrol, ptcut, CMSSW_dir, the_dir)
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)
void divide(dqm::legacy::MonitorElement *eff, const dqm::legacy::MonitorElement *numerator, const dqm::legacy::MonitorElement *denominator)
Function to fill an efficiency histograms with binomial errors.
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)
def setTitle(self, title)
def setXTitle(self, title)
def create(self, tdirectory)
def readDirs(self, files)
void print(TMatrixD &m, const char *label=nullptr, bool mathematicaFormat=false)
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="")
def adjustMarginRight(self, adjust)
def __init__(self, subfolder, translated)
def create(self, tdirectory)
TEveGeoShape * clone(const TEveElement *element, TEveElement *parent)
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="")
def setTitle(self, title)
def _th1IncludeOnlyBins(histos, xbinlabels)
def __init__(self, name, possibleDirs, plotFolder, fallbackNames=[], fallbackDqmSubFolders=[])
def _getObject(tdirectory, name)