Beispiel #1
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
Beispiel #2
0
class H1RatioPlotter(object):

    class mystyle(object):
        def __init__(self):
            self._init_big()

        def _init_small(self):
            from ROOT import kRed,kOrange,kAzure
            from ROOT import kFullCircle, kOpenCircle

            self.scalemax  = 1.
            self.scalemin  = 1.
            self.ltitle    = ''
            self.rtitle    = ''
            self.ytitle2   = 'ratio'
            self.colors    = [kRed+1      , kOrange+7   , kAzure-6    , kAzure+9    , kOrange+7   , kOrange-2  ]
            self.markers   = [kFullCircle , kOpenCircle , kFullCircle , kOpenCircle , kFullCircle , kFullCircle]
            self.fills     = [0           , 0           , 0           , 0           , 0           , 0          ]
            self.plotratio = True

            # lenghts
            self.left        = 50
            self.right       = 35
            self.top         = 35
            self.bottom      = 50

            self.gap         = 5
            self.width       = 250
            self.heightf0    = 250
            self.heightf1    = 100

            self.linewidth   = 1
            self.markersize  = 5
            self.textsize    = 15
            self.titley      = 30

            self.legmargin   = 12
            self.legboxsize  = 25
            self.legtextsize = 15

            self.axsty = {
                'labelfamily' : 4,
                'labelsize'   : 15,
                'labeloffset' : 2,
                'titlefamily' : 4,
                'titlesize'   : 15,
                'titleoffset' : 35,
                'ticklength'  : 10,
                'ndivisions'  : 505,
            }

            self.errsty      = 3005
            self.errcol      = ROOT.kGray+1

            self.logx        = False
            self.logy        = False

            self.morelogx    = False
            self.morelogy    = False

            self.userrangex = (0.,0.)

            self.yrange = (0.,0.)

            # something more active
            self._legalign  = ('l','t')

        def _init_big(self):
            from ROOT import kRed,kOrange,kAzure
            from ROOT import kFullCircle, kOpenCircle

            self.scalemax  = 1.
            self.scalemin  = 1.
            self.ltitle    = ''
            self.rtitle    = ''
            self.ytitle2   = 'ratio'
            self.colors    = [kRed+1      , kOrange+7   , kAzure-6    , kAzure+9    , kOrange+7   , kOrange-2  ]
            self.markers   = [kFullCircle , kOpenCircle , kFullCircle , kOpenCircle , kFullCircle , kFullCircle]
            self.fills     = [0           , 0           , 0           , 0           , 0           , 0          ]
            self.plotratio = True

            # lenghts
            self.left        = 100
            self.right       = 75
            self.top         = 75
            self.bottom      = 100

            self.gap         = 5
            self.width       = 500
            self.heightf0    = 500
            self.heightf1    = 200

            self.linewidth   = 2
            self.markersize  = 10
            self.textsize    = 30
            self.titley      = 60

            self.legmargin   = 25
            self.legboxsize  = 50
            self.legtextsize = 30

            self.axsty = {
                'labelfamily' : 4,
                'labelsize'   : 30,
                'labeloffset' : 5,
                'titlefamily' : 4,
                'titlesize'   : 30,
                'titleoffset' : 75,
                'ticklength'  : 20,
                'ndivisions'  : 505,
            }

            self.errsty      = 3005
            self.errcol      = ROOT.kGray+1

            self.logx        = False
            self.logy        = False

            self.morelogx    = False
            self.morelogy    = False

            self.userrangex = (0.,0.)

            self.yrange = (0.,0.)

            # something more active
            self._legalign  = ('l','t')

        @property
        def legalign(self): return self._legalign

        @legalign.setter
        def legalign(self, align):
            ha,va = align
            if ha not in 'lr': raise ValueError('Align can only be \'l\' or \'r\'')
            if va not in 'tb': raise ValueError('Align can only be \'t\' or \'b\'')
            self._legalign = align

        def scale(self,factor):
            self.left        = int(factor*self.left)
            self.right       = int(factor*self.right)
            self.top         = int(factor*self.top)
            self.bottom      = int(factor*self.bottom)

            self.gap         = int(factor*self.gap)
            self.width       = int(factor*self.width)
            self.heightf0    = int(factor*self.heightf0)
            self.heightf1    = int(factor*self.heightf1)

            self.linewidth   = int(factor*self.linewidth)
            self.markersize  = int(factor*self.markersize)
            self.textsize    = int(factor*self.textsize)
            self.titley      = int(factor*self.titley)

            self.legmargin   = int(factor*self.legmargin)
            self.legboxsize  = int(factor*self.legboxsize)
            self.legtextsize = int(factor*self.legtextsize)



            self.axsty['labelsize'   ] = int(factor*self.axsty['labelsize'   ])
            self.axsty['labeloffset' ] = int(factor*self.axsty['labeloffset' ])
            self.axsty['titlesize'   ] = int(factor*self.axsty['titlesize'   ])
            self.axsty['titleoffset' ] = int(factor*self.axsty['titleoffset' ])
            self.axsty['ticklength'  ] = int(factor*self.axsty['ticklength'  ])


    def __init__(self, **kwargs):

        from ROOT import kRed,kOrange,kAzure
        from ROOT import kFullCircle, kOpenCircle

        self.__dict__['_style'] = self.mystyle()

        for k,v in kwargs.iteritems():
            if not hasattr(self._style,k): raise AttributeError('No '+k+' style attribute')
            setattr(self._style,k,v)

        self._h0     = None
        self._hists  = []
        self._canvas = None
        self._pad0   = None
        self._pad1   = None
        self._legend = None
        self._stack  = None
        self._dstack = None

    # ---
    def __getattr__(self,name):
        if hasattr(self,'_style'):
            return getattr(self._style,name)
        else:
            raise AttributeError('Attribute '+name+' not found')

    # ---
    def __setattr__(self,name,value):
        # if the name starts with '_' it is a data member
        if name[0] != '_' and hasattr(self,'_style') and hasattr(self._style,name):
#             print 'setting opt:',name,value
            return setattr(self._style,name,value)
        else:
            self.__dict__[name] = value

    #---
    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 ]

    #---
    @staticmethod
    def _setrangeuser( ax, urange ):
        lb  = ax.FindBin( urange[0] )
        ub  = ax.FindBin( urange[1] )
        print lb,ub
        ax.SetRange( lb,ub )

    #---
    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