Пример #1
0
                    if obj.InheritsFrom("TH1") and signalMatch in name:

                        if name.split('_')[-2] == "group":

                            if "outliers" in name:
                                drawThisBin = True
                                name2D = 'W{ch}_{flav}_outliers'.format(
                                    ch=charge, flav=channel)
                                title2D = 'W{chs}: |#eta| > {etamax}#; p_{{T}} #notin [{ptmin:.0f},{ptmax:.0f})'.format(
                                    etamax=genBins.etaBins[-1],
                                    ptmin=genBins.ptBins[0],
                                    ptmax=genBins.ptBins[-1],
                                    chs=chs)
                            else:
                                etabinIndex, ptbinIndex = get_ieta_ipt_from_process_name(
                                    name)
                                if options.draw_all_bins: drawThisBin = True
                                elif options.draw_selected_etaPt != '':
                                    if etabinIndex != ieta_sel or ptbinIndex != ipt_sel:
                                        drawThisBin = False
                                    else:
                                        drawThisBin = True
                                else:
                                    drawThisBin = False
                                name2D = 'W{ch}_{flav}_ieta_{ieta}_ipt_{ipt}'.format(
                                    ch=charge,
                                    flav=channel,
                                    ieta=etabinIndex,
                                    ipt=ptbinIndex)
                                title2D = 'W{chs}: |#eta| #in [{etamin},{etamax})#; p_{{T}} #in [{ptmin:.0f},{ptmax:.0f})'.format(
                                    etamin=genBins.etaBins[etabinIndex],
Пример #2
0
                    pois_indices[impMat.GetXaxis().GetBinLabel(ib)] = ib

    nuisances = []
    nuisances_indices = []
    for ib in xrange(1, impMat.GetNbinsY() + 1):
        for n in nuis_regexps:
            if re.match(n, impMat.GetYaxis().GetBinLabel(ib)):
                nuisances.append(impMat.GetYaxis().GetBinLabel(ib))
                nuisances_indices.append(ib)

    mat = {}

    pois = sorted(pois,
                  key=lambda x: int(x.split('_')[-2]) if '_Ybin_' in x else 0)
    pois = sorted(pois,
                  key=lambda x: get_ieta_ipt_from_process_name(x)
                  if ('_ieta_' in x and '_ipt_' in x) else 0)
    # sort by charge if needed
    pois = sorted(pois,
                  key=lambda x: 0 if "plus" in x else 1 if "minus" in x else 2)

    for ipoi, poi in enumerate(pois):
        for inuis, nuis in enumerate(nuisances):
            mat[(poi, nuis)] = impMat.GetBinContent(pois_indices[poi],
                                                    nuisances_indices[inuis])

    ## sort the pois and nuisances alphabetically, except for pdfs, which are sorted by number
    if len(options.nuisgroups) == 0:
        ## for mu* QCD scales, distinguish among muR and muRXX with XX in 1-10
        nuisances = sorted(nuisances,
                           key=lambda x: int(x.replace('pdf', ''))
            th2_sub.GetZaxis().SetTitle("impact for {p} {units}".format(
                units='' if options.absolute else '(%)',
                p=poiName_target[options.target]))
            th2_sub.GetZaxis().SetTitleOffset(1.4)
            th2_sub.GetZaxis().SetTitleSize(0.05)
            th2_sub.GetZaxis().SetLabelSize(0.04)

            for p in pois:
                if charge != "allCharges" and not charge in p: continue
                if '_ieta_' in p and '_ipt_' in p:
                    if options.absolute:
                        val = mat[(p, nuisance[n])]
                    else:
                        val = 100 * mat[(p, nuisance[n])] / valuesAndErrors[p][
                            0] if valuesAndErrors[p][0] != 0 else 0.0
                    ieta, ipt = get_ieta_ipt_from_process_name(p)
                    th2_sub.SetBinContent(ieta + 1, ipt + 1, val)

            rmax = max(abs(th2_sub.GetMaximum()), abs(th2_sub.GetMinimum()))
            if not options.absolute: rmax = min(20., rmax)
            if options.absValue:
                th2_sub.GetZaxis().SetRangeUser(0, rmax)
            else:
                th2_sub.GetZaxis().SetRangeUser(-rmax, rmax)
            if options.zrange:
                if options.zrange == "template":
                    rmin = th2_sub.GetBinContent(th2_sub.GetMinimumBin())
                    rmax = th2_sub.GetBinContent(th2_sub.GetMaximumBin())
                else:
                    rmin, rmax = (float(x) for x in options.zrange.split(','))
                th2_sub.GetZaxis().SetRangeUser(rmin, rmax)
Пример #4
0
def niceName(name, genEtaPtBins="", forceLep="", drawRangeInLabel=False):

    if '_Ybin' in name:
        nn = '#mu: ' if '_mu_' in name else 'el: ' if '_el_' in name else 'l: '
        if 'plus' in name: nn += 'W+ '
        elif 'minus' in name: nn += 'W- '
        else: nn += 'W '
        if 'left' in name: nn += 'left '
        elif 'right' in name: nn += 'right '
        elif 'long' in name: nn += 'long '
        else: nn += 'unpolarized '
        idx = -2 if (name.endswith('mu') or any(
            [x in name
             for x in ['masked', 'sumxsec', 'charge', 'a0', 'a4']])) else -1
        nn += name.split('_')[idx]
        if 'eff_unc' in name:
            nn = '#epsilon_{unc}^{' + nn + '}'
        return nn

    elif '_ieta_' in name and '_ipt_' in name:
        nn = '#mu: ' if '_mu_' in name else 'el: ' if '_el_' in name else 'l:'
        nn += 'W+ ' if 'plus' in name else 'W- ' if 'minus' in name else 'W '
        ieta, ipt = get_ieta_ipt_from_process_name(name)
        nn += "i#eta, ip_{{T}} = {neta}, {npt} ".format(neta=ieta, npt=ipt)
        return nn

    elif '_ieta_' in name:

        # nn  = '#mu: ' if '_mu_' in name else 'el: ' if '_el_' in name else 'l:'
        # nn += 'W+ ' if 'plus' in name else 'W- ' if 'minus' in name else 'W '
        ieta = int((name.split("_ieta_")[1]).split("_")[0])
        # nn += "i#eta = {neta}".format(neta=ieta)
        nn = ""
        if drawRangeInLabel:
            etal, etah = 0.0, 0.0
            if genEtaPtBins:
                etal = genEtaPtBins.etaBins[ieta]
                etah = genEtaPtBins.etaBins[ieta + 1]
            wch = 'W+ ' if 'plus' in name else 'W- ' if 'minus' in name else 'W '
            lep = '#mu' if '_mu_' in name else 'el' if '_el_' in name else 'l'
            if forceLep:
                lep = '#mu' if forceLep == "mu" else 'e' if forceLep == "el" else 'l'
            nn = "{wch} |#eta^{{{lep}}}| #in [{etal:1.1f}, {etah:1.1f}]".format(
                wch=wch, lep=lep, etal=etal, etah=etah)
        else:
            nn = '#mu: ' if '_mu_' in name else 'el: ' if '_el_' in name else 'l:'
            nn += 'W+ ' if 'plus' in name else 'W- ' if 'minus' in name else 'W '
            nn += "i#eta = {neta}".format(neta=ieta)

        return nn

    elif '_ipt_' in name:
        # nn  = '#mu: ' if '_mu_' in name else 'el: ' if '_el_' in name else 'l:'
        # nn += 'W+ ' if 'plus' in name else 'W- ' if 'minus' in name else 'W '
        ipt = int((name.split("_ipt_")[1]).split("_")[0])
        # nn += "ip_{{T}} = {npt}".format(npt=ipt)
        nn = ""
        if drawRangeInLabel:
            ptl, pth = 0.0, 0.0
            if genEtaPtBins:
                ptl = genEtaPtBins.ptBins[ipt]
                pth = genEtaPtBins.ptBins[ipt + 1]
            wch = 'W+ ' if 'plus' in name else 'W- ' if 'minus' in name else 'W '
            lep = '#mu' if '_mu_' in name else 'el' if '_el_' in name else 'l'
            if forceLep:
                lep = '#mu' if forceLep == "mu" else 'e' if forceLep == "el" else 'l'
            nn = "{wch} p_{{T}}({lep}) #in [{ptl:3g}, {pth:3g}]".format(
                wch=wch, lep=lep, ptl=ptl, pth=pth)
        else:
            nn = '#mu: ' if '_mu_' in name else 'el: ' if '_el_' in name else 'l:'
            nn += 'W+ ' if 'plus' in name else 'W- ' if 'minus' in name else 'W '
            nn += "ip_{{T}} = {npt}".format(npt=ipt)
        return nn

    elif "CMS_" in name:
        # keep Wmu or We now that we do combination, they are different sources
        # if "CMS_Wmu" in name:
        #     return name.replace("CMS_Wmu_","")
        # elif "CMS_We" in name:
        #     return name.replace("CMS_We_","")
        #else:
        #    return name
        return name.replace("CMS_", "")

    elif re.match("Fakes(Eta|EtaCharge|PtNorm|PtSlope)Uncorrelated.*", name):
        num = re.findall(r'\d+', name)  # get number
        pfx = name.split(
            num[0])[1]  # split on number and read what's on the right
        leptonCharge = ""
        if len(pfx):
            leptonCharge = "{lep}{chs}".format(
                lep="#mu" if "mu" in pfx else "e",
                chs="+" if "plus" in pfx else "-" if "minus" in pfx else "")
        tmpvar = ""
        if "FakesEtaCharge" in name: tmpvar = "#eta-byCharge"
        elif "FakesEta" in name: tmpvar = "#eta"
        elif "FakesPtNorm" in name: tmpvar = "p_{T}-norm"
        elif "FakesPtSlope" in name: tmpvar = "p_{T}-slope"
        return "Fakes {var}-{n} {lepCh}".format(var=tmpvar,
                                                n=num[0],
                                                lepCh=leptonCharge)

    elif re.match(".*EffStat\d+.*", name):
        num = re.findall(
            r'\d+',
            name)  # get number (there will be two of them, need the second)
        pfx = name.split("EffStat" + str(num[1]))[
            1]  # split on second number and read what's on the right
        leptonCharge = ""
        if len(pfx):
            leptonCharge = "{lep}{chs}".format(
                lep="#mu" if "mu" in pfx else "e",
                chs="+" if "plus" in pfx else "-" if "minus" in pfx else "")
        return "Eff. uncorr. {n1}-{n2} {lepCh}".format(n1=num[0],
                                                       n2=num[1],
                                                       lepCh=leptonCharge)

    else:
        return name
Пример #5
0
                        reverse=False)
    elif any(re.match('FakesPtUncorrelated.*', x) for x in params):
        params = sorted(params,
                        key=lambda x: utilities.getNFromString(x),
                        reverse=False)
    elif any(re.match('.*EffStat.*', x) for x in params):
        params = sorted(params,
                        key=lambda x: utilities.getNFromString(x),
                        reverse=False)
    elif any('masked' in x or x.endswith('mu') for x in params):
        if any('_ieta_' in x for x in params):
            # differential xsection: get ieta, ipt index and use them as keys to sort
            params = sorted(
                params,
                key=lambda x: -1
                if "_ieta_" not in x else get_ieta_ipt_from_process_name(x),
                reverse=False)
        else:
            params = sorted(params,
                            key=lambda x: int(x.split('_')[-2])
                            if ('masked' in x or x.endswith('mu')) else -1,
                            reverse=False)

    nuis_p_i = 0
    title = "#theta"

    #hist_fit_s  = ROOT.TH1F("fit_s"   ,"S+B fit Nuisances   ;;%s "%title,len(params),0,len(params))
    hist_fit_s = ROOT.TH1F("fit_s", '', len(params), 0, len(params))
    pmin, pmax = -3., 3.
    hist_fit_1d = ROOT.TH1F("fit_1d ", '', 50, pmin, pmax)
    hist_fit_1d_e = ROOT.TH1F("fit_1d_e", '', 50, pmin, pmax)
def getXsecs_etaPt(processes, systs, etaPtBins, infile):  # in my case here, the histograms already have the cross section in pb, no need to divide by lumi

    #print "Inside getXsecs_etaPt"
    # etaPtBins is a list of 4 things: Netabins, etabins, Nptbins,ptbins

    histo_file = ROOT.TFile(infile, 'READ')
    hists = []

    for process in processes:

        etabins = etaPtBins[1]
        ptbins = etaPtBins[3]

        charge = "plus" if "plus" in process else "minus"
        # check if gen eta binning starts from negative value (probably we will stick to |eta|, but just in case)
        etavar = "absetal1" if (float(etabins[0]) >= 0.0) else "etal1" 
        cen_name = 'gen_ptl1_'+etavar+'_W'+charge+'_mu_central' 
        cen_hist = histo_file.Get(cen_name)  # this is a TH2
        useEleXsec = False
        if not cen_hist:
            cen_name = cen_name.replace("_mu_","_el_")
            cen_hist = histo_file.Get(cen_name)
            useEleXsec = True
        #print cen_name

        if not cen_hist:
            print "Error in getXsecs_etaPt(): histogram %s not found in file %s. Exit" % (cen_name, infile)
            quit()

        # before searching the bin, sum epsilon to the y value being inspected
        # Root assigns the lower bin edge to the bin, while the upper bin edge is assigned to the adjacent bin. However, depending on the number y being used,
        # there can be a precision issue which might induce the selection of the wrong bin (since yfirst and yvalue are actually bin boundaries)
        # It seems odd, but I noticed that with the fake rate graphs (I was getting events migrating between adjacent eta bins)
        epsilon = 0.00001

        # process has the form: Wplus_el_ieta_3_ipt_0_Wplus_el_group_0, where the number after group is not relevant (does not coincide with absolute bin number)
        # as it can be the same for many processes
        # one should use ieta and ipt, which identifies the template bin (first index is 0, not 1)
        # generally, ieta,ipt in name should correspond to 2D histogram X and Y bins (after adding 1)
        # However, one could use different definition for the gen level binning (used to cut and define a signal process) and the reco level one (defining the TH2)

        if "outliers" in process:
            # cross section for outliers = Integral(all) - integral(acceptance)
            totxsec = cen_hist.Integral(0, cen_hist.GetNbinsX()+1, 0, cen_hist.GetNbinsY()+1)
            ieta_low_acc = cen_hist.GetXaxis().FindFixBin(etabins[0]+epsilon)
            ieta_high_acc = cen_hist.GetXaxis().FindFixBin(etabins[-1]+epsilon) -1
            ipt_low_acc = cen_hist.GetYaxis().FindFixBin(ptbins[0]+epsilon)
            ipt_high_acc = cen_hist.GetYaxis().FindFixBin(ptbins[-1]+epsilon) -1
            xsecAccept = cen_hist.Integral(ieta_low_acc, ieta_high_acc, ipt_low_acc, ipt_high_acc)
            ncen = totxsec - xsecAccept 
        else:
            ieta,ipt = get_ieta_ipt_from_process_name(process)
            etafirst = etabins[ieta]
            etalast  = etabins[ieta+1]
            ptfirst = ptbins[ipt]
            ptlast  = ptbins[ipt+1]            
            # caution, we are using TH2, the logic below is slightly different than for TH1        
            istart_eta = cen_hist.GetXaxis().FindFixBin(etafirst + epsilon)
            iend_eta   = cen_hist.GetXaxis().FindFixBin(etalast + epsilon)
            istart_pt  = cen_hist.GetYaxis().FindFixBin(ptfirst + epsilon)
            iend_pt    = cen_hist.GetYaxis().FindFixBin(ptlast + epsilon)
            ncen = cen_hist.Integral(istart_eta, iend_eta-1, istart_pt,iend_pt-1)

        tmp_hist = ROOT.TH1F('x_'+process,'x_'+process, 1, 0., 1.)
        ## normalize back to cross section
        tmp_hist.SetBinContent(1, ncen)

        hists.append(copy.deepcopy(tmp_hist))

        for sys in systs:

            upn = sys+'Up' if not 'pdf' in sys else sys
            dnn = sys+'Dn' if not 'pdf' in sys else sys

            if useEleXsec:
                sys_upname = 'gen_ptl1_'+etavar+'_W'+charge+'_el_'+upn
                sys_dnname = 'gen_ptl1_'+etavar+'_W'+charge+'_el_'+dnn
            else:
                sys_upname = 'gen_ptl1_'+etavar+'_W'+charge+'_mu_'+upn
                sys_dnname = 'gen_ptl1_'+etavar+'_W'+charge+'_mu_'+dnn

            sys_up_hist = histo_file.Get(sys_upname)
            sys_dn_hist = histo_file.Get(sys_dnname)

            if not sys_up_hist:
                print "Error in getXsecs_etaPt(): histogram %s not found in file %s" % (sys_upname, infile)
                quit()
            if not sys_dn_hist:
                print "Error in getXsecs_etaPt(): histogram %s not found in file %s" % (sys_dnname, infile)
                quit()

            if "outliers" in process:
                totxsec = sys_up_hist.Integral(0, sys_up_hist.GetNbinsX()+1, 0, sys_up_hist.GetNbinsY()+1)
                xsecAccept = sys_up_hist.Integral(ieta_low_acc, ieta_high_acc, ipt_low_acc, ipt_high_acc)
                nup = totxsec - xsecAccept
                totxsec = sys_dn_hist.Integral(0, sys_dn_hist.GetNbinsX()+1, 0, sys_dn_hist.GetNbinsY()+1)
                xsecAccept = sys_dn_hist.Integral(ieta_low_acc, ieta_high_acc, ipt_low_acc, ipt_high_acc)
                ndn = totxsec - xsecAccept
            else:
                nup = sys_up_hist.Integral(istart_eta, iend_eta-1, istart_pt,iend_pt-1)
                ndn = sys_dn_hist.Integral(istart_eta, iend_eta-1, istart_pt,iend_pt-1)

            if 'pdf' in sys:
                ndn = 2.*ncen-nup ## or ncen/nup?

            tmp_hist_up = ROOT.TH1F('x_'+process+'_'+sys+'Up','x_'+process+'_'+sys+'Up', 1, 0., 1.)
            tmp_hist_up.SetBinContent(1, nup)
            tmp_hist_dn = ROOT.TH1F('x_'+process+'_'+sys+'Down','x_'+process+'_'+sys+'Dn', 1, 0., 1.)
            tmp_hist_dn.SetBinContent(1, ndn)
            hists.append(copy.deepcopy(tmp_hist_up))
            hists.append(copy.deepcopy(tmp_hist_dn))

    hist_data = ROOT.TH1F('x_data_obs', 'x_data_obs', 1, 0., 1.)
    hist_data.SetBinContent(1, 1.)
    hists.append(copy.deepcopy(hist_data))

    return hists
def plotPars(inputFile, pois=None, selectString='', maxPullsPerPlot=30, plotdir='./', suffix='', analysis='helicity', 
             excludeName=None, paramFamily=None,plotPull=False,
             channel='el', charge='plus',
             selection="",useMedian=False):
 
    

    chs = "+" if charge == "plus" else "-"

    isSignalStrength = False
        
    if paramFamily:
        if paramFamily == "pdf":
            pois="pdf.*"
            all_valuesAndErrors = utilities.getHistosFromToys(inputFile,getPull=plotPull,matchBranch=pois,excludeBranch=excludeName,
                                                              selection=selection,setStatOverflow=True,getMedian=useMedian)
        elif paramFamily == "scale":
            pois="" 
            for i in range(1,11):
                pois += "muR{n},muF{n},muRmuF{n},".format(n=str(i))
            if pois.endswith(','): pois = pois[:-1]
            all_valuesAndErrors = utilities.getHistosFromToys(inputFile,getPull=plotPull,matchBranch=pois,excludeBranch=excludeName,
                                                              selection=selection,setStatOverflow=True,getMedian=useMedian)
        elif paramFamily == "shapesyst":
            if channel == "el":
                pois = "alphaS,CMS_We_sig_lepeff,CMS_We_elescale,CMS_We_FRe_slope,CMS_We_FRe_continuous"
            else:
                pois = "alphaS,CMS_Wmu_sig_lepeff,CMS_Wmu_muscale,CMS_Wmu_FRmu_slope,CMS_Wmu_FR_continuous"
            all_valuesAndErrors = utilities.getHistosFromToys(inputFile,getPull=plotPull,matchBranch=pois,
                                                              excludeBranch=excludeName,selection=selection,setStatOverflow=True,getMedian=useMedian)
        elif paramFamily == "normsyst":
            if channel == "el":
                pois = "CMS_We_lepVeto,CMS_We_bkg_lepeff,CMS_VV,CMS_Top,CMS_W,CMS_DY,CMS_lumi_13TeV,CMS_We_flips,CMS_Wbkg"
            else:
                pois = "CMS_Wmu_lepVeto,CMS_Wmu_bkg_lepeff,CMS_VV,CMS_Top,CMS_W,CMS_DY,CMS_lumi_13TeV,CMS_Wbkg"
            all_valuesAndErrors = utilities.getHistosFromToys(inputFile,getPull=plotPull,matchBranch=pois,
                                                              excludeBranch=excludeName,selection=selection,setStatOverflow=True,getMedian=useMedian)
        elif paramFamily == "signalStrength":
            # add some exclusion matches if not already present
            if excludeName != None: excludeName += ",.*pmaskedexp.*" if "pmaskedexp" not in excludeName else ""
            else : excludeName = ".*pmaskedexp.*"
            pois="W{ch}.*_mu".format(ch=charge)
            isSignalStrength = True
            all_valuesAndErrors = utilities.getHistosFromToys(inputFile,200,0,2,getPull=plotPull,matchBranch=pois,
                                                              excludeBranch=excludeName,selection=selection,setStatOverflow=True,getMedian=useMedian)
        elif paramFamily == "absxsec":
            pois="W{ch}.*_pmaskedexp".format(ch=charge)
            if excludeName != None: excludeName += ",.*pmaskedexpnorm.*" if "pmaskedexpnorm" not in excludeName else ""
            else : excludeName = ".*pmaskedexpnorm.*"
            all_valuesAndErrors = utilities.getHistosFromToys(inputFile,1000,0,200,getPull=plotPull,matchBranch=pois,
                                                              excludeBranch=excludeName,selection=selection,setStatOverflow=True,getMedian=useMedian)
        elif paramFamily == "normxsec":
            pois="W{ch}.*_pmaskedexpnorm".format(ch=charge)
            all_valuesAndErrors = utilities.getHistosFromToys(inputFile,1000,0,1,getPull=plotPull,matchBranch=pois,
                                                              excludeBranch=excludeName,selection=selection,setStatOverflow=True,getMedian=useMedian)
    else:
        # warning: utilities.getHistosFromToys is working only for parameters centered around 0 (histogram is defined in -3,3)
        # this script will not work if using parameters with pmaskedexp
        if pois:
            if any (["pmaskedexp" in x for x in pois.split(",")]):
                print "Warning: current setup cannot work with parameters matching pmaskedexp: they are expected to be centered around 0. Exit"
                print "You might want to change behaviour of function utilities.getHistosFromToys to use those parameters as well" 
                exit(0)
        if any ([wc in poi for wc in ["Wplus","Wminus"] for poi in pois.split(",")]):
            all_valuesAndErrors = utilities.getHistosFromToys(inputFile,200,0,2,getPull=plotPull,matchBranch=pois,
                                                              excludeBranch=excludeName,selection=selection,setStatOverflow=True,getMedian=useMedian)
            if not any("pmaskedexp" in poi for poi in pois.split(",")):
                isSignalStrength = True
        else:
            all_valuesAndErrors = utilities.getHistosFromToys(inputFile,getPull=plotPull,matchBranch=pois,
                                                              excludeBranch=excludeName,selection=selection,setStatOverflow=True,getMedian=useMedian)
            

    print "From the list of parameters it seems that you are plotting results for channel ",channel
    print "pois = ", pois

    valuesAndErrors = {}

    excludedNames = excludeName.split(',') if excludeName else []

    if pois:
        poi_patts = pois.split(",")
        for ppatt in poi_patts:            
            for (k,v) in all_valuesAndErrors.iteritems():
                if any([re.match(x,k) for x in excludedNames]): continue
                if re.match(ppatt,k) and k not in valuesAndErrors: valuesAndErrors[k] = v
            #print valuesAndErrors.keys()

    params = valuesAndErrors.keys()
    print "----------------------------------"
    print "List of parameters:"
    print params
    print "----------------------------------"

    if any(re.match('pdf.*',x) for x in params):
        params = sorted(params, key = lambda x: int(x.split('pdf')[-1]), reverse=False)

    nPulls = 0
    pullLabelSize = 0.028
    pullSummaryMap = {}

    c = ROOT.TCanvas("c","",960,800)
    c.SetTickx(1)
    c.SetTicky(1)
    c.cd()
    c.SetLeftMargin(0.14)
    c.SetRightMargin(0.06)
    c.SetTopMargin(0.05)
    c.SetBottomMargin(0.2)
    c.cd()

    if isSignalStrength:
        chi2title = "#chi^{2} for signal strength parameters"
        chi2distr = ROOT.TH1D("chi2distr",chi2title,20,0.0,2.0)

    for name in params:

        print "Making pull for parameter ",name
        # look in utilities.py for getHistosFromToys(: if plotting pull, the histogram is defined as (x-x_gen)x_err,
        # while valuesAndErrors[name][0] and valuesAndErrors[name][1] are defined as mean and rms of original histogram from x
        # if option getPull of getHistosFromToys is False, then there is no difference
        mean_p, sigma_p = (valuesAndErrors[name][0],valuesAndErrors[name][1]-valuesAndErrors[name][0])
        #mean_p, sigma_p = (valuesAndErrors[name][3].GetMean(),valuesAndErrors[name][3].GetStdDev())

        histo = valuesAndErrors[name][3]
        if isSignalStrength and histo.GetStdDev() > 0.05:
            histo.Rebin(2)
        histo.Draw()
        histo.GetXaxis().SetTitle(histo.GetTitle());        
        histo.GetYaxis().SetTitle("number of toys (%d total)" % histo.Integral());         
        histo.SetTitle("")
        histo.GetYaxis().SetTitleOffset(1.05);     
        histo.GetXaxis().SetTitleOffset(0.9);        
        histo.GetYaxis().SetTitleSize(0.05);        
        histo.GetXaxis().SetTitleSize(0.05);        
        histo.GetXaxis().SetTitle(name)
     
        fitPull = histo.Integral()>0
        if fitPull:
            histo.Fit("gaus","Q")
            fit = histo.GetFunction("gaus")
            fit.SetLineColor(4)
            lat.DrawLatex(0.16, 0.8, 'mean:     {me:.3f}'.format(me=fit.GetParameter(1)))
            lat.DrawLatex(0.16, 0.7, 'err :     {er:.2f}'.format(er=fit.GetParameter(2)))
            lat.DrawLatex(0.16, 0.6, 'chi2/ndf: {cn:.2f}'.format(cn=fit.GetChisquare()/fit.GetNDF() if fit.GetNDF()>0 else 999))
            lat.DrawLatex(0.65, 0.8, 'mean:  {me:.3f}'.format(me=histo.GetMean()))
            lat.DrawLatex(0.65, 0.7, 'RMS :  {er:.2f}'.format(er=histo.GetStdDev()))
            if useMedian:
                lat.DrawLatex(0.65, 0.6, 'median:  {me:.3f}'.format(me=mean_p))  # in this case mean_p stores the median

            if isSignalStrength:
                if fit.GetParameter(2) < 0.1:
                    histo.GetXaxis().SetRangeUser(0.5,1.5)        
                if fit.GetParameter(2) < 0.05:
                    histo.GetXaxis().SetRangeUser(0.8,1.2)        
                if fit.GetNDF()>0:
                    chi2distr.Fill(fit.GetChisquare()/fit.GetNDF()) 

        os.system('cp /afs/cern.ch/user/g/gpetrucc/php/index.php '+plotdir)
        distrdir = plotdir+'/pulldistr'
        createPlotDirAndCopyPhp(distrdir)
        for ext in ['png', 'pdf']:
            c.SaveAs("{pdir}/{name}_postfit_{ch}_{channel}{suffix}.{ext}".format(pdir=distrdir,name=name,ch=charge,
                                                                                 suffix=("_"+suffix) if len(suffix) else "",
                                                                                 channel=channel,ext=ext))

        if fitPull:
            # tlatex = ROOT.TLatex(); tlatex.SetNDC(); 
            # tlatex.SetTextSize(0.11)
            # tlatex.SetTextColor(4);
            # tlatex.DrawLatex(0.65,0.80,"Mean    : %.3f #pm %.3f" % (histo.GetFunction("gaus").GetParameter(1),histo.GetFunction("gaus").GetParError(1)))
            # tlatex.DrawLatex(0.65,0.66,"Sigma   : %.3f #pm %.3f" % (histo.GetFunction("gaus").GetParameter(2),histo.GetFunction("gaus").GetParError(2)))
            
            # tlatex.SetTextSize(0.11);
            # tlatex.SetTextColor(1);
            # tlatex.DrawLatex(0.65,0.33,"Post-fit #pm #sigma_{#theta}: %.3f #pm %.3f" % (mean_P p), sigma_p))

            pullSummaryMap[name]=(histo.GetFunction("gaus").GetParameter(1),histo.GetFunction("gaus").GetParameter(2),
                                  histo.GetMean(),utilities.effSigma(histo))
            nPulls += 1
            
    if nPulls>0:
        
        if isSignalStrength:
            canvas_Chi2 = ROOT.TCanvas("canvas_Chi2","",700,700)
            canvas_Chi2.SetTickx(1)
            canvas_Chi2.SetTicky(1)
            chi2distr.Draw("Hist")
            chi2distr.GetXaxis().SetTitle("#chi^{2}")
            chi2distr.GetXaxis().SetTitleOffset(0.9)        
            chi2distr.GetXaxis().SetTitleSize(0.05)    
            chi2distr.GetYaxis().SetTitle("Events")
            chi2distr.GetYaxis().SetTitleOffset(1.05)     
            chi2distr.GetYaxis().SetTitleSize(0.05)       
            if chi2distr.GetEntries():
                overflow = 100. * chi2distr.GetBinContent(chi2distr.GetNbinsX() + 1) / chi2distr.GetEntries()  # use as XX %, multiplying by 100
            else:
                overflow = 0
            lat.DrawLatex(0.12, 0.8, 'W{ch} #rightarrow {lep}#nu'.format(ch=chs,lep="e" if channel == "el" else "#mu"))
            lat.DrawLatex(0.12, 0.7, 'mean:  {me:.3f}'.format(me=chi2distr.GetMean()))
            lat.DrawLatex(0.12, 0.6, 'RMS :  {er:.2f}'.format(er=chi2distr.GetStdDev()))
            lat.DrawLatex(0.12, 0.5, 'Overflow :  {of:.1f}%'.format(of=overflow))
            # following does not work, the stat box is disabled
            # chi2distr.SetStats(1)
            # canvas_Chi2.Update()
            # statBox = chi2distr.FindObject("stats")
            # if statBox:
            #     statBox.SetX1NDC(0.62)
            #     statBox.SetX2NDC(0.92)
            #     statBox.SetY1NDC(0.59)
            #     statBox.SetY2NDC(0.91)
            #     statBox.SetFillColor(0)
            #     statBox.SetFillStyle(0)
            #     statBox.SetBorderSize(0)
            #     statBox.Draw()
            # else:
            #     print "Warning: no stat box found for Chi^2" 
            for ext in ['png', 'pdf']:
                canvas_Chi2.SaveAs("{pdir}/chi2_{ch}_{channel}{suffix}.{ext}".format(pdir=distrdir,ch=charge,
                                                                                     suffix=("_"+suffix) if len(suffix) else "",
                                                                                     channel=channel,ext=ext))
        

        print "Generating Pull Summaries...\n"
        nRemainingPulls = nPulls
        hc = ROOT.TCanvas("hc","",3000,2000); 
        hc.SetTopMargin(0.05)
        hc.SetBottomMargin(0.2)
        hc.SetRightMargin(0.05)
        hc.SetGrid(0);
        pullPlots = 1;
        while nRemainingPulls > 0:
            nThisPulls = min(maxPullsPerPlot,nRemainingPulls)

            pull_rms      = ROOT.TH1F("pull_rms_{pp}".format(pp=str(pullPlots)) ,"", 3*nThisPulls+1,0,nThisPulls*3+1);
            pull_effsigma = ROOT.TH1F("pull_effsigma_{pp}".format(pp=str(pullPlots)) ,"", 3*nThisPulls+1,0,nThisPulls*3+1);
            pull_median   = ROOT.TH1F("pull_median_{pp}".format(pp=str(pullPlots)) ,"", 3*nThisPulls+1,0,nThisPulls*3+1);
            pi=1
            sortedpulls = []
            if 'pdf' in pois:
                sortedpulls = sorted(pullSummaryMap.keys(), key=lambda k: int(k.split('pdf')[-1]))
            # following condition should not happen (parameter is not centered around 0)
            #elif 'masked' in pois:
            #elif any([x in pois for x in ["Wplus","Wminus"]]) and not "masked" in pois:
            elif isSignalStrength or paramFamily == "absxsec" or paramFamily == "normxsec":
                keys = pullSummaryMap.keys()
                if analysis == "helicity":
                    keys_l = list(k for k in keys if 'left' in k)
                    keys_r = list(k for k in keys if 'right' in k)
                    norms_l = sorted(keys_l, key=lambda k: int(k.split('_')[-1]), reverse=False)
                    norms_r = sorted(keys_r, key=lambda k: int(k.split('_')[-1]), reverse=True)
                    sortedpulls = norms_r + norms_l
                else:
                    # differential xsection: get ieta, ipt index and use them as keys to sort
                    tmpkeys = [x for x in keys if "outliers" not in x]
                    sortedpulls = sorted(tmpkeys, key = lambda x: get_ieta_ipt_from_process_name(x))
                    for x in keys:
                        if "outliers" in x: sortedpulls.append(x) 
            else:
                sortedpulls = sorted(pullSummaryMap.keys(), key=lambda k: k[0])  # alphabetic order
            if len(sortedpulls)==0: break

            maxErr = 0;
            for name in sortedpulls:
                if pi>nThisPulls: break
                pull = pullSummaryMap[name]

                pull_rms.SetBinContent(3*pi+0,pull[0])
                pull_rms.SetBinError(3*pi+0,pull[1])

                pull_effsigma.SetBinContent(3*pi+1,pull[2])
                pull_effsigma.SetBinError(3*pi+1,pull[3])
                if useMedian:
                    pull_median.SetBinContent(3*pi+1,mean_p)  
                    pull_median.SetBinError(3*pi+1,0)

                newname = name
                # if isSignalStrength:
                #     newname = "_".join(name.split("_")[:6])
                # elif paramFamily == "absxsec":
                #     newname = "_".join(name.split("_")[:6]) + "_xsec"
                # elif paramFamily == "normxsec":
                #     newname = "_".join(name.split("_")[:6]) + "_xsecNorm"
                if isSignalStrength or paramFamily == "absxsec" or paramFamily == "normxsec":
                    newname = niceName(name)
                pull_rms.GetXaxis().SetBinLabel(3*pi,newname)
                pull_rms.GetXaxis().SetTickSize(0.)
                
                max2=max(pull[1],pull[3])
                if max2>maxErr: maxErr=max2
                del pullSummaryMap[name]
                pi += 1
                nRemainingPulls -= 1

            #pull_rms .SetMarkerColor(46); pull_rms .SetLineColor(45); pull_rms .SetLineWidth(2); pull_rms .SetMarkerSize(1.0); pull_rms .SetMarkerStyle(21); 
            #pull_effsigma .SetMarkerColor(21); pull_effsigma .SetLineColor(24); pull_effsigma .SetLineWidth(2); pull_effsigma .SetMarkerSize(1.0); pull_effsigma .SetMarkerStyle(22)

            # NmaxChar = 1
            # for name in sortedpulls:
            #     NmaxChar = max(NmaxChar,len(name))
            # if NmaxChar >= 8:
            #     hc.SetBottomMargin(0.2)  # hardcoded and not optimized I just looked at a random pull plot with the CMS_We_elescale and QCD scales parameters            

            pull_rms .SetMarkerColor(ROOT.kRed+2); 
            pull_rms .SetLineColor(ROOT.kRed); pull_rms .SetLineWidth(3); 
            pull_rms .SetMarkerSize(1.0);      pull_rms .SetMarkerStyle(21); 

            pull_effsigma .SetMarkerColor(ROOT.kBlack); 
            pull_effsigma .SetLineColor(ROOT.kGray+2);   pull_effsigma .SetLineWidth(3); 
            pull_effsigma .SetMarkerSize(1.0);           pull_effsigma .SetMarkerStyle(22)

            pull_median.SetMarkerColor(ROOT.kBlack); 
            pull_median.SetLineColor(ROOT.kBlack);    
            pull_median.SetLineWidth(3); 
            pull_median.SetMarkerSize(1.5);           
            pull_median.SetMarkerStyle(20)

            pull_rms.SetLabelSize(pullLabelSize)
            pull_rms.LabelsOption("v")
            yrange = 3. 
            if isSignalStrength and not plotPull:
                pull_rms.GetYaxis().SetRangeUser(0.9,1.1)
            else:
               pull_rms.GetYaxis().SetRangeUser(-yrange,yrange)
            if plotPull:
                pull_rms.GetYaxis().SetTitle("pull summary (n#sigma)")
            else:
                pull_rms.GetYaxis().SetTitle("POI summary")
            pull_rms.Draw("p")
            pull_effsigma.Draw("p same")

            line0 = ROOT.TLine(pull_rms.GetXaxis().GetXmin(), 0., pull_rms.GetXaxis().GetXmax(), 0.); line0.SetLineStyle(7)
            line0.Draw('same')

            leg = ROOT.TLegend(0.60, 0.75, 0.85, 0.95)
            leg.SetFillStyle(0)
            leg.SetBorderSize(0)
            leg.AddEntry(pull_rms,"Gaussian #sigma")
            leg.AddEntry(pull_effsigma,"Effective #sigma")
            leg.Draw("same")

            legMedian = ROOT.TLegend(0.15, 0.85, 0.4, 0.95)
            if useMedian:
                legMedian.SetFillStyle(0)
                legMedian.SetBorderSize(0)
                legMedian.AddEntry(pull_median,"Median","PL")
                legMedian.Draw("same")

            param_group=pois.replace('.*','').replace(',','_')
            for ext in ['png', 'pdf']:
                hc.SaveAs("{pdir}/pullSummaryToys_{params}_{igroup}_{ch}_{c}.{ext}".format(pdir=plotdir,ch=charge,suffix="_"+suffix,params=param_group,igroup=pullPlots,c=channel,ext=ext))
            pullPlots += 1
Пример #8
0
def niceName(name):

    if '_Ybin' in name:
        nn  = '#mu: ' if '_mu_' in name else 'el: '
        if 'plus' in name: nn += 'W+ '
        elif 'minus' in name: nn += 'W- '
        else: nn += 'W '
        if 'left' in name: nn += 'left '
        elif 'right' in name: nn += 'right '
        elif 'long' in name: nn += 'long '
        else: nn += 'unpolarized '
        idx = -2 if (name.endswith('mu') or any([x in name for x in ['masked','sumxsec','charge','a0','a4']])) else -1
        nn += name.split('_')[idx]
        if 'eff_unc' in name:
            nn = '#epsilon_{unc}^{'+nn+'}'
        return nn

    elif '_ieta_' and '_ipt_' in name:
        nn  = '#mu: ' if '_mu_' in name else 'el: '
        nn += 'W+ ' if 'plus' in name else 'W- ' if 'minus' in name else 'W '
        ieta,ipt = get_ieta_ipt_from_process_name(name)
        nn += "i#eta, ip_{{T}} = {neta}, {npt} ".format(neta=ieta,npt=ipt)
        return nn

    elif '_ieta_' in name:
        nn  = '#mu: ' if '_mu_' in name else 'el: '
        nn += 'W+ ' if 'plus' in name else 'W- ' if 'minus' in name else 'W '
        ieta = int((name.split("_ieta_")[1]).split("_")[0])
        nn += "i#eta = {neta}".format(neta=ieta)
        return nn

    elif '_ipt_' in name:
        nn  = '#mu: ' if '_mu_' in name else 'el: '
        nn += 'W+ ' if 'plus' in name else 'W- ' if 'minus' in name else 'W '
        ipt = int((name.split("_ipt_")[1]).split("_")[0])
        nn += "i#p_{{T}} = {npt}".format(npt=ipt)
        return nn

    elif "CMS_" in name:
        if "CMS_Wmu" in name:
            return name.replace("CMS_Wmu_","")
        elif "CMS_We" in name:
            return name.replace("CMS_We_","")
        else:
            return name
      
    elif re.match( "Fakes(Eta|Pt)Uncorrelated.*",name):
        num = re.findall(r'\d+', name) # get number
        pfx = name.split(num[0])[1]    # split on number and read what's on the right
        leptonCharge = ""
        if len(pfx):
            leptonCharge = "{lep}{chs}".format(lep="#mu" if "mu" in pfx else "e", chs = "+" if "plus" in pfx else "-" if "minus" in pfx else "")
        return "Fakes {var}-uncorr.{n} {lepCh}".format(var="#eta" if "FakesEta" in name else "p_{T}", n=num[0], lepCh=leptonCharge)

    elif re.match(".*EffStat\d+.*",name):
        num = re.findall(r'\d+', name) # get number (there will be two of them, need the second)
        pfx = name.split("EffStat"+str(num[1]))[1]    # split on second number and read what's on the right
        leptonCharge = ""
        if len(pfx):
            leptonCharge = "{lep}{chs}".format(lep="#mu" if "mu" in pfx else "e", chs = "+" if "plus" in pfx else "-" if "minus" in pfx else "")
        return "Eff. uncorr. {n1}-{n2} {lepCh}".format(n1=num[0],n2=num[1],lepCh=leptonCharge)


    else:  
        return name
Пример #9
0
    # to help sorting with helicity
    # if using more helicity and Y bins, sort by hel,Ybin
    helSorted = { "left" : 1, "right" : 2, "long" : 3}
    chargeSorted = { "Wplus" : 1, "Wminus" : 2}

    ## sort the floatParams. alphabetically, except for pdfs, which are sorted by number
    ## for mu* QCD scales, distinguish among muR and muRXX with XX in 1-10
    
    # why is this commented? Isn't it nice that different charge and polarizations are grouped together?
    # see old example here: 
    # http://mciprian.web.cern.ch/mciprian/wmass/13TeV/helicityAnalysis/electron/fromEmanuele/13-12-18/fitresults_poim1_exp1_bbb1/subMatrix/smallCorrelation_Wplusminus_leftrightYbin_2-5.png
    #params = sorted(params, key= lambda x: (int(chargeSorted[x.split('_')[0]]),int(helSorted[x.split('_')[1]]),int(x.split('_')[-1])) if '_Ybin_' in x else 0)
    # one might want to invert the order of charge and helicity for the sorting

    params = sorted(params, key= lambda x: utilities.getNFromString(x) if '_Ybin_' in x else 0)
    params = sorted(params, key= lambda x: get_ieta_ipt_from_process_name(x) if ('_ieta_' in x and '_ipt_' in x) else 0)
    params = sorted(params, key= lambda x: int(x.replace('pdf','')) if 'pdf' in x else 0)
    params = sorted(params, key= lambda x: int(x.replace('muRmuF','')) if ('muRmuF' in x and x != "muRmuF")  else 0)
    params = sorted(params, key= lambda x: int(x.replace('muR','')) if (''.join([j for j in x if not j.isdigit()]) == 'muR' and x != "muR") else 0)
    params = sorted(params, key= lambda x: int(x.replace('muF','')) if (''.join([j for j in x if not j.isdigit()]) == 'muF' and x != "muF") else 0)
    params = sorted(params, key= lambda x: utilities.getNFromString(x) if 'EffStat' in x else 0)            
    params = sorted(params, key= lambda x: utilities.getNFromString(x) if 'FakesEtaUncorrelated' in x else 0)            
    params = sorted(params, key= lambda x: utilities.getNFromString(x) if 'FakesPtUncorrelated' in x else 0)            

    # sort by charge if needed     
    # I think it is useful that different charges are separated in the matrix, it is easier to read it 
    params = sorted(params, key = lambda x: 0 if "plus" in x else 1 if "minus" in x else 2)
    print "sorted params = ", params

    c = ROOT.TCanvas("c","",1200,800)
    c.SetGridx()