def _plot(self, varexp, cut, options='', *args, **kwargs): ''' Primitive method to produce histograms and projections ''' if kwargs: print 'kwargs', kwargs dirsentry = utils.TH1AddDirSentry() sumsentry = utils.TH1Sumw2Sentry() options = 'goff ' + options self._log.debug('varexp: \'%s\'', varexp) self._log.debug('cut: \'%s\'', cut) self._log.debug('options: \'%s\'', options) n = self._chain.Draw(varexp, cut, options, *args, **kwargs) h = self._chain.GetHistogram() if h.__nonzero__(): # print h.GetDirectory() self._log.debug('entries %d integral %f', h.GetEntries(), h.Integral()) h.Scale(self._scale) self._log.debug('scale: %f integral %f', self._scale, h.Integral()) return h else: self._log.debug('entries %d', n) return None
def getNominalUpDown(file): finder = utils.ObjFinder("TH1D") names = finder.findRecursive(file) nomRegex = re.compile('^histo_([^_]+)$') systRegex = re.compile('^histo_([^_]+)_(.+)(Up|Down)$') nominals = {} nomupdown = {} for name in names: if not nomRegex.match(name): continue h = getHist(file,name) nominals[name.replace('histo_','')] = h for name in names: m = systRegex.match(name) if not m: continue process,syst,var = m.group(1,2,3) if process not in nomupdown: nomupdown[process] = {} if not syst in nomupdown[process]: v = variation() v.Nom = nominals[process] nomupdown[process][syst] = v hUpDown = getHist(file,name) setattr(nomupdown[process][syst],var,hUpDown) return nomupdown
def yields(self, cut='', options='', *args, **kwargs): cut = self._cutexpr(cut) # DO add the histogram, and set sumw2 (why not using TH1::Sumw2()? dirsentry = utils.TH1AddDirSentry(True) sumsentry = utils.TH1Sumw2Sentry() # new name per call or? what about using always the same histogram? tname = 'counter' #'counter_%s' % uuid.uuid1() # it might look like an overkill, but the double here helps counter = ROOT.TH1D(tname, tname, 1, 0., 1.) h = self._plot('0. >> ' + tname, cut, options, *args, **kwargs) xax = h.GetXaxis() err = ctypes.c_double(0.) int = h.IntegralAndError(xax.GetFirst(), xax.GetLast(), err) return Yield(int, err.value)
def _projexpr(name, bins=None): ''' Prepares the target for plotting if the binning is standard (n,min,max) then return a string else, it's variable binning, make the htemp and return it ''' if not bins: return 0, name, None elif not isinstance(bins, tuple): raise TypeError('bin must be an ntuple or an array') l = len(bins) # if the tuple is made of lists # if l in [1,2] and all(map(lambda o: isinstance(o,list),bins)): if (l in [1, 2] and all(map(lambda o: isinstance(o, list), bins))) or (l in [3, 6]): dirsentry = utils.TH1AddDirSentry() sumsentry = utils.TH1Sumw2Sentry() # get the hshape hdim, hclass, hargs = _bins2hclass(bins) # make the histogram htemp = hclass(name, name, *hargs) return hdim, name, htemp else: # standard approach, the string goes into the expression # WARNING: this way the constuction of the histogram is delegated to TTree::Draw, which produces a TH1F # IT would be better to retain the control over the histogram type selection (i.e. being able to make TH1D always) # In order to do so, we need to mimik the with which TTree Draw creates its histograms: # - x-check the dimention in varexp and projexp # - initial xmin,xmax (and likewise for y) # - default number of bins if l in [1]: # nx (free xmin, xmax) ndim = 1 elif l in [4]: # nx,xmin,xmax,ny (free ymin,ymax) ndim = 2 else: # only 1d or 2 d hist raise RuntimeError('What a mess!!! bin malformed!') hdef = '(' + ','.join([str(x) for x in bins]) + ')' if bins else '' return ndim, name + hdef, None
def set(self, h0, *hs ): if not hs and self._style.plotratio: raise RuntimeError('cannot compare only 1 histogram') n = h0.GetDimension() if True in [ h.GetDimension() != n for h in hs ]: raise ValueError('Cannot compare histograms with different dimensions') sentry = utils.TH1AddDirSentry() self._h0 = h0.Clone() self._hists = [ h.Clone() for h in hs ]
def GetHistPaths( path ): rootFile = ROOT.TFile.Open(path) finder = utils.ObjFinder('TH1D') names = finder.findRecursive(rootFile) plist = rootFile.Get('processes') processes = [ p.GetName() for p in plist ] if plist.__nonzero__() else None return rootFile,names,processes
def getNominals(file): # rootFile = ROOT.TFile.Open(file) finder = utils.ObjFinder("TH1D") names = finder.findRecursive(file) nomRegex = re.compile('^histo_([^_]+)$') nominals = {} for name in names: if not nomRegex.match(name): continue h = getHist(file,name) nominals[name.replace('histo_','')] = h return nominals
def readSamples(self, filename): self.dataSamples = [] self.mcSamples = [] self.virSamples = [] template = string.Template(open(filename).read()) spoolFile = tempfile.TemporaryFile() spoolFile.write(template.safe_substitute(self.variables)) # rewind spoolFile.seek(0) f = utils.BlankCommentFile(spoolFile) rows = [shlex.split(line) for line in f] i = 0 for r in rows: i += 1 if (r[0], r[1]) == ('LUMI', '='): # set the luminosity if not already set by cmd line if self.luminosity == 0: self.setLuminosity(float(r[2])) continue elif (r[0], r[1]) == ('PATH', '='): # set if not already defined in cmd line if self.baseDir == '': self.baseDir = r[2] continue e = sampleEntry() e.path = r[0] type = r[1] e.sum = r[2] e.xSec = float(r[3]) e.sFact = float(r[4]) e.fillColor = eval(r[5]) e.lineColor = eval(r[6]) e.lineWidth = int(r[7]) e.legend = r[8] e.order = i if type == 'data': self.dataSamples.append(e) elif type == 'mc': self.mcSamples.append(e) elif type == 'sum': self.virSamples.append(e) else: raise NameError('Sample type ' + type + ' what?')
def _fillvecs(self, collection): # init the vectors vecs = { 'color': ROOT.vector('int')(), # 'syst' : ROOT.vector('double')(), 'scale': ROOT.vector('double')(), 'label': ROOT.vector('std::string')(), 'norm': ROOT.vector('double')(), 'th1': ROOT.vector('TH1*')(), } # order takes precedence if self._order: iproc = self._order elif self._autosort: iproc = self._properties.iterkeys() else: iproc = collection.iterkeys() # and fill them for name in iproc: try: (h, props) = collection[name] except KeyError: # some of the processes might not be there continue # dummy = self._properties[name].copy() dummy.update(props) sentry = utils.TH1AddDirSentry() vecs['th1'].push_back(h.Clone()) vecs['label'].push_back(dummy.get('label', h.GetTitle())) vecs['color'].push_back(dummy.get('color', h.GetFillColor())) vecs['scale'].push_back(dummy.get('scale', 1.)) # negative normalisation is not applied vecs['norm'].push_back(dummy.get('norm', -1.)) return vecs
def load(self): template = string.Template(open(self.filename).read()) spoolFile = tempfile.TemporaryFile() spoolFile.write(template.safe_substitute(self.variables)) # rewind spoolFile.seek(0) f = utils.BlankCommentFile(spoolFile) rows = [shlex.split(line) for line in f] self.metaPlots = {} for r in rows: d = plotEntry() d.name = r[0] d.logX = int(r[1]) d.logY = int(r[2]) d.rebin = int(r[3]) d.title = r[4] d.xtitle = r[5] d.ytitle = r[6] self.metaPlots[d.name] = d
def match(self, rootfile): finder = utils.ObjFinder('TH1') paths = set(finder.find(rootfile)) notFound = [] self.plots = {} for name, metaPlot in self.metaPlots.iteritems(): # print name matches = fnmatch.filter(paths, name) if len(matches) == 0: notFound.append(name) for m in matches: p = copy.copy(metaPlot) p.name = m self.plots[m] = p # print '\n'.join(self.plots.iterkeys()) if len(notFound): raise RuntimeError('Histograms not found! ' + ','.join(notFound)) return self.plots
def getHistograms(self, samples, name, prefix): ## plot = self.plots[name] ## if ( plot is None ): ## raise NameValue('Plot '+name+' not found'); sentry = utils.TH1AddDirSentry() histograms = [] for s in samples: h = s.file.Get(name) if not h.__nonzero__(): raise NameError('histogram ' + name + ' not found in ' + s.path) hClone = h.Clone(prefix + '_' + name) hClone.UseCurrentStyle() hClone.SetFillColor(s.fillColor) hClone.SetLineColor(s.lineColor) hClone.SetLineWidth(s.lineWidth) histograms.append((hClone, s)) return histograms
def sum(self, histograms): #, samples): sentry = utils.TH1AddDirSentry() summed = [] sumList = {} # make a map and remove the histograms not to sum for (h, s) in histograms: if s.sum == 'no': summed.append((h, s)) continue if not s.sum in sumList: sumList[s.sum] = [h] else: sumList[s.sum].append(h) virKeys = [sample.path for sample in self.virSamples] for name, hists in sumList.iteritems(): if not name in virKeys: raise ValueError('Virtual sample ' + name + ' not defined') i = virKeys.index(name) vs = self.virSamples[i] h0 = hists[0].Clone(name) h0.Reset() for h in hists: h0.Add(h) h0.SetFillColor(vs.fillColor) h0.SetLineColor(vs.lineColor) h0.SetLineWidth(vs.lineWidth) summed.append((h0, vs)) # re-sort the array on the file's order sumsorted = sorted(summed, key=lambda pair: pair[1].order) # return histograms; return sumsorted
def plot(self, options=''): style = self._style left = style.left right = style.right top = style.top bottom = style.bottom gap = style.gap width = style.width heightf0 = style.heightf0 heightf1 = style.heightf1 linewidth = style.linewidth markersize = style.markersize textsize = style.textsize legmargin = style.legmargin titley = style.titley axsty = style.axsty # pads size pw = width+left+right ph = heightf0+top+bottom ph0 = heightf0+top+gap ph1 = heightf1+gap+bottom xaxsty = axsty.copy() xaxsty['labelsize'] = 0 yaxsty = axsty.copy() yaxsty['ndivisions'] = 505 c = Canvas() if style.plotratio: self._pad0 = c[0,0] = Pad('p0',pw,ph0,margins=(left,right, top, gap), xaxis=xaxsty, yaxis=axsty) self._pad1 = c[0,1] = Pad('p0',pw,ph1,margins=(left,right, gap, bottom), xaxis=axsty, yaxis=yaxsty) else: self._pad0 = c[0,0] = Pad('p0',pw,ph ,margins=(left,right, top, bottom), xaxis=axsty, yaxis=axsty) c.makecanvas() self._canvas = c # --- # main plot self._pad0.cd() self._pad0.SetLogx(style.logx) self._pad0.SetLogy(style.logy) hists = [self._h0] + self._hists ndim = hists[0].GetDimension() map(lambda h: ROOT.TH1.SetLineWidth(h,linewidth),hists) # border between frame and legend ha,va = style.legalign x0 = (left+legmargin) if ha == 'l' else (left+width -legmargin) y0 = (top +legmargin) if va == 't' else (top +heightf0-legmargin) leg = Legend(1,len(hists),style.legboxsize,anchor=(x0,y0), style={'textsize':self.legtextsize}, align=style.legalign) # ROOT marker size 1 = 8px. Convert pixel to root size markersize /= 8. from itertools import izip for h,col,mrk,fll in izip(hists,style.colors,style.markers,style.fills): h.SetFillStyle (fll) h.SetFillColor (col) h.SetLineColor (col) h.SetMarkerColor(col) h.SetMarkerStyle(mrk) h.SetMarkerSize (markersize) leg.addentry( h, 'pl') stack = ROOT.THStack('overlap','') map(stack.Add,hists) stack.Draw('nostack %s' % options) stack.GetXaxis().SetTitle(self._h0.GetXaxis().GetTitle()) stack.GetXaxis().SetMoreLogLabels(style.morelogx) stack.GetYaxis().SetTitle(self._h0.GetYaxis().GetTitle()) stack.GetYaxis().SetMoreLogLabels(style.morelogy) # if style.userrangex != (0.,0.): self._setrangeuser( stack.GetXaxis(), style ) if style.userrangex != (0.,0.): stack.GetXaxis().SetRangeUser(*(style.userrangex) ) if style.yrange != (0.,0.): ymin,ymax = style.yrange else: yminstored = stack.GetHistogram().GetMinimumStored() ymaxstored = stack.GetHistogram().GetMaximumStored() ymin = stack.GetMinimum('nostack '+options) if yminstored == -1111 else yminstored ymax = stack.GetMaximum('nostack '+options) if ymaxstored == -1111 else ymaxstored stack.SetMinimum( style.scalemin*ymin) stack.SetMaximum( style.scalemax*ymax) #if style.yrange != (0.,0.): #stack.SetMinimum( style.scalemin*style.yrange[0] ) #stack.SetMaximum( style.scalemin*style.yrange[1] ) #else: #if style.scalemax != 1: stack.SetMaximum(style.scalemax*stack.GetMaximum('nostack '+options)) #if style.scalemin != 1: stack.SetMaximum(style.scalemin*stack.GetMinimum('nostack '+options)) self._stack = stack leg.draw() self._legend = leg #title left self._ltitleobj = Latex(style.ltitle, anchor=(left,titley), align=('l','b'), style={'textsize':textsize} ) self._ltitleobj.draw() #rtitle self._rtitleobj = Latex(style.rtitle, anchor=(pw-right,titley), align=('r','b'), style={'textsize':textsize} ) self._rtitleobj.draw() if style.plotratio: # kill the xtitle of the upper plot self._stack.GetXaxis().SetTitle('') # --- # ratio plot self._pad1.cd() self._pad1.SetLogx(style.logx) h0 = self._h0 nbins = h0.GetNbinsX() xax = h0.GetXaxis() sentry = utils.TH1AddDirSentry() # create the h0 to hx rato hratios = [] colors = [style.errcol] + (style.colors[1:] if len(self._hists) > 1 else [ROOT.kBlack] ) markers = [ROOT.kFullCircle] + (style.markers[1:] if len(self._hists) > 1 else [ROOT.kFullCircle]) allh = [self._h0]+self._hists for hx,col,mrk in izip(allh,colors,markers): hr = hx.Clone('ratio_%s_%s' % (hx.GetName(),h.GetName()) ) # divide by hand to preserve the errors for k in xrange(nbins+2): br,er = hr.GetBinContent(k),hr.GetBinError(k) b0 = h0.GetBinContent(k) if b0 == 0: # empty h0 bin br = 0 er = 0 else: br /= b0 er /= b0 hr.SetBinContent(k,br) hr.SetBinError(k,er) hr.SetLineWidth (linewidth) hr.SetMarkerSize (markersize) hr.SetMarkerStyle (mrk) hr.SetLineColor (col) hr.SetMarkerColor (col) hratios.append(hr) dstack = ROOT.THStack('ratios','ratios') ROOT.SetOwnership(dstack,True) # and then the ratios herr = hratios[0] herr.SetNameTitle('err0','zero errors') herr.SetMarkerSize(0) herr.SetMarkerColor(style.errcol) herr.SetFillStyle(0) herr.SetFillColor(style.errcol) herr.SetLineColor(style.errcol) # error borders herrUp = herr.Clone('errup') herrDw = herr.Clone('errdw') herrUp.Reset() herrDw.Reset() for k in xrange(nbins+2): b,e = herr.GetBinContent(k),herr.GetBinError(k) herrUp.SetAt( 1+e, k) herrDw.SetAt( 1-e, k) herr.SetFillStyle(style.errsty) # build the stack dstack.Add(herr,'E2') dstack.Add(herrUp,'hist') dstack.Add(herrDw,'hist') map(dstack.Add,hratios[1:]) dstack.Draw('nostack %s' % options ) dstack.SetMinimum(0.) dstack.SetMaximum(2.) ax = dstack.GetXaxis() ay = dstack.GetYaxis() ax.SetTitle(h0.GetXaxis().GetTitle()) ax.SetMoreLogLabels(style.morelogx) ay.SetTitle(style.ytitle2) self._dstack = dstack line = ROOT.TGraph(2) line.SetNameTitle('oneline','oneline') line.SetPoint(0,ax.GetXmin(),1) line.SetPoint(1,ax.GetXmax(),1) line.SetBit(ROOT.kCanDelete) ROOT.SetOwnership(line,False) line.Draw() # if style.userrangex != (0.,0.): self._setrangeuser( ax, style ) if style.userrangex != (0.,0.): ax.SetRangeUser(*(style.userrangex) ) c.applystyle() return c
def makeDataMCPlot(self, name): # save the old dir oldDir = ROOT.gDirectory #and go to the new one path = os.path.dirname(name) self.getTDir(path).cd() # but don't write the plots sentry = utils.TH1AddDirSentry() pl = self.plots[name] data = self.getDataHistograms(name) mc = self.getMCHistograms(name) self.normalize(mc) #, self.mcSamples) mc = self.sum(mc) #,self.mcSamples) data = self.sum(data) # print data (data0, sample0) = data[0] baseName = os.path.basename(name) stack = ROOT.THStack('mcstack_' + baseName, data0.GetTitle()) if pl.rebin != 1: data0.Rebin(pl.rebin) # find the minima, move the following in a separate function mcMinima = [] for (h, s) in mc: if pl.rebin != 1: h.Rebin(pl.rebin) mcMinima.append(h.GetMinimum()) # print h.GetName(),mcMinima[-1],mcMinimaNonZero[-1] stack.Add(h, 'hist') # find the absolute minimum minima = [h.GetMinimum() for h in stack.GetStack()] minima.append(data0.GetMinimum()) # find the minimaNonZero = [h.GetMinimum(0) for h in stack.GetStack()] minimaNonZero.append(data0.GetMinimum(0)) # minYMc = min(mcMinima) maxY = ROOT.TMath.Max(data0.GetMaximum(), stack.GetMaximum()) minY = ROOT.TMath.Min(data0.GetMinimum(), min(mcMinima)) # minY = ROOT.TMath.Min(data0.GetMinimum(),stack.GetStack().First().GetMinimum()) cName = 'c_' + baseName c = ROOT.TCanvas(cName, cName, 2) # print c.GetWw(),c.GetWh() c.SetTicks() # c.Size(30,30) # print '- logx =', pl.logX, ': logy =',pl.logY if pl.logX is 1: c.SetLogx() if pl.logY is 1 and not (maxY == minY == 0): c.SetLogy() if minY == 0.: minY = min(minimaNonZero) # don't allow the min to go below 0.1 data min minY = max([minY, 0.1 * data0.GetMinimum(0)]) # maxY *= ROOT.TMath.Power(maxY/minY,0.1) # minY /= ROOT.TMath.Power(maxY/minY,0.1) # else: # maxY += (maxY-minY)*0.1 # minY -= (maxY-minY)*0.1 if minY != 0. else 0;#-1111. # print 'minmax',minY, maxY maxY += (maxY - minY) * 0.1 # minY -= (maxY-minY)*0.1 if minY != 0. else 0 minX = data0.GetXaxis().GetXmin() maxX = data0.GetXaxis().GetXmax() # frame = c.DrawFrame(minX, minY, maxX, maxY) frame = data0.Clone('frame') frame.SetFillStyle(0) frame.SetLineColor(ROOT.gStyle.GetFrameFillColor()) frame.Reset() frame.SetBinContent(1, maxY) frame.SetBinContent(frame.GetNbinsX(), minY) # frame.SetMaximum(maxY) # frame.SetMinimum(minY) # frame.GetYaxis().SetLimits(minY,maxY) frame.SetBit(ROOT.TH1.kNoStats) frame.SetTitle(pl.title if pl.title != 'self' else data0.GetTitle()) frame.SetXTitle( pl.xtitle if pl.xtitle != 'self' else data0.GetXaxis().GetTitle()) frame.SetYTitle( pl.ytitle if pl.ytitle != 'self' else data0.GetYaxis().GetTitle()) frame.Draw() # frame.GetPainter().PaintTitle() for d, s in data: d.SetFillColor(1) d.SetMarkerColor(1) d.SetMarkerStyle(20) d.SetMarkerSize(0.7) stack.Draw('same') for d, s in data: d.Draw('e1 same') title = self.makeTitle(frame.GetTitle()) title.Draw() legend = self.makeLegend(data, mc) legend.Draw() txt = self.makeCMSText() txt.Draw() c.Write() oldDir.cd()
def makeEfficiencyTable(self, name): print name # save the old dir oldDir = ROOT.gDirectory #and go to the new one path = os.path.dirname(name) # but don't write the plots sentry = utils.TH1AddDirSentry() data = self.getDataHistograms(name) mc = self.getMCHistograms(name) self.normalize(mc) #, self.mcSamples) mc = self.sum(mc) #,self.mcSamples) data = self.sum(data) (data0, sample0) = data[0] nbins = data0.GetNbinsX() print data0.GetBinContent(data0.GetNbinsX()) ## for (h,s) in mc: ## print s.legend,h.GetBinContent(h.GetNbinsX()) tableValue = odict.OrderedDict() efficiency = odict.OrderedDict() tableEntry = odict.OrderedDict() print '________________________________________________________________________________________________________________________________________________________________________________________________' print '| cut:'.ljust(18), sample0.legend.ljust(18), '|'.join( s.legend.ljust(18) for (h, s) in mc) print '________________________________________________________________________________________________________________________________________________________________________________________________' for i in range(nbins): j = i + 1 axis = data0.GetXaxis() cut = axis.GetBinLabel(j) tableValue[cut] = odict.OrderedDict() efficiency[cut] = odict.OrderedDict() tableEntry[cut] = odict.OrderedDict() tableEntry[cut]['cut'] = cut preEntry = data0.GetBinContent(i) entry = data0.GetBinContent(j) tableValue[cut][sample0.path] = str('%.1f' % (entry)) if (preEntry == 0): efficiency[cut][sample0.path] = str(0.0) else: efficiency[cut][sample0.path] = str('%.1f' % (100 * (entry / preEntry))) tableEntry[cut][sample0.path] = tableValue[cut][ sample0.path] + ' (' + efficiency[cut][sample0.path] + '\%)' # get the MC for (h, s) in mc: preEntry = h.GetBinContent(i) entry = h.GetBinContent(j) tableValue[cut][s.path] = str('%.1f' % (entry)) if (preEntry == 0): efficiency[cut][s.path] = str(0.0) else: efficiency[cut][s.path] = str('%.1f' % (100 * (entry / preEntry))) tableEntry[cut][s.path] = tableValue[cut][ s.path] + ' (' + efficiency[cut][s.path] + '\%)' ## print cut.ljust(10),'|',tableValue[cut][sample0.path].ljust(10),'|',' | '.join( [ tableValue[cut][s.path].ljust(10) for (h,s) in mc]) print '|' + cut.ljust(18), '|', tableEntry[cut][ sample0.path].ljust(18).replace('\%', '%'), '|', ' | '.join([ tableEntry[cut][s.path].ljust(18).replace('\%', '%') for (h, s) in mc ]) + '|' ## print cut.ljust(20),efficiency[cut][sample0.path].ljust(20),' | '.join( [ efficiency[cut][s.path] for (h,s) in mc]) print '________________________________________________________________________________________________________________________________________________________________________________________________' print r'\documentclass[a4paper]{article}' print r'\begin{document}' print r'\begin{tabular}{|' + 'c|' * (len(mc) + 2) + '}' print r'\hline' print ' & ', sample0.legend, ' & $', ' & $'.join( s.legend.replace('+-', ' $\\pm$ ').replace('%', '\%').replace( '#', '\\') + '$' for (h, s) in mc), r'\\' print r'\hline' for line in tableEntry.iterkeys(): print tableEntry[line]['cut'], ' & ', tableEntry[line][ sample0.path], ' & ', ' & '.join( [tableEntry[line][s.path] for (h, s) in mc]), r'\\' print r'\hline' print r'\end{tabular}' print r'\end{document}'
def draw(self, options='hist'): import ROOT if not ROOT.gPad.func(): raise RuntimeError('No active pad defined') thePad = ROOT.gPad.func() thePad.cd() self._pad0 = ROOT.TPad('pad0','pad0',0.,(1-self._ratio),1.,1.) ROOT.SetOwnership(self._pad0,False) self._pad0.SetLogx( 1 if self._logx else 0 ) self._pad0.SetLogy( 1 if self._logy else 0 ) self._pad0.SetTopMargin(self._outer/self._ratio) self._pad0.SetBottomMargin(self._inner/self._ratio) self._pad0.SetTicks() self._pad0.Draw() self._pad0.cd() hists = [self._h0] + self._hists ndim = hists[0].GetDimension() marker = 24 if ndim == 1 else 1 map(ROOT.TH1.SetLineWidth,hists, self._lwidths) # map(lambda h: ROOT.TH1.SetLineWidth(h,2),hists) map(lambda h: ROOT.TH1.SetMarkerStyle(h,marker),hists) for i,h in enumerate(hists): h.SetLineColor(self._colors[i]) h.SetMarkerColor(self._colors[i]) h.SetLineStyle(self._lstyles[i]) self._stack = None stack = ROOT.THStack('overlap','') ROOT.SetOwnership(stack,True) stack.Add(hists[0],'e1') for h in hists[1:]: stack.Add(h,'hist') stack.Draw('nostack') stack.SetMaximum(self._scale*max([h.GetMaximum() for h in hists])) stack.GetXaxis().SetLabelSize(0.00) stack.GetYaxis().SetTitle(self._ytitle if self._ytitle else self._h0.GetYaxis().GetTitle()) anchor = [1-self._marg,1-self._outer/self._ratio] anchor[1] -= 0.05 self._legend = None legend = ROOT.TLegend(anchor[0]-self._legsize[0],anchor[1]-self._legsize[1],anchor[0],anchor[1],'','NDC') legend.SetFillColor(ROOT.kWhite) legend.SetFillStyle(0) legend.SetBorderSize(0) # leg.SetNColumns(2) map(legend.AddEntry,hists,['Nominal','+1#sigma-shape','-1#sigma-shape'],['fl']*3) # for h in hists: legend.AddEntry(h,'','fl') legend.Draw() self._legend = legend l = ROOT.TLatex() l.SetNDC() l.SetTextAlign(12) l.DrawLatex(ROOT.gPad.GetLeftMargin(),1-(0.5*self._outer/self._ratio),self._ltitle) l.SetTextAlign(32) l.DrawLatex(1-ROOT.gPad.GetRightMargin(),1-(0.5*self._outer/self._ratio),self._rtitle) self._stack = stack l.SetTextAlign(22) anchorCMS = [0.25,0.09] l.SetTextSize(0.9*l.GetTextSize()) l.DrawLatex(ROOT.gPad.GetLeftMargin()+anchorCMS[0],1-ROOT.gPad.GetTopMargin()-anchorCMS[1],'CMS Preliminary') if self._lumi: anchorCMS = [0.25,0.15] l.SetTextSize(0.9*l.GetTextSize()) l.DrawLatex(ROOT.gPad.GetLeftMargin()+anchorCMS[0],1-ROOT.gPad.GetTopMargin()-anchorCMS[1],'L = %.1f fb^{-1}' % self._lumi) #- pad2 --- sentry = utils.TH1AddDirSentry() # print thePad thePad.cd() self._pad1 = ROOT.TPad('pad1','pad1',0.,0.0,1.,(1-self._ratio)) ROOT.SetOwnership(self._pad1,False) self._pad1.SetTopMargin(self._inner/(1-self._ratio)) self._pad1.SetBottomMargin(self._outer/(1-self._ratio)) self._pad1.SetTicks() self._pad1.SetGridy() self._pad1.Draw() self._pad1.cd() hdiffs = [] for i,h in enumerate(hists): hd = h.Clone('diff'+h.GetName()) hd.Divide(self._h0) hd.SetMarkerStyle(20) hd.SetLineWidth(self._lwidths[i]) # hd.SetLineColor(ROOT.kBlack) # hd.SetMarkerColor(ROOT.kBlack) hd.SetLineColor(self._colors[i]) hd.SetMarkerColor(self._colors[i]) hdiffs.append(hd) line = hdiffs[0] for i in xrange(line.GetNbinsX()+1): line.SetAt(1.,i) self._dstack = None dstack = ROOT.THStack('diffs','') ROOT.SetOwnership(dstack,False) map(dstack.Add,hdiffs,['hist']*len(hdiffs)) dstack.Draw('nostack') dstack.SetMaximum(2.) ax = dstack.GetXaxis() ay = dstack.GetYaxis() ax.SetTitle( self._xtitle if self._xtitle else self._h0.GetXaxis().GetTitle() ) ay.SetTitle(self._ytitle2) ay.SetTitleOffset(ay.GetTitleOffset()/self._ratio*(1-self._ratio) ) self._resize(ax,self._ratio) self._resize(ay,self._ratio) self._dstack = dstack