def buildWeightedHisto(histos={}, fractions={}, histoName='', histoTitle='') :
    "was getFinalRate"
    hout = first(histos).Clone(histoName if histoName else 'final_rate') # should pick a better default
    hout.SetTitle(histoTitle)
    hout.Reset()
    flatFraction = type(first(fractions)) is float
    if flatFraction :
        print "averaging flat ",histoName
        print 'keys -> ',histos.keys()
        for b in getBinIndices(hout) :
            tot, err2 = binWeightedSum(histos, fractions, b)
            hout.SetBinContent(b, tot)
            hout.SetBinError(b, sqrt(err2))
    else :
        bH, bF = getBinning(first(histos)), getBinning(first(fractions))
        assert bH == bF,"different binning %s: %s, %s: %s"%(first(histos).GetName(), bH, first(fractions).GetName(), bF)
        weightedHistos = dict((p, h.Clone(h.GetName()+'_weighted_for_'+histoName)) for p,h in histos.iteritems()) # preserve originals
        print "averaging 2d ",histoName
        for b in getBinIndices(hout):
            print "bin %d (w=%.1f):  %.3f = %s"%(b,
                                                 sum(fractions[p].GetBinContent(b) for p in fractions.keys()),
                                                 sum(fractions[p].GetBinContent(b)*weightedHistos[p].GetBinContent(b) for p in fractions.keys()),
                                                 '+'.join("%.2f*%.2f"%(fractions[p].GetBinContent(b), weightedHistos[p].GetBinContent(b))
                                                          for p in fractions.keys()))
        for p,h in weightedHistos.iteritems() :
            h.Multiply(fractions[p])
            hout.Add(h)
    return hout
def buildWeightedHistoTwice(histosA={}, fractionsA={}, histosB={}, fractionsB={},
                            histoName='', histoTitle='') :
    "was getFinalRate"
    assert not set(histosA)-set(histosB),"different keys A[%s], B[%s]"%(str(histosA.keys()), str(histosB.keys()))
    assert type(first(fractionsA)) is type(first(fractionsB)),"etherogenous fractions A %s, B %s"%(type(first(fractionsA)), type(first(fractionsB)))
    hout = first(histosA).Clone(histoName if histoName else 'final_rate') # should pick a better default
    hout.SetTitle(histoTitle)
    hout.Reset()
    flatFraction = type(first(fractionsA)) is float
    if flatFraction :
        print "averaging flat ",histoName
        print 'keys -> ',histosA.keys()
        for b in getBinIndices(hout) :
            totA, errA2 = binWeightedSum(histosA, fractionsA, b)
            totB, errB2 = binWeightedSum(histosB, fractionsB, b)
            hout.SetBinContent(b, totA + totB)
            hout.SetBinError(b, sqrt(errA2 + errB2))
    else :
        bHA, bFA = getBinning(first(histosA)), getBinning(first(fractionsA))
        bHB, bFB = getBinning(first(histosB)), getBinning(first(fractionsB))
        assert bHA == bFA,"different binning %s: %s, %s: %s"%(first(histosA).GetName(), bHA, first(fractionsA).GetName(), bFA)
        assert bHB == bFB,"different binning %s: %s, %s: %s"%(first(histosB).GetName(), bHB, first(fractionsB).GetName(), bFB)
        assert bHA == bHB,"different binning %s: %s, %s: %s"%(first(histosA).GetName(), bHA, first(histosB).GetName(), bHB)
        weightedHistosA = dict((p, h.Clone(h.GetName()+'_weighted_for_'+histoName)) for p,h in histosA.iteritems()) # preserve originals
        weightedHistosB = dict((p, h.Clone(h.GetName()+'_weighted_for_'+histoName)) for p,h in histosB.iteritems())


        print "averaging 2d ",histoName
        for b in getBinIndices(hout):
            print "bin %d (w=%.1f):  %.3f = %s"%(b,
                                                 sum(fractionsA[p].GetBinContent(b)+fractionsB[p].GetBinContent(b) for p in fractionsA.keys()),
                                                 sum(fractionsA[p].GetBinContent(b)*weightedHistosA[p].GetBinContent(b)
                                                     +fractionsB[p].GetBinContent(b)*weightedHistosB[p].GetBinContent(b)
                                                     for p in fractionsA.keys()),
                                                 '+'.join(["%.2f*%.2f"%(fractionsA[p].GetBinContent(b),
                                                                        weightedHistosA[p].GetBinContent(b))
                                                           for p in fractionsA.keys()]+
                                                          ["%.2f*%.2f"%(fractionsB[p].GetBinContent(b),
                                                                        weightedHistosB[p].GetBinContent(b))
                                                           for p in fractionsB.keys()]))


        for p in weightedHistosA.keys() :
            hA, fA = weightedHistosA[p], fractionsA[p]
            hB, fB = weightedHistosB[p], fractionsB[p]
            hA.Multiply(fA)
            hB.Multiply(fB)
            hout.Add(hA)
            hout.Add(hB)
    return hout
def frac2str(frac) :
    flatFraction = type(first(frac)) is float
    return ('\n'.join([''.join("%12s"%s for s in fakeProcesses()),
                       ''.join("%12s"%("%.3f"%frac[s]) for s in fakeProcesses())])
            if flatFraction
            else '\n'.join([''.join("%12s"%s for s in fakeProcesses())]
                           +[''.join("%12s"%("%.3f"%frac[s].GetBinContent(b)) for s in fakeProcesses())
                             for b in getBinIndices(first(frac))]))
def normalizeHistos(histos) :
    "Normalize the input histos so that in each bin the sum of the different processes amounts to 1.0"
    basename = guessBaseHistoname([h.GetName() for h in histos.values() if h])
    tot = first(histos).Clone(basename+'_tot')
    tot.Reset()
    for h in histos.values() : tot.Add(h)
    for b in getBinIndices(tot) : tot.SetBinError(b, 0.0) # norm is a constraint, without error
    for h in histos.values() : h.Divide(tot)
def histo1dToTxt(h):
    "represent a TH1 as a string with name, bin edges, contents, and errors"
    bins = getBinIndices(h)
    hisName = h.GetName()
    binEdge = [h.GetBinLowEdge(b) for b in bins]
    binEdge.append(binEdge[-1] + h.GetBinWidth(bins[-1]))
    binCont = getBinContents(h)
    binErr = [be(h, b) for b in bins]

    def lf2s(l):
        return ", ".join(["%.3f" % e for e in l])

    return "\n".join(
        [
            "%s : %s" % (n, v)
            for n, v in [("hisName", hisName)] + [(l, lf2s(eval(l))) for l in ["binEdge", "binCont", "binErr"]]
        ]
    )