Exemple #1
0
    def add_legend(self, samples, leftside=True, entries=None):
        ''' Build a legend using samples.

        If entries is None it will be taken from len(samples)

        '''
        nentries = entries if entries is not None else len(samples)
        legend = None
        if leftside:
            legend = plotting.Legend(nentries,
                                     leftmargin=0.03,
                                     topmargin=0.05,
                                     rightmargin=0.65)
        else:
            legend = plotting.Legend(nentries,
                                     rightmargin=0.07,
                                     topmargin=0.05,
                                     leftmargin=0.45)
        for sample in samples:
            legend.AddEntry(sample)
        legend.SetEntrySeparation(0.0)
        legend.SetMargin(0.35)
        legend.Draw()
        self.keep.append(legend)
        return legend
Exemple #2
0
    def add_legend(self, samples, leftside=True, entries=None):
        ''' Build a legend using samples.

      If entries is None it will be taken from len(samples)

      '''
        nentries = entries if entries is not None else len(samples)
        legend = None
        if leftside:
            legend = plotting.Legend(nentries,
                                     leftmargin=0.03,
                                     topmargin=0.05,
                                     rightmargin=0.65)
        else:
            legend = plotting.Legend(nentries,
                                     rightmargin=0.07,
                                     topmargin=0.05,
                                     leftmargin=0.45)
        for sample in samples:
            if isinstance(sample, plotting.HistStack):
                for s in sample:
                    if getattr(sample, 'inlegend', True):
                        label = s.GetTitle()
                        style = s.legendstyle
                        legend.AddEntry(s, style, label)
            else:
                legend.AddEntry(sample)
        legend.SetEntrySeparation(0.0)
        legend.SetMargin(0.35)
        legend.Draw()
        self.keep.append(legend)
        return legend
Exemple #3
0
def init_legend(hists):
    legend = rp.Legend(hists, entryheight = 0.04)
    legend.SetX1NDC(0.9)
    legend.SetX2NDC(1.)
    legend.SetY1NDC(0.5)
    legend.SetY2NDC(1.)
    legend.SetBorderSize(0)
    legend.SetLineStyle(0)
    legend.SetTextSize(0.03)
    legend.SetTextFont(42)
    legend.SetFillStyle(0)
    legend.Draw()
    
    return legend
Exemple #4
0
    def make_legend(self):
        # Create the legend Set the legend position according to LegendDefinition::position variable
        maxTextSize = 0
        if len(self.title) > maxTextSize:
            maxTextSize = min(len(self.title), 40)

        if not self.labels_ or any(i is None for i in self.labels_):
            for entry in self.entries:
                if isinstance(entry, plotting.HistStack):
                    for sub in entry:
                        maxTextSize = max(len(sub.title), maxTextSize)
                else:
                    maxTextSize = max(len(entry.title), maxTextSize)
        else:
            maxTextSize = max(maxTextSize, max(len(i) for i in self.labels_))

        if len(self.title) > 0:
            self.nentries_ += 1

        legend = plotting.Legend(
            self.nentries_,
            entrysep=0.,
            margin=0.35,
            textfont=42,
            entryheight=0.04,
            textsize=0.035,
        )
        legend.position = LegendDefinition.ndc_coordinates(
            self.position, maxTextSize, self.nentries_)
        if self.title:
            legend.SetHeader(self.title)

        if not self.labels_ or any(i is None for i in self.labels_):
            self.labels_ = [None for _ in self.entries]
        for entry, label in zip(self.entries, self.labels_):
            if label is None:
                legend.AddEntry(entry)
            else:
                legend.AddEntry(entry, label)

        # Set generic options
        legend.UseCurrentStyle()
        legend.SetBorderSize(0)
        legend.SetFillColor(0)
        legend.SetFillStyle(0)

        return legend
