def create_histograms( self, online_title, offline_title, versus_title, pileup_bins, res_n_bins, res_low, res_high, vs_n_bins, vs_low, vs_high): """ This is not in an init function so that we can by-pass this in the case where we reload things from disk """ self.online_title = online_title self.offline_title = offline_title self.versus_title = versus_title self.ymin = res_low self.ymax = res_high self.pileup_bins = bn.Sorted(pileup_bins, "pileup", use_everything_bin=True) nameTokens = [ "resolution_vs", self.versus_name, self.online_name, self.offline_name, "pu_{pileup}", ] name = "__".join(nameTokens) title = 'Resolution ({online_name} vs. {offline_name}) ' title += 'against {versus_name}' title = title.format( online_name=self.online_name, offline_name=self.offline_name, versus_name=self.versus_name, ) title += " in PU bin: {pileup}" title = ";".join([title, self.offline_title, self.online_title]) self.plots = HistogramCollection( [self.pileup_bins], "Hist2D", vs_n_bins, vs_low, vs_high, res_n_bins, res_low, res_high, name=name, title=title) self.filename_format = name
def create_histograms(self, online_title, pileup_bins, n_bins, low, high, legend_title=""): """ This is not in an init function so that we can by-pass this in the case where we reload things from disk """ self.online_title = online_title self.pileup_bins = bn.Sorted(pileup_bins, "pileup", use_everything_bin=True) self.legend_title = legend_title name = ["rate_vs_threshold", self.online_name, "pu_{pileup}"] name = "__".join(name) title = " ".join([self.online_name, "vs.", "in PU bin: {pileup}"]) title = ";".join([title, self.online_title]) self.plots = HistogramCollection([self.pileup_bins], "Hist1D", n_bins, low, high, name=name, title=title) self.filename_format = name
def create_histograms(self, online_title, thresholds, n_bins, low, high, legend_title=""): """ This is not in an init function so that we can by-pass this in the case where we reload things from disk """ self.online_title = online_title self.thresholds = thresholds self.thresholds = bn.GreaterThan(thresholds, "threshold", True) self.legend_title = legend_title name = ["rate_vs_pileup", self.online_name] name += ["thresh_{threshold}"] name = "__".join(name) title = " ".join([ self.online_name, " rate vs pileup", "passing threshold: {threshold}" ]) self.plots = HistogramCollection([self.thresholds], "Hist1D", n_bins, low, high, name=name, title=title) self.filename_format = name
def create_histograms( self, online_title, offline_title, pileup_bins, n_bins, low, high=400., ): """ This is not in an init function so that we can by-pass this in the case where we reload things from disk """ self.online_title = online_title self.offline_title = offline_title self.pileup_bins = bn.Sorted( pileup_bins, "pileup", use_everything_bin=True, ) nameTokens = [ "onlineVsOffline", self.online_name, self.offline_name, "pu_{pileup}", ] name = "__".join(nameTokens) title = " ".join([ self.online_name, "vs.", self.offline_name, "in PU bin: {pileup}", ]) title = ";".join([title, self.offline_title, self.online_title]) if isinstance(low, np.ndarray): self.plots = HistogramCollection( [self.pileup_bins], "Hist2D", low, low, name=name, title=title, ) else: self.plots = HistogramCollection( [self.pileup_bins], "Hist2D", n_bins, low, high, n_bins, low, high, name=name, title=title, ) self.filename_format = name
def create_histograms(self, online_title, offline_title, pileup_bins, thresholds, n_bins, low, high=400, legend_title=""): """ This is not in an init function so that we can by-pass this in the case where we reload things from disk """ self.online_title = online_title self.offline_title = offline_title self.pileup_bins = bn.Sorted(pileup_bins, "pileup", use_everything_bin=True) self.thresholds = bn.GreaterThan(thresholds, "threshold") self.legend_title = legend_title name = ["efficiency", self.online_name, self.offline_name] name += ["thresh_{threshold}", "pu_{pileup}"] name = "__".join(name) title = " ".join([ self.online_name, " in PU bin: {pileup}", "and passing threshold: {threshold}" ]) self.filename_format = name def make_efficiency(labels): this_name = "efficiency" + name.format(**labels) this_title = title.format(**labels) '''Checking type of 'low' to see whether it's int (x-range minimum) or array (bin edges) for constructing TEfficiency''' if isinstance(low, np.ndarray): eff = asrootpy( ROOT.TEfficiency(this_name, this_title, n_bins, low)) self.x_max = 2000 else: eff = asrootpy( ROOT.TEfficiency(this_name, this_title, n_bins, low, high)) self.x_max = high eff.drawstyle = EfficiencyPlot.drawstyle return eff self.efficiencies = HistogramCollection( [self.pileup_bins, self.thresholds], make_efficiency)
def __fit_efficiencies(self): def make_fit(labels): pileup_bin = labels["pileup"] threshold_bin = labels["threshold"] efficiency = self.efficiencies.get_bin_contents( [pileup_bin, threshold_bin]) params = fit_efficiency( efficiency, self.thresholds.get_bin_center(threshold_bin)) return params # Actually make the efficiencies self.fits = HistogramCollection([self.pileup_bins, self.thresholds], make_fit)
class RateVsPileupPlot(BasePlotter): def __init__(self, online_name): name = ["rate_vs_pileup", online_name] super(RateVsPileupPlot, self).__init__("__".join(name)) self.online_name = online_name def create_histograms(self, online_title, thresholds, n_bins, low, high, legend_title=""): """ This is not in an init function so that we can by-pass this in the case where we reload things from disk """ self.online_title = online_title self.thresholds = thresholds self.thresholds = bn.GreaterThan(thresholds, "threshold", True) self.legend_title = legend_title name = ["rate_vs_pileup", self.online_name] name += ["thresh_{threshold}"] name = "__".join(name) title = " ".join([self.online_name, " rate vs pileup", "passing threshold: {threshold}"]) self.plots = HistogramCollection([self.thresholds], "Hist1D", n_bins, low, high, name=name, title=title) self.filename_format = name def fill(self, pileup, online): self.plots[online].fill(pileup) def draw(self, with_fits=False): for (threshold, ), hist in self.plots.flat_items_all(): hists = [] labels = [] fits = [] thresholds = [] if not isinstance(threshold, int): continue label_template = '{online_title} > {threshold} GeV' label = label_template.format( online_title=self.online_title, threshold=self.thresholds.bins[threshold], ) hist.Divide(self.plots.get_bin_contents([bn.Base.everything])) hist.drawstyle = "EP" hist.SetMarkerColor(2) # if with_fits: # fit = self.fits.get_bin_contents([threshold]) # fits.append(fit) hists.append(hist) labels.append(label) thresholds.append(threshold) self.__make_overlay(hists, fits, labels, thresholds) def overlay(self, other_plotters=None, with_fits=False, comp=False): hists = [] labels = [] fits = [] thresholds = [] suffix = '__emu_overlay' titles = ['Hw', 'Emu'] if comp: suffix = '__comparison' titles = [other_plotter.comp_title for other_plotter in other_plotters] titles.insert(0, self.comp_title) for (threshold, ), hist in self.plots.flat_items_all(): if not isinstance(threshold, int): continue label_template = '{online_title} > {threshold} GeV' label = label_template.format( online_title='L1 ' + titles[0], threshold=self.thresholds.bins[threshold], ) hist.Divide(self.plots.get_bin_contents([bn.Base.everything])) hist.Scale(2855) hist.drawstyle = "EP" hist.SetMarkerColor(1) # if with_fits: # fit = self.fits.get_bin_contents([threshold]) # fits.append(fit) hists.append(hist) labels.append(label) thresholds.append(threshold) for other_plotter in other_plotters: for (threshold, ), hist in other_plotter.plots.flat_items_all(): if not isinstance(threshold, int): continue label_template = '{online_title} > {threshold} GeV' label = label_template.format( online_title='L1 ' + titles[other_plotters.index(other_plotter) + 1], threshold=other_plotter.thresholds.bins[threshold], ) hist.Divide(other_plotter.plots.get_bin_contents([bn.Base.everything])) hist.Scale(2855) hist.drawstyle = "EP" hist.SetMarkerColor(2) hist.markerstyle = 21 + other_plotters.index(other_plotter) # if with_fits: # fit = self.fits.get_bin_contents([threshold]) # fits.append(fit) hists.append(hist) labels.append(label) thresholds.append(threshold) self.__make_overlay(hists, fits, labels, thresholds, suffix) def __make_overlay(self, hists, fits, labels, thresholds, suffix=""): with preserve_current_style(): # Draw each rate vs pileup (with fit) xtitle = "< \\mu >" ytitle = "Rate (kHz)" canvas = draw(hists, draw_args={"xtitle": xtitle, "ytitle": ytitle, "xlimits": (20, 50), "ylimits": (0, 5)}) if fits: for fit, hist in zip(fits, hists): fit["asymmetric"].linecolor = hist.GetLineColor() fit["asymmetric"].Draw("same") # Add labels label_canvas() # Add a legend legend = Legend( len(hists), header=self.legend_title, topmargin=0.02, leftmargin=0.22, rightmargin=0.78, textsize=0.025, entryheight=0.028, ) for hist, label in zip(hists, labels): legend.AddEntry(hist, label) legend.SetBorderSize(0) legend.Draw() # Save canvas to file name = self.filename_format.format(threshold=thresholds[0]) self.save_canvas(canvas, name + suffix) def _is_consistent(self, new): """ Check the two plotters are the consistent, so same binning and same axis names """ return all([self.thresholds.bins == new.thresholds.bins, self.online_name == new.online_name, ]) def _merge(self, other): """ Merge another plotter into this one """ self.plots += other.plots return self.plots def get_stats(self, summary_bins=[], summary_label=''): summary_columns = list(self._summary_columns(summary_bins, summary_label)) stats = list(self._collect_stats(summary_bins, summary_label)) df = pd.DataFrame(stats) return df[['identifier', 'total', 'overflow'] + summary_columns] def _summary_columns(self, summary_bins, summary_label): for lower, upper in zip(summary_bins[:-1], summary_bins[1:]): yield '{} {}-{}'.format(summary_label, lower, upper) def _collect_stats(self, summary_bins, summary_label): normalisation = self.plots.get_bin_contents([bn.Base.everything]).integral(overflow=True) for (threshold, ), hist in self.plots.flat_items(): human_readable_threshold = '{0} > {1} GeV'.format(self.online_title, self.thresholds.bins[threshold]) rhist = hist.rebinned(summary_bins) stats = {} summary_columns = self._summary_columns(summary_bins, summary_label) for summary_column, y in zip(summary_columns, rhist.y()): stats[summary_column] = y * normalisation total = sum(stats.values()) overflow = rhist.integral(overflow=True) * normalisation - total header = dict(identifier=human_readable_threshold, total=total, overflow=overflow) header.update(stats) yield header
class EfficiencyPlot(BasePlotter): drawstyle = 'HIST' drawstyle_data = 'P' markerstyle_overlay = 23 def __init__(self, online_name, offline_name): name = ["efficiency", online_name, offline_name] super(EfficiencyPlot, self).__init__("__".join(name)) self.online_name = online_name self.offline_name = offline_name def create_histograms(self, online_title, offline_title, pileup_bins, thresholds, n_bins, low, high=400, legend_title=""): """ This is not in an init function so that we can by-pass this in the case where we reload things from disk """ self.online_title = online_title self.offline_title = offline_title self.pileup_bins = bn.Sorted(pileup_bins, "pileup", use_everything_bin=True) self.thresholds = bn.GreaterThan(thresholds, "threshold") self.legend_title = legend_title name = ["efficiency", self.online_name, self.offline_name] name += ["thresh_{threshold}", "pu_{pileup}"] name = "__".join(name) title = " ".join([ self.online_name, " in PU bin: {pileup}", "and passing threshold: {threshold}" ]) self.filename_format = name def make_efficiency(labels): this_name = "efficiency" + name.format(**labels) this_title = title.format(**labels) '''Checking type of 'low' to see whether it's int (x-range minimum) or array (bin edges) for constructing TEfficiency''' if isinstance(low, np.ndarray): eff = asrootpy( ROOT.TEfficiency(this_name, this_title, n_bins, low)) self.x_max = 2000 else: eff = asrootpy( ROOT.TEfficiency(this_name, this_title, n_bins, low, high)) self.x_max = high eff.drawstyle = EfficiencyPlot.drawstyle return eff self.efficiencies = HistogramCollection( [self.pileup_bins, self.thresholds], make_efficiency) def fill(self, pileup, offline, online): efficiencies = { (pu, thresh): eff for (pu, ), thresholds in self.efficiencies[pileup].items() for thresh, eff in thresholds.items() } for (pu_bin, threshold_bin), efficiency in efficiencies.items(): threshold = self.thresholds.get_bin_center(threshold_bin) passed = False if isinstance(threshold, str): continue elif online > threshold: passed = True efficiency.fill(passed, offline) def draw(self, with_fits=False): # Fit the efficiencies if requested if with_fits: self.__fit_efficiencies() # Overlay the "all" pile-up bin for each threshold all_pileup_effs = self.efficiencies.get_bin_contents( [bn.Base.everything]) hists = [] labels = [] fits = [] label_template = '{online_title} > {threshold} GeV' for threshold in all_pileup_effs.iter_all(): if not isinstance(threshold, int): continue hist = all_pileup_effs.get_bin_contents(threshold) hist.drawstyle = EfficiencyPlot.drawstyle hists.append(hist) label = label_template.format( online_title=self.online_title, threshold=self.thresholds.bins[threshold], ) labels.append(label) if with_fits: fits.append( self.fits.get_bin_contents([bn.Base.everything, threshold])) self.__make_overlay( "all", "all", hists, fits, labels, self.online_title, ) # Overlay individual pile-up bins for each threshold for threshold in self.thresholds: hists = [] labels = [] fits = [] for pileup in self.pileup_bins: if not isinstance(pileup, int): continue hist = self.efficiencies.get_bin_contents([pileup, threshold]) hist.drawstyle = EfficiencyPlot.drawstyle_data hists.append(hist) if with_fits: fits.append(self.fits.get_bin_contents([pileup, threshold])) labels.append(str(self.pileup_bins.bins[pileup])) self.__make_overlay(pileup, threshold, hists, fits, labels, "PU bin") # Produce the fit summary plot if with_fits: self.__summarize_fits() def overlay_with_emu(self, emu_plotter, with_fits=False): # Fit the efficiencies if requested if with_fits: self.__fit_efficiencies() # Overlay the "all" pile-up bin for each threshold all_pileup_effs = self.efficiencies.get_bin_contents( [bn.Base.everything]) emu_pileup_effs = emu_plotter.efficiencies.get_bin_contents( [bn.Base.everything]) hists = [] labels = [] fits = [] ROOT.gStyle.SetErrorX(0.) label_template = '{online_title} > {threshold} GeV' for threshold in all_pileup_effs.iter_all(): if not isinstance(threshold, int): continue hist = all_pileup_effs.get_bin_contents(threshold) hist.drawstyle = EfficiencyPlot.drawstyle_data hists.append(hist) label = label_template.format( online_title=self.online_title, threshold=self.thresholds.bins[threshold], ) labels.append(label) if with_fits: fits.append( self.fits.get_bin_contents([bn.Base.everything, threshold])) for threshold in emu_pileup_effs.iter_all(): if not isinstance(threshold, int): continue hist = emu_pileup_effs.get_bin_contents(threshold) hist.drawstyle = EfficiencyPlot.drawstyle_data hist.markerstyle = EfficiencyPlot.markerstyle_overlay hists.append(hist) label = label_template.format( online_title=emu_plotter.online_title + ' Emu', threshold=emu_plotter.thresholds.bins[threshold], ) labels.append(label) if with_fits: fits.append( emu_plotter.fits.get_bin_contents( [bn.Base.everything, threshold])) self.__make_overlay( "all", "all_overlay_with_Emu", hists, fits, labels, self.online_title, ) ''' # Overlay individual pile-up bins for each threshold for threshold in self.thresholds: hists = [] labels = [] fits = [] for pileup in self.pileup_bins: if not isinstance(pileup, int): continue hist = self.efficiencies.get_bin_contents([pileup, threshold]) hist.drawstyle = "EP" hists.append(hist) if with_fits: fits.append(self.fits.get_bin_contents( [pileup, threshold])) labels.append(str(self.pileup_bins.bins[pileup])) self.__make_overlay(pileup, threshold, hists, fits, labels, "PU bin") ''' # Produce the fit summary plot if with_fits: self.__summarize_fits() def __fit_efficiencies(self): def make_fit(labels): pileup_bin = labels["pileup"] threshold_bin = labels["threshold"] efficiency = self.efficiencies.get_bin_contents( [pileup_bin, threshold_bin]) params = fit_efficiency( efficiency, self.thresholds.get_bin_center(threshold_bin)) return params # Actually make the efficiencies self.fits = HistogramCollection([self.pileup_bins, self.thresholds], make_fit) def __make_overlay(self, pileup, threshold, hists, fits, labels, header): with preserve_current_style(): name = self.filename_format.format(pileup=pileup, threshold=threshold) # Draw each efficiency (with fit) draw_args = {"xtitle": self.offline_title, "ytitle": "Efficiency"} # TODO: special case should not be implemented here! if 'Jet' in name and 'HiRange' in name: draw_args['xlimits'] = [20, 2000] canvas = draw(hists, draw_args=draw_args) if len(fits) > 0: for fit, hist in zip(fits, hists): fit["asymmetric"].linecolor = hist.GetLineColor() fit["asymmetric"].Draw("same") # Add labels label_canvas() # Add a legend legend = Legend( len(hists), header=self.legend_title, topmargin=0.35, rightmargin=0.3, leftmargin=0.7, textsize=0.025, entryheight=0.028, ) for hist, label in zip(hists, labels): legend.AddEntry(hist, label) legend.SetBorderSize(0) legend.Draw() xmin = 0 xmax = self.x_max # TODO: also specialisation, needs removal if ("HT" in name): xmax = 800 xmin = 30 if ("MET" in name): xmin = 0 xmax = 400 if ("Jet" in name): xmin = 20 xmax = 400 if ("HiRange" in name): xmax = 2000 for val in [0.25, 0.5, 0.75, 0.95, 1.]: line = ROOT.TLine(xmin, val, xmax, val) line.SetLineStyle("dashed") line.SetLineColor(15) line.Draw() for val in range(100, xmax, 100): line = ROOT.TLine(val, 0., val, 1.) line.SetLineStyle("dashed") line.SetLineColor(15) line.Draw() # Save canvas to file self.save_canvas(canvas, name) def __summarize_fits(self): """ Implement this to show fit evolution plots """ # TODO: Implement this __summarize_fits methods pass def _is_consistent(self, new): """ Check the two plotters are the consistent, so same binning and same axis names """ return all([ self.pileup_bins.bins == new.pileup_bins.bins, self.thresholds.bins == new.thresholds.bins, self.online_name == new.online_name, self.offline_name == new.offline_name, ]) def _merge(self, other): """ Merge another plotter into this one """ self.efficiencies += other.efficiencies return self.efficiencies
class RatesPlot(BasePlotter): def __init__(self, online_name): name = ["rates", online_name] super(RatesPlot, self).__init__("__".join(name)) self.online_name = online_name def create_histograms(self, online_title, pileup_bins, n_bins, low, high, legend_title=""): """ This is not in an init function so that we can by-pass this in the case where we reload things from disk """ self.online_title = online_title self.pileup_bins = bn.Sorted(pileup_bins, "pileup", use_everything_bin=True) self.legend_title = legend_title name = ["rate_vs_threshold", self.online_name, "pu_{pileup}"] name = "__".join(name) title = " ".join([self.online_name, "vs.", "in PU bin: {pileup}"]) title = ";".join([title, self.online_title]) self.plots = HistogramCollection([self.pileup_bins], "Hist1D", n_bins, low, high, name=name, title=title) self.filename_format = name def fill(self, pileup, online): self.plots[pileup].fill(online) def draw(self, with_fits=False): hists = [] labels = [] fits = [] for (pile_up, ), hist in self.plots.flat_items_all(): h = cumulative_hist(hist) h = normalise_to_collision_rate(h) if pile_up == bn.Base.everything: h.linestyle = "dashed" label = "Everything" elif isinstance(pile_up, int): h.drawstyle = "EP" label = "~ {:.0f}".format( self.pileup_bins.get_bin_center(pile_up)) else: continue h.SetMarkerSize(0.5) hists.append(h) labels.append(label) # if with_fits: # fits.append(self.fits.get_bin_contents([pile_up])) self.__make_overlay(hists, fits, labels, "Number of events") normed_hists = list(normalise_to_unit_area(hists)) self.__make_overlay(normed_hists, fits, labels, "Fraction of events", "__shapes") def overlay_with_emu(self, emu_plotter, with_fits=False): hists = [] labels = [] fits = [] hist = self.plots.get_bin_contents([bn.Base.everything]) hist = cumulative_hist(hist) hist.drawstyle = "EP" hist.SetMarkerSize(0.5) hist.SetMarkerColor(1) # if with_fits: # fit = self.fits.get_bin_contents([threshold]) # fits.append(fit) hists.append(hist) labels.append("HW") emu_hist = emu_plotter.plots.get_bin_contents([bn.Base.everything]) emu_hist = cumulative_hist(emu_hist) emu_hist.drawstyle = "EP" emu_hist.SetMarkerSize(0.5) emu_hist.SetMarkerColor(2) # if with_fits: # emu_fit = self.fits.get_bin_contents([threshold]) # fits.append(emu_fit) hists.append(emu_hist) labels.append("Emu") self.__make_overlay(hists, fits, labels, "# Events", setlogy=True) def __make_overlay(self, hists, fits, labels, ytitle, suffix="", setlogy=False): with preserve_current_style(): # Draw each resolution (with fit) xtitle = self.online_title canvas = draw(hists, draw_args={ "xtitle": xtitle, "ytitle": ytitle, "logy": setlogy }) if fits: for fit, hist in zip(fits, hists): fit["asymmetric"].linecolor = hist.GetLineColor() fit["asymmetric"].Draw("same") # Add labels label_canvas() # Add a legend legend = Legend(len(hists), header=self.legend_title, topmargin=0.35, rightmargin=0.2, leftmargin=0.8, entryheight=0.028) for hist, label in zip(hists, labels): legend.AddEntry(hist, label) legend.SetBorderSize(0) legend.Draw() # Save canvas to file name = self.filename_format.format(pileup="all") self.save_canvas(canvas, name + suffix) def _is_consistent(self, new): """ Check the two plotters are the consistent, so same binning and same axis names """ return all([ self.pileup_bins.bins == new.pileup_bins.bins, self.online_name == new.online_name, ]) def _merge(self, other): """ Merge another plotter into this one """ self.plots += other.plots return self.plots
class EfficiencyPlot(BasePlotter): drawstyle = 'HISTC' drawstyle_data = 'PC' def __init__(self, online_name, offline_name): name = ["efficiency", online_name, offline_name] super(EfficiencyPlot, self).__init__("__".join(name)) self.online_name = online_name self.offline_name = offline_name def create_histograms(self, online_title, offline_title, pileup_bins, thresholds, n_bins, low, high=400, legend_title=""): """ This is not in an init function so that we can by-pass this in the case where we reload things from disk """ self.online_title = online_title self.offline_title = offline_title self.pileup_bins = bn.Sorted(pileup_bins, "pileup", use_everything_bin=True) self.thresholds = bn.GreaterThan(thresholds, "threshold") self.legend_title = legend_title name = ["efficiency", self.online_name, self.offline_name] name += ["thresh_{threshold}", "pu_{pileup}"] name = "__".join(name) title = " ".join([ self.online_name, " in PU bin: {pileup}", "and passing threshold: {threshold}" ]) self.filename_format = name def make_efficiency(labels): this_name = "efficiency" + name.format(**labels) this_title = title.format(**labels) '''Checking type of 'low' to see whether it's int (x-range minimum) or array (bin edges) for constructing TEfficiency''' if isinstance(low, np.ndarray): eff = asrootpy( ROOT.TEfficiency(this_name, this_title, n_bins, low)) else: eff = asrootpy( ROOT.TEfficiency(this_name, this_title, n_bins, low, high)) eff.drawstyle = EfficiencyPlot.drawstyle return eff self.efficiencies = HistogramCollection( [self.pileup_bins, self.thresholds], make_efficiency) def fill(self, pileup, offline, online): efficiencies = { (pu, thresh): eff for (pu, ), thresholds in self.efficiencies[pileup].items() for thresh, eff in thresholds.items() } for (pu_bin, threshold_bin), efficiency in efficiencies.items(): threshold = self.thresholds.get_bin_center(threshold_bin) passed = False if isinstance(threshold, str): continue elif online > threshold: passed = True efficiency.fill(passed, offline) def draw(self, with_fits=False): # Fit the efficiencies if requested if with_fits: self.__fit_efficiencies() # Overlay the "all" pile-up bin for each threshold all_pileup_effs = self.efficiencies.get_bin_contents( [bn.Base.everything]) hists = [] labels = [] fits = [] label_template = '{online_title} > {threshold} GeV' for threshold in all_pileup_effs.iter_all(): if not isinstance(threshold, int): continue hist = all_pileup_effs.get_bin_contents(threshold) hist.drawstyle = EfficiencyPlot.drawstyle_data self._dynamic_bin(hist) hists.append(hist) label = label_template.format( online_title=self.online_title, threshold=self.thresholds.bins[threshold], ) labels.append(label) if with_fits: fits.append( self.fits.get_bin_contents([bn.Base.everything, threshold])) self.__make_overlay( "all", "all", hists, fits, labels, self.online_title, ) if 'HiRange' not in self.filename_format: # Overlay individual pile-up bins for each threshold for threshold in self.thresholds: hists = [] labels = [] fits = [] for pileup in self.pileup_bins: if not isinstance(pileup, int): continue hist = self.efficiencies.get_bin_contents( [pileup, threshold]) hist.drawstyle = EfficiencyPlot.drawstyle_data self._dynamic_bin(hist) hists.append(hist) if with_fits: fits.append( self.fits.get_bin_contents([pileup, threshold])) labels.append(str(self.pileup_bins.bins[pileup])) self.__make_overlay(pileup, threshold, hists, fits, labels, "PU bin") # Produce the fit summary plot if with_fits: self.__summarize_fits() def overlay(self, other_plotters=None, with_fits=False): suffix = '__emu_overlay' titles = ['Hw', 'Emu'] if self.comp_title: suffix = '__comparison' titles = [ other_plotter.comp_title for other_plotter in other_plotters ] titles.insert(0, self.comp_title) # Fit the efficiencies if requested if with_fits: self.__fit_efficiencies() # Overlay the "all" pile-up bin for each threshold all_pileup_effs = self.efficiencies.get_bin_contents( [bn.Base.everything]) hists = [] labels = [] fits = [] label_template = '{online_title} > {threshold} GeV' for threshold in all_pileup_effs.iter_all(): if not isinstance(threshold, int): continue hist = all_pileup_effs.get_bin_contents(threshold) hist.drawstyle = EfficiencyPlot.drawstyle_data self._dynamic_bin(hist) hists.append(hist) label = label_template.format( online_title='L1 ' + titles[0], threshold=self.thresholds.bins[threshold], ) labels.append(label) if with_fits: fits.append( self.fits.get_bin_contents([bn.Base.everything, threshold])) for other_plotter in other_plotters: pileup_effs = other_plotter.efficiencies.get_bin_contents( [bn.Base.everything]) for threshold in pileup_effs.iter_all(): if not isinstance(threshold, int): continue hist = pileup_effs.get_bin_contents(threshold) hist.drawstyle = EfficiencyPlot.drawstyle_data self._dynamic_bin(hist) hists.append(hist) label = label_template.format( online_title='L1 ' + titles[other_plotters.index(other_plotter) + 1], threshold=other_plotter.thresholds.bins[threshold], ) labels.append(label) if with_fits: fits.append( other_plotter.fits.get_bin_contents( [bn.Base.everything, threshold])) self.__make_overlay( "all", suffix, hists, fits, labels, self.online_title, ) ''' # Overlay individual pile-up bins for each threshold for threshold in self.thresholds: hists = [] labels = [] fits = [] for pileup in self.pileup_bins: if not isinstance(pileup, int): continue hist = self.efficiencies.get_bin_contents([pileup, threshold]) hist.drawstyle = "EP" hists.append(hist) if with_fits: fits.append(self.fits.get_bin_contents( [pileup, threshold])) labels.append(str(self.pileup_bins.bins[pileup])) self.__make_overlay(pileup, threshold, hists, fits, labels, "PU bin") ''' # Produce the fit summary plot if with_fits: self.__summarize_fits() def __fit_efficiencies(self): def make_fit(labels): pileup_bin = labels["pileup"] threshold_bin = labels["threshold"] efficiency = self.efficiencies.get_bin_contents( [pileup_bin, threshold_bin]) params = fit_efficiency( efficiency, self.thresholds.get_bin_center(threshold_bin)) return params # Actually make the efficiencies self.fits = HistogramCollection([self.pileup_bins, self.thresholds], make_fit) def __make_overlay(self, pileup, threshold, hists, fits, labels, header): with preserve_current_style(): name = self.filename_format.format(pileup=pileup, threshold=threshold) xmin = int(hists[0].GetTotalHistogram().GetBinLowEdge(1)) xmax = int(hists[0].GetTotalHistogram().GetBinLowEdge( hists[0].GetTotalHistogram().GetNbinsX() + 1)) xtitle = "" if 'Jet' in self.online_title: xtitle = "Jet #it{p}_{T} (GeV)" if 'HT' in self.online_title: xtitle = "#it{H}_{T} (GeV)" if 'MET' in self.online_title: xtitle = "#it{E}_{T}^{miss} (GeV)" # Draw each efficiency (with fit) draw_args = { "xtitle": xtitle, "ytitle": "Efficiency", "xlimits": [xmin, xmax] } canvas = draw(hists, draw_args=draw_args) if len(fits) > 0: for fit, hist in zip(fits, hists): fit["asymmetric"].linecolor = hist.GetLineColor() fit["asymmetric"].Draw("same") # Add labels label_canvas() # Add a legend legend = Legend( len(hists), header=self.legend_title, topmargin=0.25, rightmargin=0.25, leftmargin=0.69, textsize=0.025, entryheight=0.028, ) for hist, label in zip(hists, labels): legend.AddEntry(hist, label) legend.SetBorderSize(0) legend.Draw() for val in [0.25, 0.5, 0.75, 0.95, 1.]: line = ROOT.TLine(xmin, val, xmax, val) line.SetLineStyle("dashed") line.SetLineColor(15) line.Draw() for t in xrange(xmin, xmax, 20): line = ROOT.TLine(t, 0., t, 1.) line.SetLineStyle("dashed") line.SetLineColor(15) line.Draw() # Save canvas to file self.save_canvas(canvas, name) def __summarize_fits(self): """ Implement this to show fit evolution plots """ # TODO: Implement this __summarize_fits methods pass def _is_consistent(self, new): """ Check the two plotters are the consistent, so same binning and same axis names """ return all([ self.pileup_bins.bins == new.pileup_bins.bins, self.thresholds.bins == new.thresholds.bins, self.online_name == new.online_name, self.offline_name == new.offline_name, ]) def _merge(self, other): """ Merge another plotter into this one """ self.efficiencies += other.efficiencies return self.efficiencies def _dynamic_bin(self, eff): """ Re-build efficiency plots so that there are no bins with < min_ entries """ min_ = 16 total = [] passed = [] bins = [] bins.append(eff.GetTotalHistogram().GetBinLowEdge(1)) nbins = eff.GetTotalHistogram().GetNbinsX() merge_total = 0 merge_passed = 0 for bin in range(1, nbins + 1): next_bin_total = eff.GetTotalHistogram().GetBinContent(bin + 1) merge_total += eff.GetTotalHistogram().GetBinContent(bin) merge_passed += eff.GetPassedHistogram().GetBinContent(bin) if bin == nbins: merge_total += eff.GetTotalHistogram().GetBinContent(bin + 1) merge_passed += eff.GetPassedHistogram().GetBinContent(bin + 1) if (next_bin_total > min_ and merge_total > min_) or bin == nbins: bins.append(eff.GetTotalHistogram().GetBinLowEdge(bin + 1)) total.append(merge_total) passed.append(merge_passed) merge_total = 0 merge_passed = 0 npbins = np.asarray(bins) hist_total = asrootpy( ROOT.TH1I("total", "total", len(bins) - 1, npbins)) hist_passed = asrootpy( ROOT.TH1I("passed", "passed", len(bins) - 1, npbins)) for bin in range(1, len(bins)): hist_total.SetBinContent(bin, total[bin - 1]) hist_passed.SetBinContent(bin, passed[bin - 1]) hist_total.Sumw2(False) hist_passed.Sumw2(False) eff.SetTotalHistogram(hist_total, "f") eff.SetPassedHistogram(hist_passed, "f")
class ResolutionPlot(BasePlotter): drawstyle = 'P' def __init__(self, resolution_type, online_name, offline_name): name = ["resolution", online_name, offline_name] super(ResolutionPlot, self).__init__("__".join(name)) self.online_name = online_name self.offline_name = offline_name self.resolution_method = get_resolution_function(resolution_type) def create_histograms(self, online_title, offline_title, pileup_bins, n_bins, low, high, legend_title=''): """ This is not in an init function so that we can by-pass this in the case where we reload things from disk """ self.online_title = online_title self.offline_title = offline_title self.legend_title = legend_title self.pileup_bins = bn.Sorted(pileup_bins, "pileup", use_everything_bin=True) name = ["resolution", self.online_name, self.offline_name, "pu_{pileup}"] name = "__".join(name) title = " ".join( [self.online_name, "vs.", self.offline_name, "in PU bin: {pileup}"]) title = ";".join([title, self.offline_title, self.online_title]) self.plots = HistogramCollection([self.pileup_bins], "Hist1D", n_bins, low, high, name=name, title=title) self.filename_format = name def fill(self, pileup, offline, online): difference = self.resolution_method(online, offline) self.plots[pileup].fill(difference) def draw(self, with_fits=False): hists = [] labels = [] fits = [] for (pile_up, ), hist in self.plots.flat_items_all(): if pile_up == bn.Base.everything: # hist.linestyle = "dashed" hist.drawstyle = ResolutionPlot.drawstyle label = "All PU" elif isinstance(pile_up, int): hist.drawstyle = ResolutionPlot.drawstyle if self.pileup_bins.get_bin_upper(pile_up) < 500: label = "{:.0f} \\leq PU < {:.0f}".format( self.pileup_bins.get_bin_lower(pile_up), self.pileup_bins.get_bin_upper(pile_up), ) else: label = "{:.0f} < PU".format( self.pileup_bins.get_bin_lower(pile_up)) else: continue hist.SetMarkerSize(0.5) hist.SetLineWidth(1) hists.append(hist) labels.append(label) # if with_fits: # fits.append(self.fits.get_bin_contents([pile_up])) # self.__make_overlay(hists, fits, labels, "Number of events") normed_hists = list(normalise_to_unit_area(hists)) for hist in normed_hists: hist.GetYaxis().SetRangeUser(-0.1, 1.1) self.__make_overlay(normed_hists, fits, labels, "a.u.") def overlay_with_emu(self, emu_plotter, with_fits=False): hists = [] labels = [] fits = [] for (pile_up, ), hist in self.plots.flat_items_all(): if pile_up == bn.Base.everything: hist.SetLineStyle(1) hist.drawstyle = ResolutionPlot.drawstyle label = "HW, all PU" else: continue hist.SetMarkerSize(0.5) hist.SetLineWidth(1) hists.append(hist) labels.append(label) for (pile_up, ), hist in emu_plotter.plots.flat_items_all(): if pile_up == bn.Base.everything: hist.SetLineStyle(1) hist.drawstyle = ResolutionPlot.drawstyle label = "Emu, all PU" else: continue hist.SetMarkerSize(0.5) hist.SetLineWidth(1) hists.append(hist) labels.append(label) # self.__make_overlay(hists, fits, labels, # "Number of events", "__Overlay_Emu") normed_hists = list(normalise_to_unit_area(hists)) for hist in normed_hists: hist.GetYaxis().SetRangeUser(-0.1, 1.1) self.__make_overlay(normed_hists, fits, labels, "a.u.", "__Overlay_Emu") def __make_overlay(self, hists, fits, labels, ytitle, suffix=""): with preserve_current_style(): # Draw each resolution (with fit) # TODO: this feels like it does not belong here for hist in hists: hist.GetYaxis().SetRangeUser(0, 0.1) hist.GetYaxis().SetTitleOffset(1.4) xtitle = self.resolution_method.label.format( on=self.online_title, off=self.offline_title) canvas = draw(hists, draw_args={ "xtitle": xtitle, "ytitle": ytitle}) if fits: for fit, hist in zip(fits, hists): fit["asymmetric"].linecolor = hist.GetLineColor() fit["asymmetric"].Draw("same") # Add labels label_canvas() # Add a legend legend = Legend( len(hists), header=self.legend_title, topmargin=0.35, rightmargin=0.3, leftmargin=0.7, textsize=0.03, entryheight=0.03, ) for hist, label in zip(hists, labels): legend.AddEntry(hist, label) legend.SetBorderSize(0) legend.Draw() ymax = 1.2 * max([hist.GetMaximum() for hist in hists]) line = ROOT.TLine(0., 0., 0., ymax) line.SetLineColor(15) # Save canvas to file name = self.filename_format.format(pileup="all") self.save_canvas(canvas, name + suffix) def _is_consistent(self, new): """ Check the two plotters are the consistent, so same binning and same axis names """ return all([self.pileup_bins.bins == new.pileup_bins.bins, self.resolution_method == new.resolution_method, self.online_name == new.online_name, self.offline_name == new.offline_name, ]) def _merge(self, other): """ Merge another plotter into this one """ self.plots += other.plots return self.plots
class OnlineVsOffline(BasePlotter): def __init__(self, online_name, offline_name): name = ["online_vs_offline", online_name, offline_name] super(OnlineVsOffline, self).__init__("__".join(name)) self.online_name = online_name self.offline_name = offline_name def create_histograms( self, online_title, offline_title, pileup_bins, n_bins, low, high=400., ): """ This is not in an init function so that we can by-pass this in the case where we reload things from disk """ self.online_title = online_title self.offline_title = offline_title self.pileup_bins = bn.Sorted( pileup_bins, "pileup", use_everything_bin=True, ) nameTokens = [ "onlineVsOffline", self.online_name, self.offline_name, "pu_{pileup}", ] name = "__".join(nameTokens) title = " ".join([ self.online_name, "vs.", self.offline_name, "in PU bin: {pileup}", ]) title = ";".join([title, self.offline_title, self.online_title]) if isinstance(low, np.ndarray): self.plots = HistogramCollection( [self.pileup_bins], "Hist2D", low, low, name=name, title=title, ) else: self.plots = HistogramCollection( [self.pileup_bins], "Hist2D", n_bins, low, high, n_bins, low, high, name=name, title=title, ) self.filename_format = name def fill(self, pileup, offline, online): self.plots[pileup].fill(offline, online) def draw(self, with_fits=True): for pileup in self.pileup_bins.iter_all(): plot = self.plots.get_bin_contents([pileup]) self.__do_draw(self.pileup_bins.get_bin_center(pileup), plot) def __do_draw(self, pileup, hist): with preserve_current_style(): # Draw each efficiency (with fit) canvas = draw2D(hist, draw_args={ "xtitle": self.offline_title, "ytitle": self.online_title }) canvas.SetLogz(True) # Add labels label_canvas() # Save canvas to file name = self.filename_format.format(pileup=pileup) self.save_canvas(canvas, name) def _is_consistent(self, new): """ Check the two plotters are the consistent, so same binning and same axis names """ return all([ self.pileup_bins.bins == new.pileup_bins.bins, self.online_name == new.online_name, self.offline_name == new.offline_name, ]) def _merge(self, other): """ Merge another plotter into this one """ self.plots += other.plots return self.plots
class ResolutionVsXPlot(BasePlotter): def __init__(self, resolution_type, online_name, offline_name, versus_name): name = ["resolution_vs_" + versus_name, online_name, offline_name] super(ResolutionVsXPlot, self).__init__("__".join(name)) self.online_name = online_name self.offline_name = offline_name self.versus_name = versus_name self.resolution_method = get_resolution_function(resolution_type) def create_histograms( self, online_title, offline_title, versus_title, pileup_bins, res_n_bins, res_low, res_high, vs_n_bins, vs_low, vs_high): """ This is not in an init function so that we can by-pass this in the case where we reload things from disk """ self.online_title = online_title self.offline_title = offline_title self.versus_title = versus_title self.ymin = res_low self.ymax = res_high self.pileup_bins = bn.Sorted(pileup_bins, "pileup", use_everything_bin=True) nameTokens = [ "resolution_vs", self.versus_name, self.online_name, self.offline_name, "pu_{pileup}", ] name = "__".join(nameTokens) title = 'Resolution ({online_name} vs. {offline_name}) ' title += 'against {versus_name}' title = title.format( online_name=self.online_name, offline_name=self.offline_name, versus_name=self.versus_name, ) title += " in PU bin: {pileup}" title = ";".join([title, self.offline_title, self.online_title]) self.plots = HistogramCollection( [self.pileup_bins], "Hist2D", vs_n_bins, vs_low, vs_high, res_n_bins, res_low, res_high, name=name, title=title) self.filename_format = name def fill(self, pileup, versus, offline, online): difference = self.resolution_method(online, offline) self.plots[pileup].fill(versus, difference) def draw(self, with_fits=True): for (pileup, ), hist in self.plots.flat_items_all(): self.__do_draw(pileup, hist) profileX = hist.ProfileX() projectionX = deepcopy(hist.ProjectionX()) for i in range(hist.GetNbinsX()): pX_i = profileX.GetBinContent(i) if pX_i == 0: projectionX.SetBinContent(i, 0.) continue pX_i_err = profileX.GetBinError(i) projX_i = projectionX.GetBinContent(i) newValue = sqrt(projX_i) * pX_i_err / pX_i newError = projX_i * pX_i_err projectionX.SetBinContent(i, newValue) projectionX.SetBinError(i, 0.) profileX.SetBinError(i, newError) if projectionX.GetMaximum() > 3.: projectionX.GetYaxis().SetRangeUser(0., 2.) self.__do_draw(pileup, profileX, "_profile2") self.__do_draw(pileup, projectionX, "_profile") def __do_draw(self, pileup, hist, suffix=""): with preserve_current_style(): # Draw each efficiency (with fit) if suffix == "": ytitle = "Online Jet Energy / Offline Jet Energy" elif suffix == "_profile": ytitle = "RMS/Mean (Online Jet Energy/Offline Jet Energy)" else: ytitle = self.resolution_method.label.format( on=self.online_title, off=self.offline_title, ) canvas = draw2D( hist, draw_args={"xtitle": self.versus_title, "ytitle": ytitle}, ) # Add labels label_canvas() # Save canvas to file name = self.filename_format.format(pileup=pileup) self.save_canvas(canvas, name + suffix) def _is_consistent(self, new): """ Check the two plotters are the consistent, so same binning and same axis names """ return all([ self.pileup_bins.bins == new.pileup_bins.bins, self.resolution_method == new.resolution_method, self.versus_name == new.versus_name, self.online_name == new.online_name, self.offline_name == new.offline_name, ]) def _merge(self, other): """ Merge another plotter into this one """ self.plots += other.plots return self.plots
class RatesPlot(BasePlotter): def __init__(self, online_name): name = ["rates", online_name] super(RatesPlot, self).__init__("__".join(name)) self.online_name = online_name def create_histograms(self, online_title, pileup_bins, n_bins, low, high, legend_title=""): """ This is not in an init function so that we can by-pass this in the case where we reload things from disk """ self.online_title = online_title self.pileup_bins = bn.Sorted(pileup_bins, "pileup", use_everything_bin=True) self.legend_title = legend_title name = ["rate_vs_threshold", self.online_name, "pu_{pileup}"] name = "__".join(name) title = " ".join([self.online_name, "vs.", "in PU bin: {pileup}"]) title = ";".join([title, self.online_title]) self.plots = HistogramCollection([self.pileup_bins], "Hist1D", n_bins, low, high, name=name, title=title) self.filename_format = name def fill(self, pileup, online): self.plots[pileup].fill(online) def draw(self, with_fits=False): hists = [] labels = [] fits = [] for (pile_up, ), hist in self.plots.flat_items_all(): h = cumulative_hist(hist) h = normalise_to_collision_rate(h) if pile_up == bn.Base.everything: h.linestyle = "dashed" label = "L1 Rate" # elif isinstance(pile_up, int): # h.drawstyle = "HIST" # label = str(self.pileup_bins.bins[pile_up]) else: continue hists.append(h) labels.append(label) # if with_fits: # fits.append(self.fits.get_bin_contents([pile_up])) self.__make_overlay(hists, fits, labels, "Rate (kHz)", setlogy=True) normed_hists = list(normalise_to_unit_area(hists)) self.__make_overlay(normed_hists, fits, labels, "Fraction of events", "__shapes") def overlay(self, other_plotters=None, with_fits=False, comp=False): hists = [] labels = [] fits = [] suffix = '__emu_overlay' titles = ['Hw', 'Emu'] if comp: suffix = '__comparison' titles = [ other_plotter.comp_title for other_plotter in other_plotters ] titles.insert(0, self.comp_title) hist = self.plots.get_bin_contents([bn.Base.everything]) hist = cumulative_hist(hist) hist = normalise_to_collision_rate(hist) hist.drawstyle = "HIST" hist.SetLineWidth(3) hist.SetMarkerColor(1) # if with_fits: # fit = self.fits.get_bin_contents([threshold]) # fits.append(fit) hists.append(hist) labels.append('L1 ' + titles[0]) for other_plotter in other_plotters: hist = other_plotter.plots.get_bin_contents([bn.Base.everything]) hist = cumulative_hist(hist) hist = normalise_to_collision_rate(hist) hist.drawstyle = "HIST" hist.SetLineWidth(3) hist.SetMarkerColor(2) hist.markerstyle = 21 + other_plotters.index(other_plotter) # if with_fits: # fit = self.fits.get_bin_contents([threshold]) # fits.append(fit) hists.append(hist) labels.append('L1 ' + titles[other_plotters.index(other_plotter) + 1]) self.__make_overlay(hists, fits, labels, "Rate (kHz)", suffix, setlogy=True) def __make_overlay(self, hists, fits, labels, ytitle, suffix="", setlogy=False): with preserve_current_style(): # Draw each resolution (with fit) xtitle = "" if 'Jet' in self.online_title: xtitle = "Jet #it{p}_{T} (GeV)" if 'HT' in self.online_title: xtitle = "#it{H}_{T} (GeV)" if 'MET' in self.online_title: xtitle = "#it{E}_{T}^{miss} (GeV)" canvas = draw(hists, draw_args={ "xtitle": xtitle, "ytitle": ytitle, "logy": setlogy, "ylimits": (0.1, 50000) }) if fits: for fit, hist in zip(fits, hists): fit["asymmetric"].linecolor = hist.GetLineColor() fit["asymmetric"].Draw("same") # Add labels label_canvas() # Add a legend legend = Legend(len(hists), header=self.legend_title, topmargin=0.35, rightmargin=0.2, leftmargin=0.8, entryheight=0.028, textsize=0.03) for hist, label in zip(hists, labels): legend.AddEntry(hist, label) legend.SetBorderSize(0) legend.Draw() # Save canvas to file name = self.filename_format.format(pileup="all") self.save_canvas(canvas, name + suffix) def _is_consistent(self, new): """ Check the two plotters are the consistent, so same binning and same axis names """ return all([ self.pileup_bins.bins == new.pileup_bins.bins, self.online_name == new.online_name, ]) def _merge(self, other): """ Merge another plotter into this one """ self.plots += other.plots return self.plots def get_stats(self, summary_bins=[], summary_label=''): summary_columns = list( self._summary_columns(summary_bins, summary_label)) stats = list(self._collect_stats(summary_bins, summary_label)) df = pd.DataFrame(stats) return df[['identifier', 'total', 'overflow'] + summary_columns] def _summary_columns(self, summary_bins, summary_label): for lower, upper in zip(summary_bins[:-1], summary_bins[1:]): yield '{} {}-{}'.format(summary_label, lower, upper) def _collect_stats(self, summary_bins, summary_label): for (pileup, ), hist in self.plots.flat_items(): human_readable_threshold = '{0}; PU > {1}'.format( self.online_title, self.pileup_bins.bins[pileup]) rhist = hist.rebinned(summary_bins) stats = {} summary_columns = self._summary_columns(summary_bins, summary_label) for summary_column, y in zip(summary_columns, rhist.y()): stats[summary_column] = y total = sum(stats.values()) overflow = rhist.integral(overflow=True) - total header = dict(identifier=human_readable_threshold, total=total, overflow=overflow) header.update(stats) yield header
class RateVsPileupPlot(BasePlotter): def __init__(self, online_name): name = ["rate_vs_pileup", online_name] super(RateVsPileupPlot, self).__init__("__".join(name)) self.online_name = online_name def create_histograms(self, online_title, thresholds, n_bins, low, high, legend_title=""): """ This is not in an init function so that we can by-pass this in the case where we reload things from disk """ self.online_title = online_title self.thresholds = thresholds self.thresholds = bn.GreaterThan(thresholds, "threshold", True) self.legend_title = legend_title name = ["rate_vs_pileup", self.online_name] name += ["thresh_{threshold}"] name = "__".join(name) title = " ".join([self.online_name, " rate vs pileup", "passing threshold: {threshold}"]) self.plots = HistogramCollection([self.thresholds], "Hist1D", n_bins, low, high, name=name, title=title) self.filename_format = name def fill(self, pileup, online): self.plots[online].fill(pileup) def draw(self, with_fits=False): for (threshold, ), hist in self.plots.flat_items_all(): hists = [] labels = [] fits = [] thresholds = [] if not isinstance(threshold, int): continue label_template = '{online_title} > {threshold} GeV' label = label_template.format( online_title=self.online_title, threshold=self.thresholds.bins[threshold], ) hist.Divide(self.plots.get_bin_contents([bn.Base.everything])) hist.drawstyle = "EP" hist.SetMarkerSize(0.5) hist.SetMarkerColor(2) # if with_fits: # fit = self.fits.get_bin_contents([threshold]) # fits.append(fit) hists.append(hist) labels.append(label) thresholds.append(threshold) self.__make_overlay(hists, fits, labels, thresholds) def overlay_with_emu(self, emu_plotter, with_fits=False): for (threshold, ), hist in self.plots.flat_items_all(): hists = [] labels = [] fits = [] thresholds = [] if not isinstance(threshold, int): continue label_template = '{online_title} > {threshold} GeV' label = label_template.format( online_title=self.online_title, threshold=self.thresholds.bins[threshold], ) hist.Divide(self.plots.get_bin_contents([bn.Base.everything])) hist.drawstyle = "EP" hist.SetMarkerSize(0.5) hist.SetMarkerColor(1) # if with_fits: # fit = self.fits.get_bin_contents([threshold]) # fits.append(fit) hists.append(hist) labels.append(label) thresholds.append(threshold) for (emu_threshold, ), emu_hist in emu_plotter.plots.flat_items_all(): if emu_threshold == threshold: label_template = '{online_title} > {threshold} GeV' emu_label = label_template.format( online_title=emu_plotter.online_title, threshold=emu_plotter.thresholds.bins[threshold], ) emu_hist.Divide(emu_plotter.plots.get_bin_contents([bn.Base.everything])) emu_hist.drawstyle = "EP" emu_hist.SetMarkerSize(0.5) emu_hist.SetMarkerColor(2) # if with_fits: # emu_fit = self.fits.get_bin_contents([threshold]) # fits.append(emu_fit) hists.append(emu_hist) labels.append(emu_label) thresholds.append(emu_threshold) self.__make_overlay(hists, fits, labels, thresholds) def __make_overlay(self, hists, fits, labels, thresholds, suffix=""): with preserve_current_style(): # Draw each rate vs pileup (with fit) xtitle = "# reco vertices" ytitle = "a.u." canvas = draw(hists, draw_args={"xtitle": xtitle, "ytitle": ytitle}) if fits: for fit, hist in zip(fits, hists): fit["asymmetric"].linecolor = hist.GetLineColor() fit["asymmetric"].Draw("same") # Add labels label_canvas() # Add a legend legend = Legend( len(hists), header=self.legend_title, topmargin=0.35, rightmargin=0.7, leftmargin=0.3, textsize=0.025, entryheight=0.028, ) for hist, label in zip(hists, labels): legend.AddEntry(hist, label) legend.SetBorderSize(0) legend.Draw() # Save canvas to file name = self.filename_format.format(threshold=thresholds[0]) self.save_canvas(canvas, name + suffix) def _is_consistent(self, new): """ Check the two plotters are the consistent, so same binning and same axis names """ return all([self.thresholds.bins == new.thresholds.bins, self.online_name == new.online_name, ]) def _merge(self, other): """ Merge another plotter into this one """ self.plots += other.plots return self.plots