1 from __future__
import print_function
12 ROOT.gROOT.SetBatch(
True)
13 ROOT.PyConfig.IgnoreCommandLineOptions =
True 18 _ratioYTitle =
"Ratio" 33 ROOT.gROOT.SetStyle(
"Plain")
34 ROOT.gStyle.SetPadRightMargin(0.07)
35 ROOT.gStyle.SetPadLeftMargin(0.13)
36 ROOT.gStyle.SetTitleFont(font,
"XYZ")
37 ROOT.gStyle.SetTitleSize(titleSize,
"XYZ")
38 ROOT.gStyle.SetTitleOffset(1.2,
"Y")
40 ROOT.gStyle.SetLabelFont(font,
"XYZ")
41 ROOT.gStyle.SetLabelSize(labelSize,
"XYZ")
42 ROOT.gStyle.SetTextSize(labelSize)
43 ROOT.gStyle.SetStatFont(font)
44 ROOT.gStyle.SetStatFontSize(statSize)
46 ROOT.TGaxis.SetMaxDigits(4)
49 obj = tdirectory.Get(name)
52 print(
"Did not find {obj} from {dir}".
format(obj=name, dir=tdirectory.GetPath()))
57 if hasattr(nameOrCreator,
"create"):
58 return nameOrCreator.create(tdirectory)
73 """Get TDirectory from TFile.""" 76 for pdf
in possibleDirs:
79 if subDir
is not None:
86 print(
"Did not find subdirectory '%s' from directory '%s' in file %s" % (subDir, pdf, tfile.GetName()))
93 print(
"Did not find any of directories '%s' from file %s" % (
",".
join(possibleDirs), tfile.GetName()))
100 values = collections.OrderedDict()
101 for i
in xrange(1, th1.GetNbinsX()+1):
102 binLabel = th1.GetXaxis().GetBinLabel(i)
103 if renameBin
is not None:
104 binLabel = renameBin(binLabel)
105 values[binLabel] = (th1.GetBinContent(i), th1.GetBinError(i))
111 backup = ROOT.gErrorIgnoreLevel
112 ROOT.gErrorIgnoreLevel = ROOT.kError
113 canvas = ROOT.TCanvas(name, name, width, height)
115 ROOT.gErrorIgnoreLevel = backup
121 divisionPoint = 1-1/ratioFactor
123 topMargin = pad.GetTopMargin()
124 bottomMargin = pad.GetBottomMargin()
125 divisionPoint += (1-divisionPoint)*bottomMargin
126 divisionPointForPad1 = 1-( (1-divisionPoint) / (1-0.02) )
131 ylow = divisionPointForPad1
134 pad1.SetPad(xlow, ylow, xup, yup)
135 pad1.SetFillStyle(4000)
136 pad1.SetBottomMargin(0.02)
142 pad2.SetPad(xlow, ylow, xup, yup)
143 pad2.SetFillStyle(4000)
144 pad2.SetTopMargin(0.0)
145 pad2.SetBottomMargin(bottomMargin/(ratioFactor*divisionPoint))
148 """Calculate the ratios for a list of histograms""" 150 def _divideOrZero(numerator, denominator):
153 return numerator/denominator
156 if a == 0.
and b == 0.:
160 def findBins(wrap, bins_xvalues):
162 currBin = wrap.begin()
164 while i < len(bins_xvalues)
and currBin < wrap.end():
165 (xcenter, xlow, xhigh) = bins_xvalues[i]
166 xlowEdge = xcenter-xlow
167 xupEdge = xcenter+xhigh
169 (curr_center, curr_low, curr_high) = wrap.xvalues(currBin)
170 curr_lowEdge = curr_center-curr_low
171 curr_upEdge = curr_center+curr_high
173 if equal(xlowEdge, curr_lowEdge)
and equal(xupEdge, curr_upEdge):
177 elif curr_upEdge <= xlowEdge:
179 elif curr_lowEdge >= xupEdge:
186 if len(ret) != len(bins_xvalues):
187 ret.extend([
None]*( len(bins_xvalues) - len(ret) ))
193 def __init__(self, th1, uncertainty):
195 self._uncertainty = uncertainty
197 xaxis = th1.GetXaxis()
198 xaxis_arr = xaxis.GetXbins()
199 if xaxis_arr.GetSize() > 0:
200 lst = [xaxis_arr[i]
for i
in xrange(0, xaxis_arr.GetSize())]
201 arr = array.array(
"d", lst)
202 self._ratio = ROOT.TH1F(
"foo",
"foo", xaxis.GetNbins(), arr)
204 self._ratio = ROOT.TH1F(
"foo",
"foo", xaxis.GetNbins(), xaxis.GetXmin(), xaxis.GetXmax())
206 self._ratio.SetStats(0)
207 self._ratio.SetLineColor(ROOT.kBlack)
208 self._ratio.SetLineWidth(1)
209 def draw(self, style=None):
212 if self._uncertainty:
216 self._ratio.Draw(
"same "+st)
220 return self._th1.GetNbinsX()+1
221 def xvalues(self, bin):
222 xval = self._th1.GetBinCenter(bin)
223 xlow = xval-self._th1.GetXaxis().GetBinLowEdge(bin)
224 xhigh = self._th1.GetXaxis().GetBinUpEdge(bin)-xval
225 return (xval, xlow, xhigh)
226 def yvalues(self, bin):
227 yval = self._th1.GetBinContent(bin)
228 yerr = self._th1.GetBinError(bin)
229 return (yval, yerr, yerr)
231 return self._th1.GetBinContent(bin)
232 def divide(self, bin, scale):
233 self._ratio.SetBinContent(bin, _divideOrZero(self._th1.GetBinContent(bin), scale))
234 self._ratio.SetBinError(bin, _divideOrZero(self._th1.GetBinError(bin), scale))
241 def __init__(self, gr, uncertainty):
243 self._uncertainty = uncertainty
250 def draw(self, style=None):
251 if self._ratio
is None:
255 if self._uncertainty:
259 self._ratio.Draw(
"same "+st)
263 return self._gr.GetN()
264 def xvalues(self, bin):
265 return (self._gr.GetX()[bin], self._gr.GetErrorXlow(bin), self._gr.GetErrorXhigh(bin))
266 def yvalues(self, bin):
267 return (self._gr.GetY()[bin], self._gr.GetErrorYlow(bin), self._gr.GetErrorYhigh(bin))
269 return self._gr.GetY()[bin]
270 def divide(self, bin, scale):
275 if bin >= self._gr.GetN():
278 xvals = self.xvalues(bin)
281 self._xvalues.append(xval)
282 self._xerrslow.append(xvals[1])
283 self._xerrshigh.append(xvals[2])
284 yvals = self.yvalues(bin)
285 self._yvalues.append(yvals[0] / scale)
286 if self._uncertainty:
287 self._yerrslow.append(yvals[1] / scale)
288 self._yerrshigh.append(yvals[2] / scale)
290 self._yerrslow.append(0)
291 self._yerrshigh.append(0)
293 if len(self._xvalues) == 0:
296 self._ratio = ROOT.TGraphAsymmErrors(len(self._xvalues), array.array(
"d", self._xvalues), array.array(
"d", self._yvalues),
297 array.array(
"d", self._xerrslow), array.array(
"d", self._xerrshigh),
298 array.array(
"d", self._yerrslow), array.array(
"d", self._yerrshigh))
302 class WrapTGraph2D(WrapTGraph):
303 def __init__(self, gr, uncertainty):
304 WrapTGraph.__init__(self, gr, uncertainty)
305 def xvalues(self, bin):
306 return (self._gr.GetX()[bin], self._gr.GetErrorX(bin), self._gr.GetErrorX(bin))
307 def yvalues(self, bin):
308 return (self._gr.GetY()[bin], self._gr.GetErrorY(bin), self._gr.GetErrorY(bin))
311 if isinstance(o, ROOT.TH1):
312 return WrapTH1(o, ratioUncertainty)
313 elif isinstance(o, ROOT.TGraph):
314 return WrapTGraph(o, ratioUncertainty)
315 elif isinstance(o, ROOT.TGraph2D):
316 return WrapTGraph2D(o, ratioUncertainty)
318 wrappers = [
wrap(h)
for h
in histos]
322 ref_bins = [ref.xvalues(b)
for b
in xrange(ref.begin(), ref.end())]
324 wrappers_bins.append(findBins(w, ref_bins))
326 for i, bin
in enumerate(xrange(ref.begin(), ref.end())):
327 (scale, ylow, yhigh) = ref.yvalues(bin)
328 for w, bins
in zip(wrappers, wrappers_bins):
331 w.divide(bins[i], scale)
340 if isinstance(obj, ROOT.TH1):
341 xaxis = obj.GetXaxis()
342 if limitToNonZeroContent:
343 for i
in xrange(1, obj.GetNbinsX()+1):
344 if obj.GetBinContent(i) != 0:
345 return xaxis.GetBinLowEdge(i)
349 return xaxis.GetBinLowEdge(xaxis.GetFirst())
350 elif isinstance(obj, ROOT.TGraph)
or isinstance(obj, ROOT.TGraph2D):
351 m =
min([obj.GetX()[i]
for i
in xrange(0, obj.GetN())])
352 return m*0.9
if m > 0
else m*1.1
356 if isinstance(obj, ROOT.TH1):
357 xaxis = obj.GetXaxis()
358 if limitToNonZeroContent:
359 for i
in xrange(obj.GetNbinsX(), 0, -1):
360 if obj.GetBinContent(i) != 0:
361 return xaxis.GetBinUpEdge(i)
365 return xaxis.GetBinUpEdge(xaxis.GetLast())
366 elif isinstance(obj, ROOT.TGraph)
or isinstance(obj, ROOT.TGraph2D):
367 m =
max([obj.GetX()[i]
for i
in xrange(0, obj.GetN())])
368 return m*1.1
if m > 0
else m*0.9
372 if isinstance(obj, ROOT.TH2):
373 yaxis = obj.GetYaxis()
374 return yaxis.GetBinLowEdge(yaxis.GetFirst())
375 elif isinstance(obj, ROOT.TH1):
376 if limitToNonZeroContent:
377 lst = [obj.GetBinContent(i)
for i
in xrange(1, obj.GetNbinsX()+1)
if obj.GetBinContent(i) != 0 ]
378 return min(lst)
if len(lst) != 0
else 0
380 return obj.GetMinimum()
381 elif isinstance(obj, ROOT.TGraph)
or isinstance(obj, ROOT.TGraph2D):
382 m =
min([obj.GetY()[i]
for i
in xrange(0, obj.GetN())])
383 return m*0.9
if m > 0
else m*1.1
387 if isinstance(obj, ROOT.TH2):
388 yaxis = obj.GetYaxis()
389 return yaxis.GetBinUpEdge(yaxis.GetLast())
390 elif isinstance(obj, ROOT.TH1):
391 if limitToNonZeroContent:
392 lst = [obj.GetBinContent(i)
for i
in xrange(1, obj.GetNbinsX()+1)
if obj.GetBinContent(i) != 0 ]
393 return max(lst)
if len(lst) != 0
else 0
395 return obj.GetMaximum()
396 elif isinstance(obj, ROOT.TGraph)
or isinstance(obj, ROOT.TGraph2D):
397 m =
max([obj.GetY()[i]
for i
in xrange(0, obj.GetN())])
398 return m*1.1
if m > 0
else m*0.9
402 return max([th1.GetBinContent(i)+th1.GetBinError(i)
for i
in xrange(1, th1.GetNbinsX()+1)])
405 yvals = sorted([n
for n
in [th1.GetBinContent(i)
for i
in xrange(1, th1.GetNbinsX()+1)]
if n>0])
407 return th1.GetMinimum()
412 ind_min = len(yvals)-1 -
int(len(yvals)*0.95)
413 min_val = yvals[ind_min]
414 for i
in xrange(0, ind_min):
415 if yvals[i] > 0.1*min_val:
421 inRange =
lambda x:
True 422 inRange2 =
lambda xmin,xmax:
True 424 inRange =
lambda x: coverageRange[0] <= x <= coverageRange[1]
425 inRange2 =
lambda xmin,xmax: coverageRange[0] <= xmin
and xmax <= coverageRange[1]
427 if isinstance(obj, ROOT.TH1):
428 yvals = [obj.GetBinContent(i)
for i
in xrange(1, obj.GetNbinsX()+1)
if inRange2(obj.GetXaxis().GetBinLowEdge(i), obj.GetXaxis().GetBinUpEdge(i))]
429 yvals = [x
for x
in yvals
if x != 0]
430 elif isinstance(obj, ROOT.TGraph)
or isinstance(obj, ROOT.TGraph2D):
431 yvals = [obj.GetY()[i]
for i
in xrange(0, obj.GetN())
if inRange(obj.GetX()[i])]
437 return (yvals[0], yvals[0])
439 return (yvals[0], yvals[1])
442 nvals =
int(len(yvals)*coverage)
445 if len(yvals) % 2 == 0:
447 return ( yvals[half-1], yvals[half] )
449 middle = len(yvals)/2
450 return ( yvals[middle-1], yvals[middle+1] )
451 ind_min = (len(yvals)-nvals)/2
452 ind_max = len(yvals)-1 - ind_min
454 return (yvals[ind_min], yvals[ind_max])
456 def _findBounds(th1s, ylog, xmin=None, xmax=None, ymin=None, ymax=None):
457 """Find x-y axis boundaries encompassing a list of TH1s if the bounds are not given in arguments. 461 ylog -- Boolean indicating if y axis is in log scale or not (affects the automatic ymax) 464 xmin -- Minimum x value; if None, take the minimum of TH1s 465 xmax -- Maximum x value; if None, take the maximum of TH1s 466 ymin -- Minimum y value; if None, take the minimum of TH1s 467 ymax -- Maximum y value; if None, take the maximum of TH1s 472 if xmin
is None or xmax
is None or isinstance(xmin, list)
or isinstance(max, list):
476 xmins.append(
_getXmin(th1, limitToNonZeroContent=isinstance(xmin, list)))
477 xmaxs.append(
_getXmax(th1, limitToNonZeroContent=isinstance(xmax, list)))
480 xmins = [h
for h
in xmins
if h
is not None]
481 xmaxs = [h
for h
in xmaxs
if h
is not None]
485 elif isinstance(xmin, list):
489 print(
"Histogram is zero, using the smallest given value for xmin from",
str(xmin))
492 xmins_below = [x
for x
in xmin
if x<=xm]
493 if len(xmins_below) == 0:
497 print(
"Histogram minimum x %f is below all given xmin values %s, using the smallest one" % (xm,
str(xmin)))
499 xmin =
max(xmins_below)
503 elif isinstance(xmax, list):
507 print(
"Histogram is zero, using the smallest given value for xmax from",
str(xmin))
510 xmaxs_above = [x
for x
in xmax
if x>xm]
511 if len(xmaxs_above) == 0:
515 print(
"Histogram maximum x %f is above all given xmax values %s, using the maximum one" % (xm,
str(xmax)))
517 xmax =
min(xmaxs_above)
520 th1.GetXaxis().SetRangeUser(xmin, xmax)
522 return (xmin, ymin, xmax, ymax)
524 def _findBoundsY(th1s, ylog, ymin=None, ymax=None, coverage=None, coverageRange=None):
525 """Find y axis boundaries encompassing a list of TH1s if the bounds are not given in arguments. 529 ylog -- Boolean indicating if y axis is in log scale or not (affects the automatic ymax) 532 ymin -- Minimum y value; if None, take the minimum of TH1s 533 ymax -- Maximum y value; if None, take the maximum of TH1s 534 coverage -- If set, use only values within the 'coverage' part around the median are used for min/max (useful for ratio) 535 coverageRange -- If coverage and this are set, use only the x axis specified by an (xmin,xmax) pair for the coverage 537 if coverage
is not None or isinstance(th1s[0], ROOT.TH2):
543 y_scale_max =
lambda y: y
544 y_scale_min =
lambda y: y
547 y_scale_max =
lambda y: y*1.5
549 y_scale_max =
lambda y: y*1.05
550 y_scale_min =
lambda y: y*0.9
552 if ymin
is None or ymax
is None or isinstance(ymin, list)
or isinstance(ymax, list):
556 if coverage
is not None:
559 if ylog
and isinstance(ymin, list):
562 _ymin =
_getYmin(th1, limitToNonZeroContent=isinstance(ymin, list))
563 _ymax =
_getYmax(th1, limitToNonZeroContent=isinstance(ymax, list))
571 elif isinstance(ymin, list):
572 ym_unscaled =
min(ymins)
573 ym = y_scale_min(ym_unscaled)
574 ymins_below = [y
for y
in ymin
if y<=ym]
575 if len(ymins_below) == 0:
577 if ym_unscaled < ymin:
579 print(
"Histogram minimum y %f is below all given ymin values %s, using the smallest one" % (ym,
str(ymin)))
581 ymin =
max(ymins_below)
586 ymax = y_scale_max(
max(ymaxs+[ymin]))
587 elif isinstance(ymax, list):
588 ym_unscaled =
max(ymaxs)
589 ym = y_scale_max(ym_unscaled)
590 ymaxs_above = [y
for y
in ymax
if y>ym]
591 if len(ymaxs_above) == 0:
593 if ym_unscaled > ymax:
595 print(
"Histogram maximum y %f is above all given ymax values %s, using the maximum one" % (ym_unscaled,
str(ymax)))
597 ymax =
min(ymaxs_above)
600 th1.GetYaxis().SetRangeUser(ymin, ymax)
606 for b
in xrange(1, histos[0].GetNbinsX()+1):
609 if h.GetBinContent(b) > 0:
615 if len(binsToRemove) > 0:
618 for i
in xrange(len(xbinlabels)):
619 if (i+1)
not in binsToRemove:
620 xbinlab_new.append(xbinlabels[i])
621 xbinlabels = xbinlab_new
627 for b
in xrange(1, h.GetNbinsX()+1):
628 if b
not in binsToRemove:
629 values.append( (h.GetXaxis().GetBinLabel(b), h.GetBinContent(b), h.GetBinError(b)) )
632 h_new = h.Clone(h.GetName()+
"_empty")
633 h_new.SetBins(len(values), h.GetBinLowEdge(1), h.GetBinLowEdge(1)+len(values))
634 for b, (l, v, e)
in enumerate(values):
635 h_new.GetXaxis().SetBinLabel(b+1, l)
636 h_new.SetBinContent(b+1, v)
637 h_new.SetBinError(b+1, e)
639 histos_new.append(h_new)
642 return (histos, xbinlabels)
645 xbinsToRemove = set()
646 ybinsToRemove = set()
647 for ih, h
in enumerate(histos):
648 for bx
in xrange(1, h.GetNbinsX()+1):
650 for by
in xrange(1, h.GetNbinsY()+1):
651 if h.GetBinContent(bx, by) > 0:
655 xbinsToRemove.add(bx)
657 xbinsToRemove.discard(bx)
659 for by
in xrange(1, h.GetNbinsY()+1):
661 for bx
in xrange(1, h.GetNbinsX()+1):
662 if h.GetBinContent(bx, by) > 0:
666 ybinsToRemove.add(by)
668 ybinsToRemove.discard(by)
670 if len(xbinsToRemove) > 0
or len(ybinsToRemove) > 0:
673 for b
in xrange(1, len(xbinlabels)+1):
674 if b
not in xbinsToRemove:
675 xbinlabels_new.append(histos[0].GetXaxis().GetBinLabel(b))
677 xbinlabels = xbinlabels_new
680 for b
in xrange(1, len(ybinlabels)+1):
681 if b
not in ybinsToRemove:
682 ybinlabels.append(histos[0].GetYaxis().GetBinLabel(b))
684 ybinlabels = xbinlabels_new
687 if len(xbinlabels) == 0
or len(ybinlabels) == 0:
688 return (histos_new, xbinlabels, ybinlabels)
690 h_new = ROOT.TH2F(h.GetName()+
"_empty", h.GetTitle(), len(xbinlabels),0,len(xbinlabels), len(ybinlabels),0,len(ybinlabels))
691 for b, l
in enumerate(xbinlabels):
692 h_new.GetXaxis().SetBinLabel(b+1, l)
693 for b, l
in enumerate(ybinlabels):
694 h_new.GetYaxis().SetBinLabel(b+1, l)
696 for ix, bx
in enumerate(xbins):
697 for iy, by
in enumerate(ybins):
698 h_new.SetBinContent(ix+1, iy+1, h.GetBinContent(bx, by))
699 h_new.SetBinError(ix+1, iy+1, h.GetBinError(bx, by))
700 histos_new.append(h_new)
702 return (histos, xbinlabels, ybinlabels)
705 return _mergeBinLabels([[h.GetXaxis().GetBinLabel(i)
for i
in xrange(1, h.GetNbinsX()+1)]
for h
in histos])
708 return _mergeBinLabels([[h.GetYaxis().GetBinLabel(i)
for i
in xrange(1, h.GetNbinsY()+1)]
for h
in histos])
711 labels_merged = labelsAll[0]
712 for labels
in labelsAll[1:]:
713 diff = difflib.unified_diff(labels_merged, labels, n=
max(len(labels_merged), len(labels)))
720 operation.append(item[0])
722 if lab
in labels_merged:
724 ind = labels_merged.index(lab)
725 if operation[ind] ==
"-" and operation[-1] ==
"+":
726 labels_merged.remove(lab)
728 elif operation[ind] ==
"+" and operation[-1] ==
"-":
732 raise Exception(
"This should never happen")
733 labels_merged.append(lab)
736 if len(labels_merged) == 0:
737 labels_merged = labels
744 h_new = h.Clone(h.GetName()+
"_xbinlabels")
745 h_new.SetBins(len(xbinlabels), h.GetBinLowEdge(1), h.GetBinLowEdge(1)+len(xbinlabels))
746 for i, label
in enumerate(xbinlabels):
747 bin = h.GetXaxis().FindFixBin(label)
749 h_new.SetBinContent(i+1, h.GetBinContent(bin))
750 h_new.SetBinError(i+1, h.GetBinError(bin))
752 h_new.SetBinContent(i+1, 0)
753 h_new.SetBinError(i+1, 0)
754 histos_new.append(h_new)
759 """Class for subtracting two histograms""" 764 name -- String for name of the resulting histogram (A-B) 765 nameA -- String for A histogram 766 nameB -- String for B histogram 769 title -- String for a title of the resulting histogram (default "") 771 Uncertainties are calculated with the assumption that B is a 772 subset of A, and the histograms contain event counts. 780 """String representation, returns the name""" 784 """Create and return the fake+duplicate histogram from a TDirectory""" 788 if not histoA
or not histoB:
791 ret = histoA.Clone(self.
_name)
797 ret.SetCanExtend(
False)
799 for i
in xrange(0, histoA.GetNbinsX()+2):
800 val = histoA.GetBinContent(i)-histoB.GetBinContent(i)
801 ret.SetBinContent(i, val)
802 ret.SetBinError(i, math.sqrt(val))
807 """Class to transform bin contents in an arbitrary way.""" 812 name -- String for name of the resulting histogram 813 histo -- String for a source histogram (needs to be cumulative) 814 func -- Function to operate on the bin content 822 """String representation, returns the name""" 826 """Create and return the transformed histogram from a TDirectory""" 831 ret = histo.Clone(self.
_name)
837 ret.SetCanExtend(
False)
839 for i
in xrange(0, histo.GetNbinsX()+2):
840 ret.SetBinContent(i, self.
_func(histo.GetBinContent(i)))
844 """Class to calculate the fake+duplicate rate""" 845 def __init__(self, name, assoc, dup, reco, title=""):
849 name -- String for the name of the resulting efficiency histogram 850 assoc -- String for the name of the "associated" histogram 851 dup -- String for the name of the "duplicates" histogram 852 reco -- String for the name of the "reco" (denominator) histogram 855 title -- String for a title of the resulting histogram (default "") 857 The result is calculated as 1 - (assoc - dup) / reco 866 """String representation, returns the name""" 870 """Create and return the fake+duplicate histogram from a TDirectory""" 877 if not hassoc
or not hdup
or not hreco:
880 hfakedup = hreco.Clone(self.
_name)
881 hfakedup.SetTitle(self.
_title)
883 for i
in xrange(1, hassoc.GetNbinsX()+1):
884 numerVal = hassoc.GetBinContent(i) - hdup.GetBinContent(i)
885 denomVal = hreco.GetBinContent(i)
887 fakedupVal = (1 - numerVal / denomVal)
if denomVal != 0.0
else 0.0
888 errVal = math.sqrt(fakedupVal*(1-fakedupVal)/denomVal)
if (denomVal != 0.0
and fakedupVal <= 1)
else 0.0
890 hfakedup.SetBinContent(i, fakedupVal)
891 hfakedup.SetBinError(i, errVal)
896 """Class for making a cut efficiency histograms. 906 name -- String for name of the resulting histogram 907 histo -- String for a source histogram (needs to be cumulative) 914 """String representation, returns the name""" 918 """Create and return the cut efficiency histogram from a TDirectory""" 924 ascending = histo.GetBinContent(0) < histo.GetBinContent(histo.GetNbinsX())
926 n_tot = histo.GetBinContent(histo.GetNbinsX())
928 n_tot = histo.GetBinContent(0)
933 ret = histo.Clone(self.
_name)
937 for i
in xrange(1, histo.GetNbinsX()+1):
938 n = histo.GetBinContent(i)
940 errVal = math.sqrt(val*(1-val)/n_tot)
941 ret.SetBinContent(i, val)
942 ret.SetBinError(i, errVal)
946 """Class to create a histogram by aggregating bins of another histogram to a bin of the resulting histogram.""" 947 def __init__(self, name, histoName, mapping, normalizeTo=None, scale=None, renameBin=None, ignoreMissingBins=False, minExistingBins=None, originalOrder=False, reorder=None):
951 name -- String for the name of the resulting histogram 952 histoName -- String for the name of the source histogram 953 mapping -- Dictionary for mapping the bins (see below) 956 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. 957 scale -- Optional number for scaling the histogram (passed to ROOT.TH1.Scale()) 958 renameBin -- Optional function (string -> string) to rename the bins of the input histogram 959 originalOrder -- Boolean for using the order of bins in the histogram (default False) 960 reorder -- Optional function to reorder the bins 962 Mapping structure (mapping): 964 Dictionary (you probably want to use collections.OrderedDict) 965 should be a mapping from the destination bin label to a list 966 of source bin labels ("dst -> [src]"). 979 raise Exception(
"reorder is not None and originalOrder is True, please set only one of them")
982 """String representation, returns the name""" 986 """Create and return the histogram from a TDirectory""" 992 binValues = [
None]*len(self.
_mapping)
998 for i, (key, labels)
in enumerate(six.iteritems(self.
_mapping)):
1004 sumTime += values[l][0]
1005 sumErrorSq += values[l][1]**2
1011 binValues[i] = (sumTime, math.sqrt(sumErrorSq))
1014 ivalue = len(values)+1
1020 ivalue = values.keys().
index(lab)
1022 binIndexOrder.append( (ivalue, i) )
1025 binIndexOrder.sort(key=
lambda t: t[0])
1028 for i
in xrange(0, len(binValues)):
1029 fromIndex = binIndexOrder[i][1]
1030 tmpVal.append(binValues[fromIndex])
1031 tmpLab.append(binLabels[fromIndex])
1035 order = self.
_reorder(tdirectory, binLabels)
1036 binValues = [binValues[i]
for i
in order]
1037 binLabels = [binLabels[i]
for i
in order]
1043 for i, val
in enumerate(binValues):
1046 binValues = [v
for v
in binValues
if v
is not None]
1047 binLabels = [v
for v
in binLabels
if v
is not None]
1048 if len(binValues) == 0:
1051 result = ROOT.TH1F(self.
_name, self.
_name, len(binValues), 0, len(binValues))
1052 for i, (value, label)
in enumerate(
zip(binValues, binLabels)):
1053 if value
is not None:
1054 result.SetBinContent(i+1, value[0])
1055 result.SetBinError(i+1, value[1])
1056 result.GetXaxis().SetBinLabel(i+1, label)
1063 value = th1.GetBinContent(bin)
1065 result.Scale(1/value)
1067 if self.
_scale is not None:
1068 result.Scale(self.
_scale)
1073 """Class to create a histogram by aggregaging integrals of another histoggrams.""" 1078 name -- String for the name of the resulting histogram 1079 mapping -- Dictionary for mapping the bin label to a histogram name 1082 normalizeTo -- Optional string for a histogram. If given, all bins of the resulting histograqm are divided by the integral of this histogram. 1089 """String representation, returns the name""" 1093 """Create and return the histogram from a TDirectory""" 1095 for key, histoName
in six.iteritems(self.
_mapping):
1099 result.append( (key, th1.Integral(0, th1.GetNbinsX()+1)) )
1100 if len(result) == 0:
1103 res = ROOT.TH1F(self.
_name, self.
_name, len(result), 0, len(result))
1105 for i, (name, count)
in enumerate(result):
1106 res.SetBinContent(i+1, count)
1107 res.GetXaxis().SetBinLabel(i+1, name)
1113 scale = th1.Integral(0, th1.GetNbinsX()+1)
1119 """Class to construct a ROC curve (e.g. efficiency vs. fake rate) from two histograms""" 1120 def __init__(self, name, xhistoName, yhistoName, zaxis=False):
1124 name -- String for the name of the resulting histogram 1125 xhistoName -- String for the name of the x-axis histogram (or another "creator" object) 1126 yhistoName -- String for the name of the y-axis histogram (or another "creator" object) 1129 zaxis -- If set to True (default False), create a TGraph2D with z axis showing the cut value (recommended drawStyle 'pcolz') 1137 """String representation, returns the name""" 1141 """Create and return the histogram from a TDirectory""" 1144 if xhisto
is None or yhisto
is None:
1155 for i
in xrange(1, xhisto.GetNbinsX()+1):
1156 x.append(xhisto.GetBinContent(i))
1157 xerrup.append(xhisto.GetBinError(i))
1158 xerrdown.append(xhisto.GetBinError(i))
1160 y.append(yhisto.GetBinContent(i))
1161 yerrup.append(yhisto.GetBinError(i))
1162 yerrdown.append(yhisto.GetBinError(i))
1164 z.append(xhisto.GetXaxis().GetBinUpEdge(i))
1167 if x.count(0.0) == len(x)
or y.count(0.0) == len(y):
1170 arr =
lambda v: array.array(
"d", v)
1173 gr = ROOT.TGraph2D(len(x), arr(x), arr(y), arr(z))
1175 gr = ROOT.TGraphAsymmErrors(len(x), arr(x), arr(y), arr(xerrdown), arr(xerrup), arr(yerrdown), arr(yerrup))
1181 _plotStylesColor = [4, 2, ROOT.kBlack, ROOT.kOrange+7, ROOT.kMagenta-3]
1182 _plotStylesMarker = [21, 20, 22, 34, 33]
1184 def _drawFrame(pad, bounds, zmax=None, xbinlabels=None, xbinlabelsize=None, xbinlabeloption=None, ybinlabels=None, suffix=""):
1185 """Function to draw a frame 1188 pad -- TPad to where the frame is drawn 1189 bounds -- List or 4-tuple for (xmin, ymin, xmax, ymax) 1192 zmax -- Maximum Z, needed for TH2 histograms 1193 xbinlabels -- Optional list of strings for x axis bin labels 1194 xbinlabelsize -- Optional number for the x axis bin label size 1195 xbinlabeloption -- Optional string for the x axis bin options (passed to ROOT.TH1.LabelsOption()) 1196 suffix -- Optional string for a postfix of the frame name 1198 if xbinlabels
is None and ybinlabels
is None:
1199 frame = pad.DrawFrame(*bounds)
1202 nbins = len(xbinlabels)
1203 if ybinlabels
is None:
1204 frame = ROOT.TH1F(
"hframe"+suffix,
"", nbins, bounds[0], bounds[2])
1205 frame.SetMinimum(bounds[1])
1206 frame.SetMaximum(bounds[3])
1207 frame.GetYaxis().SetLimits(bounds[1], bounds[3])
1209 ybins = len(ybinlabels)
1210 frame = ROOT.TH2F(
"hframe"+suffix,
"", nbins,bounds[0],bounds[2], ybins,bounds[1],bounds[3])
1211 frame.SetMaximum(zmax)
1213 frame.SetBit(ROOT.TH1.kNoStats)
1214 frame.SetBit(ROOT.kCanDelete)
1217 xaxis = frame.GetXaxis()
1218 for i
in xrange(nbins):
1219 xaxis.SetBinLabel(i+1, xbinlabels[i])
1220 if xbinlabelsize
is not None:
1221 xaxis.SetLabelSize(xbinlabelsize)
1222 if xbinlabeloption
is not None:
1223 frame.LabelsOption(xbinlabeloption)
1225 if ybinlabels
is not None:
1226 yaxis = frame.GetYaxis()
1227 for i, lab
in enumerate(ybinlabels):
1228 yaxis.SetBinLabel(i+1, lab)
1229 if xbinlabelsize
is not None:
1230 yaxis.SetLabelSize(xbinlabelsize)
1231 if xbinlabeloption
is not None:
1232 frame.LabelsOption(xbinlabeloption,
"Y")
1237 """Class for creating and managing a frame for a simple, one-pad plot""" 1238 def __init__(self, pad, bounds, zmax, nrows, xbinlabels=None, xbinlabelsize=None, xbinlabeloption=None, ybinlabels=None):
1240 self.
_frame =
_drawFrame(pad, bounds, zmax, xbinlabels, xbinlabelsize, xbinlabeloption, ybinlabels)
1248 yoffsetFactor *= 1.5
1249 xoffsetFactor *= 1.5
1254 self._frame.GetYaxis().SetTitleOffset(self._frame.GetYaxis().GetTitleOffset()*yoffsetFactor)
1255 self._frame.GetXaxis().SetTitleOffset(self._frame.GetXaxis().GetTitleOffset()*xoffsetFactor)
1259 self._pad.SetLogx(log)
1262 self._pad.SetLogy(log)
1265 self._pad.SetGridx(grid)
1268 self._pad.SetGridy(grid)
1271 self._pad.SetLeftMargin(self._pad.GetLeftMargin()+adjust)
1274 self._frame.Draw(
"")
1277 self._pad.SetRightMargin(self._pad.GetRightMargin()+adjust)
1280 self._frame.Draw(
"")
1283 self._frame.SetTitle(title)
1286 self._frame.GetXaxis().SetTitle(title)
1289 self._frame.GetXaxis().SetTitleSize(size)
1292 self._frame.GetXaxis().SetTitleOffset(offset)
1295 self._frame.GetXaxis().SetLabelSize(size)
1298 self._frame.GetYaxis().SetTitle(title)
1301 self._frame.GetYaxis().SetTitleSize(size)
1304 self._frame.GetYaxis().SetTitleOffset(offset)
1307 self._pad.RedrawAxis()
1310 """Class for creating and managing a frame for a ratio plot with two subpads""" 1311 def __init__(self, pad, bounds, zmax, ratioBounds, ratioFactor, nrows, xbinlabels=None, xbinlabelsize=None, xbinlabeloption=None, ratioYTitle=_ratioYTitle):
1314 if xbinlabels
is not None:
1321 self._frame.GetXaxis().SetLabelSize(0)
1322 self._frame.GetXaxis().SetTitleSize(0)
1324 yoffsetFactor = ratioFactor
1325 divisionPoint = 1-1/ratioFactor
1326 xoffsetFactor = 1/divisionPoint
1329 xoffsetFactor *= 0.6
1332 xoffsetFactor *= 1.5
1335 xoffsetFactor *= 2.3
1340 self._frame.GetYaxis().SetTitleOffset(self._frameRatio.GetYaxis().GetTitleOffset()*yoffsetFactor)
1341 self._frameRatio.GetYaxis().SetLabelSize(
int(self._frameRatio.GetYaxis().GetLabelSize()*0.8))
1342 self._frameRatio.GetYaxis().SetTitleOffset(self._frameRatio.GetYaxis().GetTitleOffset()*yoffsetFactor)
1343 self._frameRatio.GetXaxis().SetTitleOffset(self._frameRatio.GetXaxis().GetTitleOffset()*xoffsetFactor)
1345 self._frameRatio.GetYaxis().SetNdivisions(4, 5, 0)
1347 self._frameRatio.GetYaxis().SetTitle(ratioYTitle)
1350 self._pad.SetLogx(log)
1351 self._padRatio.SetLogx(log)
1354 self._pad.SetLogy(log)
1357 self._pad.SetGridx(grid)
1358 self._padRatio.SetGridx(grid)
1361 self._pad.SetGridy(grid)
1362 self._padRatio.SetGridy(grid)
1365 self._pad.SetLeftMargin(self._pad.GetLeftMargin()+adjust)
1366 self._padRatio.SetLeftMargin(self._padRatio.GetLeftMargin()+adjust)
1369 self._frame.Draw(
"")
1371 self._frameRatio.Draw(
"")
1374 self._pad.SetRightMargin(self._pad.GetRightMargin()+adjust)
1375 self._padRatio.SetRightMargin(self._padRatio.GetRightMargin()+adjust)
1378 self._frame.Draw(
"")
1380 self._frameRatio.Draw(
"")
1383 self._frame.SetTitle(title)
1386 self._frameRatio.GetXaxis().SetTitle(title)
1389 self._frameRatio.GetXaxis().SetTitleSize(size)
1392 self._frameRatio.GetXaxis().SetTitleOffset(offset)
1395 self._frameRatio.GetXaxis().SetLabelSize(size)
1398 self._frame.GetYaxis().SetTitle(title)
1401 self._frameRatio.GetYaxis().SetTitle(title)
1404 self._frame.GetYaxis().SetTitleSize(size)
1405 self._frameRatio.GetYaxis().SetTitleSize(size)
1408 self._frame.GetYaxis().SetTitleOffset(offset)
1409 self._frameRatio.GetYaxis().SetTitleOffset(offset)
1412 self._padRatio.RedrawAxis()
1413 self._pad.RedrawAxis()
1415 self._parentPad.cd()
1422 self.
_coverPad = ROOT.TPad(
"coverpad",
"coverpad", xmin, ymin, xmax, ymax)
1423 self._coverPad.SetBorderMode(0)
1424 self._coverPad.Draw()
1430 """Class for creating and managing a frame for a plot from TGraph2D""" 1431 def __init__(self, pad, bounds, histos, ratioOrig, ratioFactor):
1434 self.
_pad = pad.cd(1)
1438 (xlow, ylow, width, height) = (self._pad.GetXlowNDC(), self._pad.GetYlowNDC(), self._pad.GetWNDC(), self._pad.GetHNDC())
1442 bottomMargin = self._pad.GetBottomMargin()
1443 bottomMarginNew = ROOT.gStyle.GetPadBottomMargin()
1445 ylowNew = yup - (1-bottomMargin)/(1-bottomMarginNew) * (yup-ylow)
1446 topMarginNew = self._pad.GetTopMargin() * (yup-ylow)/(yup-ylowNew)
1448 self._pad.SetPad(xlow, ylowNew, xup, yup)
1449 self._pad.SetTopMargin(topMarginNew)
1450 self._pad.SetBottomMargin(bottomMarginNew)
1470 self._pad.SetLeftMargin(self._pad.GetLeftMargin()+adjust)
1474 self._pad.SetRightMargin(self._pad.GetRightMargin()+adjust)
1502 self._firstHisto.GetZaxis().SetTitle(title)
1505 self._firstHisto.GetZaxis().SetTitleOffset(offset)
1510 self._pad.SetPhi(epsilon)
1511 self._pad.SetTheta(90+epsilon)
1513 self._firstHisto.GetXaxis().SetTitleOffset(self.
_xtitleoffset)
1514 self._firstHisto.GetYaxis().SetTitleOffset(self.
_ytitleoffset)
1516 if hasattr(self,
"_xtitle"):
1517 self._firstHisto.GetXaxis().SetTitle(self.
_xtitle)
1518 if hasattr(self,
"_xtitlesize"):
1519 self._firstHisto.GetXaxis().SetTitleSize(self.
_xtitlesize)
1520 if hasattr(self,
"_xlabelsize"):
1521 self._firstHisto.GetXaxis().SetLabelSize(self._labelsize)
1522 if hasattr(self,
"_ytitle"):
1523 self._firstHisto.GetYaxis().SetTitle(self.
_ytitle)
1524 if hasattr(self,
"_ytitlesize"):
1525 self._firstHisto.GetYaxis().SetTitleSize(self.
_ytitlesize)
1526 if hasattr(self,
"_ytitleoffset"):
1527 self._firstHisto.GetYaxis().SetTitleOffset(self.
_ytitleoffset)
1530 """Abstraction on top of TLatex""" 1531 def __init__(self, x, y, text, size=None, bold=True, align="left", color=ROOT.kBlack, font=None):
1535 x -- X coordinate of the text (in NDC) 1536 y -- Y coordinate of the text (in NDC) 1537 text -- String to draw 1538 size -- Size of text (None for the default value, taken from gStyle) 1539 bold -- Should the text be bold? 1540 align -- Alignment of text (left, center, right) 1541 color -- Color of the text 1542 font -- Specify font explicitly 1551 self._l.SetTextFont(self._l.GetTextFont()-20)
1552 if font
is not None:
1553 self._l.SetTextFont(font)
1554 if size
is not None:
1555 self._l.SetTextSize(size)
1556 if isinstance(align, str):
1557 if align.lower() ==
"left":
1558 self._l.SetTextAlign(11)
1559 elif align.lower() ==
"center":
1560 self._l.SetTextAlign(21)
1561 elif align.lower() ==
"right":
1562 self._l.SetTextAlign(31)
1564 raise Exception(
"Error: Invalid option '%s' for text alignment! Options are: 'left', 'center', 'right'."%align)
1566 self._l.SetTextAlign(align)
1567 self._l.SetTextColor(color)
1570 """Draw the text to the current TPad. 1573 options -- For interface compatibility, ignored 1575 Provides interface compatible with ROOT's drawable objects. 1577 self._l.DrawLatex(self.
_x, self.
_y, self.
_text)
1581 """Class for drawing text and a background box.""" 1582 def __init__(self, xmin, ymin, xmax, ymax, lineheight=0.04, fillColor=ROOT.kWhite, transparent=True, **kwargs):
1586 xmin -- X min coordinate of the box (NDC) 1587 ymin -- Y min coordinate of the box (NDC) (if None, deduced automatically) 1588 xmax -- X max coordinate of the box (NDC) 1589 ymax -- Y max coordinate of the box (NDC) 1590 lineheight -- Line height 1591 fillColor -- Fill color of the box 1592 transparent -- Should the box be transparent? (in practive the TPave is not created) 1594 Keyword arguments are forwarded to constructor of PlotText 1606 self._textArgs.update(kwargs)
1611 """Add text to current position""" 1618 def move(self, dx=0, dy=0, dw=0, dh=0):
1619 """Move the box and the contained text objects 1622 dx -- Movement in x (positive is to right) 1623 dy -- Movement in y (positive is to up) 1624 dw -- Increment of width (negative to decrease width) 1625 dh -- Increment of height (negative to decrease height) 1627 dx and dy affect to both box and text objects, dw and dh 1628 affect the box only. 1632 if self.
_ymin is not None:
1637 if self.
_ymin is not None:
1645 """Draw the box and the text to the current TPad. 1648 options -- Forwarded to ROOT.TPave.Draw(), and the Draw() of the contained objects 1653 ymin = self.currenty - 0.01
1654 self.
_pave = ROOT.TPave(self.xmin, self.ymin, self.xmax, self.ymax, 0,
"NDC")
1655 self._pave.SetFillColor(self.fillColor)
1656 self._pave.Draw(options)
1662 if hasattr(src,
"GetLineColor")
and hasattr(dst,
"SetLineColor"):
1663 properties.extend([
"LineColor",
"LineStyle",
"LineWidth"])
1664 if hasattr(src,
"GetFillColor")
and hasattr(dst,
"SetFillColor"):
1665 properties.extend([
"FillColor",
"FillStyle"])
1666 if hasattr(src,
"GetMarkerColor")
and hasattr(dst,
"SetMarkerColor"):
1667 properties.extend([
"MarkerColor",
"MarkerSize",
"MarkerStyle"])
1669 for prop
in properties:
1670 getattr(dst,
"Set"+prop)(getattr(src,
"Get"+prop)())
1673 """Denotes an empty place in a group.""" 1693 """Represents one plot, comparing one or more histograms.""" 1698 name -- String for name of the plot, or Efficiency object 1701 fallback -- Dictionary for specifying fallback (default None) 1702 outname -- String for an output name of the plot (default None for the same as 'name') 1703 title -- String for a title of the plot (default None) 1704 xtitle -- String for x axis title (default None) 1705 xtitlesize -- Float for x axis title size (default None) 1706 xtitleoffset -- Float for x axis title offset (default None) 1707 xlabelsize -- Float for x axis label size (default None) 1708 ytitle -- String for y axis title (default None) 1709 ytitlesize -- Float for y axis title size (default None) 1710 ytitleoffset -- Float for y axis title offset (default None) 1711 ztitle -- String for z axis title (default None) 1712 ztitleoffset -- Float for z axis title offset (default None) 1713 xmin -- Float for x axis minimum (default None, i.e. automatic) 1714 xmax -- Float for x axis maximum (default None, i.e. automatic) 1715 ymin -- Float for y axis minimum (default 0) 1716 ymax -- Float for y axis maximum (default None, i.e. automatic) 1717 xlog -- Bool for x axis log status (default False) 1718 ylog -- Bool for y axis log status (default False) 1719 xgrid -- Bool for x axis grid status (default True) 1720 ygrid -- Bool for y axis grid status (default True) 1721 stat -- Draw stat box? (default False) 1722 fit -- Do gaussian fit? (default False) 1723 statx -- Stat box x coordinate (default 0.65) 1724 staty -- Stat box y coordinate (default 0.8) 1725 statyadjust -- List of floats for stat box y coordinate adjustments (default None) 1726 normalizeToUnitArea -- Normalize histograms to unit area? (default False) 1727 normalizeToNumberOfEvents -- Normalize histograms to number of events? If yes, the PlotFolder needs 'numberOfEventsHistogram' set to a histogram filled once per event (default False) 1728 profileX -- Take histograms via ProfileX()? (default False) 1729 fitSlicesY -- Take histograms via FitSlicesY() (default False) 1730 rebinX -- rebin x axis (default None) 1731 scale -- Scale histograms by a number (default None) 1732 xbinlabels -- List of x axis bin labels (if given, default None) 1733 xbinlabelsize -- Size of x axis bin labels (default None) 1734 xbinlabeloption -- Option string for x axis bin labels (default None) 1735 removeEmptyBins -- Bool for removing empty bins, but only if histogram has bin labels (default False) 1736 printBins -- Bool for printing bin values, but only if histogram has bin labels (default False) 1737 drawStyle -- If "hist", draw as line instead of points (default None) 1738 drawCommand -- Deliver this to Draw() (default: None for same as drawStyle) 1739 lineWidth -- If drawStyle=="hist", the width of line (default 2) 1740 legendDx -- Float for moving TLegend in x direction for separate=True (default None) 1741 legendDy -- Float for moving TLegend in y direction for separate=True (default None) 1742 legendDw -- Float for changing TLegend width for separate=True (default None) 1743 legendDh -- Float for changing TLegend height for separate=True (default None) 1744 legend -- Bool to enable/disable legend (default True) 1745 adjustMarginLeft -- Float for adjusting left margin (default None) 1746 adjustMarginRight -- Float for adjusting right margin (default None) 1747 ratio -- Possibility to disable ratio for this particular plot (default None) 1748 ratioYmin -- Float for y axis minimum in ratio pad (default: list of values) 1749 ratioYmax -- Float for y axis maximum in ratio pad (default: list of values) 1750 ratioFit -- Fit straight line in ratio? (default None) 1751 ratioUncertainty -- Plot uncertainties on ratio? (default True) 1752 ratioCoverageXrange -- Range of x axis values (xmin,xmax) to limit the automatic ratio y axis range calculation to (default None for disabled) 1753 histogramModifier -- Function to be called in create() to modify the histograms (default None) 1757 def _set(attr, default):
1758 setattr(self,
"_"+attr, kwargs.get(attr, default))
1760 _set(
"fallback",
None)
1761 _set(
"outname",
None)
1764 _set(
"xtitle",
None)
1765 _set(
"xtitlesize",
None)
1766 _set(
"xtitleoffset",
None)
1767 _set(
"xlabelsize",
None)
1768 _set(
"ytitle",
None)
1769 _set(
"ytitlesize",
None)
1770 _set(
"ytitleoffset",
None)
1771 _set(
"ztitle",
None)
1772 _set(
"ztitleoffset",
None)
1789 _set(
"statyadjust",
None)
1791 _set(
"normalizeToUnitArea",
False)
1792 _set(
"normalizeToNumberOfEvents",
False)
1793 _set(
"profileX",
False)
1794 _set(
"fitSlicesY",
False)
1795 _set(
"rebinX",
None)
1798 _set(
"xbinlabels",
None)
1799 _set(
"xbinlabelsize",
None)
1800 _set(
"xbinlabeloption",
None)
1801 _set(
"removeEmptyBins",
False)
1802 _set(
"printBins",
False)
1804 _set(
"drawStyle",
"EP")
1805 _set(
"drawCommand",
None)
1806 _set(
"lineWidth", 2)
1808 _set(
"legendDx",
None)
1809 _set(
"legendDy",
None)
1810 _set(
"legendDw",
None)
1811 _set(
"legendDh",
None)
1812 _set(
"legend",
True)
1814 _set(
"adjustMarginLeft",
None)
1815 _set(
"adjustMarginRight",
None)
1818 _set(
"ratioYmin", [0, 0.2, 0.5, 0.7, 0.8, 0.9, 0.95])
1819 _set(
"ratioYmax", [1.05, 1.1, 1.2, 1.3, 1.5, 1.8, 2, 2.5, 3, 4, 5])
1820 _set(
"ratioFit",
None)
1821 _set(
"ratioUncertainty",
True)
1822 _set(
"ratioCoverageXrange",
None)
1824 _set(
"histogramModifier",
None)
1829 for name, value
in six.iteritems(kwargs):
1830 if not hasattr(self,
"_"+name):
1831 raise Exception(
"No attribute '%s'" % name)
1832 setattr(self,
"_"+name, value)
1836 raise Exception(
"Plot can be cloned only before histograms have been created")
1837 cl = copy.copy(self)
1838 cl.setProperties(**kwargs)
1842 """Return number of existing histograms.""" 1843 return len([h
for h
in self.
_histograms if h
is not None])
1846 """Return true if there are no histograms created for the plot""" 1851 if isinstance(h, ROOT.TGraph2D):
1856 if self._ratio
is None:
1858 return ratio
and self._ratio
1861 if self._outname
is not None:
1862 return self._outname
1863 if isinstance(self.
_name, list):
1869 """Return true if the ratio uncertainty should be drawn""" 1870 return self._ratioUncertainty
1873 """Create one histogram from a TDirectory.""" 1878 if isinstance(name, list):
1882 if h
is not None and self._normalizeToNumberOfEvents
and nevents
is not None and nevents != 0:
1883 h.Scale(1.0/nevents)
1886 def create(self, tdirNEvents, requireAllHistograms=False):
1887 """Create histograms from list of TDirectories""" 1888 self.
_histograms = [self.
_createOne(self.
_name, i, tdirNEvent[0], tdirNEvent[1])
for i, tdirNEvent
in enumerate(tdirNEvents)]
1890 if self._fallback
is not None:
1894 self.
_histograms[i] = self.
_createOne(self._fallback[
"name"], i, tdirNEvents[i][0], tdirNEvents[i][1])
1895 profileX[i] = self._fallback.get(
"profileX", self._profileX)
1897 if self._histogramModifier
is not None:
1901 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)))
1906 def _modifyHisto(th1, profileX):
1911 th1 = th1.ProfileX()
1913 if self._fitSlicesY:
1914 ROOT.TH1.AddDirectory(
True)
1916 th1 = ROOT.gDirectory.Get(th1.GetName()+
"_2")
1917 th1.SetDirectory(
None)
1919 ROOT.TH1.AddDirectory(
False)
1921 if self._title
is not None:
1922 th1.SetTitle(self._title)
1924 if self._scale
is not None:
1925 th1.Scale(self._scale)
1929 if self._fallback
is not None:
1933 if requireAllHistograms
and None in self.
_histograms:
1937 """Set stats box.""" 1940 if h
is not None and hasattr(h,
"SetStats"):
1944 def _doStats(h, col, dy):
1949 if self._fit
and h.GetEntries() > 0.5:
1951 f = h.GetListOfFunctions().FindObject(
"gaus")
1959 st = h.GetListOfFunctions().FindObject(
"stats")
1963 st.SetX1NDC(startingX)
1964 st.SetX2NDC(startingX+0.3)
1965 st.SetY1NDC(startingY+dy)
1966 st.SetY2NDC(startingY+dy+0.15)
1967 st.SetTextColor(col)
1970 for i, h
in enumerate(histos):
1971 if self._statyadjust
is not None and i < len(self._statyadjust):
1972 dy += self._statyadjust[i]
1974 _doStats(h, _plotStylesColor[i], dy)
1978 """Normalise histograms to unit area""" 1986 if h.GetSumw2().fN <= 0:
1990 def draw(self, pad, ratio, ratioFactor, nrows):
1991 """Draw the histograms using values for a given algorithm.""" 2002 if self._normalizeToUnitArea:
2005 if self._rebinX
is not None:
2007 h.Rebin(self._rebinX)
2009 def _styleMarker(h, msty, col):
2010 h.SetMarkerStyle(msty)
2011 h.SetMarkerColor(col)
2012 h.SetMarkerSize(0.7)
2016 def _styleHist(h, msty, col):
2017 _styleMarker(h, msty, col)
2019 h.SetLineWidth(self._lineWidth)
2022 style = _styleMarker
2023 if "hist" in self._drawStyle.lower():
2026 if "l" in self._drawStyle.lower():
2034 style(h, _plotStylesMarker[i], _plotStylesColor[i])
2036 if len(histos) == 0:
2043 histosHaveBinLabels = len(histos[0].GetXaxis().GetBinLabel(1)) > 0
2044 xbinlabels = self._xbinlabels
2046 if xbinlabels
is None:
2047 if histosHaveBinLabels:
2049 if isinstance(histos[0], ROOT.TH2):
2058 if self._removeEmptyBins
and histosHaveBinLabels:
2061 if isinstance(histos[0], ROOT.TH2):
2066 if len(histos) == 0:
2068 print(
"No histograms with non-empty bins for plot {name}".
format(name=self.
getName()))
2071 if self._printBins
and histosHaveBinLabels:
2072 print(
"####################")
2074 width =
max([len(l)
for l
in xbinlabels])
2075 tmp =
"%%-%ds " % width
2076 for b
in xrange(1, histos[0].GetNbinsX()+1):
2077 s = tmp % xbinlabels[b-1]
2079 s +=
"%.3f " % h.GetBinContent(b)
2084 xmin=self._xmin, xmax=self._xmax,
2085 ymin=self._ymin, ymax=self._ymax)
2087 if isinstance(histos[0], ROOT.TH2):
2088 zmax =
max([h.GetMaximum()
for h
in histos])
2096 ratioHistos = [h
for h
in [r.getRatio()
for r
in self.
_ratios[1:]]
if h
is not None]
2098 if len(ratioHistos) > 0:
2099 ratioBoundsY =
_findBoundsY(ratioHistos, ylog=
False, ymin=self._ratioYmin, ymax=self._ratioYmax, coverage=0.68, coverageRange=self._ratioCoverageXrange)
2101 ratioBoundsY = (0.9, 1,1)
2103 if self._ratioFit
is not None:
2104 for i, rh
in enumerate(ratioHistos):
2105 tf_line = ROOT.TF1(
"line%d"%i,
"[0]+x*[1]")
2106 tf_line.SetRange(self._ratioFit[
"rangemin"], self._ratioFit[
"rangemax"])
2107 fitres = rh.Fit(tf_line,
"RINSQ")
2108 tf_line.SetLineColor(rh.GetMarkerColor())
2109 tf_line.SetLineWidth(2)
2110 self._ratioAdditional.append(tf_line)
2111 box =
PlotTextBox(xmin=self._ratioFit.get(
"boxXmin", 0.14), ymin=
None,
2112 xmax=self._ratioFit.get(
"boxXmax", 0.35), ymax=self._ratioFit.get(
"boxYmax", 0.09),
2113 color=rh.GetMarkerColor(), font=43, size=11, lineheight=0.02)
2114 box.move(dx=(box.width()+0.01)*i)
2117 box.addText(
"Const: %.4f#pm%.4f" % (fitres.Parameter(0), fitres.ParError(0)))
2118 box.addText(
"Slope: %.4f#pm%.4f" % (fitres.Parameter(1), fitres.ParError(1)))
2119 self._mainAdditional.append(box)
2129 self.
_setStats(histos, self._statx, self._staty)
2133 frame =
FrameTGraph2D(pad, bounds, histos, ratioOrig, ratioFactor)
2136 ratioBounds = (bounds[0], ratioBoundsY[0], bounds[2], ratioBoundsY[1])
2137 frame =
FrameRatio(pad, bounds, zmax, ratioBounds, ratioFactor, nrows, xbinlabels, self._xbinlabelsize, self._xbinlabeloption)
2139 frame =
Frame(pad, bounds, zmax, nrows, xbinlabels, self._xbinlabelsize, self._xbinlabeloption, ybinlabels=ybinlabels)
2142 frame.setLogx(self._xlog)
2143 frame.setLogy(self._ylog)
2144 frame.setGridx(self._xgrid)
2145 frame.setGridy(self._ygrid)
2150 if self._drawStyle
is not None:
2151 ds = self._drawStyle
2152 if self._drawCommand
is not None:
2153 ds = self._drawCommand
2158 frame.setTitle(histos[0].GetTitle())
2159 if self._xtitle
is not None:
2160 frame.setXTitle(self._xtitle)
2161 if self._xtitlesize
is not None:
2162 frame.setXTitleSize(self._xtitlesize)
2163 if self._xtitleoffset
is not None:
2164 frame.setXTitleOffset(self._xtitleoffset)
2165 if self._xlabelsize
is not None:
2166 frame.setXLabelSize(self._xlabelsize)
2167 if self._ytitle
is not None:
2168 frame.setYTitle(self._ytitle)
2169 if self._ytitlesize
is not None:
2170 frame.setYTitleSize(self._ytitlesize)
2171 if self._ytitleoffset
is not None:
2172 frame.setYTitleOffset(self._ytitleoffset)
2173 if self._ztitle
is not None:
2174 frame.setZTitle(self._ztitle)
2175 if self._ztitleoffset
is not None:
2176 frame.setZTitleOffset(self._ztitleoffset)
2177 if self._adjustMarginLeft
is not None:
2178 frame.adjustMarginLeft(self._adjustMarginLeft)
2179 if self._adjustMarginRight
is not None:
2180 frame.adjustMarginRight(self._adjustMarginRight)
2182 frame.adjustMarginLeft(0.03)
2183 frame.adjustMarginRight(0.08)
2189 for i, h
in enumerate(histos):
2191 if isTGraph2D
and i == 0:
2192 o = o.replace(
"sames",
"")
2199 if ratio
and len(histos) > 0:
2200 frame._padRatio.cd()
2201 firstRatio = self.
_ratios[0].getRatio()
2202 if self._ratioUncertainty
and firstRatio
is not None:
2203 firstRatio.SetFillStyle(1001)
2204 firstRatio.SetFillColor(ROOT.kGray)
2205 firstRatio.SetLineColor(ROOT.kGray)
2206 firstRatio.SetMarkerColor(ROOT.kGray)
2207 firstRatio.SetMarkerSize(0)
2209 frame._padRatio.RedrawAxis(
"G")
2220 """Add histograms to a legend. 2224 legendLabels -- List of strings for the legend labels 2226 first = denomUncertainty
2233 self._forLegend.SetFillStyle(1001)
2234 self._forLegend.SetFillColor(ROOT.kGray)
2235 entry = legend.AddEntry(self.
_forLegend, label,
"lpf")
2238 legend.AddEntry(h, label,
"LP")
2241 """Group of plots, results a TCanvas""" 2246 name -- String for name of the TCanvas, used also as the basename of the picture files 2247 plots -- List of Plot objects 2250 ncols -- Number of columns (default 2) 2251 legendDx -- Float for moving TLegend in x direction (default None) 2252 legendDy -- Float for moving TLegend in y direction (default None) 2253 legendDw -- Float for changing TLegend width (default None) 2254 legendDh -- Float for changing TLegend height (default None) 2255 legend -- Bool for disabling legend (default True for legend being enabled) 2256 overrideLegendLabels -- List of strings for legend labels, if given, these are used instead of the ones coming from Plotter (default None) 2257 onlyForPileup -- Plots this group only for pileup samples 2264 def _set(attr, default):
2265 setattr(self,
"_"+attr, kwargs.get(attr, default))
2269 _set(
"legendDx",
None)
2270 _set(
"legendDy",
None)
2271 _set(
"legendDw",
None)
2272 _set(
"legendDh",
None)
2273 _set(
"legend",
True)
2275 _set(
"overrideLegendLabels",
None)
2277 _set(
"onlyForPileup",
False)
2282 for name, value
in six.iteritems(kwargs):
2283 if not hasattr(self,
"_"+name):
2284 raise Exception(
"No attribute '%s'" % name)
2285 setattr(self,
"_"+name, value)
2294 for i, plot
in enumerate(self.
_plots):
2295 if plot.getName() == name:
2298 raise Exception(
"Did not find Plot '%s' from PlotGroup '%s'" % (name, self.
_name))
2304 self._plots.append(plot)
2308 if plot.getName() == name:
2310 raise Exception(
"No Plot named '%s'" % name)
2313 """Return True if the PlotGroup is intended only for pileup samples""" 2314 return self._onlyForPileup
2316 def create(self, tdirectoryNEvents, requireAllHistograms=False):
2317 """Create histograms from a list of TDirectories. 2320 tdirectoryNEvents -- List of (TDirectory, nevents) pairs 2321 requireAllHistograms -- If True, a plot is produced if histograms from all files are present (default: False) 2324 plot.create(tdirectoryNEvents, requireAllHistograms)
2326 def draw(self, legendLabels, prefix=None, separate=False, saveFormat=".pdf", ratio=True, directory=""):
2327 """Draw the histograms using values for a given algorithm. 2330 legendLabels -- List of strings for legend labels (corresponding to the tdirectories in create()) 2331 prefix -- Optional string for file name prefix (default None) 2332 separate -- Save the plots of a group to separate files instead of a file per group (default False) 2333 saveFormat -- String specifying the plot format (default '.pdf') 2334 ratio -- Add ratio to the plot (default True) 2335 directory -- Directory where to save the file (default "") 2338 if self._overrideLegendLabels
is not None:
2339 legendLabels = self._overrideLegendLabels
2342 onlyEmptyPlots =
True 2344 if not plot.isEmpty():
2345 onlyEmptyPlots =
False 2351 return self.
_drawSeparate(legendLabels, prefix, saveFormat, ratio, directory)
2353 cwidth = 500*self._ncols
2354 nrows =
int((len(self.
_plots)+self._ncols-1)/self._ncols)
2355 cheight = 500 * nrows
2362 canvas.Divide(self._ncols, nrows)
2364 for i, plot
in enumerate(self.
_plots):
2365 pad = canvas.cd(i+1)
2369 for i, plot
in enumerate(self.
_plots):
2370 pad = canvas.cd(i+1)
2371 if not plot.isEmpty():
2376 if len(self.
_plots) <= 4:
2386 if self._legendDx
is not None:
2387 lx1 += self._legendDx
2388 lx2 += self._legendDx
2389 if self._legendDy
is not None:
2390 ly1 += self._legendDy
2391 ly2 += self._legendDy
2392 if self._legendDw
is not None:
2393 lx2 += self._legendDw
2394 if self._legendDh
is not None:
2395 ly1 -= self._legendDh
2396 plot =
max(self.
_plots, key=
lambda p: p.getNumberOfHistograms())
2397 denomUnc = sum([p.drawRatioUncertainty()
for p
in self.
_plots]) > 0
2398 legend = self.
_createLegend(plot, legendLabels, lx1, ly1, lx2, ly2,
2399 denomUncertainty=(ratio
and denomUnc))
2401 return self.
_save(canvas, saveFormat, prefix=prefix, directory=directory)
2404 """Internal method to do the drawing to separate files per Plot instead of a file per PlotGroup""" 2412 for c
in [canvas, canvasRatio]:
2413 c.SetTopMargin(0.05)
2414 c.SetBottomMargin(0.13)
2415 c.SetLeftMargin(0.16)
2416 c.SetRightMargin(0.05)
2429 ratioForThisPlot = plot.isRatio(ratio)
2431 if ratioForThisPlot:
2447 if plot._legendDx
is not None:
2448 lx1 += plot._legendDx
2449 lx2 += plot._legendDx
2450 if plot._legendDy
is not None:
2451 ly1 += plot._legendDy
2452 ly2 += plot._legendDy
2453 if plot._legendDw
is not None:
2454 lx2 += plot._legendDw
2455 if plot._legendDh
is not None:
2456 ly1 -= plot._legendDh
2459 legend = self.
_createLegend(plot, legendLabels, lx1, ly1, lx2, ly2, textSize=0.03,
2460 denomUncertainty=(ratioForThisPlot
and plot.drawRatioUncertainty))
2462 ret.extend(self.
_save(c, saveFormat, prefix=prefix, postfix=
"_"+plot.getName(), single=
True, directory=directory))
2466 """Internal method to set divide a pad to two for ratio plots""" 2469 def _createLegend(self, plot, legendLabels, lx1, ly1, lx2, ly2, textSize=0.016, denomUncertainty=True):
2470 if not self._legend:
2473 l = ROOT.TLegend(lx1, ly1, lx2, ly2)
2474 l.SetTextSize(textSize)
2481 plot.addToLegend(l, legendLabels, denomUncertainty)
2485 def _save(self, canvas, saveFormat, prefix=None, postfix=None, single=False, directory=""):
2488 if prefix
is not None:
2490 if postfix
is not None:
2492 name = os.path.join(directory, name)
2495 backup = ROOT.gErrorIgnoreLevel
2496 ROOT.gErrorIgnoreLevel = ROOT.kWarning
2497 canvas.SaveAs(name+saveFormat)
2499 ROOT.gErrorIgnoreLevel = backup
2503 canvas.SetLogx(
False)
2504 canvas.SetLogy(
False)
2508 return [name+saveFormat]
2511 """Resembles DQM GUI's "On side" layout. 2513 Like PlotGroup, but has only a description of a single plot. The 2514 plot is drawn separately for each file. Useful for 2D histograms.""" 2516 def __init__(self, name, plot, ncols=2, onlyForPileup=False):
2517 super(PlotOnSideGroup, self).
__init__(name, [], ncols=ncols, legend=
False, onlyForPileup=onlyForPileup)
2519 self._plot.setProperties(ratio=
False)
2522 raise Exception(
"PlotOnSideGroup.append() is not implemented")
2524 def create(self, tdirectoryNEvents, requireAllHistograms=False):
2526 for element
in tdirectoryNEvents:
2527 pl = self._plot.clone()
2528 pl.create([element], requireAllHistograms)
2529 self._plots.append(pl)
2532 kargs = copy.copy(kwargs)
2533 kargs[
"ratio"] =
False 2534 return super(PlotOnSideGroup, self).
draw(*args, **kargs)
2538 """Represents a collection of PlotGroups, produced from a single folder in a DQM file""" 2543 plotGroups -- List of PlotGroup objects 2546 loopSubFolders -- Should the subfolders be looped over? (default: True) 2547 onlyForPileup -- Plots this folder only for pileup samples 2548 onlyForElectron -- Plots this folder only for electron samples 2549 onlyForConversion -- Plots this folder only for conversion samples 2550 onlyForBHadron -- Plots this folder only for B-hadron samples 2551 purpose -- html.PlotPurpose member class for the purpose of the folder, used for grouping of the plots to the HTML pages 2552 page -- Optional string for the page in HTML generatin 2553 section -- Optional string for the section within a page in HTML generation 2554 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". 2567 raise Exception(
"Got unexpected keyword arguments: "+
",".
join(kwargs.keys()))
2570 """Return True if the PlotGroups of this folder should be applied to the all subfolders""" 2574 """Return True if the folder is intended only for pileup samples""" 2599 self._plotGroups.append(plotGroup)
2609 if pg.getName() == name:
2611 raise Exception(
"No PlotGroup named '%s'" % name)
2613 def create(self, dirsNEvents, labels, isPileupSample=True, requireAllHistograms=False):
2614 """Create histograms from a list of TFiles. 2617 dirsNEvents -- List of (TDirectory, nevents) pairs 2618 labels -- List of strings for legend labels corresponding the files 2619 isPileupSample -- Is sample pileup (some PlotGroups may limit themselves to pileup) 2620 requireAllHistograms -- If True, a plot is produced if histograms from all files are present (default: False) 2623 if len(dirsNEvents) != len(labels):
2624 raise Exception(
"len(dirsNEvents) should be len(labels), now they are %d and %d" % (len(dirsNEvents), len(labels)))
2629 if pg.onlyForPileup()
and not isPileupSample:
2631 pg.create(dirsNEvents, requireAllHistograms)
2633 def draw(self, prefix=None, separate=False, saveFormat=".pdf", ratio=True, directory=""):
2634 """Draw and save all plots using settings of a given algorithm. 2637 prefix -- Optional string for file name prefix (default None) 2638 separate -- Save the plots of a group to separate files instead of a file per group (default False) 2639 saveFormat -- String specifying the plot format (default '.pdf') 2640 ratio -- Add ratio to the plot (default True) 2641 directory -- Directory where to save the file (default "") 2646 ret.extend(pg.draw(self.
_labels, prefix=prefix, separate=separate, saveFormat=saveFormat, ratio=ratio, directory=directory))
2652 """Method called to (possibly) translate a subfolder name to more 'readable' form 2654 The implementation in this (base) class just returns the 2655 argument. The idea is that a deriving class might want to do 2656 something more complex (like trackingPlots.TrackingPlotFolder 2659 return dqmSubFolderName
2662 """Iterate over possible selections name (used in output directory name and legend) from the name of PlotterFolder, and a return value of translateSubFolder""" 2664 if plotFolderName !=
"":
2665 ret +=
"_"+plotFolderName
2666 if translatedDqmSubFolder
is not None:
2667 ret +=
"_"+translatedDqmSubFolder
2671 """Return True if this subfolder should be processed 2674 limitOnlyTo -- List/set/similar containing the translatedDqmSubFolder 2675 translatedDqmSubFolder -- Return value of translateSubFolder 2677 return translatedDqmSubFolder
in limitOnlyTo
2680 """Class to hold the original name and a 'translated' name of a subfolder in the DQM ROOT file""" 2686 """Equality is defined by the 'translated' name""" 2690 """Plotter for one DQM folder. 2692 This class is supposed to be instantiated by the Plotter class (or 2693 PlotterItem, to be more specific), and not used directly by the 2696 def __init__(self, name, possibleDqmFolders, dqmSubFolders, plotFolder, fallbackNames, fallbackDqmSubFolders, tableCreators):
2701 name -- Name of the folder (is used in the output directory naming) 2702 possibleDqmFolders -- List of strings for possible directories of histograms in TFiles 2703 dqmSubFolders -- List of lists of strings for list of subfolders per input file, or None if no subfolders 2704 plotFolder -- PlotFolder object 2705 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. 2706 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. 2707 tableCreators -- List of PlotterTableItem objects for tables to be created from this folder 2713 if dqmSubFolders
is None:
2719 for sf_list
in dqmSubFolders:
2721 sf_translated = self._plotFolder.translateSubFolder(sf)
2722 if sf_translated
is not None and not sf_translated
in subfolders:
2723 subfolders[sf_translated] =
DQMSubFolder(sf, sf_translated)
2726 self._dqmSubFolders.sort(key=
lambda sf: sf.subfolder)
2736 return self._plotFolder.getPurpose()
2739 return self._plotFolder.getPage()
2742 return self._plotFolder.getSection()
2745 return self._plotFolder.onlyForPileup()
2748 return self._plotFolder.onlyForElectron()
2751 return self._plotFolder.onlyForConversion()
2754 return self._plotFolder.onlyForBHadron()
2760 """Get list of subfolders, possibly limiting to some of them. 2763 limitOnlyTo -- Object depending on the PlotFolder type for limiting the set of subfolders to be processed 2769 if limitOnlyTo
is None:
2772 return [s
for s
in self.
_dqmSubFolders if self._plotFolder.limitSubFolder(limitOnlyTo, s.translated)]
2778 """Get a generator for the 'selection name', looping over the name and fallbackNames""" 2780 for selname
in self._plotFolder.iterSelectionName(name, dqmSubFolder.translated
if dqmSubFolder
is not None else None):
2786 def create(self, files, labels, dqmSubFolder, isPileupSample=True, requireAllHistograms=False):
2787 """Create histograms from a list of TFiles. 2789 files -- List of TFiles 2790 labels -- List of strings for legend labels corresponding the files 2791 dqmSubFolder -- DQMSubFolder object for a subfolder (or None for no subfolder) 2792 isPileupSample -- Is sample pileup (some PlotGroups may limit themselves to pileup) 2793 requireAllHistograms -- If True, a plot is produced if histograms from all files are present (default: False) 2796 subfolder = dqmSubFolder.subfolder
if dqmSubFolder
is not None else None 2797 neventsHisto = self._plotFolder.getNumberOfEventsHistogram()
2805 fallback = fallbackFunc(subfolder)
2806 if fallback
is not None:
2810 d = GetDirectoryCode.codesToNone(ret)
2812 if neventsHisto
is not None and tfile
is not None:
2814 if hnev
is not None:
2815 nev = hnev.GetEntries()
2816 dirsNEvents.append( (d, nev) )
2818 self._plotFolder.create(dirsNEvents, labels, isPileupSample, requireAllHistograms)
2821 """Draw and save all plots using settings of a given algorithm.""" 2822 return self._plotFolder.draw(*args, **kwargs)
2826 """Instance of plotter that knows the directory content, holds many folders.""" 2833 if limitSubFoldersOnlyTo
is not None:
2834 limitOnlyTo = limitSubFoldersOnlyTo.get(plotterFolder.getName(),
None)
2836 for dqmSubFolder
in plotterFolder.getDQMSubFolders(limitOnlyTo=limitOnlyTo):
2837 yield plotterFolder, dqmSubFolder
2841 def __init__(self, name, possibleDirs, plotFolder, fallbackNames=[], fallbackDqmSubFolders=[]):
2845 name -- Name of the folder (is used in the output directory naming) 2846 possibleDirs -- List of strings for possible directories of histograms in TFiles 2847 plotFolder -- PlotFolder object 2850 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. 2851 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. 2867 self._tableCreators.append(tc)
2870 """Read available subfolders from the files 2873 files -- List of strings for paths to files, or list of TFiles 2875 For each file, loop over 'possibleDirs', and read the 2876 subfolders of first one that exists. 2878 Returns a PlotterFolder if at least one file for which one of 2879 'possibleDirs' exists. Otherwise, return None to signal that 2880 there is nothing available for this PlotFolder. 2883 if self._plotFolder.loopSubFolders():
2885 possibleDirFound =
False 2890 isOpenFile = isinstance(fname, ROOT.TFile)
2894 tfile = ROOT.TFile.Open(fname)
2898 possibleDirFound =
True 2899 if subFolders
is not None:
2901 for key
in d.GetListOfKeys():
2902 if isinstance(key.ReadObj(), ROOT.TDirectory):
2903 subf.append(key.GetName())
2904 subFolders.append(subf)
2910 if not possibleDirFound:
2920 def create(self, openFiles, legendLabels, dqmSubFolder):
2921 if isinstance(dqmSubFolder, list):
2922 if len(dqmSubFolder) != len(openFiles):
2923 raise Exception(
"When dqmSubFolder is a list, len(dqmSubFolder) should be len(openFiles), now they are %d and %d" % (len(dqmSubFolder), len(openFiles)))
2925 dqmSubFolder = [dqmSubFolder]*len(openFiles)
2926 dqmSubFolder = [sf.subfolder
if sf
is not None else None for sf
in dqmSubFolder]
2929 for f, sf
in zip(openFiles, dqmSubFolder):
2932 if tdir
is not None:
2933 data = self._tableCreator.create(tdir)
2948 for i
in xrange(len(tbl)):
2950 tbl[i] = [
None]*colLen
2952 return html.Table(columnHeaders=legendLabels, rowHeaders=self._tableCreator.headers(), table=tbl,
2953 purpose=self._tableCreator.getPurpose(), page=self._tableCreator.getPage(), section=self._tableCreator.getSection(dqmSubFolder[0]))
2956 """Contains PlotFolders, i.e. the information what plots to do, and creates a helper object to actually produce the plots.""" 2960 ROOT.TH1.AddDirectory(
False)
2963 """Append a plot folder to the plotter. 2965 All arguments are forwarded to the constructor of PlotterItem. 2970 for plotterItem
in self.
_plots:
2971 if plotterItem.getName() == attachToFolder:
2974 raise Exception(
"Did not find plot folder '%s' when trying to attach a table creator to it" % attachToFolder)
2977 """Remove all plot folders and tables""" 2981 return [item.getName()
for item
in self.
_plots]
2984 return [item.getPlotFolder()
for item
in self.
_plots]
2988 if item.getName() == name:
2989 return item.getPlotFolder()
2990 raise Exception(
"No PlotFolder named '%s'" % name)
2993 """Returns PlotterInstance object, which knows how exactly to produce the plots for these files"""
def create(self, tdirectory)
def iterSelectionName(self, plotFolderName, translatedDqmSubFolder)
def __init__(self, x, y, text, size=None, bold=True, align="left", color=ROOT.kBlack, font=None)
def append(self, plotGroup)
def _getYmax(obj, limitToNonZeroContent=False)
def __init__(self, name, plots, kwargs)
def __init__(self, name, nameA, nameB, title="")
def getPossibleDQMFolders(self)
def adjustMarginLeft(self, adjust)
def _findBoundsY(th1s, ylog, ymin=None, ymax=None, coverage=None, coverageRange=None)
def set(self, plotGroups)
def setXTitle(self, title)
def readDirs(self, files)
def draw(self, legendLabels, prefix=None, separate=False, saveFormat=".pdf", ratio=True, directory="")
def setXLabelSize(self, size)
def _drawFrame(pad, bounds, zmax=None, xbinlabels=None, xbinlabelsize=None, xbinlabeloption=None, ybinlabels=None, suffix="")
def _getOrCreateObject(tdirectory, nameOrCreator)
def iterFolders(self, limitSubFoldersOnlyTo=None)
def setYTitleSize(self, size)
def setXLabelSize(self, size)
def _findBounds(th1s, ylog, xmin=None, xmax=None, ymin=None, ymax=None)
def _modifyPadForRatio(self, pad)
def Draw(self, options="")
def __init__(self, name, xhistoName, yhistoName, zaxis=False)
def adjustMarginRight(self, adjust)
def __init__(self, possibleDirs, tableCreator)
def getTableCreators(self)
def __init__(self, xmin, ymin, xmax, ymax, lineheight=0.04, fillColor=ROOT.kWhite, transparent=True, kwargs)
def _getYmin(obj, limitToNonZeroContent=False)
def create(self, args, kwargs)
def setXTitleSize(self, size)
def create(self, tdirectory)
def adjustMarginLeft(self, adjust)
def setXLabelSize(self, size)
def _getYminIgnoreOutlier(th1)
def append(self, args, kwargs)
def getDQMSubFolders(self, limitOnlyTo=None)
def _getXmax(obj, limitToNonZeroContent=False)
def __init__(self, pad, bounds, zmax, nrows, xbinlabels=None, xbinlabelsize=None, xbinlabeloption=None, ybinlabels=None)
def drawRatioUncertainty(self)
def setZTitle(self, title)
S & print(S &os, JobReport::InputFile const &f)
def __init__(self, pad, bounds, histos, ratioOrig, ratioFactor)
def setZTitleOffset(self, offset)
def setXTitleSize(self, size)
def __init__(self, pad, bounds, zmax, ratioBounds, ratioFactor, nrows, xbinlabels=None, xbinlabelsize=None, xbinlabeloption=None, ratioYTitle=_ratioYTitle)
def getNumberOfHistograms(self)
def create(self, tdirectoryNEvents, requireAllHistograms=False)
bool equal(const T &first, const T &second)
def move(self, dx=0, dy=0, dw=0, dh=0)
def __init__(self, name, kwargs)
def create(self, openFiles, legendLabels, dqmSubFolder)
def _calculateRatios(histos, ratioUncertainty=False)
def appendTable(self, attachToFolder, args, kwargs)
def setYTitleOffset(self, offset)
def setYTitle(self, title)
def _save(self, canvas, saveFormat, prefix=None, postfix=None, single=False, directory="")
def setYTitleSize(self, size)
def onlyForElectron(self)
def draw(name, histos, styles=_defaultStyles, legendLabels=[], kwargs)
def _setStats(self, histos, startingX, startingY)
def getSelectionName(self, dqmSubFolder)
def _getDirectory(args, kwargs)
def setYTitle(self, title)
def Draw(self, options=None)
def draw(self, pad, ratio, ratioFactor, nrows)
OutputIterator zip(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result, Compare comp)
def setTitle(self, title)
def setXTitle(self, title)
def create(self, tdirectory)
def readDirs(self, files)
def _mergeBinLabelsY(histos)
Abs< T >::type abs(const T &t)
def adjustMarginRight(self, adjust)
def adjustMarginLeft(self, adjust)
def setProperties(self, kwargs)
def addToLegend(self, legend, legendLabels, denomUncertainty)
def _getYmaxWithError(th1)
def setXTitleOffset(self, offset)
def _getDirectoryDetailed(tfile, possibleDirs, subDir=None)
def setXTitleOffset(self, size)
def draw(self, args, kwargs)
def create(self, tdirectory)
def onlyForConversion(self)
def _getYminMaxAroundMedian(obj, coverage, coverageRange=None)
def getPlotFolder(self, name)
def setYTitleOffset(self, offset)
def __init__(self, name, histo, title="")
def onlyForConversion(self)
def limitSubFolder(self, limitOnlyTo, translatedDqmSubFolder)
def setXTitleSize(self, size)
def setYTitleRatio(self, title)
def drawRatioUncertainty(self)
static std::string join(char **cmd)
def create(self, dirsNEvents, labels, isPileupSample=True, requireAllHistograms=False)
def getNumberOfHistograms(self)
def __init__(self, name, assoc, dup, reco, title="")
void divide(MonitorElement *eff, const MonitorElement *numerator, const MonitorElement *denominator)
Function to fill an efficiency histograms with binomial errors.
def adjustMarginRight(self, adjust)
def __init__(self, subfolder, translated)
def create(self, tdirectory)
def setXTitleOffset(self, offset)
def __init__(self, name, histoName, mapping, normalizeTo=None, scale=None, renameBin=None, ignoreMissingBins=False, minExistingBins=None, originalOrder=False, reorder=None)
def __init__(self, name, mapping, normalizeTo=None)
def _createLegend(self, plot, legendLabels, lx1, ly1, lx2, ly2, textSize=0.016, denomUncertainty=True)
def translateSubFolder(self, dqmSubFolderName)
def _drawSeparate(self, legendLabels, prefix, saveFormat, ratio, directory)
def __init__(self, folders)
def setTitle(self, title)
def __init__(self, name, possibleDqmFolders, dqmSubFolders, plotFolder, fallbackNames, fallbackDqmSubFolders, tableCreators)
def setXTitle(self, title)
def setYTitleSize(self, size)
def setYTitle(self, title)
def _th1RemoveEmptyBins(histos, xbinlabels)
def _getXmin(obj, limitToNonZeroContent=False)
def onlyForElectron(self)
def append(self, args, kwargs)
def create(self, tdirNEvents, requireAllHistograms=False)
def getPlotGroup(self, name)
def appendTableCreator(self, tc)
def _modifyPadForRatio(pad, ratioFactor)
def create(self, files, labels, dqmSubFolder, isPileupSample=True, requireAllHistograms=False)
def create(self, tdirectoryNEvents, requireAllHistograms=False)
def _createCanvas(name, width, height)
def setYTitleOffset(self, offset)
auto wrap(F iFunc) -> decltype(iFunc())
def __init__(self, name, plot, ncols=2, onlyForPileup=False)
def getPlotFolderNames(self)
def getNumberOfEventsHistogram(self)
def _mergeBinLabels(labelsAll)
def __init__(self, plotGroups, kwargs)
def draw(self, args, kwargs)
def _th1ToOrderedDict(th1, renameBin=None)
def _th2RemoveEmptyBins(histos, xbinlabels, ybinlabels)
def getSelectionNameIterator(self, dqmSubFolder)
def create(self, tdirectory)
def setProperties(self, kwargs)
def _mergeBinLabelsX(histos)
def _createOne(self, name, index, tdir, nevents)
def draw(self, prefix=None, separate=False, saveFormat=".pdf", ratio=True, directory="")
How EventSelector::AcceptEvent() decides whether to accept an event for output otherwise it is excluding the probing of A single or multiple positive and the trigger will pass if any such matching triggers are PASS or EXCEPTION[A criterion thatmatches no triggers at all is detected and causes a throw.] A single negative with an expectation of appropriate bit checking in the decision and the trigger will pass if any such matching triggers are FAIL or EXCEPTION A wildcarded negative criterion that matches more than one trigger in the trigger list("!*","!HLTx*"if it matches 2 triggers or more) will accept the event if all the matching triggers are FAIL.It will reject the event if any of the triggers are PASS or EXCEPTION(this matches the behavior of"!*"before the partial wildcard feature was incorporated).Triggers which are in the READY state are completely ignored.(READY should never be returned since the trigger paths have been run
def setTitle(self, title)
def _th1IncludeOnlyBins(histos, xbinlabels)
def __init__(self, name, possibleDirs, plotFolder, fallbackNames=[], fallbackDqmSubFolders=[])
def _getObject(tdirectory, name)