Ejemplo n.º 1
0
    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
Ejemplo n.º 2
0
 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 ]
Ejemplo n.º 3
0
    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)
Ejemplo n.º 4
0
    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
Ejemplo n.º 5
0
    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
Ejemplo n.º 6
0
    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
Ejemplo n.º 7
0
    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
Ejemplo n.º 8
0
    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
Ejemplo n.º 9
0
    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()
Ejemplo n.º 10
0
    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}'
Ejemplo n.º 11
0
    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