diff --git a/config/latex_labels.py b/config/latex_labels.py index 66b0b0bf..0728f0f7 100644 --- a/config/latex_labels.py +++ b/config/latex_labels.py @@ -18,8 +18,8 @@ measurements_latex = {'unfolded': 'unfolded', 'measured': 'measured', - 'MADGRAPH': '$t\\bar{t}$ (MADPGRAPH+Pythia)', - 'MADGRAPH_ptreweight': '$t\\bar{t}$ (MADPGRAPH+$p_\mathrm{T}^\mathrm{reweight}$)', + 'MADGRAPH': '$t\\bar{t}$ (MADGRAPH+Pythia)', + 'MADGRAPH_ptreweight': '$t\\bar{t}$ (MADGRAPH+$p_\mathrm{T}^\mathrm{reweight}$)', 'MCATNLO': '$t\\bar{t}$ (MC@NLO+Herwig)', 'POWHEG_PYTHIA': '$t\\bar{t}$ (POWHEG+Pythia)', 'POWHEG_HERWIG': '$t\\bar{t}$ (POWHEG+Herwig)', @@ -99,8 +99,8 @@ 'angle_bl' : r'angle$(b,l)$', } -typical_systematics_latex = {"typical_systematics_electron": "Trigger efficiency \& electron selection", - "typical_systematics_muon": "Trigger efficiency \& muon selection", +typical_systematics_latex = {"typical_systematics_electron": "Electron trigger efficiency \& electron selection", + "typical_systematics_muon": "Muon trigger efficiency \& muon selection", "typical_systematics_btagging": "btagging", "typical_systematics_JES": "Jet Energy Scale", "typical_systematics_JER": "Jet Energy Resolution", diff --git a/setup.sh b/setup.sh index c846b062..75e37073 100755 --- a/setup.sh +++ b/setup.sh @@ -77,7 +77,7 @@ echo "Installing matplotlib" export LDFLAGS="$LDFLAGS -L$VO_CMS_SW_DIR/$SCRAM_ARCH/external/freetype/2.4.7/lib -L$VO_CMS_SW_DIR/$SCRAM_ARCH/external/libpng/1.2.46/lib" export CFLAGS="$CFLAGS -I$VO_CMS_SW_DIR/$SCRAM_ARCH/external/freetype/2.4.7/include -I$VO_CMS_SW_DIR/$SCRAM_ARCH/external/freetype/2.4.7/include/freetype2 -I$VO_CMS_SW_DIR/$SCRAM_ARCH/external/libpng/1.2.46/include" #pip install -e $base/external/matplotlib -pip install matplotlib==1.3.1 &> /dev/null +pip install matplotlib==1.4.3 &> /dev/null success $? matplotlib echo "Installing rootpy" pip install -e $base/external/rootpy &> /dev/null diff --git a/src/cross_section_measurement/04_make_plots_matplotlib.py b/src/cross_section_measurement/04_make_plots_matplotlib.py index c7d496ed..8378a134 100644 --- a/src/cross_section_measurement/04_make_plots_matplotlib.py +++ b/src/cross_section_measurement/04_make_plots_matplotlib.py @@ -22,16 +22,10 @@ import matplotlib.gridspec as gridspec from matplotlib.ticker import MultipleLocator from config import CMS -from matplotlib import rc, rcParams -rc( 'font', **CMS.font ) -rc( 'text', usetex = True ) -rcParams['text.latex.preamble'] = [ - r'\usepackage{siunitx}', # i need upright \micro symbols, but you need... - r'\sisetup{detect-all}', # ...this to force siunitx to actually use your fonts - r'\usepackage{helvet}', # set the normal font here - r'\usepackage{sansmath}', # load up the sansmath so that math -> helvet - r'\sansmath' # <- tricky! -- gotta actually tell tex to use! -] +from tools.latex import setup_matplotlib +# latex, font, etc +setup_matplotlib() + import matplotlib.patches as mpatches def read_xsection_measurement_results( category, channel ): @@ -653,7 +647,7 @@ def get_unit_string(fit_variable): if met_type == 'PFMETJetEnDown': met_type = 'patPFMetJetEnDown' - if not channel == 'combined': + if not channel == 'combined' and options.additional_plots: #Don't make additional plots for e.g. generator systematics, mass systematics, k value systematics and pdf systematics because they are now done \ #in the unfolding process with BLT unfolding files. if category in ttbar_generator_systematics or category in ttbar_mass_systematics or category in kValue_systematics or category in pdf_uncertainties: diff --git a/src/cross_section_measurement/make_control_plots.py b/src/cross_section_measurement/make_control_plots.py index 37456447..35e79938 100644 --- a/src/cross_section_measurement/make_control_plots.py +++ b/src/cross_section_measurement/make_control_plots.py @@ -8,17 +8,9 @@ make_control_region_comparison from tools.hist_utilities import prepare_histograms, clean_control_region from tools.ROOT_utils import get_histograms_from_files, set_root_defaults -from matplotlib import rc, rcParams -from config import CMS -rc( 'font', **CMS.font ) -rc( 'text', usetex = True ) -rcParams['text.latex.preamble'] = [ - r'\usepackage{siunitx}', # i need upright \micro symbols, but you need... - r'\sisetup{detect-all}', # ...this to force siunitx to actually use your fonts - r'\usepackage{helvet}', # set the normal font here - r'\usepackage{sansmath}', # load up the sansmath so that math -> helvet - r'\sansmath' # <- tricky! -- gotta actually tell tex to use! -] +from tools.latex import setup_matplotlib +# latex, font, etc +setup_matplotlib() def get_fitted_normalisation( variable, channel ): ''' @@ -106,7 +98,6 @@ def make_plot( channel, x_axis_title, y_axis_title, signal_region, name_prefix, x_limits, qcd_data_region_btag = '', - qcd_data_region = '', use_qcd_data_region = True, y_limits = [], y_max_scale = 1.2, @@ -120,19 +111,20 @@ def make_plot( channel, x_axis_title, y_axis_title, global output_folder, measurement_config, category, normalise_to_fit global preliminary, norm_variable, sum_bins, b_tag_bin, histogram_files + qcd_data_region = '' title = title_template % ( measurement_config.new_luminosity / 1000., measurement_config.centre_of_mass_energy ) normalisation = None if channel == 'electron': histogram_files['data'] = measurement_config.data_file_electron histogram_files['QCD'] = measurement_config.electron_QCD_MC_category_templates[category] normalisation = normalisations_electron[norm_variable] - if qcd_data_region_btag and qcd_data_region == '': + if use_qcd_data_region: qcd_data_region = 'QCDConversions' if channel == 'muon': histogram_files['data'] = measurement_config.data_file_muon histogram_files['QCD'] = measurement_config.muon_QCD_MC_category_templates[category] normalisation = normalisations_muon[norm_variable] - if qcd_data_region_btag and qcd_data_region == '': + if use_qcd_data_region: qcd_data_region = 'QCD non iso mu+jets ge3j' multi = isinstance( signal_region, list ) @@ -164,31 +156,39 @@ def make_plot( channel, x_axis_title, y_axis_title, else: histograms = get_histograms_from_files( [signal_region], histogram_files ) + signal_region_hists = {} + inclusive_control_region_hists = {} + for sample in histograms.keys(): + signal_region_hists[sample] = histograms[sample][signal_region] + if use_qcd_data_region: + inclusive_control_region_hists[sample] = histograms[sample][qcd_control_region] + if normalise_to_fit: - prepare_histograms( histograms, rebin = rebin, + # only scale signal region to fit (results are invalid for control region) + prepare_histograms( signal_region_hists, rebin = rebin, scale_factor = measurement_config.luminosity_scale, normalisation = normalisation ) else: - prepare_histograms( histograms, rebin = rebin, + prepare_histograms( signal_region_hists, rebin = rebin, + scale_factor = measurement_config.luminosity_scale ) + prepare_histograms( inclusive_control_region_hists, rebin = rebin, scale_factor = measurement_config.luminosity_scale ) qcd_from_data = None if use_qcd_data_region: - inclusive_control_region_hists = {} - for sample in histograms.keys(): - inclusive_control_region_hists[sample] = histograms[sample][qcd_control_region] qcd_from_data = clean_control_region( inclusive_control_region_hists, subtract = ['TTJet', 'V+Jets', 'SingleTop'] ) else: - qcd_from_data = histograms['QCD'][signal_region] + qcd_from_data = signal_region_hists['QCD'] n_qcd_predicted_mc = histograms['QCD'][signal_region].Integral() n_qcd_control_region = qcd_from_data.Integral() if not n_qcd_control_region == 0: qcd_from_data.Scale( 1.0 / n_qcd_control_region * n_qcd_predicted_mc ) - histograms_to_draw = [histograms['data'][signal_region], qcd_from_data, - histograms['V+Jets'][signal_region], - histograms['SingleTop'][signal_region], histograms['TTJet'][signal_region]] + histograms_to_draw = [signal_region_hists['data'], qcd_from_data, + signal_region_hists['V+Jets'], + signal_region_hists['SingleTop'], + signal_region_hists['TTJet']] histogram_lables = ['data', 'QCD', 'V+Jets', 'Single-Top', samples_latex['TTJet']] histogram_colors = ['black', 'yellow', 'green', 'magenta', 'red'] @@ -643,7 +643,7 @@ def make_plot( channel, x_axis_title, y_axis_title, rebin = 2, legend_location = ( 0.95, 0.78 ), cms_logo_location = 'right', - ratio_y_limits = [0.5, 1.5], + ratio_y_limits = [0.25, 1.75], ) tmp = 'TTbar_plus_X_analysis/MuPlusJets/Ref selection/Binned_MT_Analysis/MT_with_patType1CorrectedPFMet_bin_%s/angle_bl_' + b_tag_bin regions = [tmp % bin_i for bin_i in variable_bins_ROOT['MT']] @@ -670,6 +670,7 @@ def make_plot( channel, x_axis_title, y_axis_title, y_axis_title = 'Normalised events/(10 GeV)', signal_region = 'TTbar_plus_X_analysis/EPlusJets/Ref selection/bjet_invariant_mass_' + b_tag_bin, qcd_data_region_btag = '', + use_qcd_data_region = False, name_prefix = 'EPlusJets_BJets_invmass_', x_limits = [0, 800], rebin = 10, @@ -681,6 +682,7 @@ def make_plot( channel, x_axis_title, y_axis_title, y_axis_title = 'Normalised events/(10 GeV)', signal_region = 'TTbar_plus_X_analysis/MuPlusJets/Ref selection/bjet_invariant_mass_' + b_tag_bin, qcd_data_region_btag = '', + use_qcd_data_region = False, name_prefix = 'MuPlusJets_BJets_invmass_', x_limits = [0, 800], rebin = 10, @@ -697,6 +699,7 @@ def make_plot( channel, x_axis_title, y_axis_title, y_axis_title = 'Events', signal_region = 'TTbar_plus_X_analysis/EPlusJets/Ref selection/N_BJets', qcd_data_region_btag = '', + use_qcd_data_region = False, name_prefix = 'EPlusJets_N_BJets', x_limits = [1.5, 7.5], rebin = 1, @@ -708,6 +711,7 @@ def make_plot( channel, x_axis_title, y_axis_title, y_axis_title = 'Events', signal_region = 'TTbar_plus_X_analysis/MuPlusJets/Ref selection/N_BJets', qcd_data_region_btag = '', + use_qcd_data_region = False, name_prefix = 'MuPlusJets_N_BJets', x_limits = [1.5, 7.5], rebin = 1, @@ -721,6 +725,7 @@ def make_plot( channel, x_axis_title, y_axis_title, y_axis_title = 'Events', signal_region = 'TTbar_plus_X_analysis/EPlusJets/Ref selection/N_BJets_reweighted', qcd_data_region_btag = '', + use_qcd_data_region = False, name_prefix = 'EPlusJets_N_BJets_reweighted', x_limits = [1.5, 7.5], rebin = 1, @@ -732,6 +737,7 @@ def make_plot( channel, x_axis_title, y_axis_title, y_axis_title = 'Events', signal_region = 'TTbar_plus_X_analysis/MuPlusJets/Ref selection/N_BJets', qcd_data_region_btag = '', + use_qcd_data_region = False, name_prefix = 'MuPlusJets_N_BJets', x_limits = [1.5, 7.5], rebin = 1, @@ -748,6 +754,7 @@ def make_plot( channel, x_axis_title, y_axis_title, y_axis_title = 'Events', signal_region = 'TTbar_plus_X_analysis/EPlusJets/Ref selection/Jets/N_Jets_' + b_tag_bin, qcd_data_region_btag = '', + use_qcd_data_region = False, name_prefix = 'EPlusJets_N_Jets_', x_limits = [3.5, 9.5], rebin = 1, @@ -759,6 +766,7 @@ def make_plot( channel, x_axis_title, y_axis_title, y_axis_title = 'Events', signal_region = 'TTbar_plus_X_analysis/MuPlusJets/Ref selection/Jets/N_Jets_' + b_tag_bin, qcd_data_region_btag = '', + use_qcd_data_region = False, name_prefix = 'MuPlusJets_N_Jets_', x_limits = [3.5, 9.5], rebin = 1, @@ -775,6 +783,7 @@ def make_plot( channel, x_axis_title, y_axis_title, y_axis_title = 'arbitrary units', signal_region = 'TTbar_plus_X_analysis/EPlusJets/Ref selection/Vertices/nVertex', qcd_data_region_btag = '', + use_qcd_data_region = False, name_prefix = 'EPlusJets_nVertex_', x_limits = [0, 50], rebin = 1, @@ -787,6 +796,7 @@ def make_plot( channel, x_axis_title, y_axis_title, y_axis_title = 'arbitrary units', signal_region = 'TTbar_plus_X_analysis/MuPlusJets/Ref selection/Vertices/nVertex', qcd_data_region_btag = '', + use_qcd_data_region = False, name_prefix = 'MuPlusJets_nVertex_', x_limits = [0, 50], rebin = 1, @@ -800,6 +810,7 @@ def make_plot( channel, x_axis_title, y_axis_title, y_axis_title = 'arbitrary units', signal_region = 'TTbar_plus_X_analysis/EPlusJets/Ref selection/Vertices/nVertex_reweighted', qcd_data_region_btag = '', + use_qcd_data_region = False, name_prefix = 'EPlusJets_nVertex_reweighted_', x_limits = [0, 50], rebin = 1, @@ -812,6 +823,7 @@ def make_plot( channel, x_axis_title, y_axis_title, y_axis_title = 'arbitrary units', signal_region = 'TTbar_plus_X_analysis/MuPlusJets/Ref selection/Vertices/nVertex_reweighted', qcd_data_region_btag = '', + use_qcd_data_region = False, name_prefix = 'MuPlusJets_nVertex_reweighted_', x_limits = [0, 50], rebin = 1, diff --git a/src/cross_section_measurement/make_fit_variable_plots.py b/src/cross_section_measurement/make_fit_variable_plots.py index 33075194..a6883dfa 100644 --- a/src/cross_section_measurement/make_fit_variable_plots.py +++ b/src/cross_section_measurement/make_fit_variable_plots.py @@ -15,17 +15,9 @@ from config.latex_labels import b_tag_bins_latex, samples_latex, channel_latex from config.variable_binning import variable_bins_ROOT, fit_variable_bin_edges, bin_edges from config import XSectionConfig -from config import CMS -from matplotlib import rc, rcParams -rc( 'font', **CMS.font ) -rc( 'text', usetex = True ) -rcParams['text.latex.preamble'] = [ - r'\usepackage{siunitx}', # i need upright \micro symbols, but you need... - r'\sisetup{detect-all}', # ...this to force siunitx to actually use your fonts - r'\usepackage{helvet}', # set the normal font here - r'\usepackage{sansmath}', # load up the sansmath so that math -> helvet - r'\sansmath' # <- tricky! -- gotta actually tell tex to use! -] +from tools.latex import setup_matplotlib +# latex, font, etc +setup_matplotlib() common_fit_variables = ['M3', 'M_bl', 'angle_bl'] electron_fit_variables = copy( common_fit_variables ) diff --git a/test/tools_plotting.py b/test/tools_plotting.py new file mode 100644 index 00000000..bc596bb6 --- /dev/null +++ b/test/tools_plotting.py @@ -0,0 +1,28 @@ +''' +Created on 5 May 2015 + +@author: kreczko +''' +from tools.plotting import get_best_max_y +from tools.hist_utilities import value_errors_tuplelist_to_graph +from tools.hist_utilities import value_error_tuplelist_to_hist + +data_h = [( 3, 1 ), + ( 2, 1 ), + ( 1, 1 ), + ] +data_g = [( 3, 1, 1 ), + ( 2, 1, 1 ), + ( 1, 1, 1 ), + ] +bin_edges = [0, 1, 2, 3] + +def test_get_max_y_hist(): + h = value_error_tuplelist_to_hist(data_h, bin_edges) + max_y = get_best_max_y([h]) + assert max_y == 3 + 1 + +def test_get_max_y_graph(): + g = value_errors_tuplelist_to_graph(data_g, bin_edges) + max_y = get_best_max_y([g]) + assert max_y == 3 + 1 diff --git a/tools/hist_utilities.py b/tools/hist_utilities.py index 55558728..f4f4d584 100644 --- a/tools/hist_utilities.py +++ b/tools/hist_utilities.py @@ -95,25 +95,38 @@ def scale_histogram_errors( histogram, total_error ): def prepare_histograms( histograms, rebin = 1, scale_factor = 1., normalisation = {}, exclude_from_scaling = ['data'] ): for sample, histogram_dict in histograms.iteritems(): + # check if this is a simple dict + if histogram_dict.__class__.__name__ == 'Hist': + h = histogram_dict + scale = 1. + norm = None + if not sample in exclude_from_scaling: + scale = scale_factor + if sample in normalisation.keys(): + norm = normalisation[sample] + scale_and_rebin_histogram( histogram = h, scale_factor = scale, + normalisation = norm, rebin = rebin ) + continue + # otherwise go a level deeper for _, histogram in histogram_dict.iteritems(): - histogram.Rebin( rebin ) + scale = 1. + norm = None if not sample in exclude_from_scaling: - histogram.Scale( scale_factor ) - if normalisation != {} and histogram.Integral() != 0: - # TODO: this can be simplyfied and generalised - # by using normalisation.keys() + for loop - if sample == 'TTJet': - histogram.Scale( normalisation['TTJet'][0] / histogram.Integral() ) - scale_histogram_errors( histogram, normalisation['TTJet'][1] ) - if sample == 'SingleTop': - histogram.Scale( normalisation['SingleTop'][0] / histogram.Integral() ) - scale_histogram_errors( histogram, normalisation['SingleTop'][1] ) - if sample == 'V+Jets': - histogram.Scale( normalisation['V+Jets'][0] / histogram.Integral() ) - scale_histogram_errors( histogram, normalisation['V+Jets'][1] ) - if sample == 'QCD': - histogram.Scale( normalisation['QCD'][0] / histogram.Integral() ) - scale_histogram_errors( histogram, normalisation['QCD'][1] ) + scale = scale_factor + if sample in normalisation.keys(): + norm = normalisation[sample] + scale_and_rebin_histogram( histogram = histogram, + scale_factor = scale, + normalisation = norm, rebin = rebin ) + +def scale_and_rebin_histogram(histogram, scale_factor, + normalisation = None, + rebin = 1): + histogram.Rebin( rebin ) + histogram.Scale( scale_factor ) + if not normalisation is None and histogram.Integral() != 0: + histogram.Scale( normalisation[0] / histogram.Integral() ) + scale_histogram_errors( histogram, normalisation[1] ) def rebin_asymmetric( histogram, bins ): bin_array = array( 'd', bins ) diff --git a/tools/latex.py b/tools/latex.py new file mode 100644 index 00000000..d794f883 --- /dev/null +++ b/tools/latex.py @@ -0,0 +1,61 @@ +''' +Created on 5 May 2015 + +@author: kreczko +''' + +from matplotlib import rc, rcParams +from config import CMS +import subprocess +import os +from distutils.spawn import find_executable + + +def setup_matplotlib(): + ''' + Seup matplotlib with all the latex fancyness we have + ''' + rc( 'font', **CMS.font ) + rc( 'text', usetex = True ) + rcParams['text.latex.preamble'] = compile_package_list() + +def compile_package_list(): + ''' + We are looking for 3 packages: + - siunitx for scientific units + - helvet for Helvetica font (CMS style) + - sansmath for sans serif math (CMS style) + For this we use the 'kpsewhich' + ''' + package_list = [] + if is_installed('siunitx'): + # upright \micro symbols, \TeV, etc + package_list.append(r'\usepackage{siunitx}') + # force siunitx to actually use your fonts + package_list.append(r'\sisetup{detect-all}') + if is_installed('helvet'): + # set the normal font here + package_list.append(r'\usepackage{helvet}') + if is_installed('sansmath'): + # load up the sansmath so that math -> helvet + package_list.append(r'\usepackage{sansmath}') + # <- tricky! -- gotta actually tell tex to use! + package_list.append(r'\sansmath') + + return package_list + +def is_installed(latex_package): + # check if we have 'kpsewhich' installed + cmd = 'kpsewhich' + if find_executable(cmd) is None: + print 'Latex::WARNING: kpsewhich is not available' + return False + p = subprocess.check_output([cmd, latex_package + '.sty']) + # strip the line break + p = p.rstrip('\n') + # check if file exists + return os.path.exists(p) + + +if __name__ == '__main__': + print compile_package_list() diff --git a/tools/plotting.py b/tools/plotting.py index f2fec4c5..43138d87 100644 --- a/tools/plotting.py +++ b/tools/plotting.py @@ -17,10 +17,9 @@ import matplotlib.gridspec as gridspec from matplotlib.ticker import MultipleLocator, FixedLocator from itertools import cycle +from tools.latex import setup_matplotlib -from matplotlib import rc -rc('font',**CMS.font) -rc( 'text', usetex = True ) +setup_matplotlib() class Histogram_properties: name = 'Test' @@ -610,9 +609,11 @@ def get_best_max_y(histograms, include_error = True, x_limits = None): return max_y def __max__(plotable, include_error = True): - if isinstance(plotable, Hist): + if plotable is None: + return 0 + if plotable.__class__.__name__ == 'Hist': return plotable.max(include_error = include_error) - if isinstance(plotable, Graph): + if plotable.__class__.__name__ == 'Graph': ve = graph_to_value_errors_tuplelist(plotable) if not include_error: return max([v for v,_,_ in ve])