Exemple #5
0
    canvas = plotting.Canvas(name='adsf', title='asdf')
    canvas.cd()
    stack.SetMaximum(maximum*1.8)
    stack.Draw()
    stack.GetXaxis().SetTitle(options.xtitle)
    stack.GetYaxis().SetTitle(options.ytitle)
    observed.Draw('same')

    #tries to figure which side the legend goes
    obslist = list(observed)
    sx_mean = obslist[:len(obslist) / 2]
    dx_mean = obslist[len(obslist) / 2:]
    sx_mean = sum(sx_mean) / float(len(sx_mean))
    dx_mean = sum(dx_mean) / float(len(dx_mean))

    legend = plotting.Legend(len(histograms)+1, rightmargin=0.03, topmargin=0.02, leftmargin=0.45) \
             if sx_mean > dx_mean else \
             plotting.Legend(len(histograms)+1, leftmargin=0.03, topmargin=0.02, rightmargin=0.45)
    
    #for sample in samples:
    legend.AddEntry(stack)
    legend.AddEntry(observed)
    legend.SetEntrySeparation(0.0)
    legend.SetMargin(0.35)
    legend.Draw()
    canvas.Update()

    outfile = os.path.join(os.getcwd(), options.out)
    canvas.SaveAs(outfile )
    logging.info("%s created" % outfile)
    
Exemple #6
0
        bkg_sum.SetFillStyle(3013)
        bkg_sum.legendstyle = 'f'
        bkg_sum.SetTitle("Bkg. Unc.")
        bkg_sum.Draw('pe2,same')

    observed.Draw('same')

    #tries to figure which side the legend goes
    obslist = list(observed)
    sx_mean = obslist[:len(obslist) / 2]
    dx_mean = obslist[len(obslist) / 2:]
    sx_mean = sum(sx_mean) / float(len(sx_mean))
    dx_mean = sum(dx_mean) / float(len(dx_mean))

    num_entries = len(histograms)+1 if bkg_sum else len(histograms)+2
    legend = plotting.Legend(num_entries, rightmargin=0.03, topmargin=0.02, leftmargin=0.45) \
             if sx_mean > dx_mean else \
             plotting.Legend(num_entries, leftmargin=0.03, topmargin=0.02, rightmargin=0.45)
    
    #for sample in samples:
    legend.AddEntry(stack)
    if bkg_sum:
        legend.AddEntry(bkg_sum)
    legend.AddEntry(observed)
    legend.SetEntrySeparation(0.0)
    legend.SetMargin(0.35)
    legend.Draw()
    canvas.Update()

    outfile = os.path.join(os.getcwd(), options.out)
    canvas.SaveAs(outfile )
Exemple #7
0
if options.xrange:
    r = eval(options.xrange)
    to_print[0].GetXaxis().SetRangeUser(r[0], r[1])
if options.yrange:
    r = eval(options.yrange)
    to_print[0].GetYaxis().SetRangeUser(r[0], r[1])

if options.logy:
    canvas.SetLogy(True)
canvas.SetGridx()
canvas.SetGridy()

for graph in to_print:
    graph.Draw()

one_line.Draw()

legend = plotting.Legend(len(to_print), rightmargin=0.07, topmargin=0.05, leftmargin=0.45) \
    if not options.legend_left else \
    plotting.Legend(len(to_print), leftmargin=0.03, topmargin=0.05, rightmargin=0.65)
legend.SetEntrySeparation(0.0)
legend.SetMargin(0.35)

for graph in to_print[::-1]:
    legend.AddEntry(graph)

legend.Draw()
canvas.SaveAs(options.outfile + '.png')
canvas.SaveAs(options.outfile + '.pdf')
Exemple #8
0
            drawstyle='hist TEXT00',
            linecolor=color,
            linewidth=2,
            fillstyle='hollow',
            legendstyle='l',
        ),
        ch)
    chan_hists[ch] = view.Get('ss/CUT_FLOW')
    chan_hists[ch].SetLabelSize(0.035)

canvas = plotting.Canvas(name='adsf', title='asdf')
canvas.SetGridx(True)
canvas.SetGridy(True)
canvas.SetLogy(True)
legend = plotting.Legend(len(channels),
                         rightmargin=0.07,
                         topmargin=0.05,
                         leftmargin=0.45)
legend.SetEntrySeparation(0.0)
legend.SetMargin(0.35)

for graph in chan_hists.itervalues():
    legend.AddEntry(graph)

