def __init__(self, outputdir='./', defaults={}, styles={}): ''' Initialize the BasePlotter outputdir is where histograms will be saved. defaults provides basic configuration of the plotter. Most of the options can be anyway overridden by the specific command in case one exception to the general rule is needed. Available defaults: - clone : (bool, default True) chooses the clone policy. If true histograms will be cloned before being styled and drawn - show_title : (bool, default False) shows the histogram title in the canvas - name_canvas: (bool, default False) name the canvas after the histogram.name it is drawn inside - save: (dict, default {'png' : True, 'pdf' : True, 'dotc' : False, 'dotroot' : False, 'json' : False} set the formats to which save the canvas styles provides the plotter a look-up table of styles to be applied to the histograms in the form key : style. Key is a POSIX regular expression that is matched to the histogram title. ''' self.outputdir = outputdir self.base_out_dir = outputdir self.canvas = plotting.Canvas(800, 800, name='adsf', title='asdf') self.set_canvas_style(self.canvas) self.canvas.cd() self.pad = plotting.Pad(0., 0., 1., 1.) #ful-size pad self.pad.Draw() self.set_canvas_style(self.pad) self.pad.cd() self.lower_pad = None self.keep = [] self.defaults = defaults self.styles = styles self.label_factor = None BasePlotter.set_canvas_style(self.canvas) self.set_style()
def dual_pad_format(self): if self.lower_pad is None: self.canvas.cd() self.canvas.SetCanvasSize(self.canvas.GetWw(), int(self.canvas.GetWh() * 1.3)) self.set_canvas_style(self.canvas) self.pad.SetPad(0, 0.33, 1., 1.) self.set_canvas_style(self.pad) self.pad.SetBottomMargin(0.001) self.pad.Draw() self.canvas.cd() #create lower pad self.lower_pad = plotting.Pad(0, 0., 1., 0.33) self.set_canvas_style(self.lower_pad) self.lower_pad.Draw() self.lower_pad.cd() self.pad.cd() self.lower_pad.SetTopMargin(0.005) self.lower_pad.SetGridy(True) self.lower_pad.SetBottomMargin(self.lower_pad.GetBottomMargin() * 3) labelSizeFactor1 = (self.pad.GetHNDC() + self.lower_pad.GetHNDC()) / self.pad.GetHNDC() labelSizeFactor2 = (self.pad.GetHNDC() + self.lower_pad.GetHNDC() ) / self.lower_pad.GetHNDC() mm = min(labelSizeFactor1, labelSizeFactor2) return labelSizeFactor1 / mm, labelSizeFactor2 / mm
def reset(self): '''hard graphic reset''' del self.canvas del self.pad del self.lower_pad self.keep = [] self.canvas = plotting.Canvas(name='adsf', title='asdf') self.canvas.cd() self.pad = plotting.Pad('up', 'up', 0., 0., 1., 1.) #ful-size pad self.pad.Draw() self.pad.cd() self.lower_pad = None
def reset(self): '''hard graphic reset''' del self.canvas del self.pad del self.lower_pad self.keep = [] self.canvas = plotting.Canvas(800, 800, name='adsf', title='asdf') BasePlotter.set_canvas_style(self.canvas) self.canvas.cd() self.pad = plotting.Pad(0., 0., 1., 1.) #ful-size pad self.pad.Draw() BasePlotter.set_canvas_style(self.pad) self.pad.cd() self.lower_pad = None self.label_factor = None
def __init__(self, files, lumifiles, outputdir, blinder=None, forceLumi=-1): ''' Initialize the Plotter object Files should be a list of SAMPLE_NAME.root files. Lumifiles should contain floats giving the effective luminosity of each of the files. If [blinder] is not None, it will be applied to the data view. ''' self.outputdir = outputdir self.views = data_views(files, lumifiles, forceLumi) self.canvas = plotting.Canvas(name='adsf', title='asdf') self.canvas.cd() self.pad = plotting.Pad('up', 'up', 0., 0., 1., 1.) #ful-size pad self.pad.Draw() self.pad.cd() self.lower_pad = None if blinder: # Keep the unblinded data around if desired. self.views['data']['unblinded_view'] = self.views['data']['view'] # Apply a blinding function self.views['data']['view'] = blinder(self.views['data']['view']) self.data = self.views['data']['view'] self.keep = [] # List of MC sample names to use. Can be overridden. self.mc_samples = [ 'Zjets_M50', 'WplusJets_madgraph', 'TTplusJets_madgraph', 'WZ*', 'ZZ*', 'WW*', ] file_to_map = filter(lambda x: x.startswith('data_'), self.views.keys())[0] if not file_to_map: #no data here! file_to_map = self.views.keys()[0] #from pdb import set_trace; set_trace() self.file_dir_structure = Plotter.map_dir_structure( self.views[file_to_map]['file'])
def add_ratio_plot(self, data_hist, mc_stack, x_range=None, ratio_range=0.2): #resize the canvas and the pad to fit the second pad self.canvas.SetCanvasSize(self.canvas.GetWw(), int(self.canvas.GetWh() * 1.3)) self.canvas.cd() self.pad.SetPad(0, 0.33, 1., 1.) self.pad.Draw() self.canvas.cd() #create lower pad self.lower_pad = plotting.Pad('low', 'low', 0, 0., 1., 0.33) self.lower_pad.Draw() self.lower_pad.cd() mc_hist = None if isinstance(mc_stack, plotting.HistStack): mc_hist = sum(mc_stack.GetHists()) else: mc_hist = mc_stack data_clone = data_hist.Clone() data_clone.Divide(mc_hist) if not x_range: nbins = data_clone.GetNbinsX() x_range = (data_clone.GetBinLowEdge(1), data_clone.GetBinLowEdge(nbins) + data_clone.GetBinWidth(nbins)) else: data_clone.GetXaxis().SetRangeUser(*x_range) ref_function = ROOT.TF1('f', "1.", *x_range) ref_function.SetLineWidth(3) ref_function.SetLineStyle(2) data_clone.Draw('ep') if ratio_range: data_clone.GetYaxis().SetRangeUser(1 - ratio_range, 1 + ratio_range) ref_function.Draw('same') self.keep.append(data_clone) self.keep.append(ref_function) self.pad.cd() return data_clone
def add_ratio_plot(self, data_hist, mc_distribution, x_range=None, ratio_range=0.2, quote_errors=False): '''Adds a ratio plot under the main pad, with same x range''' mc_hist = mc_distribution if isinstance(mc_hist, HistStack): mc_hist = sum(mc_hist.GetHists()) quote_errors = False #resize the canvas and the pad to fit the second pad self.canvas.SetCanvasSize(self.canvas.GetWw(), int(self.canvas.GetWh() * 1.3)) self.canvas.cd() self.pad.SetPad(0, 0.33, 1., 1.) self.pad.Draw() self.canvas.cd() #create lower pad self.lower_pad = plotting.Pad('low', 'low', 0, 0., 1., 0.33) self.lower_pad.Draw() self.lower_pad.cd() nbins = data_hist.GetNbinsX() #make ratio, but use only data errors data_clone = data_hist.Clone() for ibin in range(1, nbins + 1): d_cont = data_clone.GetBinContent(ibin) d_err = data_clone.GetBinError(ibin) m_cont = mc_hist.GetBinContent(ibin) d_cont = (d_cont - m_cont) / m_cont if m_cont else -10. d_err = d_err / m_cont if m_cont else 0. data_clone.SetBinContent(ibin, d_cont) data_clone.SetBinError(ibin, d_err) data_clone.Draw('ep') self.keep.append(data_clone) if ratio_range: data_clone.GetYaxis().SetRangeUser(-ratio_range, ratio_range) #reference line if not x_range: nbins = data_clone.GetNbinsX() x_range = (data_clone.GetBinLowEdge(1), data_clone.GetBinLowEdge(nbins) + data_clone.GetBinWidth(nbins)) else: data_clone.GetXaxis().SetRangeUser(*x_range) ref_function = ROOT.TF1('f', "0.", *x_range) ref_function.SetLineWidth(3) ref_function.SetLineStyle(2) ref_function.Draw('same') self.keep.append(ref_function) if quote_errors: err_histo = mc_hist.Clone() err_histo.SetMarkerStyle(0) err_histo.SetLineColor(1) err_histo.SetFillColor(1) for ibin in range(1, nbins + 1): cont = err_histo.GetBinContent(ibin) err = err_histo.GetBinError(ibin) err = err / cont if cont else 0. err_histo.SetBinContent(ibin, 0) err_histo.SetBinError(ibin, err) err_histo.Draw('pe2 same') #was pe self.keep.append(err_histo) self.pad.cd() return data_clone
def run_module(**kwargs): args = Struct(**kwargs) mkdir(args.out) canvas = plotting.Canvas() pars_regex = None if args.pars_regex: pars_regex = re.compile(args.pars_regex) sample_regex = None if args.sample_regex: sample_regex = re.compile(args.sample_regex) pars_out_regex = None if args.pars_out_regex: pars_out_regex = re.compile(args.pars_out_regex) sample_out_regex = None if args.sample_out_regex: sample_out_regex = re.compile(args.sample_out_regex) output_file = io.root_open('%s/output.root' % args.out, 'recreate') fpars_tdir = output_file.mkdir('floating_pars') pulls_tdir = output_file.mkdir('postfit_pulls') failed_fits = set() fit_statuses = plotting.Hist(10, -1.5, 8.5) with io.root_open(args.mlfit) as mlfit: failed_results = [] passes_results = [] pars = {} yields = {} first = True toys = [i.GetName() for i in mlfit.keys() if i.GetName().startswith('toy_')] if not args.oneshot else [None] log.info('examining %i toys' % len(toys)) prefit_nuis = None if args.useprefit: prefit_nuis = ArgSet(mlfit.nuisances_prefit) nfailed = 0 for toy in toys: toy_dir = mlfit.Get(toy) if not args.oneshot else mlfit keys = set([i.GetName() for i in toy_dir.GetListOfKeys()]) if 'norm_fit_s' not in keys or 'fit_s' not in keys: log.error('Fit %s failed to produce output!' % toy) failed_fits.add(toy) continue norms = ArgSet( toy_dir.Get( 'norm_fit_s' ) ) norms = [i for i in norms] fit_result = toy_dir.Get( 'fit_s' ) fit_pars = ArgList(fit_result.floatParsFinal()) if first: first = False for i in fit_pars: if pars_regex and not pars_regex.match(i.GetName()): continue if pars_out_regex and pars_out_regex.match(i.GetName()): continue pars[i.GetName()] = [] for i in norms: if sample_regex and not sample_regex.match(i.GetName()): continue if sample_out_regex and sample_out_regex.match(i.GetName()): continue yields[i.GetName()] = [] fit_statuses.Fill(fit_result.status()) fit_failed = any(i.getError() == 0 for i in fit_pars) or fit_result.status() != 0 if fit_failed: log.error('Fit %s failed to converge properly. It has status %i!' % (toy, fit_result.status())) nfailed+=1 failed_fits.add(toy) failed_results.append(fit_result) continue passes_results.append(fit_result) for i in norms: if i.GetName() in yields: yields[i.GetName()].append(i) for i in fit_pars: if i.GetName() in pars: pars[i.GetName()].append(i) if nfailed: log.error('There were %i fit failed!' % nfailed) with open('%s/info.txt' % args.out, 'w') as info: info.write('There were %i fit failed!\n' % nfailed) fit_statuses.Draw() canvas.SaveAs('%s/fit_status.png' % args.out) if not args.nopars: #Plots the post-fit distribution of the POI and nuisances out = os.path.join(args.out, 'floating_parameters') mkdir(out) for i, j in yields.iteritems(): make_hist(i, j, out, prefix='yield_') for i, j in pars.iteritems(): make_hist(i, j, out, prefix='par_') if not args.postpulls: #Plots the post-fit pulls (nuisance(post) - nuisance(pre))/unc(post) pulls_dir = os.path.join(args.out, 'postfit_pulls') mkdir(pulls_dir) ROOT.gStyle.SetOptFit(11111) singlenames=set() for name,value in pars.iteritems(): if pars_regex and not pars_regex.match(name): continue if pars_out_regex and pars_out_regex.match(i): continue singlenames.add(get_key(name)) pulls_mean_summary={} pulls_sigma_summary={} deltas_mean_summary={} deltas_sigma_summary={} for name in singlenames: nbins = 0 for fullname in pars: if name in fullname: nbins = nbins + 1 #print name, nbins try: hist = plotting.Hist(nbins, 0.5,nbins+0.5, name = "%s_pull_mean_summary" %name) pulls_mean_summary[name] = hist hist = plotting.Hist(nbins, 0.5,nbins+0.5, name = "%s_pull_sigma_summary" %name) pulls_sigma_summary[name] = hist hist = plotting.Hist(nbins, 0.5,nbins+0.5, name = "%s_delta_mean_summary" %name) deltas_mean_summary[name] = hist hist = plotting.Hist(nbins, 0.5,nbins+0.5, name = "%s_delta_sigma_summary" %name) deltas_sigma_summary[name] = hist except: set_trace() pulls_mean_summary[ 'all'] = plotting.Hist(len(pars), 0.5, len(pars)+0.5, name = "all_pull_mean_summary" ) pulls_sigma_summary[ 'all'] = plotting.Hist(len(pars), 0.5, len(pars)+0.5, name = "all_pull_sigma_summary" ) deltas_mean_summary[ 'all'] = plotting.Hist(len(pars), 0.5, len(pars)+0.5, name = "all_delta_mean_summary" ) deltas_sigma_summary['all'] = plotting.Hist(len(pars), 0.5, len(pars)+0.5, name = "all_delta_sigma_summary") for i, j in pars.iteritems(): make_post_distributions(i, j, pulls_dir, pulls_mean_summary, pulls_sigma_summary, prefix='pull_', dist='pull', prefit=prefit_nuis, tdir=pulls_tdir, skipFit=args.skipFit) make_post_distributions(i, j, pulls_dir, deltas_mean_summary, deltas_sigma_summary, prefix='delta_', dist='delta', prefit=prefit_nuis, tdir=pulls_tdir, skipFit=args.skipFit) for name,histo in pulls_mean_summary.iteritems(): canvas = plotting.Canvas() histo.Draw() canvas.Update() line = ROOT.TLine(histo.GetBinLowEdge(1),0,histo.GetBinLowEdge(histo.GetNbinsX()+1),0) line.SetLineColor(2) line.Draw("same") canvas.Update() canvas.SaveAs('%s/%s.png' % (pulls_dir,histo.GetName())) canvas.SaveAs('%s/%s.pdf' % (pulls_dir,histo.GetName())) pulls_tdir.WriteObject(histo, histo.GetName()) for name,histo in pulls_sigma_summary.iteritems(): canvas = plotting.Canvas() histo.Draw() canvas.Update() line = ROOT.TLine(histo.GetBinLowEdge(1),1,histo.GetBinLowEdge(histo.GetNbinsX()+1),1) line.SetLineColor(2) line.Draw("same") canvas.Update() canvas.SaveAs('%s/%s.png' % (pulls_dir,histo.GetName())) canvas.SaveAs('%s/%s.pdf' % (pulls_dir,histo.GetName())) pulls_tdir.WriteObject(histo, histo.GetName()) for name,histo in deltas_mean_summary.iteritems(): canvas = plotting.Canvas() histo.Draw() canvas.Update() line = ROOT.TLine(histo.GetBinLowEdge(1),0,histo.GetBinLowEdge(histo.GetNbinsX()+1),0) line.SetLineColor(2) line.Draw("same") canvas.Update() canvas.SaveAs('%s/%s.png' % (pulls_dir,histo.GetName())) canvas.SaveAs('%s/%s.pdf' % (pulls_dir,histo.GetName())) pulls_tdir.WriteObject(histo, histo.GetName()) for name,histo in deltas_sigma_summary.iteritems(): histo.Draw() canvas.Update() #line = ROOT.TLine(histo.GetBinLowEdge(1),1,histo.GetBinLowEdge(histo.GetNbinsX()+1),1) #line.Draw("same") canvas.Update() canvas.SaveAs('%s/%s.png' % (pulls_dir,histo.GetName())) canvas.SaveAs('%s/%s.pdf' % (pulls_dir,histo.GetName())) pulls_tdir.WriteObject(histo, histo.GetName()) if not args.noshapes: #Overlays the prefit values of the different shapes with the envelope of #what is fitted by the toys out = os.path.join(args.out, 'shapes') mkdir(out) biased_shapes={} if args.biasFile: with io.root_open(args.biasFile) as biased: biased_dir= biased.prefit \ if hasattr(biased, 'prefit') else \ None ROOT.TH1.AddDirectory(False) for key in biased_dir.keys(): biased_shapes[key.name] = asrootpy(key.ReadObj().Clone()) with io.root_open(args.harvested) as harvest: has_prefit = hasattr(harvest, 'prefit') prefit = harvest.prefit if has_prefit else None toys = EnvelopeView( *[harvest.get(i.GetName()).get(args.variable) for i in harvest.keys() if i.GetName().startswith('toy_') and (i.GetName() not in failed_fits) ] ) #shapes = [i.GetName() for i in prefit.keys()] #FIXME! should not depend on prefit! first_toy = [i.GetName() for i in harvest.keys() if i.GetName().startswith('toy_')][0] not_shapes = set('correlation_matrix') shapes = [i.GetName() for i in harvest.get(first_toy).get(args.variable).keys() if i.GetName() not in not_shapes] for shape in shapes: canvas = plotting.Canvas() canvas.SetCanvasSize( canvas.GetWw(), int(canvas.GetWh()*1.3) ) upper_pad = plotting.Pad(0, 0.33, 1., 1.) lower_pad = plotting.Pad(0, 0., 1., 0.33) upper_pad.set_bottom_margin(0.001) lower_pad.set_top_margin(0.005) lower_pad.set_bottom_margin(lower_pad.get_bottom_margin()*3) upper_pad.Draw() lower_pad.Draw() upper_pad.cd() biased_shape = biased_shapes.get(shape, None) toy_shape = toys.Get(shape) pre_shape = None legend = plotting.Legend( 3+int(has_prefit)+int(bool(biased_shape)), rightmargin=0.07, topmargin=0.05, leftmargin=0.45) legend.SetBorderSize(0) if biased_shape: biased_shape.title = 'true shape' biased_shape.legendstyle = 'p' biased_shape.inlegend = True biased_shape.drawstyle = 'p' if has_prefit: pre_shape = prefit.Get(shape) pre_shape.title = 'input shape' pre_shape.legendstyle = 'p' pre_shape.drawstyle = 'p' if biased_shape: pre_shape.legendstyle = 'l' pre_shape.drawstyle = 'hist' pre_shape.linecolor = 'blue' pre_shape.fillstyle = 0 toy_shape.Draw() if has_prefit: pre_shape.Draw('same') if biased_shape: biased_shape.Draw('same') legend.AddEntry(toy_shape.two_sigma) legend.AddEntry(toy_shape.one_sigma) legend.AddEntry(toy_shape.median) if has_prefit: legend.AddEntry(pre_shape) if biased_shape: legend.AddEntry(biased_shape) legend.Draw() #compute pulls pulls = None labelSizeFactor2 = (upper_pad.GetHNDC()+lower_pad.GetHNDC()) / lower_pad.GetHNDC() labelSizeFactor1 = (upper_pad.GetHNDC()+lower_pad.GetHNDC()) / upper_pad.GetHNDC() label_factor = labelSizeFactor2/labelSizeFactor1 if has_prefit or biased_shape: lower_pad.cd() ref_histo = biased_shape if biased_shape else pre_shape pulls = toy_shape.median.Clone() pulls.Reset() for ref, toy, pull in zip(ref_histo, toy_shape, pulls): if toy.error == (0.0, 0.0): continue abs_pull = toy.median-ref.value #pick correct side of the errors err = toy.error[1] if abs_pull < 0 else toy.error[0] pull.value = abs_pull/err pulls.xaxis.title = args.variable pulls.yaxis.title = 'pulls' pulls.set_label_size(ROOT.gStyle.GetLabelSize()*label_factor, "XYZ") pulls.set_title_size(ROOT.gStyle.GetTitleSize()*label_factor, "XYZ") pulls.yaxis.set_title_offset(pulls.GetYaxis().GetTitleOffset()/label_factor) pulls.Draw() canvas.Update() canvas.SaveAs('%s/%s.png' % (out, shape)) canvas.SaveAs('%s/%s.pdf' % (out, shape)) with open(os.path.join(out, '%s.json' % shape), 'w') as jfile: jfile.write(toy_shape.json()) output_file.Close()