def mc_stack( hlist, hs_syst, systematics, colors="auto" ): if colors=="auto": coloriter = iter(plt.cm.jet(np.linspace(0,1,len(hlist)))) for h in hlist: h.color = next(coloriter) elif isinstance(colors, list) and len(colors) == len(hlist): for h, c in zip(hlist, colors): h.color = c for h in hlist: h.fillstyle = "solid" #FIXME: Temporary workaround for failed fill, only works when hatch is specified stack = hist(hlist, stacked=True, hatch=".", lw=2) htot = sum(hlist) htot.color="black" htot_u = htot.Clone() htot_d = htot.Clone() for i in range(1, htot.nbins()+1): htot_u.set_bin_content(i, htot.get_bin_content(i) + htot.get_bin_error(i)) htot_d.set_bin_content(i, htot.get_bin_content(i) - htot.get_bin_error(i)) htot_u.color="black" htot_d.color="black" fill_between(htot_u, htot_d, color="black", hatch="////////", alpha=1.0, linewidth=0, facecolor="none", edgecolor="black", zorder=10, ) #add systematic uncertainties hstat = htot_u - htot_d errs = np.array([y for y in hstat.y()]) errs = np.abs(errs) htot_usyst = htot.Clone() htot_dsyst = htot.Clone() for systUp, systDown in systematics: errs_syst_up = np.array([y for y in sum(hs_syst[systUp].values()).y()]) errs_syst_down = np.array([y for y in sum(hs_syst[systDown].values()).y()]) errs_syst = np.abs(errs_syst_up - errs_syst_down) errs = np.power(errs, 2) + np.power(errs_syst, 2) errs = np.sqrt(errs) for i in range(len(errs)): htot_usyst.SetBinContent(i+1, htot_usyst.GetBinContent(i+1) + errs[i]/2) htot_dsyst.SetBinContent(i+1, htot_dsyst.GetBinContent(i+1) - errs[i]/2) fill_between(htot_usyst, htot_dsyst, color="gray", hatch=r"\\\\", alpha=1.0, linewidth=0, facecolor="none", edgecolor="gray", zorder=10, ) return {"hists":stack, "tot":htot, "tot_u":htot_u, "tot_d":htot_d, "tot_usyst":htot_usyst, "tot_dsyst":htot_dsyst}
def draw(self, axes, facecolor = '0.75', # grey alpha = 0.5, hatch = '/', zorder = 999,): rplt.fill_between( self.__upper, self.__lower, axes, facecolor = facecolor, alpha = alpha, hatch = hatch, zorder = zorder )
def draw( self, axes, facecolor='0.75', # grey alpha=0.5, hatch='/', zorder=999, ): rplt.fill_between(self.__upper, self.__lower, axes, facecolor=facecolor, alpha=alpha, hatch=hatch, zorder=zorder)
def plot_systematic_uncertainties(systematic_uncertainties, bin_edges, variable, output_folder, subcategories=[], subname='', plot_largest=False, plot_foreground=None): ''' Plot the systematic uncertainties ''' if not subcategories: subcategories = systematic_uncertainties.keys() x_limits = [bin_edges[0], bin_edges[-1]] # y_limits = [-0.6,0.6] y_limits = [0, 0.4] fig_syst = plt.figure(figsize=(20, 16), dpi=400, facecolor='white') ax_syst = fig_syst.add_subplot(1, 1, 1) ax_syst.minorticks_on() ax_syst.xaxis.labelpad = 12 ax_syst.yaxis.labelpad = 12 error_hists_up = {} error_hists_down = {} stat_hist = None for syst, vals in systematic_uncertainties.iteritems(): if syst == 'central': n = len(systematic_uncertainties[syst]) continue elif syst == 'statistical': stat_hist_up = values_and_errors_to_hist(vals, [], bin_edges) stat_hist_down = values_and_errors_to_hist(-vals, [], bin_edges) elif syst == 'systematic': syst_hist_up = values_and_errors_to_hist(vals, [], bin_edges) syst_hist_down = values_and_errors_to_hist(-vals, [], bin_edges) elif syst in subcategories: error_hists_up[syst] = values_and_errors_to_hist( vals, [], bin_edges) error_hists_down[syst] = values_and_errors_to_hist( -vals, [], bin_edges) else: continue if plot_largest: largest_syst = [] for bin_i in range(n): high = [] for syst, vals in systematic_uncertainties.iteritems(): if syst == 'central': continue if syst == 'statistical': continue if syst == 'systematic': continue high.append([syst, vals[bin_i]]) high = sorted(high, key=itemgetter(1), reverse=True) # Retrieve highest systematics if high[0][0] not in largest_syst: largest_syst.append(high[0][0]) elif high[1][0] not in largest_syst: largest_syst.append(high[1][0]) else: continue rplt.fill_between(syst_hist_up, syst_hist_down, color='gold', label='Syst.') rplt.fill_between(stat_hist_down, stat_hist_up, color='0.75', label='Stat.') plt.tick_params(**CMS.axis_label_major) plt.tick_params(**CMS.axis_label_minor) colours = [ 'red', 'blue', 'green', 'chartreuse', 'indigo', 'magenta', 'darkmagenta', 'hotpink', 'cyan', 'darkred', 'darkgoldenrod', 'mediumvioletred', 'mediumspringgreen', 'darkgoldenrod', 'slategray', 'dodgerblue', 'cadetblue', 'darkblue', 'seagreen', 'deeppink', 'deepskyblue' ] * 2 if len(colours) < len(error_hists_up.keys()): print '---> Need to add more colours!!!' for error_hists in [error_hists_up, error_hists_down]: for i, source, in enumerate(error_hists.keys()): hist = error_hists[source] hist.linewidth = 4 hist.color = colours[i] if plot_largest: if source not in largest_syst: hist.linestyle = 'dashed' hist.alpha = 0.4 hist.linewidth = 2 # Only label systematic once if plot_foreground and plot_foreground in error_hists.keys(): source = '' if error_hists == error_hists_up: rplt.hist(hist, stacked=False, label=source) else: rplt.hist(hist, stacked=False, label='') if plot_foreground and plot_foreground in error_hists.keys(): hist = error_hists[plot_foreground] hist.color = 'black' rplt.hist(hist, stacked=False, label=source) leg = plt.legend(loc='upper right', prop={'size': 25}, ncol=3) # leg = plt.legend(loc='upper right',prop={'size':20},ncol=4) leg.draw_frame(False) x_title = variables_NonLatex[variable] if variable in ['HT', 'MET', 'WPT', 'ST', 'lepton_pt']: x_title += ' [GeV]' ax_syst.set_xlim(x_limits) ax_syst.set_ylim(y_limits) plt.xlabel(x_title, CMS.x_axis_title) plt.ylabel('Relative Uncertainty', CMS.y_axis_title) template = '%.1f fb$^{-1}$ (%d TeV)' label = template % (measurement_config.new_luminosity / 1000., measurement_config.centre_of_mass_energy) plt.title(label, loc='right', **CMS.title) logo_location = (0.05, 0.98) prelim_location = (0.05, 0.92) channel_location = (0.05, 0.86) # plt.text(logo_location[0], logo_location[1], # "CMS", # transform=ax_syst.transAxes, # fontsize=42, # verticalalignment='top', # horizontalalignment='left' # ) # # preliminary # plt.text(prelim_location[0], prelim_location[1], # r"\emph{Preliminary}", # transform=ax_syst.transAxes, # fontsize=42, # verticalalignment='top', # horizontalalignment='left' # ) # # channel text # plt.text(channel_location[0], channel_location[1], # r"\emph{%s}" % channel, # transform=ax_syst.transAxes, # fontsize=40, # verticalalignment='top', # horizontalalignment='left' # ) plt.tight_layout() file_template = output_folder + '{var}_systematics_{com}TeV'.format( var=variable, com=measurement_config.centre_of_mass_energy, ) if subname: file_template = file_template + '_' + subname file_template += '.pdf' fig_syst.savefig(file_template) print "Written plots to {f}".format(f=file_template) # plt.show() return
def plot_systematic_uncertainties(systematic_uncertainties, bin_edges, variable, output_folder, subcategories = [], subname = '', plot_largest = False): ''' Plot the systematic uncertainties ''' print subcategories if not subcategories: subcategories = systematic_uncertainties.keys() x_limits = [bin_edges[0], bin_edges[-1]] # y_limits = [-0.6,0.6] y_limits = [0,0.4] fig_syst = plt.figure( figsize = ( 20, 16 ), dpi = 400, facecolor = 'white' ) ax_syst = fig_syst.add_subplot(1, 1, 1) ax_syst.minorticks_on() ax_syst.xaxis.labelpad = 12 ax_syst.yaxis.labelpad = 12 error_hists_up = {} error_hists_down = {} stat_hist = None for syst, vals in systematic_uncertainties.iteritems(): if syst == 'central': n = len(systematic_uncertainties[syst]) continue elif syst == 'statistical': stat_hist_up = values_and_errors_to_hist( vals, [], bin_edges ) stat_hist_down = values_and_errors_to_hist( -vals, [], bin_edges ) elif syst == 'systematic': syst_hist_up = values_and_errors_to_hist( vals, [], bin_edges ) syst_hist_down = values_and_errors_to_hist( -vals, [], bin_edges ) elif syst in subcategories: error_hists_up[syst] = values_and_errors_to_hist( vals, [], bin_edges ) error_hists_down[syst] = values_and_errors_to_hist( -vals, [], bin_edges ) else: continue if plot_largest: largest_syst = [] for bin_i in range( n ): high = [] for syst, vals in systematic_uncertainties.iteritems(): if syst == 'central': continue if syst == 'statistical': continue if syst == 'systematic': continue high.append([syst,vals[bin_i]]) high = sorted(high, key = itemgetter(1), reverse=True) # Retrieve highest systematics if high[0][0] not in largest_syst: largest_syst.append(high[0][0]) elif high[1][0] not in largest_syst: largest_syst.append(high[1][0]) else: continue rplt.fill_between( syst_hist_up, syst_hist_down, color = 'yellow', label='Syst.' ) rplt.fill_between( stat_hist_down, stat_hist_up, color = 'grey', label='Stat.' ) plt.tick_params( **CMS.axis_label_major ) plt.tick_params( **CMS.axis_label_minor ) colours = ['red', 'blue', 'green', 'chartreuse', 'indigo', 'magenta', 'darkmagenta', 'hotpink', 'cyan', 'darkred', 'darkgoldenrod', 'mediumvioletred', 'mediumspringgreen', 'gold', 'darkgoldenrod', 'slategray', 'dodgerblue', 'cadetblue', 'darkblue', 'seagreen', 'deeppink', 'deepskyblue' ] # if len(colours) < len(error_hists.keys()): # print '---> Need to add more colours!!!' for error_hists in [error_hists_up, error_hists_down]: for i, source, in enumerate(error_hists.keys()): hist = error_hists[source] hist.linewidth = 4 hist.color = colours[i] if plot_largest: if source not in largest_syst: hist.linestyle = 'dashed' hist.alpha = 0.4 hist.linewidth = 2 # Only label systematic once if error_hists == error_hists_up: rplt.hist( hist, stacked=False, label = source ) else: rplt.hist( hist, stacked=False, label = '' ) leg = plt.legend(loc='upper right',prop={'size':25},ncol=3) # leg = plt.legend(loc='upper right',prop={'size':20},ncol=4) leg.draw_frame(False) x_title = variables_NonLatex[variable] if variable in ['HT', 'MET', 'WPT', 'ST', 'lepton_pt']: x_title += ' [GeV]' ax_syst.set_xlim( x_limits ) ax_syst.set_ylim( y_limits ) plt.xlabel( x_title, CMS.x_axis_title ) plt.ylabel( 'Relative Uncertainty', CMS.y_axis_title) template = '%.1f fb$^{-1}$ (%d TeV)' label = template % ( measurement_config.new_luminosity/1000, measurement_config.centre_of_mass_energy) plt.title( label,loc='right', **CMS.title ) logo_location = (0.05, 0.98) prelim_location = (0.05, 0.92) channel_location = ( 0.05, 0.86) # plt.text(logo_location[0], logo_location[1], # "CMS", # transform=ax_syst.transAxes, # fontsize=42, # verticalalignment='top', # horizontalalignment='left' # ) # # preliminary # plt.text(prelim_location[0], prelim_location[1], # r"\emph{Preliminary}", # transform=ax_syst.transAxes, # fontsize=42, # verticalalignment='top', # horizontalalignment='left' # ) # # channel text # plt.text(channel_location[0], channel_location[1], # r"\emph{%s}" % channel, # transform=ax_syst.transAxes, # fontsize=40, # verticalalignment='top', # horizontalalignment='left' # ) plt.tight_layout() file_template = output_folder + '{var}_systematics_{com}TeV'.format( var = variable, com = measurement_config.centre_of_mass_energy, ) if subname: file_template = file_template + '_' + subname file_template += '.pdf' fig_syst.savefig(file_template) print "Written plots to {f}".format(f = file_template) # plt.show() return
def make_data_mc_comparison_plot( histograms=[], histogram_lables=[], histogram_colors=[], histogram_properties=Histogram_properties(), data_index=0, save_folder='plots/', save_as=['pdf'], normalise=False, show_ratio=False, show_stat_errors_on_mc=False, draw_vertical_line=0, systematics_for_ratio=None, systematics_for_plot=None, histograms_to_compare=None, ): ''' systematics_for_plot takes the same input as systematics_for_ratio. There may be some repition with reagrds to mc_error and mc_relative_errors, but these only deal with a flat error up and down. ''' save_folder = check_save_folder(save_folder) # make copies in order not to mess with existing histograms histograms_ = deepcopy(histograms) stack = HistStack() add_mc = stack.Add for index, histogram in enumerate(histograms_): label = histogram_lables[index] color = histogram_colors[index] histogram.SetTitle(label) if normalise: histogram.Sumw2() if not index == data_index: histogram.fillstyle = 'solid' histogram.fillcolor = color histogram.legendstyle = 'F' add_mc(histogram) data = histograms_[data_index] data.SetMarkerSize(CMS.data_marker_size) if normalise: n_events_data = data.Integral() n_events_mc = stack.Integral() data.Scale(1 / n_events_data) stack.Scale(1 / n_events_mc) # plot with matplotlib plt.figure(figsize=CMS.figsize, dpi=CMS.dpi, facecolor=CMS.facecolor) axes = None if show_ratio: ratio = data.Clone('ratio') sumHists = sum(stack.GetHists()) for bin_i in range(1, sumHists.GetNbinsX()): sumHists.SetBinError(bin_i, 0) ratio.Divide(sum(stack.GetHists())) ratio.SetMarkerSize(3) gs = gridspec.GridSpec(2, 1, height_ratios=[5, 1]) axes = plt.subplot(gs[0]) else: axes = plt.axes() if histogram_properties.set_log_y: axes.set_yscale('log', nonposy="clip") axes.set_ylim(ymin=1e-2) if systematics_for_plot != None: plusErrors = [x + 1 for x in systematics_for_plot] minusErrors = [1 - x for x in systematics_for_plot] stack_lower = sum(stack.GetHists()) stack_upper = stack_lower.Clone('upper') for bin_i in range(1, stack_lower.GetNbinsX() + 1): central_value = stack_lower.GetBinContent(bin_i) error_upper_bound = plusErrors[bin_i - 1] * central_value error_lower_bound = minusErrors[bin_i - 1] * central_value stack_upper.SetBinContent(bin_i, error_upper_bound) stack_lower.SetBinContent(bin_i, error_lower_bound) rplt.fill_between( stack_lower, stack_upper, axes, hatch='//', # facecolor = 'Black', facecolor='None', edgecolor='Grey', alpha=1., linewidth=0., zorder=len(histograms_) + 1) mc_error = histogram_properties.mc_error mc_relative_errors = histogram_properties.mc_relative_errors if mc_relative_errors: stack_lower = sum(stack.GetHists()) stack_upper = stack_lower.Clone('upper') for bin_i in range(1, stack_lower.GetNbinsX()): central_value = stack_lower.GetBinContent(bin_i) relative_error = mc_relative_errors[bin_i - 1] error_upper_bound = central_value * (1 + relative_error) error_lower_bound = central_value * (1 - relative_error) stack_lower.SetBinContent(bin_i, error_upper_bound) stack_upper.SetBinContent(bin_i, error_lower_bound) rplt.fill_between(stack_upper, stack_lower, axes, facecolor='0.75', alpha=0.5, hatch='/', zorder=len(histograms_) + 1) else: if mc_error > 0: stack_lower = sum(stack.GetHists()) stack_upper = stack_lower.Clone('upper') stack_lower.Scale(1 - mc_error) stack_upper.Scale(1 + mc_error) rplt.fill_between(stack_upper, stack_lower, axes, facecolor='0.75', alpha=0.5, hatch='/', zorder=len(histograms_) + 1) if not mc_error > 0 and show_stat_errors_on_mc: stack_lower = sum(stack.GetHists()) mc_errors = list(stack_lower.yerravg()) stack_upper = stack_lower.Clone('upper') for bin_i in range(1, stack_lower.GetNbinsX()): central_value = stack_lower.GetBinContent(bin_i) error = mc_errors[bin_i - 1] error_upper_bound = central_value + error error_lower_bound = central_value - error stack_lower.SetBinContent(bin_i, error_lower_bound) stack_upper.SetBinContent(bin_i, error_upper_bound) rplt.fill_between(stack_upper, stack_lower, axes, facecolor='0.75', alpha=0.5, hatch='/', zorder=len(histograms_) + 1) # a comment on zorder: the MC stack should be always at the very back (z = 1), # then the MC error (z = len(histograms_) + 1) and finally the data # (z = len(histograms_) + 2) rplt.hist(stack, stacked=True, axes=axes, zorder=1) rplt.errorbar(data, emptybins=histogram_properties.emptybins, axes=axes, xerr=histogram_properties.xerr, elinewidth=2, capsize=10, capthick=2, zorder=len(histograms_) + 2) if histograms_to_compare: h_compare = {} for h, l, c in zip(histograms_to_compare['hists'], histograms_to_compare['labels'], histograms_to_compare['colours']): for histogram in histograms_: if histogram.GetTitle() not in [ histograms_to_compare['to_replace'], 'data' ]: h += histogram h_compare[l] = [h, c] rplt.step( h, axes=axes, label=l, color=c, linewidth=4, ) # put legend into the correct order (data is always first!) handles, labels = axes.get_legend_handles_labels() data_label_index = labels.index('data') data_handle = handles[data_label_index] labels.remove('data') handles.remove(data_handle) labels.insert(0, 'data') handles.insert(0, data_handle) if mc_error > 0 or (not mc_error > 0 and show_stat_errors_on_mc): p1 = Rectangle((0, 0), 1, 1, fc="0.75", alpha=0.5, hatch='/') handles.append(p1) labels.append(histogram_properties.mc_errors_label) l1 = axes.legend(handles, labels, numpoints=1, frameon=histogram_properties.legend_color, bbox_to_anchor=histogram_properties.legend_location, bbox_transform=plt.gcf().transFigure, prop=CMS.legend_properties, ncol=histogram_properties.legend_columns) l1.set_zorder(102) set_labels(plt, histogram_properties, show_x_label=not show_ratio, axes=axes) x_limits = histogram_properties.x_limits y_limits = histogram_properties.y_limits if len(x_limits) >= 2: axes.set_xlim(xmin=x_limits[0], xmax=x_limits[-1]) if len(y_limits) >= 2: axes.set_ylim(ymin=y_limits[0], ymax=y_limits[-1]) else: y_max = get_best_max_y( histograms_, x_limits=x_limits) * histogram_properties.y_max_scale print("Chosen limits : ", 0, y_max) axes.set_ylim(ymin=0, ymax=y_max) if histogram_properties.set_log_y: if not len(y_limits) == 2: # if not user set y-limits, set default axes.set_ylim(ymin=1e-1) #draw a red vertical line if needed: if draw_vertical_line != 0: plt.axvline(x=draw_vertical_line, color='red', linewidth=3) if show_ratio: plt.setp(axes.get_xticklabels(), visible=False) ax1 = plt.subplot(gs[1]) ax1.minorticks_on() ax1.grid(True, 'major', linewidth=1) ax1.axhline(y=1, linewidth=1) set_labels(plt, histogram_properties, show_x_label=True, show_title=False) plt.ylabel(r'$\frac{\mathrm{data}}{\mathrm{pred.}}$', CMS.y_axis_title) ax1.yaxis.set_label_coords(-0.115, 0.8) rplt.errorbar(ratio, emptybins=histogram_properties.emptybins, axes=ax1, xerr=histogram_properties.xerr, elinewidth=1.5, capsize=5, capthick=1.5) if histograms_to_compare: for l, h in h_compare.iteritems(): r = data.Clone(l).Divide(h[0]) rplt.step( r, axes=ax1, label='', colour=h[1], linewidth=2, ) if len(x_limits) >= 2: ax1.set_xlim(xmin=x_limits[0], xmax=x_limits[-1]) if len(histogram_properties.ratio_y_limits) >= 2: ax1.set_ylim(ymin=histogram_properties.ratio_y_limits[0], ymax=histogram_properties.ratio_y_limits[-1]) # dynamic tick placement adjust_ratio_ticks(ax1.yaxis, n_ticks=3, y_limits=histogram_properties.ratio_y_limits) if histogram_properties.integerXVariable: ax1.tick_params(axis='x', which='minor', bottom='off', top='off') if systematics_for_ratio != None: plusErrors = [x + 1 for x in systematics_for_ratio] minusErrors = [1 - x for x in systematics_for_ratio] ratioPlusError = ratio.Clone('plus') ratioMinusError = ratio.Clone('minus') for bin_i in range(1, ratioPlusError.GetNbinsX() + 1): ratioPlusError.SetBinContent(bin_i, plusErrors[bin_i - 1]) ratioMinusError.SetBinContent(bin_i, minusErrors[bin_i - 1]) rplt.fill_between( ratioPlusError, ratioMinusError, axes, hatch='//', # facecolor = 'Black', facecolor='None', edgecolor='Grey', alpha=1., linewidth=0., # zorder = len(histograms_) + 1 zorder=0) if CMS.tight_layout: plt.tight_layout() for save in save_as: if save == 'root': saveHistogramsToROOTFile( data, stack, save_folder + histogram_properties.name + '.' + save) else: plt.savefig(save_folder + histogram_properties.name + '.' + save) plt.close()
def draw_data_mc(tf, hname, processes, signal_processes, **kwargs): """ Given a root file in the combine datacard format, draws a data/mc histogram, ratio and systematic band. tf (TFile): input root file hname (string): name of histogram, example "sl_jge6_tge4/jetsByPt_0_pt" processes (list of (str, str) tuples): processes to use for the plot. First argument of tuple is the name in the file, second the name on the plot. The order here defines the order of plotting (bottom to top). Assume that signal is the first process. signal_processes (list of str): process names to consider as signal """ # name (string) of the data process. # Example: "data" (real data), "data_obs" (fake data) #must exist in the input file dataname = kwargs.get("dataname", "data_obs") xlabel = kwargs.get("xlabel", escape_string(hname)) xunit = kwargs.get("xunit", "XUNIT") ylabel = kwargs.get("ylabel", "auto") rebin = kwargs.get("rebin", 1) title_extended = kwargs.get("title_extended", "") #legend properties do_legend = kwargs.get("do_legend", True) legend_loc = kwargs.get("legend_loc", (1.1,0.1)) legend_fontsize = kwargs.get("legend_fontsize", 6) #Dictionary of sample (string) -> color (tuple of floats) to use as colors #or "auto" to generate a sequence of colors colors = kwargs.get("colors", "auto") #True if you want to put the contents of the overflow bin into the last #visible bin of the histogram, False otherwise show_overflow = kwargs.get("show_overflow", False) #function f: TH1D -> TH1D to apply on data to blind it. blindFunc = kwargs.get("blindFunc", None) #array of up-down pairs for systematic names to use for the systematic band, #e.g.[("_CMS_scale_jUp", "_CMS_scale_jDown")] systematics = kwargs.get("systematics", []) histograms_nominal = getHistograms(tf, processes, hname) if len(histograms_nominal) == 0: raise KeyError("did not find any histograms for MC") histograms_systematic = OrderedDict() #get the systematically variated histograms for systUp, systDown in systematics: histograms_systematic[systUp] = getHistograms(tf, processes, hname+systUp) histograms_systematic[systDown] = getHistograms(tf, processes, hname+systDown) if len(histograms_systematic[systUp])==0 or len(histograms_systematic[systDown])==0: print "Could not read histograms for {0}".format(hname+systUp) processes_d = dict(processes) for histo_dict in [histograms_nominal] + histograms_systematic.values(): for (proc, h) in histo_dict.items(): h.title = processes_d[proc] + " ({0:.1f})".format(h.Integral()) h.rebin(rebin) if show_overflow: fill_overflow(h) c = plt.figure(figsize=(6,6)) #Create top panel a1 = plt.axes([0.0, 0.22, 1.0, 0.8]) c.suptitle(r"$\textbf{CMS}$ preliminary $\sqrt{s} = 13$ TeV"+title_extended, y=1.02, x=0.02, horizontalalignment="left", verticalalignment="bottom", fontsize=16 ) stacked_hists = mc_stack( histograms_nominal.values(), histograms_systematic, systematics, colors = colors ) #Create the normalized signal shape histogram_signal = sum([histograms_nominal[sig] for sig in signal_processes]) histogram_total_mc = sum(histograms_nominal.values()) #hsig.Rebin(2) if histogram_signal.Integral()>0: histogram_signal.Scale(0.2 * histogram_total_mc.Integral() / histogram_signal.Integral()) histogram_signal.title = processes[0][1] + " norm" histogram_signal.linewidth=2 histogram_signal.fillstyle = None #draw the signal shape hist([histogram_signal]) histogram_total_mc.title = "pseudodata" histogram_total_mc.color = "black" histogram_total_bkg = sum([ histograms_nominal[k] for k in histograms_nominal.keys() if k not in signal_processes] ) #Get the data histogram data = None if dataname != "": data = tf.get(dataname + "/" + hname) data.rebin(rebin) if blindFunc: data = blindFunc(data) if show_overflow: fill_overflow(data) data.title = "data ({0:.2f})".format(data.Integral()) #set data error to 0 in case no data (FIXME) for ibin in range(data.GetNbinsX()): if data.GetBinContent(ibin) == 0: data.SetBinError(ibin, 1) errorbar(data) if do_legend: #create nice filled legend patches for all the processes patches = [] if data: dataline = mlines.Line2D([], [], color='black', marker='o', label=data.title) patches += [dataline] for (line1, line2), h in zip(stacked_hists["hists"], histograms_nominal.values()): patch = mpatches.Patch(color=line1.get_color(), label=h.title) patches += [patch] patches += [mpatches.Patch(facecolor="none", edgecolor="black", label="stat", hatch="////////")] patches += [mpatches.Patch(facecolor="none", edgecolor="gray", label="stat+syst", hatch=r"\\\\")] plt.legend(handles=patches, loc=legend_loc, numpoints=1, prop={'size':legend_fontsize}, ncol=2, frameon=False) #create an automatic bin width label on the y axis if ylabel == "auto": ylabel = "events / {0:.2f} {1}".format(histogram_signal.get_bin_width(1), xunit) plt.ylabel(ylabel) #hide x ticks on main panel ticks = a1.get_xticks() a1.get_xaxis().set_visible(False) a1.set_ylim(bottom=0, top=1.1*a1.get_ylim()[1]) a1.grid(zorder=100000) a2 = a1 #do ratio panel if data: a2 = plt.axes([0.0,0.0, 1.0, 0.18], sharex=a1) plt.xlabel(xlabel) a2.grid() data_ratio = data.Clone() data_ratio.Divide(histogram_total_mc) #In case MC was empty, set data/mc ratio to 0 for ibin in range(data_ratio.GetNbinsX()): bc = histogram_total_mc.GetBinContent(ibin) if bc==0: data_ratio.SetBinContent(ibin, 0) #create also the variated band bg_unc_u = stacked_hists["tot_u"] bg_unc_d = stacked_hists["tot_d"] bg_unc_u.Divide(stacked_hists["tot"]) bg_unc_d.Divide(stacked_hists["tot"]) bg_unc_usyst = stacked_hists["tot_usyst"] bg_unc_dsyst = stacked_hists["tot_dsyst"] bg_unc_usyst.Divide(stacked_hists["tot"]) bg_unc_dsyst.Divide(stacked_hists["tot"]) #blind the data also on the ratio if blindFunc: data_ratio = blindFunc(data_ratio) errorbar(data_ratio) fill_between( bg_unc_u, bg_unc_d, color="black", hatch="////////", alpha=1.0, linewidth=0, facecolor="none", edgecolor="black", zorder=10, ) fill_between( bg_unc_usyst, bg_unc_dsyst, color="gray", hatch=r"\\\\", alpha=1.0, linewidth=0, facecolor="none", edgecolor="gray", zorder=10, ) plt.title("data={0:.1f}\ MC={1:.1f}".format( data.Integral(), stacked_hists["tot"].Integral() ), x=0.01, y=0.8, fontsize=10, horizontalalignment="left" ) plt.ylabel(r"$\frac{\mathrm{data}}{\mathrm{pred.}}$", fontsize=16) plt.axhline(1.0, color="black") a2.set_ylim(0, 2) #hide last tick on ratio y axes a2.set_yticks(a2.get_yticks()[:-1]); a2.set_xticks(ticks); return a1, a2, histograms_nominal, stacked_hists, histograms_systematic
def draw_data_mc(tf, hname, samples, **kwargs): do_pseudodata = kwargs.get("do_pseudodata", False) dataname = kwargs.get("dataname", None) xlabel = kwargs.get("xlabel", hname.replace("_", " ")) xunit = kwargs.get("xunit", "XUNIT") ylabel = kwargs.get("ylabel", "auto") rebin = kwargs.get("rebin", 1) title_extended = kwargs.get("title_extended", "") do_legend = kwargs.get("do_legend", True) legend_loc = kwargs.get("legend_loc", (1.1,0.1)) legend_fontsize = kwargs.get("legend_fontsize", 6) colors = kwargs.get("colors", "auto") show_overflow = kwargs.get("show_overflow", False) blindFunc = kwargs.get("blindFunc", None) #array of up-down pairs for systematic names, e.g. _CMS_scale_jUp/Down systematics = kwargs.get("systematics", []) hs = OrderedDict() hs_syst = OrderedDict() hs = getHistograms(tf, samples, hname) #get the systematically variated histograms for systUp, systDown in systematics: hs_syst[systUp] = getHistograms(tf, samples, hname+systUp) hs_syst[systDown] = getHistograms(tf, samples, hname+systDown) if len(hs_syst[systUp])==0 or len(hs_syst[systDown])==0: print "Could not read histograms for {0}".format(hname+systUp) sample_d = dict(samples) for hd in [hs] + hs_syst.values(): for (sample, h) in hd.items(): make_uoflow(h) h.title = sample_d[sample] + " ({0:.1f})".format(h.Integral()) h.rebin(rebin) if show_overflow: fill_overflow(h) c = plt.figure(figsize=(6,6)) if do_pseudodata or dataname: a1 = plt.axes([0.0,0.22, 1.0, 0.8]) else: a1 = plt.axes() c.suptitle("$\\textbf{CMS}$ preliminary $\sqrt{s} = 13$ TeV"+title_extended, y=1.02, x=0.02, horizontalalignment="left", verticalalignment="bottom", fontsize=16 ) if len(hs) == 0: raise KeyError("did not find any histograms for MC") r = mc_stack(hs.values(), hs_syst, systematics, colors=colors) #Create the normalized signal shape hsig = hs[samples[0][0]].Clone() tot_mc = sum(hs.values()) #hsig.Rebin(2) if hsig.Integral()>0: hsig.Scale(0.2 * tot_mc.Integral() / hsig.Integral()) hsig.title = samples[0][1] + " norm" hsig.linewidth=2 hsig.fillstyle = None hist([hsig]) tot_mc.title = "pseudodata" tot_mc.color = "black" tot_bg = sum([hs[k] for k in hs.keys() if "tth" not in k]) data = None if do_pseudodata: data = tot_mc.Clone() data.title = "pseudodata" if blindFunc: data = blindFunc(data) idata = data.Integral() elif dataname: datas = [] for dn in dataname: try: h = tf.get(dn + "/" + hname) datas += [tf.get(dn + "/" + hname).Clone()] except rootpy.io.file.DoesNotExist: print "missing", dn, hname if len(datas)>0: data = sum(datas) data.rebin(rebin) else: data = tot_mc.Clone() data.Scale(0.0) if blindFunc: data = blindFunc(data) data.title = "data ({0})".format(data.Integral()) idata = data.Integral() if data and (blindFunc is None): if show_overflow: fill_overflow(data) for ibin in range(data.GetNbinsX()): if data.GetBinContent(ibin) == 0: data.SetBinError(ibin, 1) errorbar(data) if do_legend: patches = [] if data: dataline = mlines.Line2D([], [], color='black', marker='o', label=data.title) patches += [dataline] for line, h in zip(r["hists"], hs.values()): #import pdb #pdb.set_trace() patch = mpatches.Patch(color=line[0].get_color(), label=h.title) patches += [patch] patches += [mpatches.Patch(facecolor="none", edgecolor="black", label="stat", hatch="////////")] patches += [mpatches.Patch(facecolor="none", edgecolor="gray", label="stat+syst", hatch="\\\\\\\\")] plt.legend(handles=patches, loc=legend_loc, numpoints=1, prop={'size':legend_fontsize}, ncol=2, frameon=False) if ylabel == "auto": ylabel = "events / {0:.2f} {1}".format(hs.values()[0].get_bin_width(1), xunit) plt.ylabel(ylabel) if not data: plt.xlabel(xlabel) #hide x ticks on main panel ticks = a1.get_xticks() if data: a1.get_xaxis().set_visible(False) #print ticks a1.set_ylim(bottom=0, top=1.1*a1.get_ylim()[1]) a1.grid(zorder=100000) a2 = a1 #do ratio panel if data: a2 = plt.axes([0.0,0.0, 1.0, 0.18], sharex=a1) plt.xlabel(xlabel) a2.grid() data.Divide(tot_mc) for ibin in range(data.GetNbinsX()): bc = tot_mc.GetBinContent(ibin) if bc==0: data.SetBinContent(ibin, 0) bg_unc_u = r["tot_u"] bg_unc_d = r["tot_d"] bg_unc_u.Divide(r["tot"]) bg_unc_d.Divide(r["tot"]) bg_unc_usyst = r["tot_usyst"] bg_unc_dsyst = r["tot_dsyst"] bg_unc_usyst.Divide(r["tot"]) bg_unc_dsyst.Divide(r["tot"]) if blindFunc: data = blindFunc(data) errorbar(data) fill_between( bg_unc_u, bg_unc_d, color="black", hatch="////////", alpha=1.0, linewidth=0, facecolor="none", edgecolor="black", zorder=10, ) fill_between( bg_unc_usyst, bg_unc_dsyst, color="gray", hatch="\\\\\\\\", alpha=1.0, linewidth=0, facecolor="none", edgecolor="gray", zorder=10, ) plt.title("data={0:.1f}\ MC={1:.1f}".format(idata, r["tot"].Integral()), x=0.01, y=0.8, fontsize=10, horizontalalignment="left") plt.ylabel("$\\frac{\mathrm{data}}{\mathrm{pred.}}$", fontsize=16) plt.axhline(1.0, color="black") a2.set_ylim(0, 2) #hide last tick on ratio y axes a2.set_yticks(a2.get_yticks()[:-1]); a2.set_xticks(ticks); return a1, a2, hs, r, hs_syst
def make_data_mc_comparison_plot( histograms = [], histogram_lables = [], histogram_colors = [], histogram_properties = Histogram_properties(), data_index = 0, save_folder = 'plots/', save_as = ['pdf'], normalise = False, show_ratio = False, show_stat_errors_on_mc = False, draw_vertical_line = 0, systematics_for_ratio = None ): save_folder = check_save_folder(save_folder) # make copies in order not to mess with existing histograms histograms_ = deepcopy(histograms) stack = HistStack() add_mc = stack.Add for index, histogram in enumerate( histograms_ ): label = histogram_lables[index] color = histogram_colors[index] histogram.SetTitle( label ) if normalise: histogram.Sumw2() if not index == data_index: histogram.fillstyle = 'solid' histogram.fillcolor = color histogram.legendstyle = 'F' add_mc( histogram ) data = histograms_[data_index] data.SetMarkerSize( CMS.data_marker_size ) if normalise: n_events_data = data.Integral() n_events_mc = stack.Integral() data.Scale( 1 / n_events_data ) stack.Scale( 1 / n_events_mc ) # plot with matplotlib plt.figure( figsize = CMS.figsize, dpi = CMS.dpi, facecolor = CMS.facecolor ) axes=None if show_ratio: ratio = data.Clone( 'ratio' ) ratio.Divide( sum( stack.GetHists() ) ) ratio.SetMarkerSize( 3 ) gs = gridspec.GridSpec( 2, 1, height_ratios = [5, 1] ) axes = plt.subplot( gs[0] ) else: axes = plt.axes() if histogram_properties.set_log_y: axes.set_yscale( 'log', nonposy = "clip" ) axes.set_ylim( ymin = 1e-2 ) mc_error = histogram_properties.mc_error if mc_error > 0: stack_lower = sum( stack.GetHists() ) stack_upper = stack_lower.Clone( 'upper' ) stack_lower.Scale( 1 - mc_error ) stack_upper.Scale( 1 + mc_error ) rplt.fill_between( stack_upper, stack_lower, axes, facecolor = '0.75', alpha = 0.5, hatch = '/', zorder = len(histograms_) + 1 ) if not mc_error > 0 and show_stat_errors_on_mc: stack_lower = sum( stack.GetHists() ) mc_errors = list( stack_lower.yerravg() ) stack_upper = stack_lower.Clone( 'upper' ) for bin_i in range( 1, stack_lower.GetNbinsX() ): stack_lower.SetBinContent( bin_i, stack_lower.GetBinContent( bin_i ) - mc_errors[bin_i - 1] ) stack_upper.SetBinContent( bin_i, stack_upper.GetBinContent( bin_i ) + mc_errors[bin_i - 1] ) rplt.fill_between( stack_upper, stack_lower, axes, facecolor = '0.75', alpha = 0.5, hatch = '/', zorder = len(histograms_) + 1 ) # a comment on zorder: the MC stack should be always at the very back (z = 1), # then the MC error (z = len(histograms_) + 1) and finally the data # (z = len(histograms_) + 2) rplt.hist( stack, stacked = True, axes = axes, zorder = 1 ) rplt.errorbar( data, emptybins = histogram_properties.emptybins, axes = axes, xerr = histogram_properties.xerr, elinewidth = 2, capsize = 10, capthick = 2, zorder = len(histograms_) + 2 ) # put legend into the correct order (data is always first!) handles, labels = axes.get_legend_handles_labels() data_label_index = labels.index( 'data' ) data_handle = handles[data_label_index] labels.remove( 'data' ) handles.remove( data_handle ) labels.insert( 0, 'data' ) handles.insert( 0, data_handle ) if mc_error > 0 or ( not mc_error > 0 and show_stat_errors_on_mc ): p1 = Rectangle( ( 0, 0 ), 1, 1, fc = "0.75", alpha = 0.5, hatch = '/' ) handles.append( p1 ) labels.append( histogram_properties.mc_errors_label ) l1 = axes.legend( handles, labels, numpoints = 1, frameon = histogram_properties.legend_color, bbox_to_anchor = histogram_properties.legend_location, bbox_transform=plt.gcf().transFigure, prop = CMS.legend_properties, ncol = histogram_properties.legend_columns ) l1.set_zorder(102) set_labels( plt, histogram_properties, show_x_label = not show_ratio, axes = axes ) x_limits = histogram_properties.x_limits y_limits = histogram_properties.y_limits if len( x_limits ) >= 2: axes.set_xlim( xmin = x_limits[0], xmax = x_limits[-1] ) if len( y_limits ) >= 2: axes.set_ylim( ymin = y_limits[0], ymax = y_limits[-1] ) else: y_max = get_best_max_y(histograms_, x_limits=x_limits) * histogram_properties.y_max_scale axes.set_ylim( ymin = 0, ymax = y_max ) if histogram_properties.set_log_y: if not len( y_limits ) == 2: # if not user set y-limits, set default axes.set_ylim( ymin = 1e-1 ) #draw a red vertical line if needed: if draw_vertical_line != 0: plt.axvline(x = draw_vertical_line, color = 'red', linewidth = 3) if show_ratio: plt.setp( axes.get_xticklabels(), visible = False ) ax1 = plt.subplot( gs[1] ) ax1.minorticks_on() ax1.grid( True, 'major', linewidth = 1 ) ax1.axhline(y=1, linewidth = 1) set_labels( plt, histogram_properties, show_x_label = True, show_title = False ) plt.ylabel( r'$\frac{\mathrm{data}}{\mathrm{pred.}}$', CMS.y_axis_title ) ax1.yaxis.set_label_coords(-0.115, 0.8) rplt.errorbar( ratio, emptybins = histogram_properties.emptybins, axes = ax1, xerr = histogram_properties.xerr, elinewidth = 1.5, capsize = 5, capthick = 1.5 ) if len( x_limits ) >= 2: ax1.set_xlim( xmin = x_limits[0], xmax = x_limits[-1] ) if len( histogram_properties.ratio_y_limits ) >= 2: ax1.set_ylim( ymin = histogram_properties.ratio_y_limits[0], ymax = histogram_properties.ratio_y_limits[-1] ) # dynamic tick placement adjust_ratio_ticks(ax1.yaxis, n_ticks = 3, y_limits = histogram_properties.ratio_y_limits) if histogram_properties.integerXVariable : ax1.tick_params(axis='x',which='minor',bottom='off',top='off') if systematics_for_ratio != None: plusErrors = [x+1 for x in systematics_for_ratio] minusErrors = [1-x for x in systematics_for_ratio] print plusErrors print minusErrors ratioPlusError = ratio.Clone( 'plus' ) ratioMinusError = ratio.Clone( 'minus' ) for bin_i in range( 1, ratioPlusError.GetNbinsX()+1 ): ratioPlusError.SetBinContent( bin_i, plusErrors[bin_i-1] ) ratioMinusError.SetBinContent( bin_i, minusErrors[bin_i-1] ) rplt.fill_between( ratioPlusError, ratioMinusError, axes, alpha = 0.3, hatch = '//', facecolor = 'Black', zorder = len(histograms_) + 1 ) if CMS.tight_layout: plt.tight_layout() for save in save_as: if save == 'root': saveHistogramsToROOTFile( data, stack,save_folder + histogram_properties.name + '.' + save ) else: plt.savefig( save_folder + histogram_properties.name + '.' + save ) plt.close()
def make_plots( histograms, category, output_folder, histname, show_ratio = False, show_generator_ratio = False, show_before_unfolding = False, utype = 'normalised', preliminary=True ): global variable, phase_space channel = '' if 'electron' in histname: channel = 'electron' elif 'muon' in histname: channel = 'muon' else: channel = 'combined' # Initailise data histograms hist_data = histograms['unfolded'] hist_data.markersize = 2 hist_data.marker = 'o' if category == 'central': hist_data_with_systematics = histograms['unfolded_with_systematics'] hist_data_with_systematics.markersize = 2 hist_data_with_systematics.marker = 'o' # Create base figure to be plotted plt.figure( figsize = CMS.figsize, dpi = CMS.dpi, facecolor = CMS.facecolor ) # Split into 3 for MC/Data ratio and generator ratio and plot if show_ratio and show_generator_ratio: gs = gridspec.GridSpec( 3, 1, height_ratios = [5, 1, 1] ) axes = plt.subplot( gs[0] ) # Split into 2 for MC/Data ratio or generator Ratio and plot elif show_ratio or show_generator_ratio: gs = gridspec.GridSpec( 2, 1, height_ratios = [4, 1] ) axes = plt.subplot( gs[0] ) # Just 1 for plot and setup x axis labels else: axes = plt.axes() x_label = '${}$'.format(variables_latex[variable]) if variable in ['HT', 'ST', 'MET', 'WPT', 'lepton_pt']: x_label += ' [GeV]' plt.xlabel( x_label, CMS.x_axis_title ) # set y axis x-section labels y_label = '' xsectionUnit = '' if utype == 'absolute': y_label = r'$\frac{d\sigma}{d' + variables_latex[variable] + '}\ ' xsectionUnit = 'pb' else : y_label = r'$\frac{1}{\sigma} \frac{d\sigma}{d' + variables_latex[variable] + '}\ ' if variable in ['HT', 'ST', 'MET', 'WPT', 'lepton_pt']: if xsectionUnit is '': y_label += '\scriptstyle(\mathrm{GeV}^{-1})$' pass else: y_label += '\scriptstyle(\mathrm{' y_label += xsectionUnit y_label += '}\ \mathrm{GeV}^{-1})$' elif xsectionUnit is not '': y_label += '\scriptstyle(\mathrm{' y_label += xsectionUnit y_label += '})$' plt.ylabel( y_label, CMS.y_axis_title ) # Set up ticks on axis. Minor ticks on axis for non NJet variables plt.tick_params( **CMS.axis_label_major ) if not variable in ['NJets']: axes.minorticks_on() plt.tick_params( **CMS.axis_label_minor ) # Set raw unfolded data with stat+unfolding uncertianty to be visible hist_data.visible = True # axes.set_yscale('log') # Set raw unfolded data with systematic uncertianty to be visible # label = 'do_not_show' = do not show in legend if category == 'central': hist_data_with_systematics.visible = True rplt.errorbar( hist_data_with_systematics, axes = axes, label = 'do_not_show', xerr = None, capsize = 0, elinewidth = 2, zorder = len( histograms ) + 1 ) # Show stat+unf uncertainty on plot rplt.errorbar( hist_data, axes = axes, label = 'do_not_show', xerr = None, capsize = 15, capthick = 3, elinewidth = 2, zorder = len( histograms ) + 2 ) # And one for a nice legend entry rplt.errorbar( hist_data, axes = axes, label = 'data', xerr = None, yerr = False, capsize = 0, elinewidth = 2, zorder = len( histograms ) + 3 ) dashes = {} for key, hist in sorted( histograms.items() ): zorder = sorted( histograms, reverse = False ).index( key ) # Ordering such that systematic uncertainties are plotted first then central powhegPythia then data if key == 'TTJets_powhegPythia8' and zorder != len(histograms) - 3: zorder = len(histograms) - 3 elif key != 'TTJets_powhegPythia8' and not 'unfolded' in key: while zorder >= len(histograms) - 3: zorder = zorder - 1 # Colour and style of MC hists if not 'unfolded' in key and not 'measured' in key: hist.linewidth = 4 linestyle = None if 'powhegPythia8' in key: linestyle = 'solid' dashes[key] = None hist.SetLineColor( 633 ) elif 'powhegHerwig' in key or 'isr' in key or 'hdamp' in key: hist.SetLineColor( kBlue ) dashes[key] = [25,5,5,5,5,5,5,5] elif 'amcatnloPythia8' in key or 'fsr' in key or 'scale' in key: hist.SetLineColor( 807 ) dashes[key] = [20,5] elif 'madgraphMLM' in key or 'renormalisation' in key or 'topPt' in key: hist.SetLineColor( 417 ) dashes[key] = [5,5] elif 'factorisation' in key or 'ue' in key: hist.SetLineColor( 100 ) dashes[key] = [10,10] elif 'combined' in key or 'semiLepBr' in key: hist.SetLineColor( 200 ) dashes[key] = [20,10] elif 'semiLepBr' in key or 'mass' in key: hist.SetLineColor( 300 ) dashes[key] = [20,10,10,10] elif 'frag' in key or 'Frag' in key: hist.SetLineColor( 400 ) dashes[key] = [10,10,5,5] elif 'erdOn' in key: hist.SetLineColor( 500 ) dashes[key] = [10,10,5,5,5,5] if linestyle != None: hist.linestyle = linestyle # Add hist to plot line, h = rplt.hist( hist, axes = axes, label = measurements_latex[key], zorder = zorder ) # Set the dashes and lines if dashes[key] != None: line.set_dashes(dashes[key]) h.set_dashes(dashes[key]) handles, labels = axes.get_legend_handles_labels() # Making data first in the legend data_label_index = labels.index( 'data' ) data_handle = handles[data_label_index] labels.remove( 'data' ) handles.remove( data_handle ) labels.insert( 0, 'data' ) handles.insert( 0, data_handle ) # Order the rest of the labels in the legend new_handles, new_labels = [], [] zipped = dict( zip( labels, handles ) ) labelOrder = ['data', measurements_latex['TTJets_powhegPythia8'], measurements_latex['TTJets_amcatnloPythia8'], measurements_latex['TTJets_powhegHerwig'], measurements_latex['TTJets_madgraphMLM'], measurements_latex['TTJets_scaleup'], measurements_latex['TTJets_scaledown'], measurements_latex['TTJets_massup'], measurements_latex['TTJets_massdown'], measurements_latex['TTJets_ueup'], measurements_latex['TTJets_uedown'], measurements_latex['TTJets_fsrup'], measurements_latex['TTJets_fsrdown'], measurements_latex['TTJets_isrdown'], measurements_latex['TTJets_isrup'], # measurements_latex['TTJets_alphaSup'], # measurements_latex['TTJets_alphaSdown'], measurements_latex['TTJets_topPt'], measurements_latex['TTJets_factorisationup'], measurements_latex['TTJets_factorisationdown'], measurements_latex['TTJets_renormalisationup'], measurements_latex['TTJets_renormalisationdown'], measurements_latex['TTJets_combinedup'], measurements_latex['TTJets_combineddown'], measurements_latex['TTJets_hdampup'], measurements_latex['TTJets_hdampdown'], measurements_latex['TTJets_erdOn'], measurements_latex['TTJets_QCDbased_erdOn'], measurements_latex['TTJets_GluonMove'], measurements_latex['TTJets_semiLepBrup'], measurements_latex['TTJets_semiLepBrdown'], measurements_latex['TTJets_fragup'], measurements_latex['TTJets_fragdown'], measurements_latex['TTJets_petersonFrag'], ] for label in labelOrder: if label in labels: new_handles.append(zipped[label]) if label == 'data': new_labels.append(measurements_latex['data']) else: new_labels.append(label) # Location of the legend legend_location = (0.95, 0.82) prop = CMS.legend_properties if variable == 'MT': legend_location = (0.05, 0.82) elif variable == 'ST': legend_location = (0.97, 0.82) elif variable == 'WPT': legend_location = (1.0, 0.84) elif variable == 'abs_lepton_eta' or variable =='abs_lepton_eta_coarse': legend_location = (0.97, 0.87) elif variable == 'NJets': # Reduce size of NJets legend prop = {'size':30} # Add legend to plot plt.legend( new_handles, new_labels, numpoints = 1, prop = prop, frameon = False, bbox_to_anchor=legend_location, bbox_transform=plt.gcf().transFigure ) # Title and CMS labels # note: fontweight/weight does not change anything as we use Latex text!!! label, channel_label = get_cms_labels( channel ) plt.title( label,loc='right', **CMS.title ) # Locations of labels logo_location = (0.05, 0.97) channel_location = ( 0.05, 0.9) if preliminary: prelim_location = (0.05, 0.9) channel_location = ( 0.5, 0.97) # preliminary plt.text(prelim_location[0], prelim_location[1], r"\emph{Preliminary}", transform=axes.transAxes, fontsize=42, verticalalignment='top', horizontalalignment='left' ) # if variable == 'WPT': # logo_location = (0.05, 0.97) # prelim_location = (0.05, 0.9) # channel_location = (0.5, 0.97) # elif variable == 'abs_lepton_eta': # logo_location = (0.05, 0.97) # prelim_location = (0.05, 0.9) # channel_location = ( 0.5, 0.97) # Add labels to plot plt.text(logo_location[0], logo_location[1], r"\textbf{CMS}", transform=axes.transAxes, fontsize=42, verticalalignment='top', horizontalalignment='left' ) # channel text plt.text(channel_location[0], channel_location[1], r"%s"%channel_label, transform=axes.transAxes, fontsize=40, verticalalignment='top', horizontalalignment='left' ) # Set y limits on plot ylim = axes.get_ylim() if ylim[0] < 0: axes.set_ylim( ymin = 0.) axes.set_ylim(ymax = ylim[1]*1.1) if variable == 'abs_lepton_eta' or variable == 'abs_lepton_eta_coarse': axes.set_ylim(ymax = ylim[1]*1.6) # Now to show either of the ratio plots if show_ratio: # Set previous x axis ticks and labels to invisible plt.setp( axes.get_xticklabels(), visible = False ) # Go to ratio subplot ax1 = plt.subplot( gs[1] ) # setting the x_limits identical to the main plot x_limits = axes.get_xlim() ax1.set_xlim(x_limits) # Setting tick marks ax1.yaxis.set_major_locator( MultipleLocator( 0.5 ) ) plt.tick_params( **CMS.axis_label_major ) # if not variable in ['NJets']: # ax1.minorticks_on() # ax1.yaxis.set_minor_locator( MultipleLocator( 0.1 ) ) # plt.tick_params( **CMS.axis_label_minor ) # x axis labels as before x_label = '${}$'.format(variables_latex[variable]) if variable in ['HT', 'ST', 'MET', 'WPT', 'lepton_pt']: x_label += ' (GeV)' if not show_generator_ratio: plt.xlabel( x_label, CMS.x_axis_title ) y_label = '$\\displaystyle\\frac{\\mathrm{pred.}}{\\mathrm{data}}$' plt.ylabel( y_label, CMS.y_axis_title_small ) ax1.yaxis.set_label_coords(-0.115, 0.7) # Draw a horizontal line at y=1 for data plt.axhline(y = 1, color = 'black', linewidth = 2) # Create ratios and plot to subplot for key, hist in sorted( histograms.iteritems() ): if not 'unfolded' in key and not 'measured' in key: ratio = hist.Clone() ratio.Divide( hist_data ) line, h = rplt.hist( ratio, axes = ax1, label = 'do_not_show' ) if dashes[key] != None: line.set_dashes(dashes[key]) h.set_dashes(dashes[key]) # Now for the error bands stat_lower = hist_data.Clone() stat_upper = hist_data.Clone() syst_lower = hist_data.Clone() syst_upper = hist_data.Clone() # Plot relative error bands on data in the ratio plot stat_errors = graph_to_value_errors_tuplelist(hist_data) if category == 'central': syst_errors = graph_to_value_errors_tuplelist(hist_data_with_systematics) for bin_i in range( 1, hist_data.GetNbinsX() + 1 ): stat_value, stat_error, _ = stat_errors[bin_i-1] stat_rel_error = stat_error/stat_value stat_lower.SetBinContent( bin_i, 1 - stat_rel_error ) stat_upper.SetBinContent( bin_i, 1 + stat_rel_error ) if category == 'central': syst_value, syst_error_down, syst_error_up = syst_errors[bin_i-1] syst_rel_error_down = syst_error_down/syst_value syst_rel_error_up = syst_error_up/syst_value syst_lower.SetBinContent( bin_i, 1 - syst_rel_error_down ) syst_upper.SetBinContent( bin_i, 1 + syst_rel_error_up ) # Colour if category == 'central': rplt.fill_between( syst_lower, syst_upper, ax1, color = 'gold' ) rplt.fill_between( stat_upper, stat_lower, ax1, color = '0.75', ) # Add legend loc = 'upper left' if variable == 'MET': loc = 'lower left' elif variable == 'HT': loc = 'lower center' elif variable == 'ST': loc = 'lower center' elif variable == 'WPT': loc = 'lower left' elif variable == 'NJets': loc = 'lower left' elif variable == 'abs_lepton_eta' or variable == 'abs_lepton_eta_coarse': loc = 'upper left' elif variable == 'lepton_pt': loc = 'lower left' # legend for ratio plot p_stat = mpatches.Patch(facecolor='0.75', label='Stat.', edgecolor='black' ) p_stat_and_syst = mpatches.Patch(facecolor='gold', label=r'Stat. $\oplus$ Syst.', edgecolor='black' ) l1 = ax1.legend( handles = [p_stat, p_stat_and_syst], loc = loc, frameon = False, prop = {'size':26}, ncol = 2 ) ax1.add_artist(l1) # Setting y limits and tick parameters if variable == 'MET': ax1.set_ylim( ymin = 0.6, ymax = 1.4 ) ax1.yaxis.set_major_locator( MultipleLocator( 0.2 ) ) ax1.yaxis.set_minor_locator( MultipleLocator( 0.1 ) ) if variable == 'MT': ax1.set_ylim( ymin = 0.8, ymax = 1.2 ) ax1.yaxis.set_major_locator( MultipleLocator( 0.2 ) ) ax1.yaxis.set_minor_locator( MultipleLocator( 0.1 ) ) elif variable == 'HT': ax1.set_ylim( ymin = 0.6, ymax = 1.4 ) ax1.yaxis.set_major_locator( MultipleLocator( 0.2 ) ) ax1.yaxis.set_minor_locator( MultipleLocator( 0.1 ) ) elif variable == 'ST': ax1.set_ylim( ymin = 0.6, ymax = 1.4 ) ax1.yaxis.set_major_locator( MultipleLocator( 0.2 ) ) ax1.yaxis.set_minor_locator( MultipleLocator( 0.1 ) ) elif variable == 'WPT': ax1.set_ylim( ymin = 0.6, ymax = 1.4 ) ax1.yaxis.set_major_locator( MultipleLocator( 0.2 ) ) ax1.yaxis.set_minor_locator( MultipleLocator( 0.1 ) ) elif variable == 'NJets': ax1.set_ylim( ymin = 0.6, ymax = 1.4 ) ax1.yaxis.set_major_locator( MultipleLocator( 0.2 ) ) ax1.yaxis.set_minor_locator( MultipleLocator( 0.1 ) ) elif variable == 'abs_lepton_eta' or variable == 'abs_lepton_eta_coarse': ax1.set_ylim( ymin = 0.6, ymax = 1.4 ) ax1.yaxis.set_major_locator( MultipleLocator( 0.2 ) ) ax1.yaxis.set_minor_locator( MultipleLocator( 0.1 ) ) elif variable == 'lepton_pt': ax1.set_ylim( ymin = 0.6, ymax = 1.4 ) ax1.yaxis.set_major_locator( MultipleLocator( 0.2 ) ) ax1.yaxis.set_minor_locator( MultipleLocator( 0.1 ) ) if show_generator_ratio: ax2 = None # Remove Data/MC Ratio Axis if show_ratio: plt.setp( ax1.get_xticklabels(), visible = False ) ax2 = plt.subplot( gs[2] ) else: plt.setp( axes.get_xticklabels(), visible = False ) ax2 = plt.subplot( gs[1] ) # setting the x_limits identical to the main plot x_limits = axes.get_xlim() ax2.set_xlim(x_limits) # Setting ticks ax2.yaxis.set_major_locator( MultipleLocator( 0.5 ) ) plt.tick_params( **CMS.axis_label_major ) if not variable in ['NJets']: ax2.minorticks_on() ax2.yaxis.set_minor_locator( MultipleLocator( 0.1 ) ) plt.tick_params( **CMS.axis_label_minor ) # x axis labels as before x_label = '${}$'.format(variables_latex[variable]) if variable in ['HT', 'ST', 'MET', 'WPT', 'lepton_pt']: x_label += ' [GeV]' plt.xlabel( x_label, CMS.x_axis_title ) y_label = 'Ratio to \n$' + measurements_latex['TTJets_powhegPythia8'] + '$' plt.ylabel( y_label, CMS.y_axis_title_tiny ) #draw a horizontal line at y=1 for central MC plt.axhline(y = 1, color = 'black', linewidth = 2) central_mc = histograms['TTJets_powhegPythia8'] for key, hist in sorted( histograms.iteritems() ): if not 'measured' in key: ratio = None if not 'unfolded_with_systematics' in key: ratio = hist.Clone() ratio.Divide( central_mc ) #divide by central mc sample else: ratio = central_mc.Clone() syst_errors = graph_to_value_errors_tuplelist(hist) for bin_i in range( 1, ratio.GetNbinsX() + 1 ): syst_value, syst_error_down, syst_error_up = syst_errors[bin_i-1] mc = central_mc.GetBinContent(bin_i) data = list(hist.y())[bin_i-1] ratio.SetBinContent( bin_i, data / mc) ratio.SetBinError( bin_i, syst_error_down / mc ) if not 'unfolded' in key: line, h = rplt.hist( ratio, axes = ax2, label = 'do_not_show' ) if dashes[key] != None: line.set_dashes(dashes[key]) h.set_dashes(dashes[key]) elif 'unfolded_with_systematics' in key: ratio.markersize = 2 ratio.marker = 'o' ratio.color = 'black' rplt.errorbar( ratio, axes = ax2, label = 'do_not_show', xerr = None, capsize = 0, elinewidth = 2, zorder = len( histograms ) + 10 ) else: ratio.markersize = 2 ratio.marker = 'o' rplt.errorbar( ratio, axes = ax2, label = 'do_not_show', xerr = None, capsize = 15, capthick = 3, elinewidth = 2, zorder = len( histograms ) + 9 ) if variable == 'MET': ax2.set_ylim( ymin = 0.8, ymax = 1.2 ) ax2.yaxis.set_major_locator( MultipleLocator( 0.5 ) ) ax2.yaxis.set_minor_locator( MultipleLocator( 0.1 ) ) if variable == 'MT': ax2.set_ylim( ymin = 0.8, ymax = 1.2 ) ax2.yaxis.set_major_locator( MultipleLocator( 0.2 ) ) ax2.yaxis.set_minor_locator( MultipleLocator( 0.1 ) ) elif variable == 'HT': ax2.set_ylim( ymin = 0.7, ymax = 1.3 ) ax2.yaxis.set_major_locator( MultipleLocator( 0.2 ) ) ax2.yaxis.set_minor_locator( MultipleLocator( 0.1 ) ) elif variable == 'ST': ax2.set_ylim( ymin = 0.7, ymax = 1.5 ) ax2.yaxis.set_major_locator( MultipleLocator( 0.5 ) ) ax2.yaxis.set_minor_locator( MultipleLocator( 0.1 ) ) elif variable == 'WPT': ax2.set_ylim( ymin = 0.8, ymax = 1.2 ) ax2.yaxis.set_major_locator( MultipleLocator( 0.5 ) ) ax2.yaxis.set_minor_locator( MultipleLocator( 0.1 ) ) elif variable == 'NJets': ax2.set_ylim( ymin = 0.7, ymax = 1.5 ) elif variable == 'abs_lepton_eta' or variable == 'abs_lepton_eta_coarse': ax2.set_ylim( ymin = 0.8, ymax = 1.2 ) ax2.yaxis.set_major_locator( MultipleLocator( 0.2 ) ) ax2.yaxis.set_minor_locator( MultipleLocator( 0.1 ) ) elif variable == 'lepton_pt': ax2.set_ylim( ymin = 0.8, ymax = 1.3 ) ax2.yaxis.set_major_locator( MultipleLocator( 0.2 ) ) ax2.yaxis.set_minor_locator( MultipleLocator( 0.1 ) ) if CMS.tight_layout: plt.tight_layout() # Save the plots path = '{output_folder}/xsections/{phaseSpace}/{variable}/' path = path.format( output_folder = output_folder, phaseSpace = phase_space, variable = variable ) make_folder_if_not_exists( path ) for output_format in output_formats: filename = path + '/' + histname + '.' + output_format plt.savefig( filename ) del hist_data if 'central' in category: del hist_data_with_systematics plt.close() gc.collect() return
def make_data_mc_comparison_plot( histograms = [], histogram_lables = [], histogram_colors = [], histogram_properties = Histogram_properties(), data_index = 0, save_folder = 'plots/', save_as = ['pdf', 'png'], normalise = False, show_ratio = False, show_stat_errors_on_mc = False, draw_vertical_line = 0, ): # make copies in order not to mess with existing histograms histograms_ = deepcopy(histograms) stack = HistStack() add_mc = stack.Add for index, histogram in enumerate( histograms_ ): label = histogram_lables[index] color = histogram_colors[index] histogram.SetTitle( label ) if normalise: histogram.Sumw2() if not index == data_index: histogram.fillstyle = 'solid' histogram.fillcolor = color histogram.legendstyle = 'F' add_mc( histogram ) data = histograms_[data_index] data.SetMarkerSize( CMS.data_marker_size ) if normalise: n_events_data = data.Integral() n_events_mc = stack.Integral() data.Scale( 1 / n_events_data ) stack.Scale( 1 / n_events_mc ) # plot with matplotlib plt.figure( figsize = CMS.figsize, dpi = CMS.dpi, facecolor = CMS.facecolor ) if show_ratio: ratio = data.Clone( 'ratio' ) ratio.Divide( sum( stack.GetHists() ) ) ratio.SetMarkerSize( 3 ) gs = gridspec.GridSpec( 2, 1, height_ratios = [5, 1] ) axes = plt.subplot( gs[0] ) else: axes = plt.axes() if histogram_properties.set_log_y: axes.set_yscale( 'log', nonposy = "clip" ) axes.set_ylim( ymin = 1e-2 ) mc_error = histogram_properties.mc_error if mc_error > 0: stack_lower = sum( stack.GetHists() ) stack_upper = stack_lower.Clone( 'upper' ) stack_lower.Scale( 1 - mc_error ) stack_upper.Scale( 1 + mc_error ) rplt.fill_between( stack_upper, stack_lower, axes, facecolor = '0.75', alpha = 0.5, hatch = '/', zorder = len(histograms_) + 1 ) if not mc_error > 0 and show_stat_errors_on_mc: stack_lower = sum( stack.GetHists() ) mc_errors = list( stack_lower.yerravg() ) stack_upper = stack_lower.Clone( 'upper' ) for bin_i in range( 1, stack_lower.GetNbinsX() ): stack_lower.SetBinContent( bin_i, stack_lower.GetBinContent( bin_i ) - mc_errors[bin_i - 1] ) stack_upper.SetBinContent( bin_i, stack_upper.GetBinContent( bin_i ) + mc_errors[bin_i - 1] ) rplt.fill_between( stack_upper, stack_lower, axes, facecolor = '0.75', alpha = 0.5, hatch = '/', zorder = len(histograms_) + 1 ) # a comment on zorder: the MC stack should be always at the very back (z = 1), # then the MC error (z = len(histograms_) + 1) and finally the data # (z = len(histograms_) + 2) rplt.hist( stack, stacked = True, axes = axes, zorder = 1 ) rplt.errorbar( data, xerr = False, emptybins = False, axes = axes, elinewidth = 2, capsize = 10, capthick = 2, zorder = len(histograms_) + 2 ) # put legend into the correct order (data is always first!) handles, labels = axes.get_legend_handles_labels() data_label_index = labels.index( 'data' ) data_handle = handles[data_label_index] labels.remove( 'data' ) handles.remove( data_handle ) labels.insert( 0, 'data' ) handles.insert( 0, data_handle ) if mc_error > 0 or ( not mc_error > 0 and show_stat_errors_on_mc ): p1 = Rectangle( ( 0, 0 ), 1, 1, fc = "0.75", alpha = 0.5, hatch = '/' ) handles.append( p1 ) labels.append( histogram_properties.mc_errors_label ) plt.legend( handles, labels, numpoints = 1, loc = histogram_properties.legend_location, prop = CMS.legend_properties, ncol = histogram_properties.legend_columns ).set_zorder(102) set_labels( plt, histogram_properties, show_x_label = not show_ratio ) x_limits = histogram_properties.x_limits y_limits = histogram_properties.y_limits if len( x_limits ) == 2: axes.set_xlim( xmin = x_limits[0], xmax = x_limits[1] ) if len( y_limits ) == 2: axes.set_ylim( ymin = y_limits[0], ymax = y_limits[1] ) else: axes.set_ylim( ymin = 0 ) if histogram_properties.set_log_y: if not len( y_limits ) == 2: # if not user set y-limits, set default axes.set_ylim( ymin = 1e-1 ) #draw a red vertical line if needed: if draw_vertical_line != 0: plt.axvline(x = draw_vertical_line, color = 'red', linewidth = 3) if show_ratio: plt.setp( axes.get_xticklabels(), visible = False ) ax1 = plt.subplot( gs[1] ) ax1.minorticks_on() ax1.grid( True, 'major', linewidth = 1 ) ax1.yaxis.set_major_locator( MultipleLocator( 1.0 ) ) ax1.yaxis.set_minor_locator( MultipleLocator( 0.5 ) ) set_labels( plt, histogram_properties, show_x_label = True, show_title = False ) plt.ylabel( 'data/MC', CMS.y_axis_title ) rplt.errorbar( ratio, xerr = True, emptybins = False, axes = ax1 ) if len( x_limits ) == 2: ax1.set_xlim( xmin = x_limits[0], xmax = x_limits[1] ) ax1.set_ylim( ymin = 0, ymax = 2 ) if CMS.tight_layout: plt.tight_layout() for save in save_as: plt.savefig( save_folder + histogram_properties.name + '.' + save ) plt.close()
def make_plots( histograms, category, output_folder, histname, show_ratio = True, show_before_unfolding = False ): global variable, k_values channel = 'electron' if 'electron' in histname: channel = 'electron' elif 'muon' in histname: channel = 'muon' else: channel = 'combined' # plot with matplotlib hist_data = histograms['unfolded'] if category == 'central': hist_data_with_systematics = histograms['unfolded_with_systematics'] hist_measured = histograms['measured'] hist_data.markersize = 2 hist_data.marker = 'o' if category == 'central': hist_data_with_systematics.markersize = 2 hist_data_with_systematics.marker = 'o' hist_measured.markersize = 2 hist_measured.marker = 'o' hist_measured.color = 'red' plt.figure( figsize = CMS.figsize, dpi = CMS.dpi, facecolor = CMS.facecolor ) if show_ratio: gs = gridspec.GridSpec( 2, 1, height_ratios = [5, 1] ) axes = plt.subplot( gs[0] ) else: axes = plt.axes() plt.xlabel( '$%s$ [GeV]' % variables_latex[variable], CMS.x_axis_title ) axes.minorticks_on() plt.ylabel( r'$\frac{1}{\sigma} \frac{d\sigma}{d' + variables_latex[variable] + '} \left[\mathrm{GeV}^{-1}\\right]$', CMS.y_axis_title ) plt.tick_params( **CMS.axis_label_major ) plt.tick_params( **CMS.axis_label_minor ) hist_data.visible = True if category == 'central': hist_data_with_systematics.visible = True rplt.errorbar( hist_data_with_systematics, axes = axes, label = 'do_not_show', xerr = None, capsize = 0, elinewidth = 2, zorder = len( histograms ) + 1 ) rplt.errorbar( hist_data, axes = axes, label = 'do_not_show', xerr = None, capsize = 15, capthick = 3, elinewidth = 2, zorder = len( histograms ) + 2 ) rplt.errorbar( hist_data, axes = axes, label = 'data', xerr = None, yerr = False, zorder = len( histograms ) + 3 ) # this makes a nicer legend entry if show_before_unfolding: rplt.errorbar( hist_measured, axes = axes, label = 'data (before unfolding)', xerr = None, zorder = len( histograms ) ) for key, hist in sorted( histograms.iteritems() ): if not 'unfolded' in key and not 'measured' in key: hist.linewidth = 4 # setting colours if 'POWHEG_PYTHIA' in key or 'matchingdown' in key: hist.linestyle = 'longdashdot' hist.SetLineColor( kBlue ) elif 'POWHEG_HERWIG' in key or 'scaledown' in key: hist.linestyle = 'dashed' hist.SetLineColor( kGreen ) elif 'MADGRAPH_ptreweight' in key: hist.linestyle = 'dashed' hist.SetLineColor( kBlack ) elif 'MADGRAPH' in key: hist.linestyle = 'solid' hist.SetLineColor( kRed + 1 ) elif 'matchingup' in key: hist.linestyle = 'verylongdashdot' hist.linecolor = 'orange' elif 'MCATNLO' in key or 'scaleup' in key: hist.linestyle = 'dotted' hist.SetLineColor( kMagenta + 3 ) rplt.hist( hist, axes = axes, label = measurements_latex[key], zorder = sorted( histograms, reverse = True ).index( key ) ) handles, labels = axes.get_legend_handles_labels() # making data first in the list data_label_index = labels.index( 'data' ) data_handle = handles[data_label_index] labels.remove( 'data' ) handles.remove( data_handle ) labels.insert( 0, 'unfolded data' ) handles.insert( 0, data_handle ) new_handles, new_labels = [], [] for handle, label in zip( handles, labels ): if not label == 'do_not_show': new_handles.append( handle ) new_labels.append( label ) legend_location = (0.98, 0.88) if variable == 'MT': legend_location = (0.05, 0.88) elif variable == 'ST': legend_location = (0.95, 0.88) plt.legend( new_handles, new_labels, numpoints = 1, prop = CMS.legend_properties, frameon = False, bbox_to_anchor=legend_location, bbox_transform=plt.gcf().transFigure ) label, channel_label = get_cms_labels( channel ) # title plt.title( label,loc='right', **CMS.title ) # CMS text # note: fontweight/weight does not change anything as we use Latex text!!! plt.text(0.05, 0.98, r"\textbf{CMS}", transform=axes.transAxes, fontsize=42, verticalalignment='top',horizontalalignment='left') # channel text axes.text(0.95, 0.98, r"\emph{%s}" %channel_label, transform=axes.transAxes, fontsize=40, verticalalignment='top',horizontalalignment='right') if show_ratio: plt.setp( axes.get_xticklabels(), visible = False ) ax1 = plt.subplot( gs[1] ) ax1.minorticks_on() #ax1.grid( True, 'major', linewidth = 1 ) # setting the x_limits identical to the main plot x_limits = axes.get_xlim() ax1.set_xlim(x_limits) ax1.yaxis.set_major_locator( MultipleLocator( 0.5 ) ) ax1.yaxis.set_minor_locator( MultipleLocator( 0.1 ) ) plt.xlabel( '$%s$ [GeV]' % variables_latex[variable], CMS.x_axis_title ) plt.tick_params( **CMS.axis_label_major ) plt.tick_params( **CMS.axis_label_minor ) plt.ylabel( '$\\frac{\\textrm{pred.}}{\\textrm{data}}$', CMS.y_axis_title_small ) ax1.yaxis.set_label_coords(-0.115, 0.8) #draw a horizontal line at y=1 for data plt.axhline(y = 1, color = 'black', linewidth = 2) for key, hist in sorted( histograms.iteritems() ): if not 'unfolded' in key and not 'measured' in key: ratio = hist.Clone() ratio.Divide( hist_data ) #divide by data rplt.hist( ratio, axes = ax1, label = 'do_not_show' ) stat_lower = hist_data.Clone() stat_upper = hist_data.Clone() syst_lower = hist_data.Clone() syst_upper = hist_data.Clone() # plot error bands on data in the ratio plot for bin_i in range( 1, hist_data.GetNbinsX() + 1 ): stat_errors = graph_to_value_errors_tuplelist(hist_data) stat_lower.SetBinContent( bin_i, 1 - stat_errors[bin_i-1][1]/stat_errors[bin_i-1][0] ) stat_upper.SetBinContent( bin_i, 1 + stat_errors[bin_i-1][2]/stat_errors[bin_i-1][0] ) if category == 'central': syst_errors = graph_to_value_errors_tuplelist(hist_data_with_systematics) syst_lower.SetBinContent( bin_i, 1 - syst_errors[bin_i-1][1]/syst_errors[bin_i-1][0] ) syst_upper.SetBinContent( bin_i, 1 + syst_errors[bin_i-1][2]/syst_errors[bin_i-1][0] ) if category == 'central': rplt.fill_between( syst_lower, syst_upper, ax1, color = 'yellow', alpha = 0.5 ) rplt.fill_between( stat_upper, stat_lower, ax1, color = '0.75', alpha = 0.5 ) # legend for ratio plot p_stat = mpatches.Patch(facecolor='0.75', label='Stat.',alpha = 0.5, edgecolor='black' ) p_stat_and_syst = mpatches.Patch(facecolor='yellow', label=r'Stat. $\oplus$ Syst.', alpha = 0.5, edgecolor='black' ) l1 = ax1.legend(handles = [p_stat], loc = 'upper left', frameon = False, prop = {'size':26}) ax1.legend(handles = [p_stat_and_syst], loc = 'lower left', frameon = False, prop = {'size':26}) ax1.add_artist(l1) if variable == 'MET': ax1.set_ylim( ymin = 0.7, ymax = 1.3 ) ax1.yaxis.set_major_locator( MultipleLocator( 0.2 ) ) # ax1.yaxis.set_minor_locator( MultipleLocator( 0.1 ) ) if variable == 'MT': ax1.set_ylim( ymin = 0.8, ymax = 1.2 ) ax1.yaxis.set_major_locator( MultipleLocator( 0.2 ) ) ax1.yaxis.set_minor_locator( MultipleLocator( 0.1 ) ) elif variable == 'HT' or variable == 'ST': ax1.set_ylim( ymin = 0.5, ymax = 1.5 ) ax1.yaxis.set_major_locator( MultipleLocator( 0.5 ) ) ax1.yaxis.set_minor_locator( MultipleLocator( 0.1 ) ) elif variable == 'WPT': ax1.set_ylim( ymin = 0.75, ymax = 1.5 ) ax1.yaxis.set_major_locator( MultipleLocator( 0.25 ) ) ax1.yaxis.set_minor_locator( MultipleLocator( 0.05 ) ) if CMS.tight_layout: plt.tight_layout() path = output_folder + str( measurement_config.centre_of_mass_energy ) + 'TeV/' + variable + '/' + category make_folder_if_not_exists( path ) for output_format in output_formats: filename = path + '/' + histname + '_kv' + str( k_values[channel] ) + '.' + output_format if channel == 'combined': filename = filename.replace( '_kv' + str( k_values[channel] ), '' ) plt.savefig( filename ) del hist_data, hist_measured plt.close() gc.collect()
htot_usyst = h_bkg_s.Clone() htot_dsyst = h_bkg_s.Clone() for ibin in range(1, h_bkg_s.GetNbinsX() + 1): htot_usyst.SetBinContent( ibin, h_bkg_s.GetBinContent(ibin) + h_bkg_s.GetBinErrorUp(ibin)) htot_dsyst.SetBinContent( ibin, h_bkg_s.GetBinContent(ibin) - h_bkg_s.GetBinErrorLow(ibin)) rplt.fill_between(htot_usyst, htot_dsyst, hatch=r"////////", alpha=1.0, linewidth=0, facecolor="none", edgecolor="black", zorder=10, label=r"Bkgd. Unc") plot_unc = mpatches.Patch(facecolor="none", edgecolor="black", label="Bkgd. Unc", hatch="////////") plt.legend(loc=1, handles=[plot_data, plot_sig1, plot_sig2, plot_bkg, plot_unc], numpoints=1, frameon=False) a2 = plt.axes([0.0, 0.0, 1.0, 0.20], sharex=a1)
def make_plots( histograms, category, output_folder, histname, show_ratio = True, show_before_unfolding = False ): global variable, phase_space channel = 'electron' if 'electron' in histname: channel = 'electron' elif 'muon' in histname: channel = 'muon' else: channel = 'combined' # plot with matplotlib hist_data = histograms['unfolded'] if category == 'central': hist_data_with_systematics = histograms['unfolded_with_systematics'] hist_measured = histograms['measured'] hist_data.markersize = 2 hist_data.marker = 'o' if category == 'central': hist_data_with_systematics.markersize = 2 hist_data_with_systematics.marker = 'o' hist_measured.markersize = 2 hist_measured.marker = 'o' hist_measured.color = 'red' plt.figure( figsize = CMS.figsize, dpi = CMS.dpi, facecolor = CMS.facecolor ) if show_ratio: gs = gridspec.GridSpec( 2, 1, height_ratios = [5, 1] ) axes = plt.subplot( gs[0] ) else: axes = plt.axes() if variable in ['NJets', 'abs_lepton_eta', 'lepton_eta']: plt.xlabel( '$%s$' % variables_latex[variable], CMS.x_axis_title ) else: plt.xlabel( '$%s$ [GeV]' % variables_latex[variable], CMS.x_axis_title ) if not variable in ['NJets']: axes.minorticks_on() if variable in ['NJets', 'abs_lepton_eta', 'lepton_eta']: plt.ylabel( r'$\frac{1}{\sigma} \frac{d\sigma}{d' + variables_latex[variable] + '}$', CMS.y_axis_title ) else: plt.ylabel( r'$\frac{1}{\sigma} \frac{d\sigma}{d' + variables_latex[variable] + '} \left[\mathrm{GeV}^{-1}\\right]$', CMS.y_axis_title ) plt.tick_params( **CMS.axis_label_major ) if not variable in ['NJets']: plt.tick_params( **CMS.axis_label_minor ) hist_data.visible = True if category == 'central': hist_data_with_systematics.visible = True rplt.errorbar( hist_data_with_systematics, axes = axes, label = 'do_not_show', xerr = None, capsize = 0, elinewidth = 2, zorder = len( histograms ) + 1 ) rplt.errorbar( hist_data, axes = axes, label = 'do_not_show', xerr = None, capsize = 15, capthick = 3, elinewidth = 2, zorder = len( histograms ) + 2 ) rplt.errorbar( hist_data, axes = axes, label = 'data', xerr = None, yerr = False, zorder = len( histograms ) + 3 ) # this makes a nicer legend entry if show_before_unfolding: rplt.errorbar( hist_measured, axes = axes, label = 'data (before unfolding)', xerr = None, zorder = len( histograms ) ) dashes = {} for key, hist in sorted( histograms.items() ): zorder = sorted( histograms, reverse = False ).index( key ) if key == 'powhegPythia8' and zorder != len(histograms) - 3: zorder = len(histograms) - 3 elif key != 'powhegPythia8' and not 'unfolded' in key: while zorder >= len(histograms) - 3: zorder = zorder - 1 if not 'unfolded' in key and not 'measured' in key: hist.linewidth = 4 # setting colours linestyle = None if 'amcatnlo_HERWIG' in key or 'massdown' in key: hist.SetLineColor( kBlue ) dashes[key] = [25,5,5,5,5,5,5,5] elif 'madgraphMLM' in key or 'scaledown' in key: hist.SetLineColor( 417 ) dashes[key] = [5,5] elif 'MADGRAPH_ptreweight' in key: hist.SetLineColor( kBlack ) elif 'powhegPythia8' in key: linestyle = 'solid' dashes[key] = None hist.SetLineColor( 633 ) elif 'massup' in key or 'amcatnlo' in key: hist.SetLineColor( 807 ) dashes[key] = [20,5] elif 'MCATNLO' in key or 'scaleup' in key: hist.SetLineColor( 619 ) dashes[key] = [5,5,10,5] if linestyle != None: hist.linestyle = linestyle line, h = rplt.hist( hist, axes = axes, label = measurements_latex[key], zorder = zorder ) if dashes[key] != None: line.set_dashes(dashes[key]) h.set_dashes(dashes[key]) handles, labels = axes.get_legend_handles_labels() # making data first in the list data_label_index = labels.index( 'data' ) data_handle = handles[data_label_index] labels.remove( 'data' ) handles.remove( data_handle ) labels.insert( 0, 'data' ) handles.insert( 0, data_handle ) new_handles, new_labels = [], [] zipped = dict( zip( labels, handles ) ) labelOrder = ['data', measurements_latex['powhegPythia8'], measurements_latex['amcatnlo'], measurements_latex['amcatnlo_HERWIG'], measurements_latex['madgraphMLM'], measurements_latex['scaleup'], measurements_latex['scaledown'], measurements_latex['massup'], measurements_latex['massdown'] ] for label in labelOrder: if label in labels: new_handles.append(zipped[label]) new_labels.append(label) legend_location = (0.97, 0.82) if variable == 'MT': legend_location = (0.05, 0.82) elif variable == 'ST': legend_location = (0.97, 0.82) elif variable == 'WPT': legend_location = (1.0, 0.84) elif variable == 'abs_lepton_eta': legend_location = (1.0, 0.94) plt.legend( new_handles, new_labels, numpoints = 1, prop = CMS.legend_properties, frameon = False, bbox_to_anchor=legend_location, bbox_transform=plt.gcf().transFigure ) label, channel_label = get_cms_labels( channel ) # title plt.title( label,loc='right', **CMS.title ) # CMS text # note: fontweight/weight does not change anything as we use Latex text!!! logo_location = (0.05, 0.98) prelim_location = (0.05, 0.92) channel_location = ( 0.05, 0.86) if variable == 'WPT': logo_location = (0.03, 0.98) prelim_location = (0.03, 0.92) channel_location = (0.03, 0.86) elif variable == 'abs_lepton_eta': logo_location = (0.03, 0.98) prelim_location = (0.03, 0.92) channel_location = (0.03, 0.86) plt.text(logo_location[0], logo_location[1], r"\textbf{CMS}", transform=axes.transAxes, fontsize=42, verticalalignment='top',horizontalalignment='left') # preliminary plt.text(prelim_location[0], prelim_location[1], r"\emph{Preliminary}", transform=axes.transAxes, fontsize=42, verticalalignment='top',horizontalalignment='left') # channel text plt.text(channel_location[0], channel_location[1], r"\emph{%s}" %channel_label, transform=axes.transAxes, fontsize=40, verticalalignment='top',horizontalalignment='left') ylim = axes.get_ylim() if ylim[0] < 0: axes.set_ylim( ymin = 0.) if variable == 'WPT': axes.set_ylim(ymax = ylim[1]*1.3) elif variable == 'abs_lepton_eta': axes.set_ylim(ymax = ylim[1]*1.3) else : axes.set_ylim(ymax = ylim[1]*1.2) if show_ratio: plt.setp( axes.get_xticklabels(), visible = False ) ax1 = plt.subplot( gs[1] ) if not variable in ['NJets']: ax1.minorticks_on() #ax1.grid( True, 'major', linewidth = 1 ) # setting the x_limits identical to the main plot x_limits = axes.get_xlim() ax1.set_xlim(x_limits) ax1.yaxis.set_major_locator( MultipleLocator( 0.5 ) ) if not variable in ['NJets']: ax1.yaxis.set_minor_locator( MultipleLocator( 0.1 ) ) if variable in ['NJets', 'abs_lepton_eta', 'lepton_eta']: plt.xlabel('$%s$' % variables_latex[variable], CMS.x_axis_title ) else: plt.xlabel( '$%s$ [GeV]' % variables_latex[variable], CMS.x_axis_title ) plt.tick_params( **CMS.axis_label_major ) if not variable in ['NJets']: plt.tick_params( **CMS.axis_label_minor ) plt.ylabel( '$\\frac{\\textrm{pred.}}{\\textrm{data}}$', CMS.y_axis_title ) ax1.yaxis.set_label_coords(-0.115, 0.8) #draw a horizontal line at y=1 for data plt.axhline(y = 1, color = 'black', linewidth = 2) for key, hist in sorted( histograms.iteritems() ): if not 'unfolded' in key and not 'measured' in key: ratio = hist.Clone() ratio.Divide( hist_data ) #divide by data line, h = rplt.hist( ratio, axes = ax1, label = 'do_not_show' ) if dashes[key] != None: h.set_dashes(dashes[key]) stat_lower = hist_data.Clone() stat_upper = hist_data.Clone() syst_lower = hist_data.Clone() syst_upper = hist_data.Clone() # plot error bands on data in the ratio plot stat_errors = graph_to_value_errors_tuplelist(hist_data) if category == 'central': syst_errors = graph_to_value_errors_tuplelist(hist_data_with_systematics) for bin_i in range( 1, hist_data.GetNbinsX() + 1 ): stat_value, stat_error, _ = stat_errors[bin_i-1] stat_rel_error = stat_error/stat_value stat_lower.SetBinContent( bin_i, 1 - stat_rel_error ) stat_upper.SetBinContent( bin_i, 1 + stat_rel_error ) if category == 'central': syst_value, syst_error_down, syst_error_up = syst_errors[bin_i-1] syst_rel_error_down = syst_error_down/syst_value syst_rel_error_up = syst_error_up/syst_value syst_lower.SetBinContent( bin_i, 1 - syst_rel_error_down ) syst_upper.SetBinContent( bin_i, 1 + syst_rel_error_up ) if category == 'central': rplt.fill_between( syst_lower, syst_upper, ax1, color = 'yellow' ) rplt.fill_between( stat_upper, stat_lower, ax1, color = '0.75', ) loc = 'upper left' # if variable in ['ST']: # loc = 'upper right' # legend for ratio plot p_stat = mpatches.Patch(facecolor='0.75', label='Stat.', edgecolor='black' ) p_stat_and_syst = mpatches.Patch(facecolor='yellow', label=r'Stat. $\oplus$ Syst.', edgecolor='black' ) l1 = ax1.legend(handles = [p_stat, p_stat_and_syst], loc = loc, frameon = False, prop = {'size':26}, ncol = 2) # ax1.legend(handles = [p_stat_and_syst], loc = 'lower left', # frameon = False, prop = {'size':30}) ax1.add_artist(l1) if variable == 'MET': ax1.set_ylim( ymin = 0.8, ymax = 1.2 ) ax1.yaxis.set_major_locator( MultipleLocator( 0.5 ) ) # ax1.yaxis.set_minor_locator( MultipleLocator( 0.1 ) ) if variable == 'MT': ax1.set_ylim( ymin = 0.8, ymax = 1.2 ) ax1.yaxis.set_major_locator( MultipleLocator( 0.2 ) ) ax1.yaxis.set_minor_locator( MultipleLocator( 0.1 ) ) elif variable == 'HT': ax1.set_ylim( ymin = 0.8, ymax = 1.37 ) ax1.yaxis.set_major_locator( MultipleLocator( 0.2 ) ) ax1.yaxis.set_minor_locator( MultipleLocator( 0.1 ) ) elif variable == 'ST': ax1.set_ylim( ymin = 0.7, ymax = 1.5 ) ax1.yaxis.set_major_locator( MultipleLocator( 0.5 ) ) ax1.yaxis.set_minor_locator( MultipleLocator( 0.1 ) ) elif variable == 'WPT': ax1.set_ylim( ymin = 0.8, ymax = 1.2 ) ax1.yaxis.set_major_locator( MultipleLocator( 0.5 ) ) ax1.yaxis.set_minor_locator( MultipleLocator( 0.1 ) ) elif variable == 'NJets': ax1.set_ylim( ymin = 0.7, ymax = 1.5 ) elif variable == 'abs_lepton_eta': ax1.set_ylim( ymin = 0.8, ymax = 1.2 ) ax1.yaxis.set_major_locator( MultipleLocator( 0.2 ) ) ax1.yaxis.set_minor_locator( MultipleLocator( 0.1 ) ) elif variable == 'lepton_pt': ax1.set_ylim( ymin = 0.8, ymax = 1.3 ) ax1.yaxis.set_major_locator( MultipleLocator( 0.2 ) ) ax1.yaxis.set_minor_locator( MultipleLocator( 0.1 ) ) if CMS.tight_layout: plt.tight_layout() path = '{output_folder}/{centre_of_mass_energy}TeV/{phaseSpace}/{variable}/' path = path.format( output_folder = output_folder, centre_of_mass_energy = measurement_config.centre_of_mass_energy, phaseSpace = phase_space, variable = variable ) make_folder_if_not_exists( path ) for output_format in output_formats: filename = path + '/' + histname + '.' + output_format plt.savefig( filename ) del hist_data, hist_measured plt.close() gc.collect()
import matplotlib import matplotlib.pyplot as plt import numpy as np import rootpy.plotting.root2matplotlib as rplt from rootpy.plotting import Hist x = np.linspace(0, 2 * np.pi, 100) plt.figure(figsize=(8, 8), dpi=100) #plt.fill(x,np.sin(x),color='blue',alpha=0.5) plt.fill(x, np.sin(x), color='None', edgecolor='blue', hatch='///') plt.fill(x, np.sin(2 * x), color='None', linewidth=0, hatch=r'\\', zorder=950) a = Hist(5, x[0], x[-1]) b = a.Clone() b.Fill(3, .5) rplt.fill_between( a, b, edgecolor='black', linewidth=0, facecolor=(0, 0, 0, 0), hatch=r'\\\\\\\\', zorder=900, ) plt.savefig('./test.eps') plt.savefig('./test.pdf')
import matplotlib import matplotlib.pyplot as plt import numpy as np import rootpy.plotting.root2matplotlib as rplt from rootpy.plotting import Hist x = np.linspace(0,2*np.pi,100) plt.figure(figsize=(8, 8), dpi=100) #plt.fill(x,np.sin(x),color='blue',alpha=0.5) plt.fill(x,np.sin(x),color='None', edgecolor='blue', hatch='///') plt.fill(x,np.sin(2 * x),color='None',linewidth=0,hatch=r'\\', zorder=950) a = Hist(5, x[0], x[-1]) b = a.Clone() b.Fill(3, .5) rplt.fill_between(a, b, edgecolor='black', linewidth=0, facecolor=(0,0,0,0), hatch=r'\\\\\\\\', zorder=900, ) plt.savefig('./test.eps') plt.savefig('./test.pdf')