ymax = max([i.GetBinContent(1) for i in chan_hists.itervalues()])
for i, hist in enumerate(chan_hists.itervalues()):
    drawattr = '' if i == 0 else 'same'
    hist.GetYaxis().SetRangeUser(50, ymax * 2)
    hist.Draw(drawattr)
legend.Draw()

canvas.Print(os.path.join(public, 'bare_cut_flow%s.png' % postfix))
    to_print[0].GetYaxis().SetRangeUser(r[0], r[1])
else:
    ys = [
        max([
            y for x, y in zip(graph.x(), graph.y())
            if not x_range or x_range[0] < x < x_range[1]
        ]) for graph in to_print
    ]
    to_print[0].GetYaxis().SetRangeUser(0., max(ys) * 1.2)

if options.logy:
    canvas.SetLogy(True)

for graph in to_print:
    graph.Draw()

one_line.Draw()

legend = plotting.Legend(len([i for i in to_print if i.inlegend]), rightmargin=0.03, topmargin=0.03, leftmargin=0.49) \
    if not options.legend_left else \
    plotting.Legend(len([i for i in to_print if i.inlegend]), leftmargin=0.03, topmargin=0.03, rightmargin=0.49)
legend.SetEntrySeparation(0.0)
legend.SetMargin(0.35)

for graph in to_print[::-1]:
    legend.AddEntry(graph)

legend.Draw()
canvas.SaveAs(options.outfile + '.png')
canvas.SaveAs(options.outfile + '.pdf')
Exemple #10
0
            if inputF == inputfile_10GeV: h_3D_10GeV.fill(entry.d3D_SecReco)

canvas_3Ddist = plt.Canvas(800, 600)
h_3D_4GeV.markercolor = 'crimson'
h_3D_7GeV.markercolor = 'darkblue'
h_3D_10GeV.markercolor = 'green'
h_3D_4GeV.Scale(1 / h_3D_4GeV.Integral())
h_3D_7GeV.Scale(1 / h_3D_7GeV.Integral())
h_3D_10GeV.Scale(1 / h_3D_10GeV.Integral())
h_3D_4GeV.xaxis.title = 'd_xyz'
h_3D_4GeV.yaxis.title = 'A.U.'
h_3D_4GeV.Draw()
h_3D_7GeV.Draw('SAME')
h_3D_10GeV.Draw('SAME')
legend = plt.Legend([h_3D_4GeV, h_3D_7GeV, h_3D_10GeV],
                    leftmargin=0.45,
                    margin=0.3,
                    textsize=20)
legend.Draw()
canvas_3Ddist.SetLogy()
canvas_3Ddist.Draw()

canvas_effBin = plt.Canvas(800, 600)
h_effBin_4GeV.markercolor = 'crimson'
h_effBin_7GeV.markercolor = 'darkblue'
h_effBin_10GeV.markercolor = 'green'
h_effBin_4GeV.xaxis.title = 'd_xyz'
h_effBin_4GeV.yaxis.title = 'A.U.'
h_effBin_4GeV.SetMaximum(1.2)
#h_effBin_4GeV.SetMarkerStyle(7)
h_effBin_4GeV.Draw()
#h_effBin_7GeV.Draw('SAME')
Exemple #11
0
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()
Exemple #12
0
    'graph_path': graph_path,
}

jout = output.split('.')[0]
with open('%s.json' % jout, 'w') as out:
    out.write(prettyjson.dumps(jconf))

canvas = plt.Canvas(800, 800)
canvas.SetLogy()
canvas.SetGridx()
canvas.SetGridy()

max_txt_len = max(len(i) for _, i in file_names)
legend = plt.Legend(len(file_names),
                    leftmargin=0.18 + (30 - max_txt_len) * 0.016,
                    rightmargin=0.005,
                    topmargin=0.60 - 0.057 * (len(file_names) - 3),
                    entrysep=0,
                    margin=0.1 + 0.006 * (30 - max_txt_len))
legend.SetTextSize(legend.GetTextSize() * 0.8)
legend.SetFillColor(0)
legend.SetFillStyle(1001)

tfiles = []
graphs = []
idx = 0
for name, legname in file_names:
    tfile = root_open(name)
    tfiles.append(tfile)
    graph = tfile.Get(graph_path)
    graph.linecolor = idx + 2
    graph.linewidth = 2