def test_stack(): stack = HistStack() assert_equal(len(stack), 0) stack.Add(Hist(10, 0, 1, fillstyle='solid', color='red')) stack.Add(Hist(10, 0, 1, fillstyle='solid', color='blue')) stack.Add(Hist(10, 0, 1, fillstyle='solid', color='green')) assert_equal(len(stack), 3) stack2 = stack.Clone() assert_equal(stack2[2].linecolor, 'green') # test stacked=True a = Hist(2, 0, 1) b = Hist(2, 0, 1) a.Fill(0.2) b.Fill(0.2) b.Fill(0.8, 5) stack = HistStack([a, b]) assert_equal(stack.min(), 2) assert_equal(stack.max(), 5) # test stacked=False a = Hist(2, 0, 20) b = Hist(2, 10, 20) # binning may be different a.Fill(0.2) b.Fill(15, 5) stack = HistStack([a, b], stacked=False) assert_equal(stack.min(), 0) assert_equal(stack.max(), 5)
def test_stack(): stack = HistStack() stack.Add(Hist(10, 0, 1, fillstyle='solid', color='red')) stack.Add(Hist(10, 0, 1, fillstyle='solid', color='blue')) stack.Add(Hist(10, 0, 1, fillstyle='solid', color='green')) assert_equal(len(stack), 3) stack2 = stack.Clone() assert_equal(stack2[2].linecolor, 'green')
def make_control_region_data_mc_comparision( histograms, histogram_name, variable, x_label=r'$m(\mathrm{t}\bar{\mathrm{t}})$ [GeV]', x_min=300, x_max=1800, y_label='Events/50 GeV'): qcd = histograms['QCD'][histogram_name] ttjet = histograms['TTJet'][histogram_name] wjets = histograms['WJets'][histogram_name] zjets = histograms['ZJets'][histogram_name] single_top = histograms['SingleTop'][histogram_name] other = ttjet + wjets + zjets + single_top data = histograms['data'][histogram_name] data.SetMarkerSize(3) qcd.SetTitle('QCD from data') other.SetTitle('Combined other background') data.SetTitle('Data') qcd.fillcolor = 'yellow' other.fillcolor = 'red' qcd.fillstyle = 'solid' other.fillstyle = 'solid' stack = HistStack() stack.Add(other) stack.Add(qcd) # plot with matplotlib plt.figure(figsize=(16, 12), dpi=200, facecolor='white') axes = plt.axes() rplt.hist(stack, stacked=True, axes=axes) rplt.errorbar(data, xerr=None, emptybins=False, axes=axes) plt.xlabel(x_label, CMS.x_axis_title) plt.ylabel(y_label, CMS.y_axis_title) plt.tick_params(**CMS.axis_label_major) plt.tick_params(**CMS.axis_label_minor) plt.title(get_title(variable), CMS.title) plt.legend(numpoints=1, loc='upper right', prop=CMS.legend_properties) axes.set_xlim(xmin=x_min, xmax=x_max) axes.set_ylim(ymin=0) plt.tight_layout() plt.savefig(variable + '.png') plt.savefig(variable + '.pdf')
map(h3.Fill, x1_obs) map(h3.Fill, x2_obs) # set visual attributes h1.fillstyle = 'solid' h1.fillcolor = 'green' h1.linecolor = 'green' h1.linewidth = 0 h2.fillstyle = 'solid' h2.fillcolor = 'red' h2.linecolor = 'red' h2.linewidth = 0 stack = HistStack() stack.Add(h1) stack.Add(h2) ratio = h3 / (h1 + h2) ratio = Hist.divide(h3, h1 + h2) # plot with matplotlib plt.figure(figsize=(16, 12), dpi=200) gs = gridspec.GridSpec(2, 1, height_ratios=[5, 1]) axes = plt.axes() ax0 = plt.subplot(gs[0]) ax0.minorticks_on() rplt.bar(stack, stacked=True) rplt.errorbar(h3, xerr=False, emptybins=False) # plt.xlabel('Mass', position=(1., 0.), ha='right', fontsize = 24) plt.ylabel('Events', va='top', fontsize=40)
set_style('ATLAS') mus = (0, -1, 2) sigmas = (2, 1, 0.5) events = (1000, 2000, 100) colors = ('lawngreen', 'forestgreen', 'mistyrose') styles = ('\\', '/', '-') canvas = Canvas() objects = [] # create a stack stack = HistStack() stack.Add( Hist(100, -5, 5, color='salmon', drawstyle='hist').FillRandom(F1('TMath::Gaus(x, 2, 1)'), 500)) stack.Add( Hist(100, -5, 5, color='powderblue', drawstyle='hist').FillRandom(F1('TMath::Gaus(x, 2, 0.6)'), 300)) objects.append(stack) # create some random histograms for i, (mu, sigma, n, c, s) in enumerate(zip(mus, sigmas, events, colors, styles)): hist = Hist(100, -5, 5, color=c, fillstyle=s, drawstyle='hist' if i % 2 == 0 else '')
compressed = background.CompressedAnalysis print compressed histname = "hist" + rootfile histogram = histname + "(" + nbins + "," + xmin + "," + xmax + ")" histname = compressed.Draw(variable + ">>" + histogram, selection=weight * total, drawstyle='hist', fillstyle='solid', linecolor='black', fillcolor=color) print histname print background_name legend.AddEntry(histname, label=background_name, style='F') #was label=background_name stack.Add(histname) #=================== DATA SAMPLES ====================================# objects = [] dataobjects = [] for (datafilename, data_weight, data_bool) in zip(data_list, data_weight_list, data_bool_list): print datafilename, data_weight, data_bool if data_bool == "Plot": print "datafilename: ", datafilename data = root_open(data_location + "/" + datafilename) treesSR = data.CompressedAnalysis datacut = total if data_weight != "1": print "WARNING: DATA WEIGHT IS NOT 1 PLEASE CHECK IF YOU DO NOT INTEND TO WEIGHT THE DATA"
#SelectionCriteria = Cut(Luminosity) * Cut(Weight) * total #histogram = Hist(nbins,xmin,xmax) temphist = treeDict[sample].Draw(variable, hist= Hist(nbins,xmin,xmax),selection = Cut(Luminosity) * Cut(Weight) * total) temphist = temphist.merge_bins([(0,1), (nbins,nbins+1) ]) sampleStyleFunc(temphist,sample,sampleDictionary) backgroundstacks[LegendEntry].Add(temphist.Clone()) skimmed = 1 for key in backgroundstacks: #print "key: " + str(key ) if 'Data' not in key: if 'Signal' in key:continue stack.Add(backgroundstacks[key].sum.Clone()) if 'Data' in key and not BLINDED : datastack.Add(backgroundstacks[key].sum.Clone()) # print "type of stack.mergebins" + str(type(stack.merge_bins([(nbins,nbins+1)]))) if doBreakdown: cutflowstring, yieldstring = produceRegionBreakdown(backgroundstacks,stack,datastack,Region,CRlist,SRlist,VVCRlist,TOPCRlist,ABCDlist) print "[BREAKDOWN][PRODUCED]" print cutflowstring print yieldstring SetNegativeYieldsToZero(stack,nbins) print "[BEFORE DRAW]" + str(round(time.time() - t0,2)) + "seconds" drawBackgrounds(stack)
# else: # # hists[sample].markersize = 1.2 # pass outputROOTFile.cd() # print histsToStack[0].Integral() # print histsToStack sortedHistsToStack = sorted(histsToStack, key=lambda x: x.Integral(), reverse=False) # print sortedHistsToStack for tmphist in sortedHistsToStack: if tmphist.Integral(): stack.Add(tmphist) try: stack.sum.Integral() except: print "stack has no integral!" continue if plotWithMPL: gs = mpl.gridspec.GridSpec(2, 1, height_ratios=[4, 1]) gs.update(wspace=0.00, hspace=0.00) axes = plt.subplot(gs[0]) axes_ratio = plt.subplot(gs[1], sharex=axes) plt.setp(axes.get_xticklabels(), visible=False) if plotWithROOT:
def stack(x, *args, **kwargs): ## parse arguments _data = kwargs.pop('data', None) _bkgs = kwargs.pop('bkgs', None) _sigs = kwargs.pop('sigs', None) _treename = kwargs.pop('treename', None) _datasearchpath = kwargs.pop('datasearchpath', None) _datadrivensearchpath = kwargs.pop('datadrivensearchpath', None) _bkgsearchpath = kwargs.pop('bkgsearchpath', None) _sigsearchpath = kwargs.pop('sigsearchpath', None) _lumi = kwargs.pop('lumi', None) global data global bkgs global sigs global treename global datasearchpath global datadrivensearchpath global bkgsearchpath global sigsearchpath global lumi data = _data or data bkgs = _bkgs or bkgs sigs = _sigs or sigs treename = _treename or treename datasearchpath = _datasearchpath or datasearchpath datadrivensearchpath = _datadrivensearchpath or datadrivensearchpath bkgsearchpath = _bkgsearchpath or bkgsearchpath sigsearchpath = _sigsearchpath or sigsearchpath if _lumi: lumi = float(_lumi) xtitle = kwargs.pop('xtitle', '') ytitle = kwargs.pop('ytitle', '') logx = bool(kwargs.pop('logx', False)) logy = bool(kwargs.pop('logy', False)) blind = kwargs.pop('blind', None) has_blinded_data = False ## save stuff to bookkeep and return stuff = dict() stuff['x'] = x ## get data histogram h_data = None if data: sp = datasearchpath # HACK: just data to True! newx = '%s::%s::%s' % (sp, treename, x) h_data = ipyhep.tree.project(newx, *args, **kwargs) if h_data: stuff['h_data'] = h_data ## blind the data? if h_data and not blind is None: if isinstance(blind, tuple): blind1, blind2 = blind nbins = h_data.GetNbinsX() for i_bin in xrange(1, nbins + 2): # skip underflow (but not overflow) xval1 = h_data.GetXaxis().GetBinLowEdge(i_bin) xval2 = h_data.GetXaxis().GetBinUpEdge(i_bin) if xval1 >= blind1 and xval2 <= blind2: h_data.SetBinContent(i_bin, 0.0) h_data.SetBinError(i_bin, 0.0) has_blinded_data = True else: nbins = h_data.GetNbinsX() for i_bin in xrange(1, nbins + 2): # skip underflow (but not overflow) xval = h_data.GetXaxis().GetBinLowEdge(i_bin) if xval >= blind: h_data.SetBinContent(i_bin, 0.0) h_data.SetBinError(i_bin, 0.0) has_blinded_data = True ## get background histograms h_bkgs = list() n_bkgs = list() if bkgs: for bkg in bkgs: if isinstance(bkg, list): h_subtotal = None for dsid in bkg: assert isinstance(dsid, str) h_bkg = None if dsid.isdigit(): ## mc backgrounds sp = bkgsearchpath % int(dsid) newx = '%s::%s::%s' % (sp, treename, x) h_bkg = ipyhep.tree.project(newx, *args, **kwargs) else: ## data-driven backgrounds assert dsid == 'fakes' or dsid == 'efakes' sp = datadrivensearchpath % dsid newx = '%s::%s::%s' % (sp, treename, x) h_bkg = ipyhep.tree.project(newx, *args, **kwargs) if h_bkg: if h_subtotal: h_subtotal.Add(h_bkg) else: h_subtotal = h_bkg.Clone() if h_subtotal: h_bkgs.append(h_subtotal) dsid = bkg[0] n_bkgs.append(dsid) else: dsid = bkg assert isinstance(dsid, str) h_bkg = None if dsid.isdigit(): ## mc backgrounds sp = bkgsearchpath % int(dsid) newx = '%s::%s::%s' % (sp, treename, x) h_bkg = ipyhep.tree.project(newx, *args, **kwargs) else: ## data-driven backgrounds assert dsid == 'fakes' or dsid == 'efakes' sp = datadrivensearchpath % dsid newx = '%s::%s::%s' % (sp, treename, x) h_bkg = ipyhep.tree.project(newx, *args, **kwargs) if h_bkg: h_bkgs.append(h_bkg) n_bkgs.append(dsid) if h_bkgs: stuff['h_bkgs'] = h_bkgs ## get signal histograms h_sigs = list() n_sigs = list() if sigs: for dsid in sigs: sp = sigsearchpath % int(dsid) newx = '%s::%s::%s' % (sp, treename, x) h_sig = ipyhep.tree.project(newx, *args, **kwargs) if h_sig: h_sigs.append(h_sig) n_sigs.append(dsid) if h_sigs: stuff['h_sigs'] = h_sigs assert h_sigs ## style data if h_data: h_data.title = 'Data' h_data.linecolor = ipyhep.style.black h_data.linewidth = 2 h_data.markercolor = ipyhep.style.black h_data.markerstyle = 20 h_data.markersize = 1.2 h_data.fillstyle = ipyhep.style.fill_hollow h_data.drawstyle = 'PE' h_data.legendstyle = 'LP' ## scale and style background histograms if h_bkgs: assert len(h_bkgs) == len(n_bkgs), '%s\n%s' % (h_bkgs, n_bkgs) for h, dsid in zip(h_bkgs, n_bkgs): sf = ipyhep.sampleops.get_sf(dsid) if dsid.isdigit(): sf *= lumi / __ntuple_lumi h.Scale(sf) h.title = ipyhep.sampleops.get_label(dsid) h.linecolor = ipyhep.style.black h.linewidth = 1 h.markercolor = ipyhep.sampleops.get_color(dsid) h.fillcolor = ipyhep.sampleops.get_color(dsid) h.fillstyle = ipyhep.style.fill_solid h.legendstyle = 'F' ## calculate stat error on total background h_bkg_total = None if h_bkgs: for h_bkg in h_bkgs: if h_bkg_total: h_bkg_total.Add(h_bkg) else: h_bkg_total = h_bkg.Clone() stuff['h_bkg_total'] = h_bkg_total ## style h_bkg_total if h_bkg_total: h_bkg_total.title = 'stat. uncert.' h_bkg_total.linecolor = ipyhep.style.black h_bkg_total.linewidth = 1 h_bkg_total.markerstyle = 0 h_bkg_total.fillcolor = ipyhep.style.dark_gray h_bkg_total.fillstyle = ipyhep.style.fill_lines h_bkg_total.drawstyle = 'E2' h_bkg_total.legendstyle = 'LF' ## scale and style signal histograms if h_sigs: assert len(h_sigs) == len(n_sigs) for h, dsid in zip(h_sigs, n_sigs): sf = ipyhep.sampleops.get_sf(dsid) sf *= lumi / __ntuple_lumi h.Scale(sf) h.title = ipyhep.sampleops.get_label(dsid) h.linecolor = ipyhep.sampleops.get_color(dsid) h.linewidth = 3 h.fillstyle = ipyhep.style.fill_hollow h.markerstyle = 0 h.drawstyle = 'HIST' h.legendstyle = 'L' ## build list of all_hists all_hists = list() main_hists = list() if h_data: all_hists.append(h_data) main_hists.append(h_data) if h_bkgs: all_hists.extend(h_bkgs) main_hists.extend(h_bkgs) if h_bkg_total: all_hists.append(h_bkg_total) main_hists.append(h_bkg_total) if h_sigs: all_hists.extend(h_sigs) ## get statistics if all_hists: stats_list = list() for h in all_hists: stats_list.extend(get_stats(h)) html = convert_table_to_html(convert_stats_to_table(stats_list)) stuff['html'] = html ## renormalize for bin widths bins = kwargs.pop('bins', None) if bins and isinstance(bins, list): for h in all_hists: renormalize_for_bin_widths(h, bins) ## stack background histograms if h_bkgs: assert len(h_bkgs) == len(n_bkgs), '%s\n%s' % (h_bkgs, n_bkgs) h_bkgs.reverse() n_bkgs.reverse() hstack = HistStack() for h in h_bkgs: hstack.Add(h) hstack.title = 'stack sum' hstack.drawstyle = 'HIST' stuff['stack'] = hstack h_bkgs.reverse() n_bkgs.reverse() # ## convert data to TGraphAsymmErrors # g_data = None # if h_data: # if __use_poissonize: # g_data = poissonize.GetPoissonizedGraph(h_data) # else: # g_data = ROOT.TGraphAsymmErrors() # i_g = 0 # nbins = h_data.GetNbinsX() # for i_bin in xrange(1, nbins+1): # skip underflow/overflow # c = h_data.GetBinContent(i_bin) # e = h_data.GetBinError(i_bin) # if c != 0.0: # g_data.SetPoint(i_g, h_data.GetBinCenter(i_bin), c) # g_ratio.SetPointError(i_g, # h_data.GetBinWidth(i_bin)/2., # h_data.GetBinWidth(i_bin)/2., # e, # e) # i_g += 1 ## build list of objects to draw objects = list() if h_bkgs: objects.append(stuff['stack']) objects.append(stuff['h_bkg_total']) if h_sigs: objects.extend(h_sigs) if h_data: objects.append(h_data) ## set xlimits and ylimits ypadding = 0.21 logy_crop_value = 7e-3 xmin, xmax, ymin, ymax = 0.0, 1.0, 0.0, 1.0 if objects: xmin, xmax, ymin, ymax = get_limits(objects, logx=logx, logy=logy, ypadding=ypadding, logy_crop_value=logy_crop_value) if logy: ymin = 7e-3 else: ymin = 0.0 xlimits = (xmin, xmax) ylimits = (ymin, ymax) stuff['xlimits'] = xlimits stuff['ylimits'] = ylimits ## remove xtitle for do_ratio _xtitle = xtitle if h_data and h_bkg_total and kwargs.get('do_ratio'): _xtitle = '' ## make canvas canvas = Canvas(800, 600) stuff['canvas'] = canvas ## draw the objects if objects: canvas.cd() draw(objects, pad=canvas, xtitle=_xtitle, ytitle=ytitle, xlimits=xlimits, ylimits=ylimits) ## set log x/y, for some reason doesn't work before draw if logx or logy: if logx: canvas.SetLogx() if logy: canvas.SetLogy() canvas.Update() ## draw blind_line if has_blinded_data: if isinstance(blind, tuple): blind_list = list(blind) else: blind_list = [blind] blind_lines = list() for bl in blind_list: line_y1 = ymin line_y2 = ymax blind_line = ROOT.TLine(bl, line_y1, bl, line_y2) blind_line.SetLineColor(ROOT.kGray + 2) blind_line.SetLineStyle(7) blind_line.SetLineWidth(2) blind_line.Draw() blind_lines.append(blind_line) stuff['blind_lines'] = blind_lines canvas.Update() ## legend lefty = True if h_bkg_total: lefty = is_left_sided(h_bkg_total) elif h_data: lefty = is_left_sided(h_data) elif h_sigs: lefty = is_left_sided(h_sigs[0]) if main_hists: header = '%.1f fb^{-1}, 13 TeV' % (lumi / 1000.0) if lefty: legend = Legend(main_hists, pad=canvas, header=header, textsize=16, topmargin=0.03, leftmargin=0.60, rightmargin=0.02, entrysep=0.01, entryheight=0.04) else: legend = Legend(main_hists, pad=canvas, header=header, textsize=16, topmargin=0.03, leftmargin=0.03, rightmargin=0.59, entrysep=0.01, entryheight=0.04) legend.Draw() stuff['legend'] = legend if h_sigs: # header = 'ATLAS Internal' header = '' if lefty: legend2 = Legend(h_sigs, pad=canvas, header=header, textsize=16, topmargin=0.03, leftmargin=0.37, rightmargin=0.23, entrysep=0.01, entryheight=0.04) else: legend2 = Legend(h_sigs, pad=canvas, header=header, textsize=16, topmargin=0.03, leftmargin=0.20, rightmargin=0.40, entrysep=0.01, entryheight=0.04) legend2.Draw() stuff['legend2'] = legend2 ## do_ratio if h_data and h_bkg_total and kwargs.get('do_ratio'): ## top canvas top_canvas = stuff.pop('canvas') stuff['top_canvas'] = top_canvas ## make SM/SM with error band: h_ratio_band i_sfratio = int(kwargs.get('sfratio', -1)) if i_sfratio < 0: # ratio plot of Data/Model h_ratio_band = h_bkg_total.Clone() nbins = h_ratio_band.GetNbinsX() for i_bin in xrange(nbins + 2): h_ratio_band.SetBinContent(i_bin, 1.0) c = h_bkg_total.GetBinContent(i_bin) e = h_bkg_total.GetBinError(i_bin) / c if c > 0.0 else 0.0 h_ratio_band.SetBinError(i_bin, e) stuff['h_ratio_band'] = h_ratio_band else: # ratio plot of Scale Factor for ith background hi = h_bkgs[i_sfratio] h_ratio_band = hi.Clone() nbins = h_ratio_band.GetNbinsX() for i_bin in xrange(nbins + 2): h_ratio_band.SetBinContent(i_bin, 1.0) c = hi.GetBinContent(i_bin) e = hi.GetBinError(i_bin) / c if c > 0.0 else 0.0 h_ratio_band.SetBinError(i_bin, e) stuff['h_ratio_band'] = h_ratio_band ## make data/(SM) h_ratio if i_sfratio < 0: h_ratio = h_data.Clone() h_ratio.Divide(h_data, h_bkg_total, 1.0, 1.0) stuff['h_ratio'] = h_ratio else: ## SF1 = 1.0 + (data - MCtot) / MC1 sfname = kwargs.get('sfname') sffile = kwargs.get('sffile') if not sfname: sfname = 'h_sf' hi = h_bkgs[i_sfratio] h_numer = h_data.Clone() h_numer.Add(h_bkg_total, -1.0) ## do the division h_ratio = h_data.Clone(sfname) h_ratio.Divide(h_numer, hi, 1.0, 1.0) ## add the 1.0 nbins = h_ratio.GetNbinsX() for i_bin in xrange(nbins + 2): c = h_ratio.GetBinContent(i_bin) h_ratio.SetBinContent(i_bin, c + 1.0) h_ratio_band.SetBinContent(i_bin, c + 1.0) ## ignore bins with no data for SF for i_bin in xrange(nbins + 2): c = h_data.GetBinContent(i_bin) if c <= 0: h_ratio.SetBinContent(i_bin, 0.0) h_ratio.SetBinError(i_bin, 0.0) h_ratio_band.SetBinError(i_bin, 0.0) stuff['h_ratio'] = h_ratio if sffile: f_out = ipyhep.file.write(h_ratio, sffile) # f_out.Close() ## convert ratio to a TGraphErrors so that Draw('E0') ## shows error bars for points off the pad g_ratio = ROOT.TGraphErrors() i_g = 0 for i_bin in xrange(1, nbins + 1): # skip underflow/overflow ratio_content = h_ratio.GetBinContent(i_bin) if ratio_content != 0.0: g_ratio.SetPoint(i_g, h_ratio.GetBinCenter(i_bin), ratio_content) g_ratio.SetPointError(i_g, h_ratio.GetBinWidth(i_bin) / 2., h_ratio.GetBinError(i_bin)) i_g += 1 else: h_ratio.SetBinError(i_bin, 0.0) stuff['g_ratio'] = g_ratio ## style ratio h_ratio_band.title = 'bkg uncert.' if i_sfratio < 0: h_ratio_band.linecolor = ipyhep.style.yellow else: h_ratio_band.linecolor = ipyhep.style.light_gray h_ratio_band.linewidth = 0 h_ratio_band.markerstyle = 0 if i_sfratio < 0: h_ratio_band.fillcolor = ipyhep.style.yellow else: h_ratio_band.linecolor = ipyhep.style.light_gray h_ratio_band.fillstyle = ipyhep.style.fill_solid h_ratio_band.drawstyle = 'E2' h_ratio_band.legendstyle = 'F' h_ratio.title = 'ratio' h_ratio.linecolor = ipyhep.style.black h_ratio.linewidth = 2 h_ratio.markercolor = ipyhep.style.black h_ratio.markerstyle = 20 h_ratio.markersize = 1.2 h_ratio.fillstyle = ipyhep.style.fill_hollow h_ratio.drawstyle = 'PE' h_ratio.legendstyle = 'LP' ## bottom canvas bottom_canvas = Canvas(800, 600) bottom_canvas.cd() stuff['bottom_canvas'] = bottom_canvas ## set ratio ylimits ratio_min = kwargs.get('ratio_min', -0.2) ratio_max = kwargs.get('ratio_max', 2.2) ratio_ylimits = (ratio_min, ratio_max) ## draw ratio band if i_sfratio < 0: _ytitle = 'Data / Model' else: hi = h_bkgs[i_sfratio] _ytitle = 'SF(%s)' % hi.title draw([h_ratio_band], pad=bottom_canvas, xtitle=xtitle, ytitle=_ytitle, xlimits=xlimits, ylimits=ratio_ylimits) ## set log x/y, for some reason doesn't work before draw? if logx: bottom_canvas.SetLogx() bottom_canvas.Update() ### make horiz lines in ratio plot every 0.5: line_ys = [ y / 10.0 for y in range(10 * int(round(ratio_min)), 10 * int(round(ratio_max)) + 5, 5) ] line_x1 = canvas.GetUxmin() line_x2 = canvas.GetUxmax() line_xwidth = abs(line_x2 - line_x1) lines = [] for line_y in line_ys: line = ROOT.TLine(line_x1 + 0.02 * line_xwidth, line_y, line_x2 - 0.02 * line_xwidth, line_y) line.SetLineWidth(1) line.SetLineStyle(7) if line_y == 1.0: line.SetLineColor(ROOT.kGray + 2) else: line.SetLineColor(ROOT.kGray + 0) line.Draw() lines.append(line) stuff['lines'] = lines ## draw blind_line if has_blinded_data: if isinstance(blind, tuple): blind_list = list(blind) else: blind_list = [blind] blind_lines = list() for bl in blind_list: line_y1 = ymin line_y2 = ymax blind_line = ROOT.TLine(bl, line_y1, bl, line_y2) blind_line.SetLineColor(ROOT.kGray + 2) blind_line.SetLineStyle(7) blind_line.SetLineWidth(2) blind_line.Draw() blind_lines.append(blind_line) stuff['blind_lines2'] = blind_lines canvas.Update() ## draw ratio g_ratio.Draw('PE0') # h_ratio.GetYaxis().SetRangeUser(ratio_min, ratio_max) # h_ratio.Draw('PE,SAME') ## shared canvas shared_canvas = Canvas(800, 800) shared_plot = plot_shared_axis(top_canvas, bottom_canvas, canvas=shared_canvas, split=0.35, axissep=0.01) stuff['canvas'] = shared_canvas canvas = shared_canvas ## save figures save = kwargs.get('save') if save is None: # NOTE: save can be False to skip saving save = ['pdf', 'png'] if save: ipyhep.file.save_figures(canvas, x, save) global results results = stuff return stuff
def draw( name, category, data=None, data_info=None, model=None, model_colors=None, signal=None, signal_scale=1., signal_on_top=False, signal_linestyles=None, signal_colors=None, show_signal_error=False, fill_signal=False, stack_signal=True, units=None, plot_label=None, ylabel='Events', blind=False, show_ratio=False, ratio_range=(0, 2), ratio_height=0.15, ratio_margin=0.06, output_formats=None, systematics=None, #systematics_components=None, integer=False, textsize=22, logy=False, logy_min=None, separate_legends=False, ypadding=None, legend_position='right', range=None, output_name=None, output_dir=PLOTS_DIR, arrow_values=None, overflow=True, show_pvalue=False, top_label=None, poisson_errors=True): if model is None and data is None and signal is None: # insufficient input raise ValueError("at least one of model, data, " "or signal must be specified") if model is not None: if not isinstance(model, (list, tuple)): model = [model] if overflow: for hist in model: fold_overflow(hist) if signal is not None: if not isinstance(signal, (list, tuple)): signal = [signal] if overflow: for hist in signal: fold_overflow(hist) if data is not None and overflow: fold_overflow(data) # objects will be populated with all histograms in the main pad objects = [] legends = [] if show_ratio and (data is None or model is None): # cannot show the ratio if data or model was not specified show_ratio = False if ypadding is None: # select good defaults for log or linear scales if logy: ypadding = (.6, .0) else: ypadding = (.35, .0) template = data or model[0] xdivisions = min(template.nbins(), 7) if integer else 507 if show_ratio: fig = RatioPlot(logy=logy, ratio_title='Data / Model', ratio_limits=(0, 2), offset=-72, ratio_margin=22, prune_ratio_ticks=True) else: fig = SimplePlot(logy=logy) if signal is not None: if signal_scale != 1.: scaled_signal = [] for sig in signal: scaled_h = sig * signal_scale scaled_h.SetTitle(r'%g #times %s' % (signal_scale, sig.GetTitle())) scaled_signal.append(scaled_h) else: scaled_signal = signal if signal_colors is not None: set_colors(scaled_signal, signal_colors) for i, s in enumerate(scaled_signal): s.drawstyle = 'HIST' if fill_signal: s.fillstyle = 'solid' s.fillcolor = s.linecolor s.linewidth = 0 s.linestyle = 'solid' alpha = .75 else: s.fillstyle = 'hollow' s.linewidth = 3 if signal_linestyles is not None: s.linestyle = signal_linestyles[i] else: s.linestyle = 'solid' alpha = 1. if model is not None: if model_colors is not None: set_colors(model, model_colors) # create the model stack model_stack = HistStack() for hist in model: hist.SetLineWidth(0) hist.drawstyle = 'hist' model_stack.Add(hist) if signal is not None and signal_on_top: for s in scaled_signal: model_stack.Add(s) objects.append(model_stack) if signal is not None and not signal_on_top: if stack_signal: # create the signal stack signal_stack = HistStack() for hist in scaled_signal: signal_stack.Add(hist) objects.append(signal_stack) else: objects.extend(scaled_signal) if model is not None: # draw uncertainty band total_model, high_band_model, low_band_model = uncertainty_band( model, systematics) #, systematics_components) high = total_model + high_band_model low = total_model - low_band_model error_band_model = rootpy_utils.get_band(low, high, middle_hist=total_model) error_band_model.fillstyle = '/' error_band_model.fillcolor = 13 error_band_model.linecolor = 10 error_band_model.markersize = 0 error_band_model.markercolor = 10 error_band_model.drawstyle = 'e2' objects.append(error_band_model) if signal is not None and show_signal_error: total_signal, high_band_signal, low_band_signal = uncertainty_band( signal, systematics) #, systematics_components) high = (total_signal + high_band_signal) * signal_scale low = (total_signal - low_band_signal) * signal_scale if signal_on_top: high += total_model low += total_model error_band_signal = rootpy_utils.get_band(low, high, middle_hist=total_signal * signal_scale) error_band_signal.fillstyle = '\\' error_band_signal.fillcolor = 13 error_band_signal.linecolor = 10 error_band_signal.markersize = 0 error_band_signal.markercolor = 10 error_band_signal.drawstyle = 'e2' objects.append(error_band_signal) if data is not None and blind is not True: # create the data histogram if isinstance(blind, tuple): low, high = blind # zero out bins in blind region for bin in data.bins(): if (low < bin.x.high <= high or low <= bin.x.low < high): data[bin.idx] = (0., 0.) if poisson_errors: # convert data to TGraphAsymmErrors with Poisson errors data_poisson = data.poisson_errors() data_poisson.markersize = 1.2 data_poisson.drawstyle = 'PZ' objects.append(data_poisson) else: # Gaussian errors data.drawstyle = 'E0' objects.append(data) # draw ratio plot if model is not None and show_ratio: fig.cd('ratio') total_model = sum(model) ratio_hist = Hist.divide(data, total_model) # remove bins where data is zero max_dev = 0 for bin in data.bins(): if bin.value <= 0: ratio_hist[bin.idx] = (-100, 0) else: ratio_value = ratio_hist[bin.idx].value dev = abs(ratio_value - 1) if dev > max_dev: max_dev = dev if max_dev < 0.2: ratio_range = (0.8, 1.2) elif max_dev < 0.4: ratio_range = (0.6, 1.4) ruler_high = (ratio_range[1] + 1.) / 2. ruler_low = (ratio_range[0] + 1.) / 2. ratio_hist.linecolor = 'black' ratio_hist.linewidth = 2 ratio_hist.fillstyle = 'hollow' ratio_hist.drawstyle = 'E0' """ # draw empty copy of ratio_hist first so lines will show ratio_hist_tmp = ratio_hist.Clone() ratio_hist_tmp.Reset() ratio_hist_tmp.Draw() ratio_hist_tmp.yaxis.SetLimits(*ratio_range) ratio_hist_tmp.yaxis.SetRangeUser(*ratio_range) ratio_hist_tmp.yaxis.SetTitle('Data / Model') ratio_hist_tmp.yaxis.SetNdivisions(4) # not certain why the following is needed ratio_hist_tmp.yaxis.SetTitleOffset(style.GetTitleYOffset()) ratio_xrange = range or ratio_hist.bounds() ratio_hist_tmp.xaxis.SetLimits(*ratio_xrange) #ratio_hist_tmp.xaxis.SetRangeUser(*ratio_xrange) ratio_hist_tmp.xaxis.SetTickLength( ratio_hist_tmp.xaxis.GetTickLength() * 2) # draw ratio=1 line line = Line(ratio_xrange[0], 1, ratio_xrange[1], 1) line.linestyle = 'dashed' line.linewidth = 2 line.Draw() # draw high ratio line line_up = Line(ratio_xrange[0], ruler_high, ratio_xrange[1], ruler_high) line_up.linestyle = 'dashed' line_up.linewidth = 2 line_up.Draw() # draw low ratio line line_dn = Line(ratio_xrange[0], ruler_low, ratio_xrange[1], ruler_low) line_dn.linestyle = 'dashed' line_dn.linewidth = 2 line_dn.Draw() """ # draw band below points on ratio plot ratio_hist_high = Hist.divide(total_model + high_band_model, total_model) ratio_hist_low = Hist.divide(total_model - low_band_model, total_model) fig.cd('ratio') error_band = rootpy_utils.get_band(ratio_hist_high, ratio_hist_low) error_band.fillstyle = '/' error_band.fillcolor = '#858585' error_band.drawstyle = 'E2' fig.draw('ratio', [error_band, ratio_hist], xdivisions=xdivisions) if separate_legends: fig.cd('main') right_legend = Legend(len(signal) + 1 if signal is not None else 1, pad=fig.pad('main'), **legend_params('right', textsize)) right_legend.AddEntry(data, style='lep') if signal is not None: for s in reversed(scaled_signal): right_legend.AddEntry(s, style='F' if fill_signal else 'L') legends.append(right_legend) if model is not None: n_entries = len(model) if systematics: n_entries += 1 model_legend = Legend(n_entries, pad=fig.pad('main'), **legend_params('left', textsize)) for hist in reversed(model): model_legend.AddEntry(hist, style='F') if systematics: model_err_band = error_band_model.Clone() model_err_band.linewidth = 0 model_err_band.linecolor = 'white' model_err_band.fillcolor = '#858585' model_err_band.title = 'Uncert.' model_legend.AddEntry(model_err_band, style='F') legends.append(model_legend) else: n_entries = 1 if signal is not None: n_entries += len(scaled_signal) if model is not None: n_entries += len(model) if systematics: n_entries += 1 fig.cd('main') legend = Legend(n_entries, pad=fig.pad('main'), **legend_params(legend_position, textsize)) if data is not None: legend.AddEntry(data, style='lep') if signal is not None: for s in reversed(scaled_signal): legend.AddEntry(s, style='F' if fill_signal else 'L') if model: for hist in reversed(model): legend.AddEntry(hist, style='F') model_err_band = error_band_model.Clone() model_err_band.linewidth = 0 model_err_band.linecolor = 'white' model_err_band.fillcolor = '#858585' model_err_band.title = 'Uncert.' legend.AddEntry(model_err_band, style='F') legends.append(legend) # draw the objects bounds = fig.draw('main', objects, ypadding=ypadding, logy_crop_value=1E-1, xdivisions=xdivisions) xaxis, yaxis = fig.axes('main') base_xaxis = xaxis base_xaxis.range_user = template.bounds() base_xaxis.limits = template.bounds() xmin, xmax, ymin, ymax = bounds if show_ratio: base_xaxis = fig.axes('ratio')[0] base_xaxis.range_user = template.bounds() base_xaxis.limits = template.bounds() # draw the legends fig.cd('main') for legend in legends: legend.Draw() label_plot( fig.pad('main'), template=template, xaxis=base_xaxis, yaxis=yaxis, xlabel=name, ylabel=ylabel, units=units, category_label=category.label, extra_label=plot_label, extra_label_position='right' if legend_position == 'left' else 'left', data_info=data_info) if logy and logy_min is not None: yaxis.min = logy_min ymin = logy_min # draw arrows if arrow_values is not None: arrow_top = ymin + (ymax - ymin) / 2. fig.cd('main') for value in arrow_values: arrow = Arrow(value, arrow_top, value, ymin, 0.05, '|>') arrow.SetAngle(30) arrow.SetLineWidth(2) arrow.Draw() if show_pvalue and data is not None and model: fig.cd('main') total_model = sum(model) # show p-value and chi^2 pvalue = total_model.Chi2Test(data, 'WW') pvalue_label = ROOT.TLatex(0.6, 0.97, "p-value={0:.2f}".format(pvalue)) pvalue_label.SetNDC(True) pvalue_label.SetTextFont(43) pvalue_label.SetTextSize(16) pvalue_label.Draw() chi2 = total_model.Chi2Test(data, 'WW CHI2/NDF') chi2_label = ROOT.TLatex(0.78, 0.97, "#chi^{{2}}/ndf={0:.2f}".format(chi2)) chi2_label.SetNDC(True) chi2_label.SetTextFont(43) chi2_label.SetTextSize(16) chi2_label.Draw() if top_label is not None: fig.cd('main') label = ROOT.TLatex( fig.pad('main').GetLeftMargin() + 0.08, 0.97, top_label) label.SetNDC(True) label.SetTextFont(43) label.SetTextSize(16) label.Draw() if output_name is not None: # create the output filename filename = 'var_{0}_{1}'.format(category.name, output_name.lower().replace(' ', '_')) if logy: filename += '_logy' filename += '_root' if output_formats is None: output_formats = ('png', ) # save the figure save_canvas(fig, output_dir, filename, formats=output_formats) return fig
def plotHistos(histos, text="", option="", statbox=True): """ Plots a list of histograms """ log = logging.getLogger('pyroplot') import rootpy from rootpy.plotting import Hist, HistStack from ROOT import kRed, gPad, TPaveStats # only for 1D and 2D type histograms: # determine and set maximum for all histograms stack = HistStack() for hist in histos: if not hist.__class__.__name__ == "Hist3D": stack.Add(hist) # determine maximum value and set it for all histograms if stack.GetHists(): maxplot = stack.GetMaximum() minplot = stack.GetMinimum() for hist in stack.GetHists(): hist.SetMaximum(maxplot) # special treatment for log scale Y if gPad.GetLogy(): hist.SetMinimum(1.) else: # if histogram minimum is positive, set to 0. if minplot > 0: hist.SetMinimum(0.) for idx, hist in enumerate(histos): try: thisopt = option # if not first histo, add "same" to options so previous ones are not overwritten if idx: if statbox: thisopt += "sames" else: thisopt += "same" histcopy = hist.DrawCopy(thisopt) # on first go: print identifying text on pad if not idx and text: markPad(text=text, x=.14, y=.85, size=0.041) if statbox: thisopt += "sames" else: thisopt += "same" histcopy.Draw(thisopt) gPad.Update() if statbox: try: statBox = histcopy.GetListOfFunctions().FindObject("stats") # offset from last statbox offset = .18 # needs to be larger for Profile & 2D histos if (hist.__class__.__name__ == "Profile" or hist.__class__.__name__ == "Hist2D" or hist.__class__.__name__ == "Profile2D" or hist.__class__.__name__ == "Hist3D"): offset = .26 statBox.SetY1NDC(statBox.GetY1NDC() - offset * (idx)) statBox.SetY2NDC(statBox.GetY2NDC() - offset * (idx)) statBox.SetTextColor(hist.GetLineColor()) statBox.SetBorderSize(2) except AttributeError: log.debug("Could not get statbox for histogram " + hist.GetName()) except rootpy.ROOTError, e: log.error( "Drawing histogram %s caused ROOTError exception ('%s')" % (hist.GetName(), e.msg)) gPad.Clear() # otherwise this happens again when drawing.. markPad(text="Could not draw %s ('%s')" % (hist.GetName(), e.msg), x=0.14, y=0.4, size=0.023, color=kRed) return # give up!