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)
1251 yoffsetFactor *= 1.5
1252 xoffsetFactor *= 1.5
1257 self.
_frame.GetYaxis().SetTitleOffset(self.
_frame.GetYaxis().GetTitleOffset()*yoffsetFactor)
1258 self.
_frame.GetXaxis().SetTitleOffset(self.
_frame.GetXaxis().GetTitleOffset()*xoffsetFactor)
1262 self.
_pad.SetLogx(log)
1265 self.
_pad.SetLogy(log)
1268 self.
_pad.SetGridx(grid)
1271 self.
_pad.SetGridy(grid)
1274 self.
_pad.SetLeftMargin(self.
_pad.GetLeftMargin()+adjust)
1280 self.
_pad.SetRightMargin(self.
_pad.GetRightMargin()+adjust)
1286 self.
_frame.SetTitle(title)
1289 self.
_frame.GetXaxis().SetTitle(title)
1292 self.
_frame.GetXaxis().SetTitleSize(size)
1295 self.
_frame.GetXaxis().SetTitleOffset(offset)
1298 self.
_frame.GetXaxis().SetLabelSize(size)
1301 self.
_frame.GetYaxis().SetTitle(title)
1304 self.
_frame.GetYaxis().SetTitleSize(size)
1307 self.
_frame.GetYaxis().SetTitleOffset(offset)
1310 self.
_pad.RedrawAxis()
1313 """Class for creating and managing a frame for a ratio plot with two subpads""" 1314 def __init__(self, pad, bounds, zmax, ratioBounds, ratioFactor, nrows, xbinlabels=None, xbinlabelsize=None, xbinlabeloption=None, ratioYTitle=_ratioYTitle):
1317 if xbinlabels
is not None:
1324 self.
_frame.GetXaxis().SetLabelSize(0)
1325 self.
_frame.GetXaxis().SetTitleSize(0)
1327 yoffsetFactor = ratioFactor
1328 divisionPoint = 1-1/ratioFactor
1329 xoffsetFactor = 1/divisionPoint
1332 xoffsetFactor *= 0.6
1335 xoffsetFactor *= 1.5
1338 xoffsetFactor *= 2.3
1343 self.
_frame.GetYaxis().SetTitleOffset(self.
_frameRatio.GetYaxis().GetTitleOffset()*yoffsetFactor)
1348 self.
_frameRatio.GetYaxis().SetNdivisions(4, 5, 0)
1353 self.
_pad.SetLogx(log)
1357 self.
_pad.SetLogy(log)
1360 self.
_pad.SetGridx(grid)
1364 self.
_pad.SetGridy(grid)
1368 self.
_pad.SetLeftMargin(self.
_pad.GetLeftMargin()+adjust)
1377 self.
_pad.SetRightMargin(self.
_pad.GetRightMargin()+adjust)
1386 self.
_frame.SetTitle(title)
1395 self.
_frameRatio.GetXaxis().SetTitleOffset(offset)
1401 self.
_frame.GetYaxis().SetTitle(title)
1407 self.
_frame.GetYaxis().SetTitleSize(size)
1411 self.
_frame.GetYaxis().SetTitleOffset(offset)
1412 self.
_frameRatio.GetYaxis().SetTitleOffset(offset)
1416 self.
_pad.RedrawAxis()
1425 self.
_coverPad = ROOT.TPad(
"coverpad",
"coverpad", xmin, ymin, xmax, ymax)
1433 """Class for creating and managing a frame for a plot from TGraph2D""" 1434 def __init__(self, pad, bounds, histos, ratioOrig, ratioFactor):
1437 self.
_pad = pad.cd(1)
1441 (xlow, ylow, width, height) = (self.
_pad.GetXlowNDC(), self.
_pad.GetYlowNDC(), self.
_pad.GetWNDC(), self.
_pad.GetHNDC())
1445 bottomMargin = self.
_pad.GetBottomMargin()
1446 bottomMarginNew = ROOT.gStyle.GetPadBottomMargin()
1448 ylowNew = yup - (1-bottomMargin)/(1-bottomMarginNew) * (yup-ylow)
1449 topMarginNew = self.
_pad.GetTopMargin() * (yup-ylow)/(yup-ylowNew)
1451 self.
_pad.SetPad(xlow, ylowNew, xup, yup)
1452 self.
_pad.SetTopMargin(topMarginNew)
1453 self.
_pad.SetBottomMargin(bottomMarginNew)
1473 self._pad.SetLeftMargin(self._pad.GetLeftMargin()+adjust)
1477 self.
_pad.SetRightMargin(self.
_pad.GetRightMargin()+adjust)
1508 self.
_firstHisto.GetZaxis().SetTitleOffset(offset)
1513 self.
_pad.SetPhi(epsilon)
1514 self.
_pad.SetTheta(90+epsilon)
1519 if hasattr(self,
"_xtitle"):
1521 if hasattr(self,
"_xtitlesize"):
1523 if hasattr(self,
"_xlabelsize"):
1524 self.
_firstHisto.GetXaxis().SetLabelSize(self._labelsize)
1525 if hasattr(self,
"_ytitle"):
1527 if hasattr(self,
"_ytitlesize"):
1529 if hasattr(self,
"_ytitleoffset"):
1533 """Abstraction on top of TLatex""" 1534 def __init__(self, x, y, text, size=None, bold=True, align="left", color=ROOT.kBlack, font=None):
1538 x -- X coordinate of the text (in NDC) 1539 y -- Y coordinate of the text (in NDC) 1540 text -- String to draw 1541 size -- Size of text (None for the default value, taken from gStyle) 1542 bold -- Should the text be bold? 1543 align -- Alignment of text (left, center, right) 1544 color -- Color of the text 1545 font -- Specify font explicitly 1554 self.
_l.SetTextFont(self.
_l.GetTextFont()-20)
1555 if font
is not None:
1556 self.
_l.SetTextFont(font)
1557 if size
is not None:
1558 self.
_l.SetTextSize(size)
1559 if isinstance(align, str):
1560 if align.lower() ==
"left":
1561 self.
_l.SetTextAlign(11)
1562 elif align.lower() ==
"center":
1563 self.
_l.SetTextAlign(21)
1564 elif align.lower() ==
"right":
1565 self.
_l.SetTextAlign(31)
1567 raise Exception(
"Error: Invalid option '%s' for text alignment! Options are: 'left', 'center', 'right'."%align)
1569 self.
_l.SetTextAlign(align)
1570 self.
_l.SetTextColor(color)
1573 """Draw the text to the current TPad. 1576 options -- For interface compatibility, ignored 1578 Provides interface compatible with ROOT's drawable objects. 1584 """Class for drawing text and a background box.""" 1585 def __init__(self, xmin, ymin, xmax, ymax, lineheight=0.04, fillColor=ROOT.kWhite, transparent=True, **kwargs):
1589 xmin -- X min coordinate of the box (NDC) 1590 ymin -- Y min coordinate of the box (NDC) (if None, deduced automatically) 1591 xmax -- X max coordinate of the box (NDC) 1592 ymax -- Y max coordinate of the box (NDC) 1593 lineheight -- Line height 1594 fillColor -- Fill color of the box 1595 transparent -- Should the box be transparent? (in practive the TPave is not created) 1597 Keyword arguments are forwarded to constructor of PlotText 1614 """Add text to current position""" 1621 def move(self, dx=0, dy=0, dw=0, dh=0):
1622 """Move the box and the contained text objects 1625 dx -- Movement in x (positive is to right) 1626 dy -- Movement in y (positive is to up) 1627 dw -- Increment of width (negative to decrease width) 1628 dh -- Increment of height (negative to decrease height) 1630 dx and dy affect to both box and text objects, dw and dh 1631 affect the box only. 1635 if self.
_ymin is not None:
1640 if self.
_ymin is not None:
1648 """Draw the box and the text to the current TPad. 1651 options -- Forwarded to ROOT.TPave.Draw(), and the Draw() of the contained objects 1656 ymin = self.currenty - 0.01
1657 self.
_pave = ROOT.TPave(self.xmin, self.ymin, self.xmax, self.ymax, 0,
"NDC")
1658 self.
_pave.SetFillColor(self.fillColor)
1665 if hasattr(src,
"GetLineColor")
and hasattr(dst,
"SetLineColor"):
1666 properties.extend([
"LineColor",
"LineStyle",
"LineWidth"])
1667 if hasattr(src,
"GetFillColor")
and hasattr(dst,
"SetFillColor"):
1668 properties.extend([
"FillColor",
"FillStyle"])
1669 if hasattr(src,
"GetMarkerColor")
and hasattr(dst,
"SetMarkerColor"):
1670 properties.extend([
"MarkerColor",
"MarkerSize",
"MarkerStyle"])
1672 for prop
in properties:
1673 getattr(dst,
"Set"+prop)(getattr(src,
"Get"+prop)())
1676 """Denotes an empty place in a group.""" 1696 """Represents one plot, comparing one or more histograms.""" 1701 name -- String for name of the plot, or Efficiency object 1704 fallback -- Dictionary for specifying fallback (default None) 1705 outname -- String for an output name of the plot (default None for the same as 'name') 1706 title -- String for a title of the plot (default None) 1707 xtitle -- String for x axis title (default None) 1708 xtitlesize -- Float for x axis title size (default None) 1709 xtitleoffset -- Float for x axis title offset (default None) 1710 xlabelsize -- Float for x axis label size (default None) 1711 ytitle -- String for y axis title (default None) 1712 ytitlesize -- Float for y axis title size (default None) 1713 ytitleoffset -- Float for y axis title offset (default None) 1714 ztitle -- String for z axis title (default None) 1715 ztitleoffset -- Float for z axis title offset (default None) 1716 xmin -- Float for x axis minimum (default None, i.e. automatic) 1717 xmax -- Float for x axis maximum (default None, i.e. automatic) 1718 ymin -- Float for y axis minimum (default 0) 1719 ymax -- Float for y axis maximum (default None, i.e. automatic) 1720 xlog -- Bool for x axis log status (default False) 1721 ylog -- Bool for y axis log status (default False) 1722 xgrid -- Bool for x axis grid status (default True) 1723 ygrid -- Bool for y axis grid status (default True) 1724 stat -- Draw stat box? (default False) 1725 fit -- Do gaussian fit? (default False) 1726 statx -- Stat box x coordinate (default 0.65) 1727 staty -- Stat box y coordinate (default 0.8) 1728 statyadjust -- List of floats for stat box y coordinate adjustments (default None) 1729 normalizeToUnitArea -- Normalize histograms to unit area? (default False) 1730 normalizeToNumberOfEvents -- Normalize histograms to number of events? If yes, the PlotFolder needs 'numberOfEventsHistogram' set to a histogram filled once per event (default False) 1731 profileX -- Take histograms via ProfileX()? (default False) 1732 fitSlicesY -- Take histograms via FitSlicesY() (default False) 1733 rebinX -- rebin x axis (default None) 1734 scale -- Scale histograms by a number (default None) 1735 xbinlabels -- List of x axis bin labels (if given, default None) 1736 xbinlabelsize -- Size of x axis bin labels (default None) 1737 xbinlabeloption -- Option string for x axis bin labels (default None) 1738 removeEmptyBins -- Bool for removing empty bins, but only if histogram has bin labels (default False) 1739 printBins -- Bool for printing bin values, but only if histogram has bin labels (default False) 1740 drawStyle -- If "hist", draw as line instead of points (default None) 1741 drawCommand -- Deliver this to Draw() (default: None for same as drawStyle) 1742 lineWidth -- If drawStyle=="hist", the width of line (default 2) 1743 legendDx -- Float for moving TLegend in x direction for separate=True (default None) 1744 legendDy -- Float for moving TLegend in y direction for separate=True (default None) 1745 legendDw -- Float for changing TLegend width for separate=True (default None) 1746 legendDh -- Float for changing TLegend height for separate=True (default None) 1747 legend -- Bool to enable/disable legend (default True) 1748 adjustMarginLeft -- Float for adjusting left margin (default None) 1749 adjustMarginRight -- Float for adjusting right margin (default None) 1750 ratio -- Possibility to disable ratio for this particular plot (default None) 1751 ratioYmin -- Float for y axis minimum in ratio pad (default: list of values) 1752 ratioYmax -- Float for y axis maximum in ratio pad (default: list of values) 1753 ratioFit -- Fit straight line in ratio? (default None) 1754 ratioUncertainty -- Plot uncertainties on ratio? (default True) 1755 ratioCoverageXrange -- Range of x axis values (xmin,xmax) to limit the automatic ratio y axis range calculation to (default None for disabled) 1756 histogramModifier -- Function to be called in create() to modify the histograms (default None) 1760 def _set(attr, default):
1761 setattr(self,
"_"+attr, kwargs.get(attr, default))
1763 _set(
"fallback",
None)
1764 _set(
"outname",
None)
1767 _set(
"xtitle",
None)
1768 _set(
"xtitlesize",
None)
1769 _set(
"xtitleoffset",
None)
1770 _set(
"xlabelsize",
None)
1771 _set(
"ytitle",
None)
1772 _set(
"ytitlesize",
None)
1773 _set(
"ytitleoffset",
None)
1774 _set(
"ztitle",
None)
1775 _set(
"ztitleoffset",
None)
1792 _set(
"statyadjust",
None)
1794 _set(
"normalizeToUnitArea",
False)
1795 _set(
"normalizeToNumberOfEvents",
False)
1796 _set(
"profileX",
False)
1797 _set(
"fitSlicesY",
False)
1798 _set(
"rebinX",
None)
1801 _set(
"xbinlabels",
None)
1802 _set(
"xbinlabelsize",
None)
1803 _set(
"xbinlabeloption",
None)
1804 _set(
"removeEmptyBins",
False)
1805 _set(
"printBins",
False)
1807 _set(
"drawStyle",
"EP")
1808 _set(
"drawCommand",
None)
1809 _set(
"lineWidth", 2)
1811 _set(
"legendDx",
None)
1812 _set(
"legendDy",
None)
1813 _set(
"legendDw",
None)
1814 _set(
"legendDh",
None)
1815 _set(
"legend",
True)
1817 _set(
"adjustMarginLeft",
None)
1818 _set(
"adjustMarginRight",
None)
1821 _set(
"ratioYmin", [0, 0.2, 0.5, 0.7, 0.8, 0.9, 0.95])
1822 _set(
"ratioYmax", [1.05, 1.1, 1.2, 1.3, 1.5, 1.8, 2, 2.5, 3, 4, 5])
1823 _set(
"ratioFit",
None)
1824 _set(
"ratioUncertainty",
True)
1825 _set(
"ratioCoverageXrange",
None)
1827 _set(
"histogramModifier",
None)
1832 for name, value
in kwargs.items():
1833 if not hasattr(self,
"_"+name):
1834 raise Exception(
"No attribute '%s'" % name)
1835 setattr(self,
"_"+name, value)
1839 raise Exception(
"Plot can be cloned only before histograms have been created")
1840 cl = copy.copy(self)
1841 cl.setProperties(**kwargs)
1845 """Return number of existing histograms.""" 1846 return len([h
for h
in self.
_histograms if h
is not None])
1849 """Return true if there are no histograms created for the plot""" 1854 if isinstance(h, ROOT.TGraph2D):
1859 if self._ratio
is None:
1861 return ratio
and self._ratio
1867 if self._outname
is not None:
1868 return self._outname
1869 if isinstance(self.
_name, list):
1875 """Return true if the ratio uncertainty should be drawn""" 1876 return self._ratioUncertainty
1879 """Create one histogram from a TDirectory.""" 1884 if isinstance(name, list):
1888 if h
is not None and self._normalizeToNumberOfEvents
and nevents
is not None and nevents != 0:
1889 h.Scale(1.0/nevents)
1892 def create(self, tdirNEvents, requireAllHistograms=False):
1893 """Create histograms from list of TDirectories""" 1894 self.
_histograms = [self.
_createOne(self.
_name, i, tdirNEvent[0], tdirNEvent[1])
for i, tdirNEvent
in enumerate(tdirNEvents)]
1896 if self._fallback
is not None:
1900 self.
_histograms[i] = self.
_createOne(self._fallback[
"name"], i, tdirNEvents[i][0], tdirNEvents[i][1])
1901 profileX[i] = self._fallback.get(
"profileX", self._profileX)
1903 if self._histogramModifier
is not None:
1907 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)))
1912 def _modifyHisto(th1, profileX):
1917 th1 = th1.ProfileX()
1919 if self._fitSlicesY:
1920 ROOT.TH1.AddDirectory(
True)
1922 th1 = ROOT.gDirectory.Get(th1.GetName()+
"_2")
1923 th1.SetDirectory(
None)
1925 ROOT.TH1.AddDirectory(
False)
1927 if self._title
is not None:
1928 th1.SetTitle(self._title)
1930 if self._scale
is not None:
1931 th1.Scale(self._scale)
1935 if self._fallback
is not None:
1939 if requireAllHistograms
and None in self.
_histograms:
1943 """Set stats box.""" 1946 if h
is not None and hasattr(h,
"SetStats"):
1950 def _doStats(h, col, dy):
1955 if self._fit
and h.GetEntries() > 0.5:
1957 f = h.GetListOfFunctions().FindObject(
"gaus")
1965 st = h.GetListOfFunctions().FindObject(
"stats")
1970 st.SetX1NDC(startingX)
1971 st.SetX2NDC(startingX+0.3)
1972 st.SetY1NDC(startingY+dy)
1973 st.SetY2NDC(startingY+dy+0.12)
1974 st.SetTextColor(col)
1977 for i, h
in enumerate(histos):
1978 if self._statyadjust
is not None and i < len(self._statyadjust):
1979 dy += self._statyadjust[i]
1981 _doStats(h, _plotStylesColor[i], dy)
1985 """Normalise histograms to unit area""" 1993 if h.GetSumw2().fN <= 0:
1997 def draw(self, pad, ratio, ratioFactor, nrows):
1998 """Draw the histograms using values for a given algorithm.""" 2009 if self._normalizeToUnitArea:
2012 if self._rebinX
is not None:
2014 h.Rebin(self._rebinX)
2016 def _styleMarker(h, msty, col):
2017 h.SetMarkerStyle(msty)
2018 h.SetMarkerColor(col)
2019 h.SetMarkerSize(0.7)
2023 def _styleHist(h, msty, col):
2024 _styleMarker(h, msty, col)
2026 h.SetLineWidth(self._lineWidth)
2029 style = _styleMarker
2030 if "hist" in self._drawStyle.lower():
2033 if "l" in self._drawStyle.lower():
2041 style(h, _plotStylesMarker[i], _plotStylesColor[i])
2043 if len(histos) == 0:
2050 histosHaveBinLabels = len(histos[0].GetXaxis().GetBinLabel(1)) > 0
2051 xbinlabels = self._xbinlabels
2053 if xbinlabels
is None:
2054 if histosHaveBinLabels:
2056 if isinstance(histos[0], ROOT.TH2):
2065 if self._removeEmptyBins
and histosHaveBinLabels:
2068 if isinstance(histos[0], ROOT.TH2):
2073 if len(histos) == 0:
2075 print(
"No histograms with non-empty bins for plot {name}".
format(name=self.
getName()))
2078 if self._printBins
and histosHaveBinLabels:
2079 print(
"####################")
2081 width =
max([len(l)
for l
in xbinlabels])
2082 tmp =
"%%-%ds " % width
2083 for b
in range(1, histos[0].GetNbinsX()+1):
2084 s = tmp % xbinlabels[b-1]
2086 s +=
"%.3f " % h.GetBinContent(b)
2091 xmin=self._xmin, xmax=self._xmax,
2092 ymin=self._ymin, ymax=self._ymax)
2094 if isinstance(histos[0], ROOT.TH2):
2095 zmax =
max([h.GetMaximum()
for h
in histos])
2103 ratioHistos = [h
for h
in [r.getRatio()
for r
in self.
_ratios[1:]]
if h
is not None]
2105 if len(ratioHistos) > 0:
2106 ratioBoundsY =
_findBoundsY(ratioHistos, ylog=
False, ymin=self._ratioYmin, ymax=self._ratioYmax, coverage=0.68, coverageRange=self._ratioCoverageXrange)
2108 ratioBoundsY = (0.9, 1,1)
2110 if self._ratioFit
is not None:
2111 for i, rh
in enumerate(ratioHistos):
2112 tf_line = ROOT.TF1(
"line%d"%i,
"[0]+x*[1]")
2113 tf_line.SetRange(self._ratioFit[
"rangemin"], self._ratioFit[
"rangemax"])
2114 fitres = rh.Fit(tf_line,
"RINSQ")
2115 tf_line.SetLineColor(rh.GetMarkerColor())
2116 tf_line.SetLineWidth(2)
2118 box =
PlotTextBox(xmin=self._ratioFit.get(
"boxXmin", 0.14), ymin=
None,
2119 xmax=self._ratioFit.get(
"boxXmax", 0.35), ymax=self._ratioFit.get(
"boxYmax", 0.09),
2120 color=rh.GetMarkerColor(), font=43, size=11, lineheight=0.02)
2121 box.move(dx=(box.width()+0.01)*i)
2124 box.addText(
"Const: %.4f#pm%.4f" % (fitres.Parameter(0), fitres.ParError(0)))
2125 box.addText(
"Slope: %.4f#pm%.4f" % (fitres.Parameter(1), fitres.ParError(1)))
2136 self.
_setStats(histos, self._statx, self._staty)
2140 frame =
FrameTGraph2D(pad, bounds, histos, ratioOrig, ratioFactor)
2143 ratioBounds = (bounds[0], ratioBoundsY[0], bounds[2], ratioBoundsY[1])
2144 frame =
FrameRatio(pad, bounds, zmax, ratioBounds, ratioFactor, nrows, xbinlabels, self._xbinlabelsize, self._xbinlabeloption)
2146 frame =
Frame(pad, bounds, zmax, nrows, xbinlabels, self._xbinlabelsize, self._xbinlabeloption, ybinlabels=ybinlabels)
2149 frame.setLogx(self._xlog)
2150 frame.setLogy(self._ylog)
2151 frame.setGridx(self._xgrid)
2152 frame.setGridy(self._ygrid)
2157 if self._drawStyle
is not None:
2158 ds = self._drawStyle
2159 if self._drawCommand
is not None:
2160 ds = self._drawCommand
2165 frame.setTitle(histos[0].GetTitle())
2167 frame.setXTitle( histos[0].GetXaxis().GetTitle() )
2168 elif self.
_xtitle is not None:
2170 if self._xtitlesize
is not None:
2171 frame.setXTitleSize(self._xtitlesize)
2172 if self._xtitleoffset
is not None:
2173 frame.setXTitleOffset(self._xtitleoffset)
2174 if self._xlabelsize
is not None:
2175 frame.setXLabelSize(self._xlabelsize)
2177 frame.setYTitle( histos[0].GetYaxis().GetTitle() )
2178 elif self.
_ytitle is not None:
2180 if self._ytitlesize
is not None:
2181 frame.setYTitleSize(self._ytitlesize)
2182 if self._ytitleoffset
is not None:
2183 frame.setYTitleOffset(self._ytitleoffset)
2184 if self._ztitle
is not None:
2185 frame.setZTitle(self._ztitle)
2186 if self._ztitleoffset
is not None:
2187 frame.setZTitleOffset(self._ztitleoffset)
2188 if self._adjustMarginLeft
is not None:
2189 frame.adjustMarginLeft(self._adjustMarginLeft)
2190 if self._adjustMarginRight
is not None:
2191 frame.adjustMarginRight(self._adjustMarginRight)
2193 frame.adjustMarginLeft(0.03)
2194 frame.adjustMarginRight(0.08)
2200 for i, h
in enumerate(histos):
2202 if isTGraph2D
and i == 0:
2203 o = o.replace(
"sames",
"")
2210 if ratio
and len(self.
_ratios) > 0:
2211 frame._padRatio.cd()
2212 firstRatio = self.
_ratios[0].getRatio()
2213 if self._ratioUncertainty
and firstRatio
is not None:
2214 firstRatio.SetFillStyle(1001)
2215 firstRatio.SetFillColor(ROOT.kGray)
2216 firstRatio.SetLineColor(ROOT.kGray)
2217 firstRatio.SetMarkerColor(ROOT.kGray)
2218 firstRatio.SetMarkerSize(0)
2220 frame._padRatio.RedrawAxis(
"G")
2231 """Add histograms to a legend. 2235 legendLabels -- List of strings for the legend labels 2237 first = denomUncertainty
2246 entry = legend.AddEntry(self.
_forLegend, label,
"lpf")
2249 legend.AddEntry(h, label,
"LP")
2252 """Group of plots, results a TCanvas""" 2257 name -- String for name of the TCanvas, used also as the basename of the picture files 2258 plots -- List of Plot objects 2261 ncols -- Number of columns (default 2) 2262 legendDx -- Float for moving TLegend in x direction (default None) 2263 legendDy -- Float for moving TLegend in y direction (default None) 2264 legendDw -- Float for changing TLegend width (default None) 2265 legendDh -- Float for changing TLegend height (default None) 2266 legend -- Bool for disabling legend (default True for legend being enabled) 2267 overrideLegendLabels -- List of strings for legend labels, if given, these are used instead of the ones coming from Plotter (default None) 2268 onlyForPileup -- Plots this group only for pileup samples 2275 def _set(attr, default):
2276 setattr(self,
"_"+attr, kwargs.get(attr, default))
2280 _set(
"legendDx",
None)
2281 _set(
"legendDy",
None)
2282 _set(
"legendDw",
None)
2283 _set(
"legendDh",
None)
2284 _set(
"legend",
True)
2286 _set(
"overrideLegendLabels",
None)
2288 _set(
"onlyForPileup",
False)
2293 for name, value
in kwargs.items():
2294 if not hasattr(self,
"_"+name):
2295 raise Exception(
"No attribute '%s'" % name)
2296 setattr(self,
"_"+name, value)
2305 for i, plot
in enumerate(self.
_plots):
2306 if plot.getName() == name:
2309 raise Exception(
"Did not find Plot '%s' from PlotGroup '%s'" % (name, self.
_name))
2319 if plot.getName() == name:
2321 raise Exception(
"No Plot named '%s'" % name)
2324 """Return True if the PlotGroup is intended only for pileup samples""" 2325 return self._onlyForPileup
2327 def create(self, tdirectoryNEvents, requireAllHistograms=False):
2328 """Create histograms from a list of TDirectories. 2331 tdirectoryNEvents -- List of (TDirectory, nevents) pairs 2332 requireAllHistograms -- If True, a plot is produced if histograms from all files are present (default: False) 2335 plot.create(tdirectoryNEvents, requireAllHistograms)
2337 def draw(self, legendLabels, prefix=None, separate=False, saveFormat=".pdf", ratio=True, directory=""):
2338 """Draw the histograms using values for a given algorithm. 2341 legendLabels -- List of strings for legend labels (corresponding to the tdirectories in create()) 2342 prefix -- Optional string for file name prefix (default None) 2343 separate -- Save the plots of a group to separate files instead of a file per group (default False) 2344 saveFormat -- String specifying the plot format (default '.pdf') 2345 ratio -- Add ratio to the plot (default True) 2346 directory -- Directory where to save the file (default "") 2349 if self._overrideLegendLabels
is not None:
2350 legendLabels = self._overrideLegendLabels
2353 onlyEmptyPlots =
True 2355 if not plot.isEmpty():
2356 onlyEmptyPlots =
False 2362 return self.
_drawSeparate(legendLabels, prefix, saveFormat, ratio, directory)
2364 cwidth = 500*self._ncols
2365 nrows =
int((len(self.
_plots)+self._ncols-1)/self._ncols)
2366 cheight = 500 * nrows
2373 canvas.Divide(self._ncols, nrows)
2375 for i, plot
in enumerate(self.
_plots):
2376 pad = canvas.cd(i+1)
2380 for i, plot
in enumerate(self.
_plots):
2381 pad = canvas.cd(i+1)
2382 if not plot.isEmpty():
2388 if len(self.
_plots) <= 4:
2398 if self._legendDx
is not None:
2399 lx1 += self._legendDx
2400 lx2 += self._legendDx
2401 if self._legendDy
is not None:
2402 ly1 += self._legendDy
2403 ly2 += self._legendDy
2404 if self._legendDw
is not None:
2405 lx2 += self._legendDw
2406 if self._legendDh
is not None:
2407 ly1 -= self._legendDh
2408 plot =
max(self.
_plots, key=
lambda p: p.getNumberOfHistograms())
2409 denomUnc = sum([p.drawRatioUncertainty()
for p
in self.
_plots]) > 0
2410 legend = self.
_createLegend(plot, legendLabels, lx1, ly1, lx2, ly2,
2411 denomUncertainty=(ratio
and denomUnc))
2413 return self.
_save(canvas, saveFormat, prefix=prefix, directory=directory)
2416 """Internal method to do the drawing to separate files per Plot instead of a file per PlotGroup""" 2435 for c
in [canvas, canvasRatio]:
2436 c.SetTopMargin(0.05)
2437 c.SetBottomMargin(0.13)
2438 c.SetLeftMargin(0.16)
2439 c.SetRightMargin(0.05)
2441 ratioForThisPlot = plot.isRatio(ratio)
2443 if ratioForThisPlot:
2459 if plot._legendDx
is not None:
2460 lx1 += plot._legendDx
2461 lx2 += plot._legendDx
2462 if plot._legendDy
is not None:
2463 ly1 += plot._legendDy
2464 ly2 += plot._legendDy
2465 if plot._legendDw
is not None:
2466 lx2 += plot._legendDw
2467 if plot._legendDh
is not None:
2468 ly1 -= plot._legendDh
2471 legend = self.
_createLegend(plot, legendLabels, lx1, ly1, lx2, ly2, textSize=0.03,
2472 denomUncertainty=(ratioForThisPlot
and plot.drawRatioUncertainty))
2474 ret.extend(self.
_save(c, saveFormat, prefix=prefix, postfix=
"/"+plot.getName(), single=
True, directory=directory))
2478 """Internal method to set divide a pad to two for ratio plots""" 2481 def _createLegend(self, plot, legendLabels, lx1, ly1, lx2, ly2, textSize=0.016, denomUncertainty=True):
2482 if not self._legend:
2485 l = ROOT.TLegend(lx1, ly1, lx2, ly2)
2486 l.SetTextSize(textSize)
2493 plot.addToLegend(l, legendLabels, denomUncertainty)
2497 def _save(self, canvas, saveFormat, prefix=None, postfix=None, single=False, directory=""):
2500 if not os.path.exists(directory+
'/'+name):
2501 os.makedirs(directory+
'/'+name, exist_ok=
True)
2502 if prefix
is not None:
2504 if postfix
is not None:
2506 name = os.path.join(directory, name)
2509 backup = ROOT.gErrorIgnoreLevel
2510 ROOT.gErrorIgnoreLevel = ROOT.kWarning
2511 canvas.SaveAs(name+saveFormat)
2513 ROOT.gErrorIgnoreLevel = backup
2517 canvas.SetLogx(
False)
2518 canvas.SetLogy(
False)
2522 return [name+saveFormat]
2525 """Resembles DQM GUI's "On side" layout. 2527 Like PlotGroup, but has only a description of a single plot. The 2528 plot is drawn separately for each file. Useful for 2D histograms.""" 2530 def __init__(self, name, plot, ncols=2, onlyForPileup=False):
2531 super(PlotOnSideGroup, self).
__init__(name, [], ncols=ncols, legend=
False, onlyForPileup=onlyForPileup)
2536 raise Exception(
"PlotOnSideGroup.append() is not implemented")
2538 def create(self, tdirectoryNEvents, requireAllHistograms=False):
2540 for i, element
in enumerate(tdirectoryNEvents):
2542 pl.create([element], requireAllHistograms)
2543 pl.setName(pl.getName()+
"_"+
str(i))
2547 kargs = copy.copy(kwargs)
2548 kargs[
"ratio"] =
False 2549 return super(PlotOnSideGroup, self).
draw(*args, **kargs)
2553 """Represents a collection of PlotGroups, produced from a single folder in a DQM file""" 2558 plotGroups -- List of PlotGroup objects 2561 loopSubFolders -- Should the subfolders be looped over? (default: True) 2562 onlyForPileup -- Plots this folder only for pileup samples 2563 onlyForElectron -- Plots this folder only for electron samples 2564 onlyForConversion -- Plots this folder only for conversion samples 2565 onlyForBHadron -- Plots this folder only for B-hadron samples 2566 purpose -- html.PlotPurpose member class for the purpose of the folder, used for grouping of the plots to the HTML pages 2567 page -- Optional string for the page in HTML generatin 2568 section -- Optional string for the section within a page in HTML generation 2569 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". 2582 raise Exception(
"Got unexpected keyword arguments: "+
",".
join(kwargs.keys()))
2585 """Return True if the PlotGroups of this folder should be applied to the all subfolders""" 2589 """Return True if the folder is intended only for pileup samples""" 2624 if pg.getName() == name:
2626 raise Exception(
"No PlotGroup named '%s'" % name)
2628 def create(self, dirsNEvents, labels, isPileupSample=True, requireAllHistograms=False):
2629 """Create histograms from a list of TFiles. 2632 dirsNEvents -- List of (TDirectory, nevents) pairs 2633 labels -- List of strings for legend labels corresponding the files 2634 isPileupSample -- Is sample pileup (some PlotGroups may limit themselves to pileup) 2635 requireAllHistograms -- If True, a plot is produced if histograms from all files are present (default: False) 2638 if len(dirsNEvents) != len(labels):
2639 raise Exception(
"len(dirsNEvents) should be len(labels), now they are %d and %d" % (len(dirsNEvents), len(labels)))
2644 if pg.onlyForPileup()
and not isPileupSample:
2646 pg.create(dirsNEvents, requireAllHistograms)
2648 def draw(self, prefix=None, separate=False, saveFormat=".pdf", ratio=True, directory=""):
2649 """Draw and save all plots using settings of a given algorithm. 2652 prefix -- Optional string for file name prefix (default None) 2653 separate -- Save the plots of a group to separate files instead of a file per group (default False) 2654 saveFormat -- String specifying the plot format (default '.pdf') 2655 ratio -- Add ratio to the plot (default True) 2656 directory -- Directory where to save the file (default "") 2661 ret.extend(pg.draw(self.
_labels, prefix=prefix, separate=separate, saveFormat=saveFormat, ratio=ratio, directory=directory))
2667 """Method called to (possibly) translate a subfolder name to more 'readable' form 2669 The implementation in this (base) class just returns the 2670 argument. The idea is that a deriving class might want to do 2671 something more complex (like trackingPlots.TrackingPlotFolder 2674 return dqmSubFolderName
2677 """Iterate over possible selections name (used in output directory name and legend) from the name of PlotterFolder, and a return value of translateSubFolder""" 2679 if plotFolderName !=
"":
2680 ret +=
"_"+plotFolderName
2681 if translatedDqmSubFolder
is not None:
2682 ret +=
"_"+translatedDqmSubFolder
2686 """Return True if this subfolder should be processed 2689 limitOnlyTo -- List/set/similar containing the translatedDqmSubFolder 2690 translatedDqmSubFolder -- Return value of translateSubFolder 2692 return translatedDqmSubFolder
in limitOnlyTo
2695 """Class to hold the original name and a 'translated' name of a subfolder in the DQM ROOT file""" 2701 """Equality is defined by the 'translated' name""" 2705 """Plotter for one DQM folder. 2707 This class is supposed to be instantiated by the Plotter class (or 2708 PlotterItem, to be more specific), and not used directly by the 2711 def __init__(self, name, possibleDqmFolders, dqmSubFolders, plotFolder, fallbackNames, fallbackDqmSubFolders, tableCreators):
2716 name -- Name of the folder (is used in the output directory naming) 2717 possibleDqmFolders -- List of strings for possible directories of histograms in TFiles 2718 dqmSubFolders -- List of lists of strings for list of subfolders per input file, or None if no subfolders 2719 plotFolder -- PlotFolder object 2720 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. 2721 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. 2722 tableCreators -- List of PlotterTableItem objects for tables to be created from this folder 2728 if dqmSubFolders
is None:
2734 for sf_list
in dqmSubFolders:
2736 sf_translated = self.
_plotFolder.translateSubFolder(sf)
2737 if sf_translated
is not None and not sf_translated
in subfolders:
2738 subfolders[sf_translated] =
DQMSubFolder(sf, sf_translated)
2740 self.
_dqmSubFolders = sorted(subfolders.values(), key=
lambda sf: sf.subfolder)
2774 """Get list of subfolders, possibly limiting to some of them. 2777 limitOnlyTo -- Object depending on the PlotFolder type for limiting the set of subfolders to be processed 2783 if limitOnlyTo
is None:
2792 """Get a generator for the 'selection name', looping over the name and fallbackNames""" 2794 for selname
in self.
_plotFolder.iterSelectionName(name, dqmSubFolder.translated
if dqmSubFolder
is not None else None):
2800 def create(self, files, labels, dqmSubFolder, isPileupSample=True, requireAllHistograms=False):
2801 """Create histograms from a list of TFiles. 2803 files -- List of TFiles 2804 labels -- List of strings for legend labels corresponding the files 2805 dqmSubFolder -- DQMSubFolder object for a subfolder (or None for no subfolder) 2806 isPileupSample -- Is sample pileup (some PlotGroups may limit themselves to pileup) 2807 requireAllHistograms -- If True, a plot is produced if histograms from all files are present (default: False) 2810 subfolder = dqmSubFolder.subfolder
if dqmSubFolder
is not None else None 2811 neventsHisto = self.
_plotFolder.getNumberOfEventsHistogram()
2819 fallback = fallbackFunc(subfolder)
2820 if fallback
is not None:
2824 d = GetDirectoryCode.codesToNone(ret)
2826 if neventsHisto
is not None and tfile
is not None:
2828 if hnev
is not None:
2829 nev = hnev.GetEntries()
2830 dirsNEvents.append( (d, nev) )
2832 self.
_plotFolder.
create(dirsNEvents, labels, isPileupSample, requireAllHistograms)
2835 """Draw and save all plots using settings of a given algorithm.""" 2840 """Instance of plotter that knows the directory content, holds many folders.""" 2847 if limitSubFoldersOnlyTo
is not None:
2848 limitOnlyTo = limitSubFoldersOnlyTo.get(plotterFolder.getName(),
None)
2850 for dqmSubFolder
in plotterFolder.getDQMSubFolders(limitOnlyTo=limitOnlyTo):
2851 yield plotterFolder, dqmSubFolder
2855 def __init__(self, name, possibleDirs, plotFolder, fallbackNames=[], fallbackDqmSubFolders=[]):
2859 name -- Name of the folder (is used in the output directory naming) 2860 possibleDirs -- List of strings for possible directories of histograms in TFiles 2861 plotFolder -- PlotFolder object 2864 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. 2865 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. 2884 """Read available subfolders from the files 2887 files -- List of strings for paths to files, or list of TFiles 2889 For each file, loop over 'possibleDirs', and read the 2890 subfolders of first one that exists. 2892 Returns a PlotterFolder if at least one file for which one of 2893 'possibleDirs' exists. Otherwise, return None to signal that 2894 there is nothing available for this PlotFolder. 2899 possibleDirFound =
False 2904 isOpenFile = isinstance(fname, ROOT.TFile)
2908 tfile = ROOT.TFile.Open(fname)
2912 possibleDirFound =
True 2913 if subFolders
is not None:
2915 for key
in d.GetListOfKeys():
2916 if isinstance(key.ReadObj(), ROOT.TDirectory):
2917 subf.append(key.GetName())
2918 subFolders.append(subf)
2921 print(
"Did not find directory '%s' from file %s" % (pd, tfile.GetName()))
2926 if not possibleDirFound:
2936 def create(self, openFiles, legendLabels, dqmSubFolder):
2937 if isinstance(dqmSubFolder, list):
2938 if len(dqmSubFolder) != len(openFiles):
2939 raise Exception(
"When dqmSubFolder is a list, len(dqmSubFolder) should be len(openFiles), now they are %d and %d" % (len(dqmSubFolder), len(openFiles)))
2941 dqmSubFolder = [dqmSubFolder]*len(openFiles)
2942 dqmSubFolder = [sf.subfolder
if sf
is not None else None for sf
in dqmSubFolder]
2945 for f, sf
in zip(openFiles, dqmSubFolder):
2948 if tdir
is not None:
2964 for i
in range(len(tbl)):
2966 tbl[i] = [
None]*colLen
2972 """Contains PlotFolders, i.e. the information what plots to do, and creates a helper object to actually produce the plots.""" 2976 ROOT.TH1.AddDirectory(
False)
2979 """Append a plot folder to the plotter. 2981 All arguments are forwarded to the constructor of PlotterItem. 2986 for plotterItem
in self.
_plots:
2987 if plotterItem.getName() == attachToFolder:
2990 raise Exception(
"Did not find plot folder '%s' when trying to attach a table creator to it" % attachToFolder)
2993 """Remove all plot folders and tables""" 2997 return [item.getName()
for item
in self.
_plots]
3000 return [item.getPlotFolder()
for item
in self.
_plots]
3004 if item.getName() == name:
3005 return item.getPlotFolder()
3006 raise Exception(
"No PlotFolder named '%s'" % name)
3009 """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, 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)
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)
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)