def plotFractionsStacked(histos={}, canvasName='', outputDir='./', frameTitle='title;p_{T} [GeV]; fraction'):
    "plot stack of histos[source][group]"
    can = r.TCanvas(canvasName, '', 800, 600)
    can.cd()
    can.SetRightMargin(2.0*can.GetRightMargin())
    stack = r.THStack('stack_'+canvasName, '')
    leg = rightLegend(can)
    leg.SetBorderSize(0)
    colors = SampleUtils.colors
    sources = sorted(histos.keys())
    groups  = sorted(first(histos).keys())
    fillStyles = {'light':3365, 'heavy':3356, 'conv':3663}
    assert len(sources)<4,"can only plot up to three sources, %s"%str(sources)
    def setHistoAtts(histo, group, colors=colors, fillStyle=None) :
        h, g = histo, group
        h.SetMarkerSize(0)
        h.SetFillColor(colors[g])
        h.SetLineColor(h.GetFillColor())
        h.SetDrawOption('bar')
        if fillStyle : h.SetFillStyle(fillStyle)
    for s in sources:
        for g in groups:
            h = histos[s][g]
            setHistoAtts(h, g, fillStyle=fillStyles[s])
            stack.Add(h)
    for s in sources[::-1]: # stack goes b-t, legend goes t-b
        leg.AddEntry(r.TObject(), s, '')
        def niceLabel(group) : return 'bb/cc' if group=='heavyflavor' else group
        for g in groups[::-1] : leg.AddEntry(histos[s][g], niceLabel(g) , 'F')
    stack.Draw('hist')
    leg.Draw('same')
    tex = r.TLatex()
    tex.SetNDC(True)
    tex.DrawLatex(0.1, 0.9, 'fractions: '+frameTitle[:frameTitle.find(';')-1])
    can.Update() # force stack to create canMaster
    canMaster = stack.GetHistogram()
    canMaster.SetTitle(frameTitle)
    canMaster.Draw('axis same')
    can._graphical_objects = [stack, canMaster, leg, tex] + [h for h in stack.GetStack()]
    can.Update()
    for ext in ['png','eps'] :
        outFilename = outputDir+'/'+canvasName+'.'+ext
        rmIfExists(outFilename)
        can.SaveAs(outFilename)
def plotIsoComparison(histosPerSource={}, outputDir='', region='', lepton='', verbose=False):
    """
    plot a comparison of eff(T|L) for real and for fake leptons
    vs. pt, where the numerator is one of the tight definitions
    """
    var = 'pt'
    sources = histosPerSource.keys()
    lOrTOrTs = first(first(histosPerSource)).keys()
    histosPtPerSource = dict((s, dict((lt, histosPerSource[s][var][lt]) for lt in lOrTOrTs)) for s in sources)
    def buildTotFakeHistos():
        "add up all the non-real (fake) sources"
        notRealSources = [s for s in sources if s!='real']
        aSource = first(notRealSources)
        totFakeHistos = dict()
        for lt in ['loose', 'tight', 'tight_std', 'tight_minden', 'tight_tight']:
            template = histosPtPerSource[aSource][lt]
            h = template.Clone(template.GetName().replace(aSource, 'fake'))
            h.Reset()
            for s in sources : h.Add(histosPtPerSource[s][lt])
            totFakeHistos[lt] = h
        return totFakeHistos
    histosPtPerSource['fake'] = buildTotFakeHistos()
    effReal_wh     = rootUtils.buildRatioHistogram(histosPtPerSource['real']['tight'       ], histosPtPerSource['real']['loose'])
    effReal_std    = rootUtils.buildRatioHistogram(histosPtPerSource['real']['tight_std'   ], histosPtPerSource['real']['loose'])
    effReal_minden = rootUtils.buildRatioHistogram(histosPtPerSource['real']['tight_minden'], histosPtPerSource['real']['loose'])
    effReal_tight  = rootUtils.buildRatioHistogram(histosPtPerSource['real']['tight_tight' ], histosPtPerSource['real']['loose'])
    effFake_wh     = rootUtils.buildRatioHistogram(histosPtPerSource['fake']['tight'       ], histosPtPerSource['fake']['loose'])
    effFake_std    = rootUtils.buildRatioHistogram(histosPtPerSource['fake']['tight_std'   ], histosPtPerSource['fake']['loose'])
    effFake_minden = rootUtils.buildRatioHistogram(histosPtPerSource['fake']['tight_minden'], histosPtPerSource['fake']['loose'])
    effFake_tight  = rootUtils.buildRatioHistogram(histosPtPerSource['fake']['tight_tight' ], histosPtPerSource['fake']['loose'])
    frameName, frameTitle = region+'_'+lepton, "fake and real efficiencies for %s in %s"%(lepton, region)
    can = r.TCanvas('c_'+frameName, frameTitle, 800, 600)
    can.cd()
    pm = effReal_wh
    pm.SetMinimum(0.0)
    pm.SetMaximum(1.1)
    pm.GetYaxis().SetTitle("#epsilon(T|L)")
    colorReal, colorFake = r.kBlue, r.kRed
    markerWh, markerStd, markerMinden, markerTight = r.kMultiply, r.kCircle, r.kOpenTriangleUp, r.kOpenSquare
    def setAttrs(h, mark, col):
        h.SetLineColor(col)
        h.SetMarkerColor(col)
        h.SetMarkerStyle(mark)
    setAttrs(effReal_wh,     markerWh,     colorReal)
    setAttrs(effReal_std,    markerStd,    colorReal)
    setAttrs(effReal_minden, markerMinden, colorReal)
    setAttrs(effReal_tight,  markerTight,  colorReal)
    setAttrs(effFake_wh,     markerWh,     colorFake)
    setAttrs(effFake_std,    markerStd,    colorFake)
    setAttrs(effFake_minden, markerMinden, colorFake)
    setAttrs(effFake_tight,  markerTight,  colorFake)
    pm.SetStats(0)
    pm.Draw('axis')
    #for h in [effReal_wh, effReal_std, effReal_tight, effFake_wh, effFake_std, effFake_tight]:
    for h in [effReal_wh, effReal_std, effReal_minden, effFake_wh, effFake_std, effFake_minden]:
        h.Draw('same')
    leg = rightLegend(can)
    leg.SetBorderSize(0)
    leg.AddEntry(r.TObject(),   'Real', '')
    leg.AddEntry(effReal_std,   'std iso', 'lp')
    #leg.AddEntry(effReal_tight, 'tight iso', 'lp')
    leg.AddEntry(effReal_minden,'minden iso', 'lp')
    leg.AddEntry(effReal_wh,    'wh iso',  'lp')
    leg.AddEntry(r.TObject(),   'Fake', '')
    leg.AddEntry(effFake_std,   'std iso', 'lp')
    #leg.AddEntry(effFake_tight, 'tight iso', 'lp')
    leg.AddEntry(effFake_minden,'minden iso', 'lp')
    leg.AddEntry(effFake_wh,  '  wh iso',  'lp')
    leg.Draw()
    topRightLabel(can, "#splitline{%s}{%s}"%(lepton, region), xpos=0.125, align=13)
    can.RedrawAxis()
    can._histos = [effReal_wh, effReal_std, effFake_wh, effFake_std]
    can.Update()
    mkdirIfNeeded(outputDir)
    can.SaveAs(os.path.join(outputDir, frameTitle+'.png'))