def compare_vjets_templates( variable = 'MET', met_type = 'patType1CorrectedPFMet', title = 'Untitled', channel = 'electron' ): ''' Compares the V+jets templates in different bins of the current variable''' global fit_variable_properties, b_tag_bin, save_as variable_bins = variable_bins_ROOT[variable] histogram_template = get_histogram_template( variable ) for fit_variable in electron_fit_variables: all_hists = {} inclusive_hist = None save_path = 'plots/%dTeV/fit_variables/%s/%s/' % ( measurement_config.centre_of_mass_energy, variable, fit_variable ) make_folder_if_not_exists( save_path + '/vjets/' ) max_bins = len( variable_bins ) for bin_range in variable_bins[0:max_bins]: params = {'met_type': met_type, 'bin_range':bin_range, 'fit_variable':fit_variable, 'b_tag_bin':b_tag_bin, 'variable':variable} fit_variable_distribution = histogram_template % params # format: histograms['data'][qcd_fit_variable_distribution] histograms = get_histograms_from_files( [fit_variable_distribution], histogram_files ) prepare_histograms( histograms, rebin = fit_variable_properties[fit_variable]['rebin'], scale_factor = measurement_config.luminosity_scale ) all_hists[bin_range] = histograms['V+Jets'][fit_variable_distribution] # create the inclusive distributions inclusive_hist = deepcopy( all_hists[variable_bins[0]] ) for bin_range in variable_bins[1:max_bins]: inclusive_hist += all_hists[bin_range] for bin_range in variable_bins[0:max_bins]: if not all_hists[bin_range].Integral() == 0: all_hists[bin_range].Scale( 1 / all_hists[bin_range].Integral() ) # normalise all histograms inclusive_hist.Scale( 1 / inclusive_hist.Integral() ) # now compare inclusive to all bins histogram_properties = Histogram_properties() histogram_properties.x_axis_title = fit_variable_properties[fit_variable]['x-title'] histogram_properties.y_axis_title = fit_variable_properties[fit_variable]['y-title'] histogram_properties.y_axis_title = histogram_properties.y_axis_title.replace( 'Events', 'a.u.' ) histogram_properties.x_limits = [fit_variable_properties[fit_variable]['min'], fit_variable_properties[fit_variable]['max']] histogram_properties.title = title histogram_properties.additional_text = channel_latex[channel] + ', ' + b_tag_bins_latex[b_tag_bin] histogram_properties.name = variable + '_' + fit_variable + '_' + b_tag_bin + '_VJets_template_comparison' histogram_properties.y_max_scale = 1.5 measurements = {bin_range + ' GeV': histogram for bin_range, histogram in all_hists.iteritems()} measurements = OrderedDict( sorted( measurements.items() ) ) fit_var = fit_variable.replace( 'electron_', '' ) fit_var = fit_var.replace( 'muon_', '' ) graphs = spread_x( measurements.values(), fit_variable_bin_edges[fit_var] ) for key, graph in zip( sorted( measurements.keys() ), graphs ): measurements[key] = graph compare_measurements( models = {'inclusive' : inclusive_hist}, measurements = measurements, show_measurement_errors = True, histogram_properties = histogram_properties, save_folder = save_path + '/vjets/', save_as = save_as )
def compare( central_mc, expected_result = None, measured_result = None, results = {}, variable = 'MET', channel = 'electron', bin_edges = [] ): global input_file, plot_location, ttbar_xsection, luminosity, centre_of_mass, method, test, log_plots channel_label = '' if channel == 'electron': channel_label = 'e+jets, $\geq$4 jets' elif channel == 'muon': channel_label = '$\mu$+jets, $\geq$4 jets' else: channel_label = '$e, \mu$ + jets combined, $\geq$4 jets' if test == 'data': title_template = 'CMS Preliminary, $\mathcal{L} = %.1f$ fb$^{-1}$ at $\sqrt{s}$ = %d TeV \n %s' title = title_template % ( luminosity / 1000., centre_of_mass, channel_label ) else: title_template = 'CMS Simulation at $\sqrt{s}$ = %d TeV \n %s' title = title_template % ( centre_of_mass, channel_label ) models = {latex_labels.measurements_latex['MADGRAPH'] : central_mc} if expected_result and test == 'data': models.update({'fitted data' : expected_result}) # scale central MC to lumi nEvents = input_file.EventFilter.EventCounter.GetBinContent( 1 ) # number of processed events lumiweight = ttbar_xsection * luminosity / nEvents central_mc.Scale( lumiweight ) elif expected_result: models.update({'expected' : expected_result}) if measured_result and test != 'data': models.update({'measured' : measured_result}) measurements = collections.OrderedDict() for key, value in results['k_value_results'].iteritems(): measurements['k = ' + str( key )] = value # get some spread in x graphs = spread_x( measurements.values(), bin_edges ) for key, graph in zip( measurements.keys(), graphs ): measurements[key] = graph histogram_properties = Histogram_properties() histogram_properties.name = channel + '_' + variable + '_' + method + '_' + test histogram_properties.title = title + ', ' + latex_labels.b_tag_bins_latex['2orMoreBtags'] histogram_properties.x_axis_title = '$' + latex_labels.variables_latex[variable] + '$' histogram_properties.y_axis_title = r'Events' # histogram_properties.y_limits = [0, 0.03] histogram_properties.x_limits = [bin_edges[0], bin_edges[-1]] if log_plots: histogram_properties.set_log_y = True histogram_properties.name += '_log' compare_measurements( models, measurements, show_measurement_errors = True, histogram_properties = histogram_properties, save_folder = plot_location, save_as = ['pdf'] )
def plot_fit_results(fit_results, initial_values, channel): global variable, output_folder title = electron_histogram_title if channel == 'electron' else muon_histogram_title histogram_properties = Histogram_properties() histogram_properties.title = title histogram_properties.x_axis_title = variable + ' [GeV]' histogram_properties.mc_error = 0.0 histogram_properties.legend_location = 'upper right' # we will need 4 histograms: TTJet, SingleTop, QCD, V+Jets for sample in ['TTJet', 'SingleTop', 'QCD', 'V+Jets']: histograms = {} # absolute eta measurement as baseline h_absolute_eta = None h_before = None histogram_properties.y_axis_title = 'Fitted number of events for ' + samples_latex[ sample] for fit_var_input in fit_results.keys(): latex_string = create_latex_string(fit_var_input) fit_data = fit_results[fit_var_input][sample] h = value_error_tuplelist_to_hist(fit_data, bin_edges[variable]) if fit_var_input == 'absolute_eta': h_absolute_eta = h elif fit_var_input == 'before': h_before = h else: histograms[latex_string] = h graphs = spread_x(histograms.values(), bin_edges[variable]) for key, graph in zip(histograms.keys(), graphs): histograms[key] = graph filename = sample.replace('+', '_') + '_fit_var_comparison_' + channel histogram_properties.name = filename histogram_properties.y_limits = 0, limit_range_y( h_absolute_eta)[1] * 1.3 histogram_properties.x_limits = bin_edges[variable][0], bin_edges[ variable][-1] h_initial_values = value_error_tuplelist_to_hist( initial_values[sample], bin_edges[variable]) h_initial_values.Scale(closure_tests['simple'][sample]) compare_measurements(models={ fit_variables_latex['absolute_eta']: h_absolute_eta, 'initial values': h_initial_values, 'before': h_before }, measurements=histograms, show_measurement_errors=True, histogram_properties=histogram_properties, save_folder=output_folder, save_as=['png', 'pdf'])
def plot_fit_results(fit_results, initial_values, channel): global variable, output_folder title = electron_histogram_title if channel == "electron" else muon_histogram_title histogram_properties = Histogram_properties() histogram_properties.title = title histogram_properties.x_axis_title = variable + " [GeV]" histogram_properties.mc_error = 0.0 histogram_properties.legend_location = "upper right" # we will need 4 histograms: TTJet, SingleTop, QCD, V+Jets for sample in ["TTJet", "SingleTop", "QCD", "V+Jets"]: histograms = {} # absolute eta measurement as baseline h_absolute_eta = None h_before = None histogram_properties.y_axis_title = "Fitted number of events for " + samples_latex[sample] for fit_var_input in fit_results.keys(): latex_string = create_latex_string(fit_var_input) fit_data = fit_results[fit_var_input][sample] h = value_error_tuplelist_to_hist(fit_data, bin_edges[variable]) if fit_var_input == "absolute_eta": h_absolute_eta = h elif fit_var_input == "before": h_before = h else: histograms[latex_string] = h graphs = spread_x(histograms.values(), bin_edges[variable]) for key, graph in zip(histograms.keys(), graphs): histograms[key] = graph filename = sample.replace("+", "_") + "_fit_var_comparison_" + channel histogram_properties.name = filename histogram_properties.y_limits = 0, limit_range_y(h_absolute_eta)[1] * 1.3 histogram_properties.x_limits = bin_edges[variable][0], bin_edges[variable][-1] h_initial_values = value_error_tuplelist_to_hist(initial_values[sample], bin_edges[variable]) h_initial_values.Scale(closure_tests["simple"][sample]) compare_measurements( models={ fit_variables_latex["absolute_eta"]: h_absolute_eta, "initial values": h_initial_values, "before": h_before, }, measurements=histograms, show_measurement_errors=True, histogram_properties=histogram_properties, save_folder=output_folder, save_as=["png", "pdf"], )
def plot_fit_results( fit_results, initial_values, channel ): global variable, output_folder title = electron_histogram_title if channel == 'electron' else muon_histogram_title histogram_properties = Histogram_properties() histogram_properties.title = title histogram_properties.x_axis_title = variable + ' [GeV]' histogram_properties.mc_error = 0.0 histogram_properties.legend_location = 'upper right' # we will need 4 histograms: TTJet, SingleTop, QCD, V+Jets for sample in ['TTJet', 'SingleTop', 'QCD', 'V+Jets']: histograms = {} # absolute eta measurement as baseline h_absolute_eta = None h_before = None histogram_properties.y_axis_title = 'Fitted number of events for ' + samples_latex[sample] for fit_var_input in fit_results.keys(): latex_string = create_latex_string( fit_var_input ) fit_data = fit_results[fit_var_input][sample] h = value_error_tuplelist_to_hist( fit_data, bin_edges[variable] ) if fit_var_input == 'absolute_eta': h_absolute_eta = h elif fit_var_input == 'before': h_before = h else: histograms[latex_string] = h graphs = spread_x( histograms.values(), bin_edges[variable] ) for key, graph in zip( histograms.keys(), graphs ): histograms[key] = graph filename = sample.replace( '+', '_' ) + '_fit_var_comparison_' + channel histogram_properties.name = filename histogram_properties.y_limits = 0, limit_range_y( h_absolute_eta )[1] * 1.3 histogram_properties.x_limits = bin_edges[variable][0], bin_edges[variable][-1] h_initial_values = value_error_tuplelist_to_hist( initial_values[sample], bin_edges[variable] ) h_initial_values.Scale(closure_tests['simple'][sample]) compare_measurements( models = {fit_variables_latex['absolute_eta']:h_absolute_eta, 'initial values' : h_initial_values, 'before': h_before}, measurements = histograms, show_measurement_errors = True, histogram_properties = histogram_properties, save_folder = output_folder, save_as = ['png', 'pdf'] )
def compare_vjets_templates(variable='MET', met_type='patType1CorrectedPFMet', title='Untitled', channel='electron'): ''' Compares the V+jets templates in different bins of the current variable''' global fit_variable_properties, b_tag_bin, save_as variable_bins = variable_bins_ROOT[variable] histogram_template = get_histogram_template(variable) for fit_variable in electron_fit_variables: all_hists = {} inclusive_hist = None save_path = 'plots/%dTeV/fit_variables/%s/%s/' % ( measurement_config.centre_of_mass_energy, variable, fit_variable) make_folder_if_not_exists(save_path + '/vjets/') max_bins = len(variable_bins) for bin_range in variable_bins[0:max_bins]: params = { 'met_type': met_type, 'bin_range': bin_range, 'fit_variable': fit_variable, 'b_tag_bin': b_tag_bin, 'variable': variable } fit_variable_distribution = histogram_template % params # format: histograms['data'][qcd_fit_variable_distribution] histograms = get_histograms_from_files([fit_variable_distribution], histogram_files) prepare_histograms( histograms, rebin=fit_variable_properties[fit_variable]['rebin'], scale_factor=measurement_config.luminosity_scale) all_hists[bin_range] = histograms['V+Jets'][ fit_variable_distribution] # create the inclusive distributions inclusive_hist = deepcopy(all_hists[variable_bins[0]]) for bin_range in variable_bins[1:max_bins]: inclusive_hist += all_hists[bin_range] for bin_range in variable_bins[0:max_bins]: if not all_hists[bin_range].Integral() == 0: all_hists[bin_range].Scale(1 / all_hists[bin_range].Integral()) # normalise all histograms inclusive_hist.Scale(1 / inclusive_hist.Integral()) # now compare inclusive to all bins histogram_properties = Histogram_properties() histogram_properties.x_axis_title = fit_variable_properties[ fit_variable]['x-title'] histogram_properties.y_axis_title = fit_variable_properties[ fit_variable]['y-title'] histogram_properties.y_axis_title = histogram_properties.y_axis_title.replace( 'Events', 'a.u.') histogram_properties.x_limits = [ fit_variable_properties[fit_variable]['min'], fit_variable_properties[fit_variable]['max'] ] histogram_properties.title = title histogram_properties.additional_text = channel_latex[ channel] + ', ' + b_tag_bins_latex[b_tag_bin] histogram_properties.name = variable + '_' + fit_variable + '_' + b_tag_bin + '_VJets_template_comparison' histogram_properties.y_max_scale = 1.5 measurements = { bin_range + ' GeV': histogram for bin_range, histogram in all_hists.iteritems() } measurements = OrderedDict(sorted(measurements.items())) fit_var = fit_variable.replace('electron_', '') fit_var = fit_var.replace('muon_', '') graphs = spread_x(measurements.values(), fit_variable_bin_edges[fit_var]) for key, graph in zip(sorted(measurements.keys()), graphs): measurements[key] = graph compare_measurements(models={'inclusive': inclusive_hist}, measurements=measurements, show_measurement_errors=True, histogram_properties=histogram_properties, save_folder=save_path + '/vjets/', save_as=save_as)
def make_shape_comparison_plot( shapes = [], names = [], colours = [], histogram_properties = Histogram_properties(), fill_area = True, make_ratio = False, alpha = 0.5, save_folder = 'plots/', save_as = ['pdf', 'png'], normalise_ratio_to_errors = False ): save_folder = check_save_folder(save_folder) # make copies in order not to mess with existing histograms shapes_ = deepcopy(shapes) # normalise as we are comparing shapes for shape, colour, label in zip(shapes_, colours, names): shape.SetTitle(label) integral = shape.Integral() if integral > 0: shape.Sumw2() shape.Scale( 1 / integral ) if fill_area: shape.fillcolor = colour shape.fillstyle = 'solid' shape.legendstyle = 'F' else: shape.linecolor = colour shape.legendstyle = 'F' shape.linewidth = 5 if not histogram_properties.y_limits: histogram_properties.y_limits = [0, get_best_max_y(shapes_, False)] # plot with matplotlib plt.figure( figsize = CMS.figsize, dpi = CMS.dpi, facecolor = CMS.facecolor ) gs = gridspec.GridSpec( 2, 1, height_ratios = [5, 1] ) axes = None if make_ratio: axes = plt.subplot( gs[0] ) else: axes = plt.axes() axes.minorticks_on() for shape in shapes_: rplt.hist( shape, axes = axes, alpha = alpha ) set_labels( plt, histogram_properties, show_x_label = not make_ratio, axes = axes ) handles, labels = axes.get_legend_handles_labels() for i,name in enumerate(names): labels.insert(i, name) # always fill legends if not fill_area: for handle in handles: handle.set_fill(True) handle.set_facecolor(handle.get_edgecolor()) 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) #add error bars graphs = spread_x(shapes_, list(shapes_[0].xedges())) for graph in graphs: rplt.errorbar( graph, axes = axes ) adjust_axis_limits(axes, histogram_properties, shapes_) if make_ratio: plt.setp( axes.get_xticklabels(), visible = False ) ratios = get_histogram_ratios(shapes_[0], shapes_[1:], normalise_ratio_to_errors) ax1 = plt.subplot( gs[1] ) ax1.minorticks_on() ax1.grid( True, 'major', linewidth = 1 ) set_labels( plt, histogram_properties, show_x_label = True, show_title = False ) if normalise_ratio_to_errors: plt.ylabel( r'$\frac{1-2}{\sqrt{(\sigma_1)^2 + (\sigma_2)^2}}$', CMS.y_axis_title ) else: plt.ylabel( '(1)/(2)', CMS.y_axis_title ) for ratio in ratios: ratio.SetMarkerSize( 2 ) rplt.errorbar( ratio, xerr = True, emptybins = histogram_properties.emptybins, axes = ax1 ) if len( histogram_properties.x_limits ) == 2: ax1.set_xlim( xmin = histogram_properties.x_limits[0], xmax = histogram_properties.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) if CMS.tight_layout: plt.tight_layout() for save in save_as: plt.savefig( save_folder + histogram_properties.name + '.' + save ) plt.close()
def debug_last_bin(): ''' For debugging why the last bin in the problematic variables deviates a lot in _one_ of the channels only. ''' file_template = '/hdfs/TopQuarkGroup/run2/dpsData/' file_template += 'data/normalisation/background_subtraction/13TeV/' file_template += '{variable}/VisiblePS/central/' file_template += 'normalised_xsection_{channel}_RooUnfoldSvd{suffix}.txt' problematic_variables = ['HT', 'MET', 'NJets', 'lepton_pt'] for variable in problematic_variables: results = {} Result = namedtuple('Result', ['before_unfolding', 'after_unfolding', 'model']) for channel in ['electron', 'muon', 'combined']: input_file_data = file_template.format( variable=variable, channel=channel, suffix='_with_errors', ) input_file_model = file_template.format( variable=variable, channel=channel, suffix='', ) data = read_data_from_JSON(input_file_data) data_model = read_data_from_JSON(input_file_model) before_unfolding = data['TTJet_measured_withoutFakes'] after_unfolding = data['TTJet_unfolded'] model = data_model['powhegPythia8'] # only use the last bin h_before_unfolding = value_errors_tuplelist_to_graph( [before_unfolding[-1]], bin_edges_vis[variable][-2:]) h_after_unfolding = value_errors_tuplelist_to_graph( [after_unfolding[-1]], bin_edges_vis[variable][-2:]) h_model = value_error_tuplelist_to_hist( [model[-1]], bin_edges_vis[variable][-2:]) r = Result(before_unfolding, after_unfolding, model) h = Result(h_before_unfolding, h_after_unfolding, h_model) results[channel] = (r, h) models = {'POWHEG+PYTHIA': results['combined'][1].model} h_unfolded = [ results[channel][1].after_unfolding for channel in ['electron', 'muon', 'combined'] ] tmp_hists = spread_x(h_unfolded, bin_edges_vis[variable][-2:]) measurements = {} for channel, hist in zip(['electron', 'muon', 'combined'], tmp_hists): value = results[channel][0].after_unfolding[-1][0] error = results[channel][0].after_unfolding[-1][1] label = '{c_label} ({value:1.2g} $\pm$ {error:1.2g})'.format( c_label=channel, value=value, error=error, ) measurements[label] = hist properties = Histogram_properties() properties.name = 'normalised_xsection_compare_channels_{0}_{1}_last_bin'.format( variable, channel) properties.title = 'Comparison of channels' properties.path = 'plots' properties.has_ratio = True properties.xerr = False properties.x_limits = (bin_edges_vis[variable][-2], bin_edges_vis[variable][-1]) properties.x_axis_title = variables_latex[variable] properties.y_axis_title = r'$\frac{1}{\sigma} \frac{d\sigma}{d' + \ variables_latex[variable] + '}$' properties.legend_location = (0.95, 0.40) if variable == 'NJets': properties.legend_location = (0.97, 0.80) properties.formats = ['png'] compare_measurements(models=models, measurements=measurements, show_measurement_errors=True, histogram_properties=properties, save_folder='plots/', save_as=properties.formats)
def debug_last_bin(): ''' For debugging why the last bin in the problematic variables deviates a lot in _one_ of the channels only. ''' file_template = '/hdfs/TopQuarkGroup/run2/dpsData/' file_template += 'data/normalisation/background_subtraction/13TeV/' file_template += '{variable}/VisiblePS/central/' file_template += 'normalised_xsection_{channel}_RooUnfoldSvd{suffix}.txt' problematic_variables = ['HT', 'MET', 'NJets', 'lepton_pt'] for variable in problematic_variables: results = {} Result = namedtuple( 'Result', ['before_unfolding', 'after_unfolding', 'model']) for channel in ['electron', 'muon', 'combined']: input_file_data = file_template.format( variable=variable, channel=channel, suffix='_with_errors', ) input_file_model = file_template.format( variable=variable, channel=channel, suffix='', ) data = read_data_from_JSON(input_file_data) data_model = read_data_from_JSON(input_file_model) before_unfolding = data['TTJet_measured_withoutFakes'] after_unfolding = data['TTJet_unfolded'] model = data_model['powhegPythia8'] # only use the last bin h_before_unfolding = value_errors_tuplelist_to_graph( [before_unfolding[-1]], bin_edges_vis[variable][-2:]) h_after_unfolding = value_errors_tuplelist_to_graph( [after_unfolding[-1]], bin_edges_vis[variable][-2:]) h_model = value_error_tuplelist_to_hist( [model[-1]], bin_edges_vis[variable][-2:]) r = Result(before_unfolding, after_unfolding, model) h = Result(h_before_unfolding, h_after_unfolding, h_model) results[channel] = (r, h) models = {'POWHEG+PYTHIA': results['combined'][1].model} h_unfolded = [results[channel][1].after_unfolding for channel in [ 'electron', 'muon', 'combined']] tmp_hists = spread_x(h_unfolded, bin_edges_vis[variable][-2:]) measurements = {} for channel, hist in zip(['electron', 'muon', 'combined'], tmp_hists): value = results[channel][0].after_unfolding[-1][0] error = results[channel][0].after_unfolding[-1][1] label = '{c_label} ({value:1.2g} $\pm$ {error:1.2g})'.format( c_label=channel, value=value, error=error, ) measurements[label] = hist properties = Histogram_properties() properties.name = 'normalised_xsection_compare_channels_{0}_{1}_last_bin'.format( variable, channel) properties.title = 'Comparison of channels' properties.path = 'plots' properties.has_ratio = True properties.xerr = False properties.x_limits = ( bin_edges_vis[variable][-2], bin_edges_vis[variable][-1]) properties.x_axis_title = variables_latex[variable] properties.y_axis_title = r'$\frac{1}{\sigma} \frac{d\sigma}{d' + \ variables_latex[variable] + '}$' properties.legend_location = (0.95, 0.40) if variable == 'NJets': properties.legend_location = (0.97, 0.80) properties.formats = ['png'] compare_measurements(models=models, measurements=measurements, show_measurement_errors=True, histogram_properties=properties, save_folder='plots/', save_as=properties.formats)
def make_shape_comparison_plot(shapes=[], names=[], colours=[], histogram_properties=Histogram_properties(), fill_area=True, make_ratio=False, alpha=0.5, save_folder='plots/', save_as=['pdf', 'png'], normalise_ratio_to_errors=False): save_folder = check_save_folder(save_folder) # make copies in order not to mess with existing histograms shapes_ = deepcopy(shapes) # normalise as we are comparing shapes for shape, colour, label in zip(shapes_, colours, names): shape.SetTitle(label) integral = shape.Integral() if integral > 0: shape.Sumw2() shape.Scale(1 / integral) if fill_area: shape.fillcolor = colour shape.fillstyle = 'solid' shape.legendstyle = 'F' else: shape.linecolor = colour shape.legendstyle = 'F' shape.linewidth = 5 if not histogram_properties.y_limits: histogram_properties.y_limits = [0, get_best_max_y(shapes_, False)] # plot with matplotlib plt.figure(figsize=CMS.figsize, dpi=CMS.dpi, facecolor=CMS.facecolor) gs = gridspec.GridSpec(2, 1, height_ratios=[5, 1]) axes = None if make_ratio: axes = plt.subplot(gs[0]) else: axes = plt.axes() axes.minorticks_on() for shape in shapes_: rplt.hist(shape, axes=axes, alpha=alpha) set_labels(plt, histogram_properties, show_x_label=not make_ratio, axes=axes) handles, labels = axes.get_legend_handles_labels() for i, name in enumerate(names): labels.insert(i, name) # always fill legends if not fill_area: for handle in handles: handle.set_fill(True) handle.set_facecolor(handle.get_edgecolor()) 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) #add error bars graphs = spread_x(shapes_, list(shapes_[0].xedges())) for graph in graphs: rplt.errorbar(graph, axes=axes) adjust_axis_limits(axes, histogram_properties, shapes_) if make_ratio: plt.setp(axes.get_xticklabels(), visible=False) ratios = get_histogram_ratios(shapes_[0], shapes_[1:], normalise_ratio_to_errors) ax1 = plt.subplot(gs[1]) ax1.minorticks_on() ax1.grid(True, 'major', linewidth=1) set_labels(plt, histogram_properties, show_x_label=True, show_title=False) if normalise_ratio_to_errors: plt.ylabel(r'$\frac{1-2}{\sqrt{(\sigma_1)^2 + (\sigma_2)^2}}$', CMS.y_axis_title) else: plt.ylabel('(1)/(2)', CMS.y_axis_title) for ratio in ratios: ratio.SetMarkerSize(2) rplt.errorbar(ratio, xerr=True, emptybins=histogram_properties.emptybins, axes=ax1) if len(histogram_properties.x_limits) == 2: ax1.set_xlim(xmin=histogram_properties.x_limits[0], xmax=histogram_properties.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) if CMS.tight_layout: plt.tight_layout() for save in save_as: plt.savefig(save_folder + histogram_properties.name + '.' + save) plt.close()