10 ROOT.gROOT.SetBatch(
True)
11 ROOT.PyConfig.IgnoreCommandLineOptions =
True 16 _ratioYTitle =
"Ratio" 31 ROOT.gROOT.SetStyle(
"Plain")
32 ROOT.gStyle.SetPadRightMargin(0.07)
33 ROOT.gStyle.SetPadLeftMargin(0.13)
34 ROOT.gStyle.SetTitleFont(font,
"XYZ")
35 ROOT.gStyle.SetTitleSize(titleSize,
"XYZ")
36 ROOT.gStyle.SetTitleOffset(1.2,
"Y")
38 ROOT.gStyle.SetLabelFont(font,
"XYZ")
39 ROOT.gStyle.SetLabelSize(labelSize,
"XYZ")
40 ROOT.gStyle.SetTextSize(labelSize)
41 ROOT.gStyle.SetStatFont(font)
42 ROOT.gStyle.SetStatFontSize(statSize)
44 ROOT.TGaxis.SetMaxDigits(4)
47 obj = tdirectory.Get(name)
50 print "Did not find {obj} from {dir}".
format(obj=name, dir=tdirectory.GetPath())
55 if hasattr(nameOrCreator,
"create"):
56 return nameOrCreator.create(tdirectory)
71 """Get TDirectory from TFile.""" 74 for pdf
in possibleDirs:
77 if subDir
is not None:
84 print "Did not find subdirectory '%s' from directory '%s' in file %s" % (subDir, pdf, tfile.GetName())
91 print "Did not find any of directories '%s' from file %s" % (
",".
join(possibleDirs), tfile.GetName())
98 values = collections.OrderedDict()
99 for i
in xrange(1, th1.GetNbinsX()+1):
100 binLabel = th1.GetXaxis().GetBinLabel(i)
101 if renameBin
is not None:
102 binLabel = renameBin(binLabel)
103 values[binLabel] = (th1.GetBinContent(i), th1.GetBinError(i))
109 backup = ROOT.gErrorIgnoreLevel
110 ROOT.gErrorIgnoreLevel = ROOT.kError
111 canvas = ROOT.TCanvas(name, name, width, height)
113 ROOT.gErrorIgnoreLevel = backup
119 divisionPoint = 1-1/ratioFactor
121 topMargin = pad.GetTopMargin()
122 bottomMargin = pad.GetBottomMargin()
123 divisionPoint += (1-divisionPoint)*bottomMargin
124 divisionPointForPad1 = 1-( (1-divisionPoint) / (1-0.02) )
129 ylow = divisionPointForPad1
132 pad1.SetPad(xlow, ylow, xup, yup)
133 pad1.SetFillStyle(4000)
134 pad1.SetBottomMargin(0.02)
140 pad2.SetPad(xlow, ylow, xup, yup)
141 pad2.SetFillStyle(4000)
142 pad2.SetTopMargin(0.0)
143 pad2.SetBottomMargin(bottomMargin/(ratioFactor*divisionPoint))
146 """Calculate the ratios for a list of histograms""" 148 def _divideOrZero(numerator, denominator):
151 return numerator/denominator
154 if a == 0.
and b == 0.:
158 def findBins(wrap, bins_xvalues):
160 currBin = wrap.begin()
162 while i < len(bins_xvalues)
and currBin < wrap.end():
163 (xcenter, xlow, xhigh) = bins_xvalues[i]
164 xlowEdge = xcenter-xlow
165 xupEdge = xcenter+xhigh
167 (curr_center, curr_low, curr_high) = wrap.xvalues(currBin)
168 curr_lowEdge = curr_center-curr_low
169 curr_upEdge = curr_center+curr_high
171 if equal(xlowEdge, curr_lowEdge)
and equal(xupEdge, curr_upEdge):
175 elif curr_upEdge <= xlowEdge:
177 elif curr_lowEdge >= xupEdge:
184 if len(ret) != len(bins_xvalues):
185 ret.extend([
None]*( len(bins_xvalues) - len(ret) ))
191 def __init__(self, th1, uncertainty):
193 self._uncertainty = uncertainty
195 xaxis = th1.GetXaxis()
196 xaxis_arr = xaxis.GetXbins()
197 if xaxis_arr.GetSize() > 0:
198 lst = [xaxis_arr[i]
for i
in xrange(0, xaxis_arr.GetSize())]
199 arr = array.array(
"d", lst)
200 self._ratio = ROOT.TH1F(
"foo",
"foo", xaxis.GetNbins(), arr)
202 self._ratio = ROOT.TH1F(
"foo",
"foo", xaxis.GetNbins(), xaxis.GetXmin(), xaxis.GetXmax())
204 self._ratio.SetStats(0)
205 self._ratio.SetLineColor(ROOT.kBlack)
206 self._ratio.SetLineWidth(1)
207 def draw(self, style=None):
210 if self._uncertainty:
214 self._ratio.Draw(
"same "+st)
218 return self._th1.GetNbinsX()+1
219 def xvalues(self, bin):
220 xval = self._th1.GetBinCenter(bin)
221 xlow = xval-self._th1.GetXaxis().GetBinLowEdge(bin)
222 xhigh = self._th1.GetXaxis().GetBinUpEdge(bin)-xval
223 return (xval, xlow, xhigh)
224 def yvalues(self, bin):
225 yval = self._th1.GetBinContent(bin)
226 yerr = self._th1.GetBinError(bin)
227 return (yval, yerr, yerr)
229 return self._th1.GetBinContent(bin)
230 def divide(self, bin, scale):
231 self._ratio.SetBinContent(bin, _divideOrZero(self._th1.GetBinContent(bin), scale))
232 self._ratio.SetBinError(bin, _divideOrZero(self._th1.GetBinError(bin), scale))
239 def __init__(self, gr, uncertainty):
241 self._uncertainty = uncertainty
248 def draw(self, style=None):
249 if self._ratio
is None:
253 if self._uncertainty:
257 self._ratio.Draw(
"same "+st)
261 return self._gr.GetN()
262 def xvalues(self, bin):
263 return (self._gr.GetX()[bin], self._gr.GetErrorXlow(bin), self._gr.GetErrorXhigh(bin))
264 def yvalues(self, bin):
265 return (self._gr.GetY()[bin], self._gr.GetErrorYlow(bin), self._gr.GetErrorYhigh(bin))
267 return self._gr.GetY()[bin]
268 def divide(self, bin, scale):
273 if bin >= self._gr.GetN():
276 xvals = self.xvalues(bin)
279 self._xvalues.append(xval)
280 self._xerrslow.append(xvals[1])
281 self._xerrshigh.append(xvals[2])
282 yvals = self.yvalues(bin)
283 self._yvalues.append(yvals[0] / scale)
284 if self._uncertainty:
285 self._yerrslow.append(yvals[1] / scale)
286 self._yerrshigh.append(yvals[2] / scale)
288 self._yerrslow.append(0)
289 self._yerrshigh.append(0)
291 if len(self._xvalues) == 0:
294 self._ratio = ROOT.TGraphAsymmErrors(len(self._xvalues), array.array(
"d", self._xvalues), array.array(
"d", self._yvalues),
295 array.array(
"d", self._xerrslow), array.array(
"d", self._xerrshigh),
296 array.array(
"d", self._yerrslow), array.array(
"d", self._yerrshigh))
300 class WrapTGraph2D(WrapTGraph):
301 def __init__(self, gr, uncertainty):
302 WrapTGraph.__init__(self, gr, uncertainty)
303 def xvalues(self, bin):
304 return (self._gr.GetX()[bin], self._gr.GetErrorX(bin), self._gr.GetErrorX(bin))
305 def yvalues(self, bin):
306 return (self._gr.GetY()[bin], self._gr.GetErrorY(bin), self._gr.GetErrorY(bin))
309 if isinstance(o, ROOT.TH1):
310 return WrapTH1(o, ratioUncertainty)
311 elif isinstance(o, ROOT.TGraph):
312 return WrapTGraph(o, ratioUncertainty)
313 elif isinstance(o, ROOT.TGraph2D):
314 return WrapTGraph2D(o, ratioUncertainty)
316 wrappers = [
wrap(h)
for h
in histos]
320 ref_bins = [ref.xvalues(b)
for b
in xrange(ref.begin(), ref.end())]
322 wrappers_bins.append(findBins(w, ref_bins))
324 for i, bin
in enumerate(xrange(ref.begin(), ref.end())):
325 (scale, ylow, yhigh) = ref.yvalues(bin)
326 for w, bins
in zip(wrappers, wrappers_bins):
329 w.divide(bins[i], scale)
338 if isinstance(obj, ROOT.TH1):
339 xaxis = obj.GetXaxis()
340 if limitToNonZeroContent:
341 for i
in xrange(1, obj.GetNbinsX()+1):
342 if obj.GetBinContent(i) != 0:
343 return xaxis.GetBinLowEdge(i)
347 return xaxis.GetBinLowEdge(xaxis.GetFirst())
348 elif isinstance(obj, ROOT.TGraph)
or isinstance(obj, ROOT.TGraph2D):
349 m =
min([obj.GetX()[i]
for i
in xrange(0, obj.GetN())])
350 return m*0.9
if m > 0
else m*1.1
354 if isinstance(obj, ROOT.TH1):
355 xaxis = obj.GetXaxis()
356 if limitToNonZeroContent:
357 for i
in xrange(obj.GetNbinsX(), 0, -1):
358 if obj.GetBinContent(i) != 0:
359 return xaxis.GetBinUpEdge(i)
363 return xaxis.GetBinUpEdge(xaxis.GetLast())
364 elif isinstance(obj, ROOT.TGraph)
or isinstance(obj, ROOT.TGraph2D):
365 m =
max([obj.GetX()[i]
for i
in xrange(0, obj.GetN())])
366 return m*1.1
if m > 0
else m*0.9
370 if isinstance(obj, ROOT.TH2):
371 yaxis = obj.GetYaxis()
372 return yaxis.GetBinLowEdge(yaxis.GetFirst())
373 elif isinstance(obj, ROOT.TH1):
374 if limitToNonZeroContent:
375 lst = [obj.GetBinContent(i)
for i
in xrange(1, obj.GetNbinsX()+1)
if obj.GetBinContent(i) != 0 ]
376 return min(lst)
if len(lst) != 0
else 0
378 return obj.GetMinimum()
379 elif isinstance(obj, ROOT.TGraph)
or isinstance(obj, ROOT.TGraph2D):
380 m =
min([obj.GetY()[i]
for i
in xrange(0, obj.GetN())])
381 return m*0.9
if m > 0
else m*1.1
385 if isinstance(obj, ROOT.TH2):
386 yaxis = obj.GetYaxis()
387 return yaxis.GetBinUpEdge(yaxis.GetLast())
388 elif isinstance(obj, ROOT.TH1):
389 if limitToNonZeroContent:
390 lst = [obj.GetBinContent(i)
for i
in xrange(1, obj.GetNbinsX()+1)
if obj.GetBinContent(i) != 0 ]
391 return max(lst)
if len(lst) != 0
else 0
393 return obj.GetMaximum()
394 elif isinstance(obj, ROOT.TGraph)
or isinstance(obj, ROOT.TGraph2D):
395 m =
max([obj.GetY()[i]
for i
in xrange(0, obj.GetN())])
396 return m*1.1
if m > 0
else m*0.9
400 return max([th1.GetBinContent(i)+th1.GetBinError(i)
for i
in xrange(1, th1.GetNbinsX()+1)])
403 yvals =
filter(
lambda n: n>0, [th1.GetBinContent(i)
for i
in xrange(1, th1.GetNbinsX()+1)])
406 return th1.GetMinimum()
411 ind_min = len(yvals)-1 -
int(len(yvals)*0.95)
412 min_val = yvals[ind_min]
413 for i
in xrange(0, ind_min):
414 if yvals[i] > 0.1*min_val:
420 inRange =
lambda x:
True 421 inRange2 =
lambda xmin,xmax:
True 423 inRange =
lambda x: coverageRange[0] <= x <= coverageRange[1]
424 inRange2 =
lambda xmin,xmax: coverageRange[0] <= xmin
and xmax <= coverageRange[1]
426 if isinstance(obj, ROOT.TH1):
427 yvals = [obj.GetBinContent(i)
for i
in xrange(1, obj.GetNbinsX()+1)
if inRange2(obj.GetXaxis().GetBinLowEdge(i), obj.GetXaxis().GetBinUpEdge(i))]
428 yvals =
filter(
lambda x: x != 0, yvals)
429 elif isinstance(obj, ROOT.TGraph)
or isinstance(obj, ROOT.TGraph2D):
430 yvals = [obj.GetY()[i]
for i
in xrange(0, obj.GetN())
if inRange(obj.GetX()[i])]
436 return (yvals[0], yvals[0])
438 return (yvals[0], yvals[1])
441 nvals =
int(len(yvals)*coverage)
444 if len(yvals) % 2 == 0:
446 return ( yvals[half-1], yvals[half] )
448 middle = len(yvals)/2
449 return ( yvals[middle-1], yvals[middle+1] )
450 ind_min = (len(yvals)-nvals)/2
451 ind_max = len(yvals)-1 - ind_min
453 return (yvals[ind_min], yvals[ind_max])
455 def _findBounds(th1s, ylog, xmin=None, xmax=None, ymin=None, ymax=None):
456 """Find x-y axis boundaries encompassing a list of TH1s if the bounds are not given in arguments. 460 ylog -- Boolean indicating if y axis is in log scale or not (affects the automatic ymax) 463 xmin -- Minimum x value; if None, take the minimum of TH1s 464 xmax -- Maximum x value; if None, take the maximum of TH1s 465 ymin -- Minimum y value; if None, take the minimum of TH1s 466 ymax -- Maximum y value; if None, take the maximum of TH1s 471 if xmin
is None or xmax
is None or isinstance(xmin, list)
or isinstance(max, list):
475 xmins.append(
_getXmin(th1, limitToNonZeroContent=isinstance(xmin, list)))
476 xmaxs.append(
_getXmax(th1, limitToNonZeroContent=isinstance(xmax, list)))
479 xmins =
filter(
lambda h: h
is not None, xmins)
480 xmaxs =
filter(
lambda h: h
is not None, xmaxs)
484 elif isinstance(xmin, list):
488 print "Histogram is zero, using the smallest given value for xmin from",
str(xmin)
491 xmins_below =
filter(
lambda x: x<=xm, xmin)
492 if len(xmins_below) == 0:
496 print "Histogram minimum x %f is below all given xmin values %s, using the smallest one" % (xm,
str(xmin))
498 xmin =
max(xmins_below)
502 elif isinstance(xmax, list):
506 print "Histogram is zero, using the smallest given value for xmax from",
str(xmin)
509 xmaxs_above =
filter(
lambda x: x>xm, xmax)
510 if len(xmaxs_above) == 0:
514 print "Histogram maximum x %f is above all given xmax values %s, using the maximum one" % (xm,
str(xmax))
516 xmax =
min(xmaxs_above)
519 th1.GetXaxis().SetRangeUser(xmin, xmax)
521 return (xmin, ymin, xmax, ymax)
523 def _findBoundsY(th1s, ylog, ymin=None, ymax=None, coverage=None, coverageRange=None):
524 """Find y axis boundaries encompassing a list of TH1s if the bounds are not given in arguments. 528 ylog -- Boolean indicating if y axis is in log scale or not (affects the automatic ymax) 531 ymin -- Minimum y value; if None, take the minimum of TH1s 532 ymax -- Maximum y value; if None, take the maximum of TH1s 533 coverage -- If set, use only values within the 'coverage' part around the median are used for min/max (useful for ratio) 534 coverageRange -- If coverage and this are set, use only the x axis specified by an (xmin,xmax) pair for the coverage 536 if coverage
is not None or isinstance(th1s[0], ROOT.TH2):
542 y_scale_max =
lambda y: y
543 y_scale_min =
lambda y: y
546 y_scale_max =
lambda y: y*1.5
548 y_scale_max =
lambda y: y*1.05
549 y_scale_min =
lambda y: y*0.9
551 if ymin
is None or ymax
is None or isinstance(ymin, list)
or isinstance(ymax, list):
555 if coverage
is not None:
558 if ylog
and isinstance(ymin, list):
561 _ymin =
_getYmin(th1, limitToNonZeroContent=isinstance(ymin, list))
562 _ymax =
_getYmax(th1, limitToNonZeroContent=isinstance(ymax, list))
570 elif isinstance(ymin, list):
571 ym_unscaled =
min(ymins)
572 ym = y_scale_min(ym_unscaled)
573 ymins_below =
filter(
lambda y: y<=ym, ymin)
574 if len(ymins_below) == 0:
576 if ym_unscaled < ymin:
578 print "Histogram minimum y %f is below all given ymin values %s, using the smallest one" % (ym,
str(ymin))
580 ymin =
max(ymins_below)
585 ymax = y_scale_max(
max(ymaxs+[ymin]))
586 elif isinstance(ymax, list):
587 ym_unscaled =
max(ymaxs)
588 ym = y_scale_max(ym_unscaled)
589 ymaxs_above =
filter(
lambda y: y>ym, ymax)
590 if len(ymaxs_above) == 0:
592 if ym_unscaled > ymax:
594 print "Histogram maximum y %f is above all given ymax values %s, using the maximum one" % (ym_unscaled,
str(ymax))
596 ymax =
min(ymaxs_above)
599 th1.GetYaxis().SetRangeUser(ymin, ymax)
605 for b
in xrange(1, histos[0].GetNbinsX()+1):
608 if h.GetBinContent(b) > 0:
614 if len(binsToRemove) > 0:
617 for i
in xrange(len(xbinlabels)):
618 if (i+1)
not in binsToRemove:
619 xbinlab_new.append(xbinlabels[i])
620 xbinlabels = xbinlab_new
626 for b
in xrange(1, h.GetNbinsX()+1):
627 if b
not in binsToRemove:
628 values.append( (h.GetXaxis().GetBinLabel(b), h.GetBinContent(b), h.GetBinError(b)) )
631 h_new = h.Clone(h.GetName()+
"_empty")
632 h_new.SetBins(len(values), h.GetBinLowEdge(1), h.GetBinLowEdge(1)+len(values))
633 for b, (l, v, e)
in enumerate(values):
634 h_new.GetXaxis().SetBinLabel(b+1, l)
635 h_new.SetBinContent(b+1, v)
636 h_new.SetBinError(b+1, e)
638 histos_new.append(h_new)
641 return (histos, xbinlabels)
644 xbinsToRemove = set()
645 ybinsToRemove = set()
646 for ih, h
in enumerate(histos):
647 for bx
in xrange(1, h.GetNbinsX()+1):
649 for by
in xrange(1, h.GetNbinsY()+1):
650 if h.GetBinContent(bx, by) > 0:
654 xbinsToRemove.add(bx)
656 xbinsToRemove.discard(bx)
658 for by
in xrange(1, h.GetNbinsY()+1):
660 for bx
in xrange(1, h.GetNbinsX()+1):
661 if h.GetBinContent(bx, by) > 0:
665 ybinsToRemove.add(by)
667 ybinsToRemove.discard(by)
669 if len(xbinsToRemove) > 0
or len(ybinsToRemove) > 0:
672 for b
in xrange(1, len(xbinlabels)+1):
673 if b
not in xbinsToRemove:
674 xbinlabels_new.append(histos[0].GetXaxis().GetBinLabel(b))
676 xbinlabels = xbinlabels_new
679 for b
in xrange(1, len(ybinlabels)+1):
680 if b
not in ybinsToRemove:
681 ybinlabels.append(histos[0].GetYaxis().GetBinLabel(b))
683 ybinlabels = xbinlabels_new
686 if len(xbinlabels) == 0
or len(ybinlabels) == 0:
687 return (histos_new, xbinlabels, ybinlabels)
689 h_new = ROOT.TH2F(h.GetName()+
"_empty", h.GetTitle(), len(xbinlabels),0,len(xbinlabels), len(ybinlabels),0,len(ybinlabels))
690 for b, l
in enumerate(xbinlabels):
691 h_new.GetXaxis().SetBinLabel(b+1, l)
692 for b, l
in enumerate(ybinlabels):
693 h_new.GetYaxis().SetBinLabel(b+1, l)
695 for ix, bx
in enumerate(xbins):
696 for iy, by
in enumerate(ybins):
697 h_new.SetBinContent(ix+1, iy+1, h.GetBinContent(bx, by))
698 h_new.SetBinError(ix+1, iy+1, h.GetBinError(bx, by))
699 histos_new.append(h_new)
701 return (histos, xbinlabels, ybinlabels)
704 return _mergeBinLabels([[h.GetXaxis().GetBinLabel(i)
for i
in xrange(1, h.GetNbinsX()+1)]
for h
in histos])
707 return _mergeBinLabels([[h.GetYaxis().GetBinLabel(i)
for i
in xrange(1, h.GetNbinsY()+1)]
for h
in histos])
710 labels_merged = labelsAll[0]
711 for labels
in labelsAll[1:]:
712 diff = difflib.unified_diff(labels_merged, labels, n=
max(len(labels_merged), len(labels)))
719 operation.append(item[0])
721 if lab
in labels_merged:
723 ind = labels_merged.index(lab)
724 if operation[ind] ==
"-" and operation[-1] ==
"+":
725 labels_merged.remove(lab)
727 elif operation[ind] ==
"+" and operation[-1] ==
"-":
731 raise Exception(
"This should never happen")
732 labels_merged.append(lab)
735 if len(labels_merged) == 0:
736 labels_merged = labels
743 h_new = h.Clone(h.GetName()+
"_xbinlabels")
744 h_new.SetBins(len(xbinlabels), h.GetBinLowEdge(1), h.GetBinLowEdge(1)+len(xbinlabels))
745 for i, label
in enumerate(xbinlabels):
746 bin = h.GetXaxis().FindFixBin(label)
748 h_new.SetBinContent(i+1, h.GetBinContent(bin))
749 h_new.SetBinError(i+1, h.GetBinError(bin))
751 h_new.SetBinContent(i+1, 0)
752 h_new.SetBinError(i+1, 0)
753 histos_new.append(h_new)
758 """Class for subtracting two histograms""" 763 name -- String for name of the resulting histogram (A-B) 764 nameA -- String for A histogram 765 nameB -- String for B histogram 768 title -- String for a title of the resulting histogram (default "") 770 Uncertainties are calculated with the assumption that B is a 771 subset of A, and the histograms contain event counts. 779 """String representation, returns the name""" 783 """Create and return the fake+duplicate histogram from a TDirectory""" 787 if not histoA
or not histoB:
790 ret = histoA.Clone(self.
_name)
796 ret.SetCanExtend(
False)
798 for i
in xrange(0, histoA.GetNbinsX()+2):
799 val = histoA.GetBinContent(i)-histoB.GetBinContent(i)
800 ret.SetBinContent(i, val)
801 ret.SetBinError(i, math.sqrt(val))
806 """Class to transform bin contents in an arbitrary way.""" 811 name -- String for name of the resulting histogram 812 histo -- String for a source histogram (needs to be cumulative) 813 func -- Function to operate on the bin content 821 """String representation, returns the name""" 825 """Create and return the transformed histogram from a TDirectory""" 830 ret = histo.Clone(self.
_name)
836 ret.SetCanExtend(
False)
838 for i
in xrange(0, histo.GetNbinsX()+2):
839 ret.SetBinContent(i, self.
_func(histo.GetBinContent(i)))
843 """Class to calculate the fake+duplicate rate""" 844 def __init__(self, name, assoc, dup, reco, title=""):
848 name -- String for the name of the resulting efficiency histogram 849 assoc -- String for the name of the "associated" histogram 850 dup -- String for the name of the "duplicates" histogram 851 reco -- String for the name of the "reco" (denominator) histogram 854 title -- String for a title of the resulting histogram (default "") 856 The result is calculated as 1 - (assoc - dup) / reco 865 """String representation, returns the name""" 869 """Create and return the fake+duplicate histogram from a TDirectory""" 876 if not hassoc
or not hdup
or not hreco:
879 hfakedup = hreco.Clone(self.
_name)
880 hfakedup.SetTitle(self.
_title)
882 for i
in xrange(1, hassoc.GetNbinsX()+1):
883 numerVal = hassoc.GetBinContent(i) - hdup.GetBinContent(i)
884 denomVal = hreco.GetBinContent(i)
886 fakedupVal = (1 - numerVal / denomVal)
if denomVal != 0.0
else 0.0
887 errVal = math.sqrt(fakedupVal*(1-fakedupVal)/denomVal)
if (denomVal != 0.0
and fakedupVal <= 1)
else 0.0
889 hfakedup.SetBinContent(i, fakedupVal)
890 hfakedup.SetBinError(i, errVal)
895 """Class for making a cut efficiency histograms. 905 name -- String for name of the resulting histogram 906 histo -- String for a source histogram (needs to be cumulative) 913 """String representation, returns the name""" 917 """Create and return the cut efficiency histogram from a TDirectory""" 923 ascending = histo.GetBinContent(0) < histo.GetBinContent(histo.GetNbinsX())
925 n_tot = histo.GetBinContent(histo.GetNbinsX())
927 n_tot = histo.GetBinContent(0)
932 ret = histo.Clone(self.
_name)
936 for i
in xrange(1, histo.GetNbinsX()+1):
937 n = histo.GetBinContent(i)
939 errVal = math.sqrt(val*(1-val)/n_tot)
940 ret.SetBinContent(i, val)
941 ret.SetBinError(i, errVal)
945 """Class to create a histogram by aggregating bins of another histogram to a bin of the resulting histogram.""" 946 def __init__(self, name, histoName, mapping, normalizeTo=None, scale=None, renameBin=None, ignoreMissingBins=False, minExistingBins=None, originalOrder=False, reorder=None):
950 name -- String for the name of the resulting histogram 951 histoName -- String for the name of the source histogram 952 mapping -- Dictionary for mapping the bins (see below) 955 normalizeTo -- Optional string of a bin label in the source histogram. If given, all bins of the resulting histogram are divided by the value of this bin. 956 scale -- Optional number for scaling the histogram (passed to ROOT.TH1.Scale()) 957 renameBin -- Optional function (string -> string) to rename the bins of the input histogram 958 originalOrder -- Boolean for using the order of bins in the histogram (default False) 959 reorder -- Optional function to reorder the bins 961 Mapping structure (mapping): 963 Dictionary (you probably want to use collections.OrderedDict) 964 should be a mapping from the destination bin label to a list 965 of source bin labels ("dst -> [src]"). 978 raise Exception(
"reorder is not None and originalOrder is True, please set only one of them")
981 """String representation, returns the name""" 985 """Create and return the histogram from a TDirectory""" 991 binValues = [
None]*len(self.
_mapping)
997 for i, (key, labels)
in enumerate(self._mapping.iteritems()):
1003 sumTime += values[l][0]
1004 sumErrorSq += values[l][1]**2
1010 binValues[i] = (sumTime, math.sqrt(sumErrorSq))
1013 ivalue = len(values)+1
1019 ivalue = values.keys().
index(lab)
1021 binIndexOrder.append( (ivalue, i) )
1024 binIndexOrder.sort(key=
lambda t: t[0])
1027 for i
in xrange(0, len(binValues)):
1028 fromIndex = binIndexOrder[i][1]
1029 tmpVal.append(binValues[fromIndex])
1030 tmpLab.append(binLabels[fromIndex])
1034 order = self.
_reorder(tdirectory, binLabels)
1035 binValues = [binValues[i]
for i
in order]
1036 binLabels = [binLabels[i]
for i
in order]
1042 for i, val
in enumerate(binValues):
1045 binValues =
filter(
lambda v: v
is not None, binValues)
1046 binLabels =
filter(
lambda v: v
is not None, binLabels)
1047 if len(binValues) == 0:
1050 result = ROOT.TH1F(self.
_name, self.
_name, len(binValues), 0, len(binValues))
1051 for i, (value, label)
in enumerate(
zip(binValues, binLabels)):
1052 if value
is not None:
1053 result.SetBinContent(i+1, value[0])
1054 result.SetBinError(i+1, value[1])
1055 result.GetXaxis().SetBinLabel(i+1, label)
1060 print "Trying to normalize {name} to {binlabel}, which does not exist".
format(name=self.
_name, binlabel=self.
_normalizeTo)
1062 value = th1.GetBinContent(bin)
1064 result.Scale(1/value)
1066 if self.
_scale is not None:
1067 result.Scale(self.
_scale)
1072 """Class to create a histogram by aggregaging integrals of another histoggrams.""" 1077 name -- String for the name of the resulting histogram 1078 mapping -- Dictionary for mapping the bin label to a histogram name 1081 normalizeTo -- Optional string for a histogram. If given, all bins of the resulting histograqm are divided by the integral of this histogram. 1088 """String representation, returns the name""" 1092 """Create and return the histogram from a TDirectory""" 1094 for key, histoName
in self._mapping.iteritems():
1098 result.append( (key, th1.Integral(0, th1.GetNbinsX()+1)) )
1099 if len(result) == 0:
1102 res = ROOT.TH1F(self.
_name, self.
_name, len(result), 0, len(result))
1104 for i, (name, count)
in enumerate(result):
1105 res.SetBinContent(i+1, count)
1106 res.GetXaxis().SetBinLabel(i+1, name)
1112 scale = th1.Integral(0, th1.GetNbinsX()+1)
1118 """Class to construct a ROC curve (e.g. efficiency vs. fake rate) from two histograms""" 1119 def __init__(self, name, xhistoName, yhistoName, zaxis=False):
1123 name -- String for the name of the resulting histogram 1124 xhistoName -- String for the name of the x-axis histogram (or another "creator" object) 1125 yhistoName -- String for the name of the y-axis histogram (or another "creator" object) 1128 zaxis -- If set to True (default False), create a TGraph2D with z axis showing the cut value (recommended drawStyle 'pcolz') 1136 """String representation, returns the name""" 1140 """Create and return the histogram from a TDirectory""" 1143 if xhisto
is None or yhisto
is None:
1154 for i
in xrange(1, xhisto.GetNbinsX()+1):
1155 x.append(xhisto.GetBinContent(i))
1156 xerrup.append(xhisto.GetBinError(i))
1157 xerrdown.append(xhisto.GetBinError(i))
1159 y.append(yhisto.GetBinContent(i))
1160 yerrup.append(yhisto.GetBinError(i))
1161 yerrdown.append(yhisto.GetBinError(i))
1163 z.append(xhisto.GetXaxis().GetBinUpEdge(i))
1166 if x.count(0.0) == len(x)
or y.count(0.0) == len(y):
1169 arr =
lambda v: array.array(
"d", v)
1172 gr = ROOT.TGraph2D(len(x), arr(x), arr(y), arr(z))
1174 gr = ROOT.TGraphAsymmErrors(len(x), arr(x), arr(y), arr(xerrdown), arr(xerrup), arr(yerrdown), arr(yerrup))
1180 _plotStylesColor = [4, 2, ROOT.kBlack, ROOT.kOrange+7, ROOT.kMagenta-3]
1181 _plotStylesMarker = [21, 20, 22, 34, 33]
1183 def _drawFrame(pad, bounds, xbinlabels=None, xbinlabelsize=None, xbinlabeloption=None, ybinlabels=None, suffix=""):
1184 """Function to draw a frame 1187 pad -- TPad to where the frame is drawn 1188 bounds -- List or 4-tuple for (xmin, ymin, xmax, ymax) 1191 xbinlabels -- Optional list of strings for x axis bin labels 1192 xbinlabelsize -- Optional number for the x axis bin label size 1193 xbinlabeloption -- Optional string for the x axis bin options (passed to ROOT.TH1.LabelsOption()) 1194 suffix -- Optional string for a postfix of the frame name 1196 if xbinlabels
is None and ybinlabels
is None:
1197 frame = pad.DrawFrame(*bounds)
1200 nbins = len(xbinlabels)
1201 if ybinlabels
is None:
1202 frame = ROOT.TH1F(
"hframe"+suffix,
"", nbins, bounds[0], bounds[2])
1203 frame.SetMinimum(bounds[1])
1204 frame.SetMaximum(bounds[3])
1205 frame.GetYaxis().SetLimits(bounds[1], bounds[3])
1207 ybins = len(ybinlabels)
1208 frame = ROOT.TH2F(
"hframe"+suffix,
"", nbins,bounds[0],bounds[2], ybins,bounds[1],bounds[3])
1210 frame.SetBit(ROOT.TH1.kNoStats)
1211 frame.SetBit(ROOT.kCanDelete)
1214 xaxis = frame.GetXaxis()
1215 for i
in xrange(nbins):
1216 xaxis.SetBinLabel(i+1, xbinlabels[i])
1217 if xbinlabelsize
is not None:
1218 xaxis.SetLabelSize(xbinlabelsize)
1219 if xbinlabeloption
is not None:
1220 frame.LabelsOption(xbinlabeloption)
1222 if ybinlabels
is not None:
1223 yaxis = frame.GetYaxis()
1224 for i, lab
in enumerate(ybinlabels):
1225 yaxis.SetBinLabel(i+1, lab)
1226 if xbinlabelsize
is not None:
1227 yaxis.SetLabelSize(xbinlabelsize)
1228 if xbinlabeloption
is not None:
1229 frame.LabelsOption(xbinlabeloption,
"Y")
1234 """Class for creating and managing a frame for a simple, one-pad plot""" 1235 def __init__(self, pad, bounds, nrows, xbinlabels=None, xbinlabelsize=None, xbinlabeloption=None, ybinlabels=None):
1245 yoffsetFactor *= 1.5
1246 xoffsetFactor *= 1.5
1251 self._frame.GetYaxis().SetTitleOffset(self._frame.GetYaxis().GetTitleOffset()*yoffsetFactor)
1252 self._frame.GetXaxis().SetTitleOffset(self._frame.GetXaxis().GetTitleOffset()*xoffsetFactor)
1256 self._pad.SetLogx(log)
1259 self._pad.SetLogy(log)
1262 self._pad.SetGridx(grid)
1265 self._pad.SetGridy(grid)
1268 self._pad.SetLeftMargin(self._pad.GetLeftMargin()+adjust)
1271 self._frame.Draw(
"")
1274 self._pad.SetRightMargin(self._pad.GetRightMargin()+adjust)
1277 self._frame.Draw(
"")
1280 self._frame.SetTitle(title)
1283 self._frame.GetXaxis().SetTitle(title)
1286 self._frame.GetXaxis().SetTitleSize(size)
1289 self._frame.GetXaxis().SetTitleOffset(offset)
1292 self._frame.GetXaxis().SetLabelSize(size)
1295 self._frame.GetYaxis().SetTitle(title)
1298 self._frame.GetYaxis().SetTitleSize(size)
1301 self._frame.GetYaxis().SetTitleOffset(offset)
1304 self._pad.RedrawAxis()
1307 """Class for creating and managing a frame for a ratio plot with two subpads""" 1308 def __init__(self, pad, bounds, ratioBounds, ratioFactor, nrows, xbinlabels=None, xbinlabelsize=None, xbinlabeloption=None, ratioYTitle=_ratioYTitle):
1311 if xbinlabels
is not None:
1318 self._frame.GetXaxis().SetLabelSize(0)
1319 self._frame.GetXaxis().SetTitleSize(0)
1321 yoffsetFactor = ratioFactor
1322 divisionPoint = 1-1/ratioFactor
1323 xoffsetFactor = 1/divisionPoint
1326 xoffsetFactor *= 0.6
1329 xoffsetFactor *= 1.5
1332 xoffsetFactor *= 2.3
1337 self._frame.GetYaxis().SetTitleOffset(self._frameRatio.GetYaxis().GetTitleOffset()*yoffsetFactor)
1338 self._frameRatio.GetYaxis().SetLabelSize(
int(self._frameRatio.GetYaxis().GetLabelSize()*0.8))
1339 self._frameRatio.GetYaxis().SetTitleOffset(self._frameRatio.GetYaxis().GetTitleOffset()*yoffsetFactor)
1340 self._frameRatio.GetXaxis().SetTitleOffset(self._frameRatio.GetXaxis().GetTitleOffset()*xoffsetFactor)
1342 self._frameRatio.GetYaxis().SetNdivisions(4, 5, 0)
1344 self._frameRatio.GetYaxis().SetTitle(ratioYTitle)
1347 self._pad.SetLogx(log)
1348 self._padRatio.SetLogx(log)
1351 self._pad.SetLogy(log)
1354 self._pad.SetGridx(grid)
1355 self._padRatio.SetGridx(grid)
1358 self._pad.SetGridy(grid)
1359 self._padRatio.SetGridy(grid)
1362 self._pad.SetLeftMargin(self._pad.GetLeftMargin()+adjust)
1363 self._padRatio.SetLeftMargin(self._padRatio.GetLeftMargin()+adjust)
1366 self._frame.Draw(
"")
1368 self._frameRatio.Draw(
"")
1371 self._pad.SetRightMargin(self._pad.GetRightMargin()+adjust)
1372 self._padRatio.SetRightMargin(self._padRatio.GetRightMargin()+adjust)
1375 self._frame.Draw(
"")
1377 self._frameRatio.Draw(
"")
1380 self._frame.SetTitle(title)
1383 self._frameRatio.GetXaxis().SetTitle(title)
1386 self._frameRatio.GetXaxis().SetTitleSize(size)
1389 self._frameRatio.GetXaxis().SetTitleOffset(offset)
1392 self._frameRatio.GetXaxis().SetLabelSize(size)
1395 self._frame.GetYaxis().SetTitle(title)
1398 self._frameRatio.GetYaxis().SetTitle(title)
1401 self._frame.GetYaxis().SetTitleSize(size)
1402 self._frameRatio.GetYaxis().SetTitleSize(size)
1405 self._frame.GetYaxis().SetTitleOffset(offset)
1406 self._frameRatio.GetYaxis().SetTitleOffset(offset)
1409 self._padRatio.RedrawAxis()
1410 self._pad.RedrawAxis()
1412 self._parentPad.cd()
1419 self.
_coverPad = ROOT.TPad(
"coverpad",
"coverpad", xmin, ymin, xmax, ymax)
1420 self._coverPad.SetBorderMode(0)
1421 self._coverPad.Draw()
1427 """Class for creating and managing a frame for a plot from TGraph2D""" 1428 def __init__(self, pad, bounds, histos, ratioOrig, ratioFactor):
1431 self.
_pad = pad.cd(1)
1435 (xlow, ylow, width, height) = (self._pad.GetXlowNDC(), self._pad.GetYlowNDC(), self._pad.GetWNDC(), self._pad.GetHNDC())
1439 bottomMargin = self._pad.GetBottomMargin()
1440 bottomMarginNew = ROOT.gStyle.GetPadBottomMargin()
1442 ylowNew = yup - (1-bottomMargin)/(1-bottomMarginNew) * (yup-ylow)
1443 topMarginNew = self._pad.GetTopMargin() * (yup-ylow)/(yup-ylowNew)
1445 self._pad.SetPad(xlow, ylowNew, xup, yup)
1446 self._pad.SetTopMargin(topMarginNew)
1447 self._pad.SetBottomMargin(bottomMarginNew)
1450 self._view.SetRange(bounds[0], bounds[1], 0, bounds[2], bounds[3], 20)
1452 self._view.ShowAxis()
1472 self._pad.SetLeftMargin(self._pad.GetLeftMargin()+adjust)
1476 self._pad.SetRightMargin(self._pad.GetRightMargin()+adjust)
1504 self._firstHisto.GetZaxis().SetTitle(title)
1507 self._firstHisto.GetZaxis().SetTitleOffset(offset)
1511 ROOT.TAxis3D.ToggleRulers()
1512 ROOT.TAxis3D.ToggleRulers()
1513 axis = ROOT.TAxis3D.GetPadAxis()
1514 axis.SetLabelColor(ROOT.kBlack);
1515 axis.SetAxisColor(ROOT.kBlack);
1520 if hasattr(self,
"_xtitle"):
1521 axis.GetXaxis().SetTitle(self.
_xtitle)
1522 if hasattr(self,
"_xtitlesize"):
1524 if hasattr(self,
"_xlabelsize"):
1525 axis.GetXaxis().SetLabelSize(self._labelsize)
1526 if hasattr(self,
"_ytitle"):
1527 axis.GetYaxis().SetTitle(self.
_ytitle)
1528 if hasattr(self,
"_ytitlesize"):
1530 if hasattr(self,
"_ytitleoffset"):
1534 """Abstraction on top of TLatex""" 1535 def __init__(self, x, y, text, size=None, bold=True, align="left", color=ROOT.kBlack, font=None):
1539 x -- X coordinate of the text (in NDC) 1540 y -- Y coordinate of the text (in NDC) 1541 text -- String to draw 1542 size -- Size of text (None for the default value, taken from gStyle) 1543 bold -- Should the text be bold? 1544 align -- Alignment of text (left, center, right) 1545 color -- Color of the text 1546 font -- Specify font explicitly 1555 self._l.SetTextFont(self._l.GetTextFont()-20)
1556 if font
is not None:
1557 self._l.SetTextFont(font)
1558 if size
is not None:
1559 self._l.SetTextSize(size)
1560 if isinstance(align, basestring):
1561 if align.lower() ==
"left":
1562 self._l.SetTextAlign(11)
1563 elif align.lower() ==
"center":
1564 self._l.SetTextAlign(21)
1565 elif align.lower() ==
"right":
1566 self._l.SetTextAlign(31)
1568 raise Exception(
"Error: Invalid option '%s' for text alignment! Options are: 'left', 'center', 'right'."%align)
1570 self._l.SetTextAlign(align)
1571 self._l.SetTextColor(color)
1574 """Draw the text to the current TPad. 1577 options -- For interface compatibility, ignored 1579 Provides interface compatible with ROOT's drawable objects. 1581 self._l.DrawLatex(self.
_x, self.
_y, self.
_text)
1585 """Class for drawing text and a background box.""" 1586 def __init__(self, xmin, ymin, xmax, ymax, lineheight=0.04, fillColor=ROOT.kWhite, transparent=True, **kwargs):
1590 xmin -- X min coordinate of the box (NDC) 1591 ymin -- Y min coordinate of the box (NDC) (if None, deduced automatically) 1592 xmax -- X max coordinate of the box (NDC) 1593 ymax -- Y max coordinate of the box (NDC) 1594 lineheight -- Line height 1595 fillColor -- Fill color of the box 1596 transparent -- Should the box be transparent? (in practive the TPave is not created) 1598 Keyword arguments are forwarded to constructor of PlotText 1610 self._textArgs.update(kwargs)
1615 """Add text to current position""" 1622 def move(self, dx=0, dy=0, dw=0, dh=0):
1623 """Move the box and the contained text objects 1626 dx -- Movement in x (positive is to right) 1627 dy -- Movement in y (positive is to up) 1628 dw -- Increment of width (negative to decrease width) 1629 dh -- Increment of height (negative to decrease height) 1631 dx and dy affect to both box and text objects, dw and dh 1632 affect the box only. 1636 if self.
_ymin is not None:
1641 if self.
_ymin is not None:
1649 """Draw the box and the text to the current TPad. 1652 options -- Forwarded to ROOT.TPave.Draw(), and the Draw() of the contained objects 1657 ymin = self.currenty - 0.01
1658 self.
_pave = ROOT.TPave(self.xmin, self.ymin, self.xmax, self.ymax, 0,
"NDC")
1659 self._pave.SetFillColor(self.fillColor)
1660 self._pave.Draw(options)
1666 if hasattr(src,
"GetLineColor")
and hasattr(dst,
"SetLineColor"):
1667 properties.extend([
"LineColor",
"LineStyle",
"LineWidth"])
1668 if hasattr(src,
"GetFillColor")
and hasattr(dst,
"SetFillColor"):
1669 properties.extend([
"FillColor",
"FillStyle"])
1670 if hasattr(src,
"GetMarkerColor")
and hasattr(dst,
"SetMarkerColor"):
1671 properties.extend([
"MarkerColor",
"MarkerSize",
"MarkerStyle"])
1673 for prop
in properties:
1674 getattr(dst,
"Set"+prop)(getattr(src,
"Get"+prop)())
1677 """Denotes an empty place in a group.""" 1697 """Represents one plot, comparing one or more histograms.""" 1702 name -- String for name of the plot, or Efficiency object 1705 fallback -- Dictionary for specifying fallback (default None) 1706 outname -- String for an output name of the plot (default None for the same as 'name') 1707 title -- String for a title of the plot (default None) 1708 xtitle -- String for x axis title (default None) 1709 xtitlesize -- Float for x axis title size (default None) 1710 xtitleoffset -- Float for x axis title offset (default None) 1711 xlabelsize -- Float for x axis label size (default None) 1712 ytitle -- String for y axis title (default None) 1713 ytitlesize -- Float for y axis title size (default None) 1714 ytitleoffset -- Float for y axis title offset (default None) 1715 ztitle -- String for z axis title (default None) 1716 ztitleoffset -- Float for z axis title offset (default None) 1717 xmin -- Float for x axis minimum (default None, i.e. automatic) 1718 xmax -- Float for x axis maximum (default None, i.e. automatic) 1719 ymin -- Float for y axis minimum (default 0) 1720 ymax -- Float for y axis maximum (default None, i.e. automatic) 1721 xlog -- Bool for x axis log status (default False) 1722 ylog -- Bool for y axis log status (default False) 1723 xgrid -- Bool for x axis grid status (default True) 1724 ygrid -- Bool for y axis grid status (default True) 1725 stat -- Draw stat box? (default False) 1726 fit -- Do gaussian fit? (default False) 1727 statx -- Stat box x coordinate (default 0.65) 1728 staty -- Stat box y coordinate (default 0.8) 1729 statyadjust -- List of floats for stat box y coordinate adjustments (default None) 1730 normalizeToUnitArea -- Normalize histograms to unit area? (default False) 1731 normalizeToNumberOfEvents -- Normalize histograms to number of events? If yes, the PlotFolder needs 'numberOfEventsHistogram' set to a histogram filled once per event (default False) 1732 profileX -- Take histograms via ProfileX()? (default False) 1733 fitSlicesY -- Take histograms via FitSlicesY() (default False) 1734 rebinX -- rebin x axis (default None) 1735 scale -- Scale histograms by a number (default None) 1736 xbinlabels -- List of x axis bin labels (if given, default None) 1737 xbinlabelsize -- Size of x axis bin labels (default None) 1738 xbinlabeloption -- Option string for x axis bin labels (default None) 1739 removeEmptyBins -- Bool for removing empty bins, but only if histogram has bin labels (default False) 1740 printBins -- Bool for printing bin values, but only if histogram has bin labels (default False) 1741 drawStyle -- If "hist", draw as line instead of points (default None) 1742 drawCommand -- Deliver this to Draw() (default: None for same as drawStyle) 1743 lineWidth -- If drawStyle=="hist", the width of line (default 2) 1744 legendDx -- Float for moving TLegend in x direction for separate=True (default None) 1745 legendDy -- Float for moving TLegend in y direction for separate=True (default None) 1746 legendDw -- Float for changing TLegend width for separate=True (default None) 1747 legendDh -- Float for changing TLegend height for separate=True (default None) 1748 legend -- Bool to enable/disable legend (default True) 1749 adjustMarginLeft -- Float for adjusting left margin (default None) 1750 adjustMarginRight -- Float for adjusting right margin (default None) 1751 ratio -- Possibility to disable ratio for this particular plot (default None) 1752 ratioYmin -- Float for y axis minimum in ratio pad (default: list of values) 1753 ratioYmax -- Float for y axis maximum in ratio pad (default: list of values) 1754 ratioFit -- Fit straight line in ratio? (default None) 1755 ratioUncertainty -- Plot uncertainties on ratio? (default True) 1756 ratioCoverageXrange -- Range of x axis values (xmin,xmax) to limit the automatic ratio y axis range calculation to (default None for disabled) 1757 histogramModifier -- Function to be called in create() to modify the histograms (default None) 1761 def _set(attr, default):
1762 setattr(self,
"_"+attr, kwargs.get(attr, default))
1764 _set(
"fallback",
None)
1765 _set(
"outname",
None)
1768 _set(
"xtitle",
None)
1769 _set(
"xtitlesize",
None)
1770 _set(
"xtitleoffset",
None)
1771 _set(
"xlabelsize",
None)
1772 _set(
"ytitle",
None)
1773 _set(
"ytitlesize",
None)
1774 _set(
"ytitleoffset",
None)
1775 _set(
"ztitle",
None)
1776 _set(
"ztitleoffset",
None)
1793 _set(
"statyadjust",
None)
1795 _set(
"normalizeToUnitArea",
False)
1796 _set(
"normalizeToNumberOfEvents",
False)
1797 _set(
"profileX",
False)
1798 _set(
"fitSlicesY",
False)
1799 _set(
"rebinX",
None)
1802 _set(
"xbinlabels",
None)
1803 _set(
"xbinlabelsize",
None)
1804 _set(
"xbinlabeloption",
None)
1805 _set(
"removeEmptyBins",
False)
1806 _set(
"printBins",
False)
1808 _set(
"drawStyle",
"EP")
1809 _set(
"drawCommand",
None)
1810 _set(
"lineWidth", 2)
1812 _set(
"legendDx",
None)
1813 _set(
"legendDy",
None)
1814 _set(
"legendDw",
None)
1815 _set(
"legendDh",
None)
1816 _set(
"legend",
True)
1818 _set(
"adjustMarginLeft",
None)
1819 _set(
"adjustMarginRight",
None)
1822 _set(
"ratioYmin", [0, 0.2, 0.5, 0.7, 0.8, 0.9, 0.95])
1823 _set(
"ratioYmax", [1.05, 1.1, 1.2, 1.3, 1.5, 1.8, 2, 2.5, 3, 4, 5])
1824 _set(
"ratioFit",
None)
1825 _set(
"ratioUncertainty",
True)
1826 _set(
"ratioCoverageXrange",
None)
1828 _set(
"histogramModifier",
None)
1833 for name, value
in kwargs.iteritems():
1834 if not hasattr(self,
"_"+name):
1835 raise Exception(
"No attribute '%s'" % name)
1836 setattr(self,
"_"+name, value)
1840 raise Exception(
"Plot can be cloned only before histograms have been created")
1841 cl = copy.copy(self)
1842 cl.setProperties(**kwargs)
1846 """Return number of existing histograms.""" 1850 """Return true if there are no histograms created for the plot""" 1855 if isinstance(h, ROOT.TGraph2D):
1860 if self._ratio
is None:
1862 return ratio
and self._ratio
1865 if self._outname
is not None:
1866 return self._outname
1867 if isinstance(self.
_name, list):
1873 """Return true if the ratio uncertainty should be drawn""" 1874 return self._ratioUncertainty
1877 """Create one histogram from a TDirectory.""" 1882 if isinstance(name, list):
1886 if h
is not None and self._normalizeToNumberOfEvents
and nevents
is not None and nevents != 0:
1887 h.Scale(1.0/nevents)
1890 def create(self, tdirNEvents, requireAllHistograms=False):
1891 """Create histograms from list of TDirectories""" 1892 self.
_histograms = [self.
_createOne(self.
_name, i, tdirNEvent[0], tdirNEvent[1])
for i, tdirNEvent
in enumerate(tdirNEvents)]
1894 if self._fallback
is not None:
1898 self.
_histograms[i] = self.
_createOne(self._fallback[
"name"], i, tdirNEvents[i][0], tdirNEvents[i][1])
1899 profileX[i] = self._fallback.get(
"profileX", self._profileX)
1901 if self._histogramModifier
is not None:
1905 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)))
1910 def _modifyHisto(th1, profileX):
1915 th1 = th1.ProfileX()
1917 if self._fitSlicesY:
1918 ROOT.TH1.AddDirectory(
True)
1920 th1 = ROOT.gDirectory.Get(th1.GetName()+
"_2")
1921 th1.SetDirectory(
None)
1923 ROOT.TH1.AddDirectory(
False)
1925 if self._title
is not None:
1926 th1.SetTitle(self._title)
1928 if self._scale
is not None:
1929 th1.Scale(self._scale)
1933 if self._fallback
is not None:
1937 if requireAllHistograms
and None in self.
_histograms:
1941 """Set stats box.""" 1944 if h
is not None and hasattr(h,
"SetStats"):
1948 def _doStats(h, col, dy):
1953 if self._fit
and h.GetEntries() > 0.5:
1955 f = h.GetListOfFunctions().FindObject(
"gaus")
1963 st = h.GetListOfFunctions().FindObject(
"stats")
1967 st.SetX1NDC(startingX)
1968 st.SetX2NDC(startingX+0.3)
1969 st.SetY1NDC(startingY+dy)
1970 st.SetY2NDC(startingY+dy+0.15)
1971 st.SetTextColor(col)
1974 for i, h
in enumerate(histos):
1975 if self._statyadjust
is not None and i < len(self._statyadjust):
1976 dy += self._statyadjust[i]
1978 _doStats(h, _plotStylesColor[i], dy)
1982 """Normalise histograms to unit area""" 1990 if h.GetSumw2().fN <= 0:
1994 def draw(self, pad, ratio, ratioFactor, nrows):
1995 """Draw the histograms using values for a given algorithm.""" 2006 if self._normalizeToUnitArea:
2009 if self._rebinX
is not None:
2011 h.Rebin(self._rebinX)
2013 def _styleMarker(h, msty, col):
2014 h.SetMarkerStyle(msty)
2015 h.SetMarkerColor(col)
2016 h.SetMarkerSize(0.7)
2020 def _styleHist(h, msty, col):
2021 _styleMarker(h, msty, col)
2023 h.SetLineWidth(self._lineWidth)
2026 style = _styleMarker
2027 if "hist" in self._drawStyle.lower():
2030 if "l" in self._drawStyle.lower():
2038 style(h, _plotStylesMarker[i], _plotStylesColor[i])
2040 if len(histos) == 0:
2042 print "No histograms for plot {name}".
format(name=self.
getName())
2047 histosHaveBinLabels = len(histos[0].GetXaxis().GetBinLabel(1)) > 0
2048 xbinlabels = self._xbinlabels
2050 if xbinlabels
is None:
2051 if histosHaveBinLabels:
2053 if isinstance(histos[0], ROOT.TH2):
2062 if self._removeEmptyBins
and histosHaveBinLabels:
2065 if isinstance(histos[0], ROOT.TH2):
2070 if len(histos) == 0:
2072 print "No histograms with non-empty bins for plot {name}".
format(name=self.
getName())
2075 if self._printBins
and histosHaveBinLabels:
2076 print "####################" 2078 width =
max([len(l)
for l
in xbinlabels])
2079 tmp =
"%%-%ds " % width
2080 for b
in xrange(1, histos[0].GetNbinsX()+1):
2081 s = tmp % xbinlabels[b-1]
2083 s +=
"%.3f " % h.GetBinContent(b)
2088 xmin=self._xmin, xmax=self._xmax,
2089 ymin=self._ymin, ymax=self._ymax)
2097 ratioHistos =
filter(
lambda h: h
is not None, [r.getRatio()
for r
in self.
_ratios[1:]])
2099 if len(ratioHistos) > 0:
2100 ratioBoundsY =
_findBoundsY(ratioHistos, ylog=
False, ymin=self._ratioYmin, ymax=self._ratioYmax, coverage=0.68, coverageRange=self._ratioCoverageXrange)
2102 ratioBoundsY = (0.9, 1,1)
2104 if self._ratioFit
is not None:
2105 for i, rh
in enumerate(ratioHistos):
2106 tf_line = ROOT.TF1(
"line%d"%i,
"[0]+x*[1]")
2107 tf_line.SetRange(self._ratioFit[
"rangemin"], self._ratioFit[
"rangemax"])
2108 fitres = rh.Fit(tf_line,
"RINSQ")
2109 tf_line.SetLineColor(rh.GetMarkerColor())
2110 tf_line.SetLineWidth(2)
2111 self._ratioAdditional.append(tf_line)
2112 box =
PlotTextBox(xmin=self._ratioFit.get(
"boxXmin", 0.14), ymin=
None,
2113 xmax=self._ratioFit.get(
"boxXmax", 0.35), ymax=self._ratioFit.get(
"boxYmax", 0.09),
2114 color=rh.GetMarkerColor(), font=43, size=11, lineheight=0.02)
2115 box.move(dx=(box.width()+0.01)*i)
2118 box.addText(
"Const: %.4f#pm%.4f" % (fitres.Parameter(0), fitres.ParError(0)))
2119 box.addText(
"Slope: %.4f#pm%.4f" % (fitres.Parameter(1), fitres.ParError(1)))
2120 self._mainAdditional.append(box)
2130 self.
_setStats(histos, self._statx, self._staty)
2134 frame =
FrameTGraph2D(pad, bounds, histos, ratioOrig, ratioFactor)
2137 ratioBounds = (bounds[0], ratioBoundsY[0], bounds[2], ratioBoundsY[1])
2138 frame =
FrameRatio(pad, bounds, ratioBounds, ratioFactor, nrows, xbinlabels, self._xbinlabelsize, self._xbinlabeloption)
2140 frame =
Frame(pad, bounds, nrows, xbinlabels, self._xbinlabelsize, self._xbinlabeloption, ybinlabels=ybinlabels)
2143 frame.setLogx(self._xlog)
2144 frame.setLogy(self._ylog)
2145 frame.setGridx(self._xgrid)
2146 frame.setGridy(self._ygrid)
2151 if self._drawStyle
is not None:
2152 ds = self._drawStyle
2153 if self._drawCommand
is not None:
2154 ds = self._drawCommand
2159 frame.setTitle(histos[0].GetTitle())
2160 if self._xtitle
is not None:
2161 frame.setXTitle(self._xtitle)
2162 if self._xtitlesize
is not None:
2163 frame.setXTitleSize(self._xtitlesize)
2164 if self._xtitleoffset
is not None:
2165 frame.setXTitleOffset(self._xtitleoffset)
2166 if self._xlabelsize
is not None:
2167 frame.setXLabelSize(self._xlabelsize)
2168 if self._ytitle
is not None:
2169 frame.setYTitle(self._ytitle)
2170 if self._ytitlesize
is not None:
2171 frame.setYTitleSize(self._ytitlesize)
2172 if self._ytitleoffset
is not None:
2173 frame.setYTitleOffset(self._ytitleoffset)
2174 if self._ztitle
is not None:
2175 frame.setZTitle(self._ztitle)
2176 if self._ztitleoffset
is not None:
2177 frame.setZTitleOffset(self._ztitleoffset)
2178 if self._adjustMarginLeft
is not None:
2179 frame.adjustMarginLeft(self._adjustMarginLeft)
2180 if self._adjustMarginRight
is not None:
2181 frame.adjustMarginRight(self._adjustMarginRight)
2183 frame.adjustMarginLeft(0.03)
2184 frame.adjustMarginRight(0.08)
2197 if ratio
and len(histos) > 0:
2198 frame._padRatio.cd()
2199 firstRatio = self.
_ratios[0].getRatio()
2200 if self._ratioUncertainty
and firstRatio
is not None:
2201 firstRatio.SetFillStyle(1001)
2202 firstRatio.SetFillColor(ROOT.kGray)
2203 firstRatio.SetLineColor(ROOT.kGray)
2204 firstRatio.SetMarkerColor(ROOT.kGray)
2205 firstRatio.SetMarkerSize(0)
2207 frame._padRatio.RedrawAxis(
"G")
2218 """Add histograms to a legend. 2222 legendLabels -- List of strings for the legend labels 2224 first = denomUncertainty
2231 self._forLegend.SetFillStyle(1001)
2232 self._forLegend.SetFillColor(ROOT.kGray)
2233 entry = legend.AddEntry(self.
_forLegend, label,
"lpf")
2236 legend.AddEntry(h, label,
"LP")
2239 """Group of plots, results a TCanvas""" 2244 name -- String for name of the TCanvas, used also as the basename of the picture files 2245 plots -- List of Plot objects 2248 ncols -- Number of columns (default 2) 2249 legendDx -- Float for moving TLegend in x direction (default None) 2250 legendDy -- Float for moving TLegend in y direction (default None) 2251 legendDw -- Float for changing TLegend width (default None) 2252 legendDh -- Float for changing TLegend height (default None) 2253 legend -- Bool for disabling legend (default True for legend being enabled) 2254 overrideLegendLabels -- List of strings for legend labels, if given, these are used instead of the ones coming from Plotter (default None) 2255 onlyForPileup -- Plots this group only for pileup samples 2262 def _set(attr, default):
2263 setattr(self,
"_"+attr, kwargs.get(attr, default))
2267 _set(
"legendDx",
None)
2268 _set(
"legendDy",
None)
2269 _set(
"legendDw",
None)
2270 _set(
"legendDh",
None)
2271 _set(
"legend",
True)
2273 _set(
"overrideLegendLabels",
None)
2275 _set(
"onlyForPileup",
False)
2280 for name, value
in kwargs.iteritems():
2281 if not hasattr(self,
"_"+name):
2282 raise Exception(
"No attribute '%s'" % name)
2283 setattr(self,
"_"+name, value)
2292 for i, plot
in enumerate(self.
_plots):
2293 if plot.getName() == name:
2296 raise Exception(
"Did not find Plot '%s' from PlotGroup '%s'" % (name, self.
_name))
2302 self._plots.append(plot)
2306 if plot.getName() == name:
2308 raise Exception(
"No Plot named '%s'" % name)
2311 """Return True if the PlotGroup is intended only for pileup samples""" 2312 return self._onlyForPileup
2314 def create(self, tdirectoryNEvents, requireAllHistograms=False):
2315 """Create histograms from a list of TDirectories. 2318 tdirectoryNEvents -- List of (TDirectory, nevents) pairs 2319 requireAllHistograms -- If True, a plot is produced if histograms from all files are present (default: False) 2322 plot.create(tdirectoryNEvents, requireAllHistograms)
2324 def draw(self, legendLabels, prefix=None, separate=False, saveFormat=".pdf", ratio=True, directory=""):
2325 """Draw the histograms using values for a given algorithm. 2328 legendLabels -- List of strings for legend labels (corresponding to the tdirectories in create()) 2329 prefix -- Optional string for file name prefix (default None) 2330 separate -- Save the plots of a group to separate files instead of a file per group (default False) 2331 saveFormat -- String specifying the plot format (default '.pdf') 2332 ratio -- Add ratio to the plot (default True) 2333 directory -- Directory where to save the file (default "") 2336 if self._overrideLegendLabels
is not None:
2337 legendLabels = self._overrideLegendLabels
2340 onlyEmptyPlots =
True 2342 if not plot.isEmpty():
2343 onlyEmptyPlots =
False 2349 return self.
_drawSeparate(legendLabels, prefix, saveFormat, ratio, directory)
2351 cwidth = 500*self._ncols
2352 nrows =
int((len(self.
_plots)+self._ncols-1)/self._ncols)
2353 cheight = 500 * nrows
2360 canvas.Divide(self._ncols, nrows)
2362 for i, plot
in enumerate(self.
_plots):
2363 pad = canvas.cd(i+1)
2367 for i, plot
in enumerate(self.
_plots):
2368 pad = canvas.cd(i+1)
2369 if not plot.isEmpty():
2374 if len(self.
_plots) <= 4:
2384 if self._legendDx
is not None:
2385 lx1 += self._legendDx
2386 lx2 += self._legendDx
2387 if self._legendDy
is not None:
2388 ly1 += self._legendDy
2389 ly2 += self._legendDy
2390 if self._legendDw
is not None:
2391 lx2 += self._legendDw
2392 if self._legendDh
is not None:
2393 ly1 -= self._legendDh
2394 plot =
max(self.
_plots, key=
lambda p: p.getNumberOfHistograms())
2395 denomUnc = sum([p.drawRatioUncertainty()
for p
in self.
_plots]) > 0
2396 legend = self.
_createLegend(plot, legendLabels, lx1, ly1, lx2, ly2,
2397 denomUncertainty=(ratio
and denomUnc))
2399 return self.
_save(canvas, saveFormat, prefix=prefix, directory=directory)
2402 """Internal method to do the drawing to separate files per Plot instead of a file per PlotGroup""" 2410 for c
in [canvas, canvasRatio]:
2411 c.SetTopMargin(0.05)
2412 c.SetBottomMargin(0.13)
2413 c.SetLeftMargin(0.16)
2414 c.SetRightMargin(0.05)
2427 ratioForThisPlot = plot.isRatio(ratio)
2429 if ratioForThisPlot:
2445 if plot._legendDx
is not None:
2446 lx1 += plot._legendDx
2447 lx2 += plot._legendDx
2448 if plot._legendDy
is not None:
2449 ly1 += plot._legendDy
2450 ly2 += plot._legendDy
2451 if plot._legendDw
is not None:
2452 lx2 += plot._legendDw
2453 if plot._legendDh
is not None:
2454 ly1 -= plot._legendDh
2457 legend = self.
_createLegend(plot, legendLabels, lx1, ly1, lx2, ly2, textSize=0.03,
2458 denomUncertainty=(ratioForThisPlot
and plot.drawRatioUncertainty))
2460 ret.extend(self.
_save(c, saveFormat, prefix=prefix, postfix=
"_"+plot.getName(), single=
True, directory=directory))
2464 """Internal method to set divide a pad to two for ratio plots""" 2467 def _createLegend(self, plot, legendLabels, lx1, ly1, lx2, ly2, textSize=0.016, denomUncertainty=True):
2468 if not self._legend:
2471 l = ROOT.TLegend(lx1, ly1, lx2, ly2)
2472 l.SetTextSize(textSize)
2479 plot.addToLegend(l, legendLabels, denomUncertainty)
2483 def _save(self, canvas, saveFormat, prefix=None, postfix=None, single=False, directory=""):
2486 if prefix
is not None:
2488 if postfix
is not None:
2490 name = os.path.join(directory, name)
2493 backup = ROOT.gErrorIgnoreLevel
2494 ROOT.gErrorIgnoreLevel = ROOT.kWarning
2495 canvas.SaveAs(name+saveFormat)
2497 ROOT.gErrorIgnoreLevel = backup
2501 canvas.SetLogx(
False)
2502 canvas.SetLogy(
False)
2506 return [name+saveFormat]
2509 """Resembles DQM GUI's "On side" layout. 2511 Like PlotGroup, but has only a description of a single plot. The 2512 plot is drawn separately for each file. Useful for 2D histograms.""" 2514 def __init__(self, name, plot, ncols=2, onlyForPileup=False):
2515 super(PlotOnSideGroup, self).
__init__(name, [], ncols=ncols, legend=
False, onlyForPileup=onlyForPileup)
2517 self._plot.setProperties(ratio=
False)
2520 raise Exception(
"PlotOnSideGroup.append() is not implemented")
2522 def create(self, tdirectoryNEvents, requireAllHistograms=False):
2524 for element
in tdirectoryNEvents:
2525 pl = self._plot.clone()
2526 pl.create([element], requireAllHistograms)
2527 self._plots.append(pl)
2530 kargs = copy.copy(kwargs)
2531 kargs[
"ratio"] =
False 2532 return super(PlotOnSideGroup, self).
draw(*args, **kargs)
2536 """Represents a collection of PlotGroups, produced from a single folder in a DQM file""" 2541 plotGroups -- List of PlotGroup objects 2544 loopSubFolders -- Should the subfolders be looped over? (default: True) 2545 onlyForPileup -- Plots this folder only for pileup samples 2546 onlyForElectron -- Plots this folder only for electron samples 2547 onlyForConversion -- Plots this folder only for conversion samples 2548 onlyForBHadron -- Plots this folder only for B-hadron samples 2549 purpose -- html.PlotPurpose member class for the purpose of the folder, used for grouping of the plots to the HTML pages 2550 page -- Optional string for the page in HTML generatin 2551 section -- Optional string for the section within a page in HTML generation 2552 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". 2565 raise Exception(
"Got unexpected keyword arguments: "+
",".
join(kwargs.keys()))
2568 """Return True if the PlotGroups of this folder should be applied to the all subfolders""" 2572 """Return True if the folder is intended only for pileup samples""" 2597 self._plotGroups.append(plotGroup)
2607 if pg.getName() == name:
2609 raise Exception(
"No PlotGroup named '%s'" % name)
2611 def create(self, dirsNEvents, labels, isPileupSample=True, requireAllHistograms=False):
2612 """Create histograms from a list of TFiles. 2615 dirsNEvents -- List of (TDirectory, nevents) pairs 2616 labels -- List of strings for legend labels corresponding the files 2617 isPileupSample -- Is sample pileup (some PlotGroups may limit themselves to pileup) 2618 requireAllHistograms -- If True, a plot is produced if histograms from all files are present (default: False) 2621 if len(dirsNEvents) != len(labels):
2622 raise Exception(
"len(dirsNEvents) should be len(labels), now they are %d and %d" % (len(dirsNEvents), len(labels)))
2627 if pg.onlyForPileup()
and not isPileupSample:
2629 pg.create(dirsNEvents, requireAllHistograms)
2631 def draw(self, prefix=None, separate=False, saveFormat=".pdf", ratio=True, directory=""):
2632 """Draw and save all plots using settings of a given algorithm. 2635 prefix -- Optional string for file name prefix (default None) 2636 separate -- Save the plots of a group to separate files instead of a file per group (default False) 2637 saveFormat -- String specifying the plot format (default '.pdf') 2638 ratio -- Add ratio to the plot (default True) 2639 directory -- Directory where to save the file (default "") 2644 ret.extend(pg.draw(self.
_labels, prefix=prefix, separate=separate, saveFormat=saveFormat, ratio=ratio, directory=directory))
2650 """Method called to (possibly) translate a subfolder name to more 'readable' form 2652 The implementation in this (base) class just returns the 2653 argument. The idea is that a deriving class might want to do 2654 something more complex (like trackingPlots.TrackingPlotFolder 2657 return dqmSubFolderName
2660 """Iterate over possible selections name (used in output directory name and legend) from the name of PlotterFolder, and a return value of translateSubFolder""" 2662 if plotFolderName !=
"":
2663 ret +=
"_"+plotFolderName
2664 if translatedDqmSubFolder
is not None:
2665 ret +=
"_"+translatedDqmSubFolder
2669 """Return True if this subfolder should be processed 2672 limitOnlyTo -- List/set/similar containing the translatedDqmSubFolder 2673 translatedDqmSubFolder -- Return value of translateSubFolder 2675 return translatedDqmSubFolder
in limitOnlyTo
2678 """Class to hold the original name and a 'translated' name of a subfolder in the DQM ROOT file""" 2684 """Equality is defined by the 'translated' name""" 2688 """Plotter for one DQM folder. 2690 This class is supposed to be instantiated by the Plotter class (or 2691 PlotterItem, to be more specific), and not used directly by the 2694 def __init__(self, name, possibleDqmFolders, dqmSubFolders, plotFolder, fallbackNames, fallbackDqmSubFolders, tableCreators):
2699 name -- Name of the folder (is used in the output directory naming) 2700 possibleDqmFolders -- List of strings for possible directories of histograms in TFiles 2701 dqmSubFolders -- List of lists of strings for list of subfolders per input file, or None if no subfolders 2702 plotFolder -- PlotFolder object 2703 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. 2704 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. 2705 tableCreators -- List of PlotterTableItem objects for tables to be created from this folder 2711 if dqmSubFolders
is None:
2717 for sf_list
in dqmSubFolders:
2719 sf_translated = self._plotFolder.translateSubFolder(sf)
2720 if sf_translated
is not None and not sf_translated
in subfolders:
2721 subfolders[sf_translated] =
DQMSubFolder(sf, sf_translated)
2724 self._dqmSubFolders.sort(key=
lambda sf: sf.subfolder)
2734 return self._plotFolder.getPurpose()
2737 return self._plotFolder.getPage()
2740 return self._plotFolder.getSection()
2743 return self._plotFolder.onlyForPileup()
2746 return self._plotFolder.onlyForElectron()
2749 return self._plotFolder.onlyForConversion()
2752 return self._plotFolder.onlyForBHadron()
2758 """Get list of subfolders, possibly limiting to some of them. 2761 limitOnlyTo -- Object depending on the PlotFolder type for limiting the set of subfolders to be processed 2767 if limitOnlyTo
is None:
2770 return filter(
lambda s: self._plotFolder.limitSubFolder(limitOnlyTo, s.translated), self.
_dqmSubFolders)
2776 """Get a generator for the 'selection name', looping over the name and fallbackNames""" 2778 for selname
in self._plotFolder.iterSelectionName(name, dqmSubFolder.translated
if dqmSubFolder
is not None else None):
2784 def create(self, files, labels, dqmSubFolder, isPileupSample=True, requireAllHistograms=False):
2785 """Create histograms from a list of TFiles. 2787 files -- List of TFiles 2788 labels -- List of strings for legend labels corresponding the files 2789 dqmSubFolder -- DQMSubFolder object for a subfolder (or None for no subfolder) 2790 isPileupSample -- Is sample pileup (some PlotGroups may limit themselves to pileup) 2791 requireAllHistograms -- If True, a plot is produced if histograms from all files are present (default: False) 2794 subfolder = dqmSubFolder.subfolder
if dqmSubFolder
is not None else None 2795 neventsHisto = self._plotFolder.getNumberOfEventsHistogram()
2803 fallback = fallbackFunc(subfolder)
2804 if fallback
is not None:
2808 d = GetDirectoryCode.codesToNone(ret)
2810 if neventsHisto
is not None and tfile
is not None:
2812 if hnev
is not None:
2813 nev = hnev.GetEntries()
2814 dirsNEvents.append( (d, nev) )
2816 self._plotFolder.create(dirsNEvents, labels, isPileupSample, requireAllHistograms)
2819 """Draw and save all plots using settings of a given algorithm.""" 2820 return self._plotFolder.draw(*args, **kwargs)
2824 """Instance of plotter that knows the directory content, holds many folders.""" 2831 if limitSubFoldersOnlyTo
is not None:
2832 limitOnlyTo = limitSubFoldersOnlyTo.get(plotterFolder.getName(),
None)
2834 for dqmSubFolder
in plotterFolder.getDQMSubFolders(limitOnlyTo=limitOnlyTo):
2835 yield plotterFolder, dqmSubFolder
2839 def __init__(self, name, possibleDirs, plotFolder, fallbackNames=[], fallbackDqmSubFolders=[]):
2843 name -- Name of the folder (is used in the output directory naming) 2844 possibleDirs -- List of strings for possible directories of histograms in TFiles 2845 plotFolder -- PlotFolder object 2848 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. 2849 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. 2865 self._tableCreators.append(tc)
2868 """Read available subfolders from the files 2871 files -- List of strings for paths to files, or list of TFiles 2873 For each file, loop over 'possibleDirs', and read the 2874 subfolders of first one that exists. 2876 Returns a PlotterFolder if at least one file for which one of 2877 'possibleDirs' exists. Otherwise, return None to signal that 2878 there is nothing available for this PlotFolder. 2881 if self._plotFolder.loopSubFolders():
2883 possibleDirFound =
False 2888 isOpenFile = isinstance(fname, ROOT.TFile)
2892 tfile = ROOT.TFile.Open(fname)
2896 possibleDirFound =
True 2897 if subFolders
is not None:
2899 for key
in d.GetListOfKeys():
2900 if isinstance(key.ReadObj(), ROOT.TDirectory):
2901 subf.append(key.GetName())
2902 subFolders.append(subf)
2908 if not possibleDirFound:
2918 def create(self, openFiles, legendLabels, dqmSubFolder):
2919 if isinstance(dqmSubFolder, list):
2920 if len(dqmSubFolder) != len(openFiles):
2921 raise Exception(
"When dqmSubFolder is a list, len(dqmSubFolder) should be len(openFiles), now they are %d and %d" % (len(dqmSubFolder), len(openFiles)))
2923 dqmSubFolder = [dqmSubFolder]*len(openFiles)
2924 dqmSubFolder = [sf.subfolder
if sf
is not None else None for sf
in dqmSubFolder]
2927 for f, sf
in zip(openFiles, dqmSubFolder):
2930 if tdir
is not None:
2931 data = self._tableCreator.create(tdir)
2946 for i
in xrange(len(tbl)):
2948 tbl[i] = [
None]*colLen
2950 return html.Table(columnHeaders=legendLabels, rowHeaders=self._tableCreator.headers(), table=tbl,
2951 purpose=self._tableCreator.getPurpose(), page=self._tableCreator.getPage(), section=self._tableCreator.getSection(dqmSubFolder[0]))
2954 """Contains PlotFolders, i.e. the information what plots to do, and creates a helper object to actually produce the plots.""" 2958 ROOT.TH1.AddDirectory(
False)
2961 """Append a plot folder to the plotter. 2963 All arguments are forwarded to the constructor of PlotterItem. 2968 for plotterItem
in self.
_plots:
2969 if plotterItem.getName() == attachToFolder:
2972 raise Exception(
"Did not find plot folder '%s' when trying to attach a table creator to it" % attachToFolder)
2975 """Remove all plot folders and tables""" 2979 return [item.getName()
for item
in self.
_plots]
2982 return [item.getPlotFolder()
for item
in self.
_plots]
2986 if item.getName() == name:
2987 return item.getPlotFolder()
2988 raise Exception(
"No PlotFolder named '%s'" % name)
2991 """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 _getOrCreateObject(tdirectory, nameOrCreator)
def iterFolders(self, limitSubFoldersOnlyTo=None)
def setYTitleSize(self, size)
def setXLabelSize(self, size)
def _findBounds(th1s, ylog, xmin=None, xmax=None, ymin=None, ymax=None)
def _modifyPadForRatio(self, pad)
def Draw(self, options="")
def __init__(self, name, xhistoName, yhistoName, zaxis=False)
def __init__(self, pad, bounds, ratioBounds, ratioFactor, nrows, xbinlabels=None, xbinlabelsize=None, xbinlabeloption=None, ratioYTitle=_ratioYTitle)
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 divide(outfile, dest, numer, denom)
def append(self, args, kwargs)
def getDQMSubFolders(self, limitOnlyTo=None)
def _getXmax(obj, limitToNonZeroContent=False)
def drawRatioUncertainty(self)
def setZTitle(self, title)
def __init__(self, pad, bounds, histos, ratioOrig, ratioFactor)
def setZTitleOffset(self, offset)
def setXTitleSize(self, size)
def getNumberOfHistograms(self)
def create(self, tdirectoryNEvents, requireAllHistograms=False)
bool equal(const T &first, const T &second)
def move(self, dx=0, dy=0, dw=0, dh=0)
def __init__(self, name, kwargs)
def create(self, openFiles, legendLabels, dqmSubFolder)
def _calculateRatios(histos, ratioUncertainty=False)
def appendTable(self, attachToFolder, args, kwargs)
def setYTitleOffset(self, offset)
def setYTitle(self, title)
def _save(self, canvas, saveFormat, prefix=None, postfix=None, single=False, directory="")
def setYTitleSize(self, size)
def onlyForElectron(self)
def draw(name, histos, styles=_defaultStyles, legendLabels=[], kwargs)
def _setStats(self, histos, startingX, startingY)
def getSelectionName(self, dqmSubFolder)
def _getDirectory(args, kwargs)
def setYTitle(self, title)
def Draw(self, options=None)
def draw(self, pad, ratio, ratioFactor, nrows)
OutputIterator zip(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result, Compare comp)
def setTitle(self, title)
def setXTitle(self, title)
def create(self, tdirectory)
def readDirs(self, files)
def _mergeBinLabelsY(histos)
Abs< T >::type abs(const T &t)
def adjustMarginRight(self, adjust)
def adjustMarginLeft(self, adjust)
def setProperties(self, kwargs)
def addToLegend(self, legend, legendLabels, denomUncertainty)
def _getYmaxWithError(th1)
def setXTitleOffset(self, offset)
def _getDirectoryDetailed(tfile, possibleDirs, subDir=None)
def setXTitleOffset(self, size)
def draw(self, args, kwargs)
def create(self, tdirectory)
def __init__(self, pad, bounds, nrows, xbinlabels=None, xbinlabelsize=None, xbinlabeloption=None, ybinlabels=None)
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)
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 _drawFrame(pad, bounds, xbinlabels=None, xbinlabelsize=None, xbinlabeloption=None, ybinlabels=None, suffix="")
def appendTableCreator(self, tc)
def _modifyPadForRatio(pad, ratioFactor)
def create(self, files, labels, dqmSubFolder, isPileupSample=True, requireAllHistograms=False)
def create(self, tdirectoryNEvents, requireAllHistograms=False)
def _createCanvas(name, width, height)
def setYTitleOffset(self, offset)
auto wrap(F iFunc) -> decltype(iFunc())
def __init__(self, name, plot, ncols=2, onlyForPileup=False)
def getPlotFolderNames(self)
def getNumberOfEventsHistogram(self)
def _mergeBinLabels(labelsAll)
def __init__(self, plotGroups, kwargs)
def draw(self, args, kwargs)
def _th1ToOrderedDict(th1, renameBin=None)
def _th2RemoveEmptyBins(histos, xbinlabels, ybinlabels)
def getSelectionNameIterator(self, dqmSubFolder)
def create(self, tdirectory)
def setProperties(self, kwargs)
def _mergeBinLabelsX(histos)
def _createOne(self, name, index, tdir, nevents)
def draw(self, prefix=None, separate=False, saveFormat=".pdf", ratio=True, directory="")
How EventSelector::AcceptEvent() decides whether to accept an event for output otherwise it is excluding the probing of A single or multiple positive and the trigger will pass if any such matching triggers are PASS or EXCEPTION[A criterion thatmatches no triggers at all is detected and causes a throw.] A single negative with an expectation of appropriate bit checking in the decision and the trigger will pass if any such matching triggers are FAIL or EXCEPTION A wildcarded negative criterion that matches more than one trigger in the trigger list("!*","!HLTx*"if it matches 2 triggers or more) will accept the event if all the matching triggers are FAIL.It will reject the event if any of the triggers are PASS or EXCEPTION(this matches the behavior of"!*"before the partial wildcard feature was incorporated).Triggers which are in the READY state are completely ignored.(READY should never be returned since the trigger paths have been run
def setTitle(self, title)
def _th1IncludeOnlyBins(histos, xbinlabels)
def __init__(self, name, possibleDirs, plotFolder, fallbackNames=[], fallbackDqmSubFolders=[])
def _getObject(tdirectory, name)