Skip to content

Comparing histograms¤

mplhep provides dedicated comparison plotters in the mh.comp module for creating plots with different comparison panels. The following functions are available:

  • mh.comp.hists(): compare two histograms, plot the main plot and a comparison panel.
  • mh.comp.data_model(): compare a model made of histograms or functions to data, plot the main plot and a comparison panel.
  • mh.comp.comparison(): to only plot the comparison panel given two histograms.
  • mh.comp.get_comparison(): to get the [values, lower_uncertainties, upper_uncertainties] for a given comparison type.
Prerequisites

Throughout this guide the following codeblock is assumed.

import matplotlib.pyplot as plt
import numpy as np
import hist
np.random.seed(42)
import mplhep as mh
# mh.style.use('<as appropriate>')

Comparing two histograms¤

Available methods¤

To compare two histograms, use mh.comp.hists(). This function takes two histograms as input and creates a figure with a main plot showing both histograms and a comparison panel below it.

The comparison parameter accepts:

  • ratio: \(\frac{\text{h1}}{\text{h2}}\)
  • split_ratio: same as ratio, but the uncertainties of h1 and h2 are shown separately in the comparison panel (used extensively in data/model comparisons, see below)
  • pull: \(\frac{\text{h1} - \text{h2}}{\sqrt{\sigma_{\text{h1}}^2 + \sigma_{\text{h2}}^2}}\)
  • difference: \(\text{h1} - \text{h2}\)
  • relative_difference: \(\frac{\text{h1} - \text{h2}}{\text{h2}}\)
  • asymmetry: \(\frac{\text{h1} - \text{h2}}{\text{h1} + \text{h2}}\)
  • efficiency: \(\frac{\text{h1}}{\text{h2}}\) (with uncertainties from eq.19 here)
# Generate sample data and model
x1 = np.random.normal(0, 1, 1000)
x2 = np.random.normal(0, 1.05, 1000)
h1 = hist.new.Reg(25, -4, 4).Weight().fill(x1)
h2 = hist.new.Reg(25, -4, 4).Weight().fill(x2)

# Create comparison plot
fig, ax_main, ax_comp = mh.comp.hists(
 h1,
 h2,
 comparison='ratio',
 xlabel='Observable [GeV]',
 ylabel='Events',
 h1_label='h1',
 h2_label='h2'
)
# Generate sample data and model
x1 = np.random.normal(0, 1, 1000)
x2 = np.random.normal(0, 1.05, 1000)
h1 = hist.new.Reg(25, -4, 4).Weight().fill(x1)
h2 = hist.new.Reg(25, -4, 4).Weight().fill(x2)

# Create comparison plot
fig, ax_main, ax_comp = mh.comp.hists(
 h1,
 h2,
 comparison='split_ratio',
 xlabel='Observable [GeV]',
 ylabel='Events',
 h1_label='h1',
 h2_label='h2'
)
# Generate sample data and model
x1 = np.random.normal(0, 1, 1000)
x2 = np.random.normal(0, 1.05, 1000)
h1 = hist.new.Reg(25, -4, 4).Weight().fill(x1)
h2 = hist.new.Reg(25, -4, 4).Weight().fill(x2)

# Create comparison plot
fig, ax_main, ax_comp = mh.comp.hists(
 h1,
 h2,
 comparison='pull',
 xlabel='Observable [GeV]',
 ylabel='Events',
 h1_label='h1',
 h2_label='h2'
)
# Generate sample data and model
x1 = np.random.normal(0, 1, 1000)
x2 = np.random.normal(0, 1.05, 1000)
h1 = hist.new.Reg(25, -4, 4).Weight().fill(x1)
h2 = hist.new.Reg(25, -4, 4).Weight().fill(x2)

# Create comparison plot
fig, ax_main, ax_comp = mh.comp.hists(
 h1,
 h2,
 comparison='difference',
 xlabel='Observable [GeV]',
 ylabel='Events',
 h1_label='h1',
 h2_label='h2'
)
# Generate sample data and model
x1 = np.random.normal(0, 1, 1000)
x2 = np.random.normal(0, 1.05, 1000)
h1 = hist.new.Reg(25, -4, 4).Weight().fill(x1)
h2 = hist.new.Reg(25, -4, 4).Weight().fill(x2)

# Create comparison plot
fig, ax_main, ax_comp = mh.comp.hists(
 h1,
 h2,
 comparison='relative_difference',
 xlabel='Observable [GeV]',
 ylabel='Events',
 h1_label='h1',
 h2_label='h2'
)
# Generate sample data and model
x1 = np.random.normal(0, 1, 1000)
x2 = np.random.normal(0, 1.05, 1000)
h1 = hist.new.Reg(25, -4, 4).Weight().fill(x1)
h2 = hist.new.Reg(25, -4, 4).Weight().fill(x2)

# Create comparison plot
fig, ax_main, ax_comp = mh.comp.hists(
 h1,
 h2,
 comparison='asymmetry',
 xlabel='Observable [GeV]',
 ylabel='Events',
 h1_label='h1',
 h2_label='h2'
)
# Generate sample data and model
x2 = np.random.normal(0, 1, 1000)
x1 = np.random.choice(x2, size=500, replace=False)
h1 = hist.new.Reg(25, -4, 4).Weight().fill(x1) # h1 needs to be a subset of h2
h2 = hist.new.Reg(25, -4, 4).Weight().fill(x2)

# Create comparison plot
fig, ax_main, ax_comp = mh.comp.hists(
 h1,
 h2,
 comparison='efficiency',
 xlabel='Observable [GeV]',
 ylabel='Events',
 h1_label='h1',
 h2_label='h2'
)
# Generate sample data and model
x1 = np.random.normal(0, 1, 1000)
x2 = np.random.normal(0, 1.05, 1000)
h1 = hist.new.Reg(25, -4, 4).Weight().fill(x1)
h2 = hist.new.Reg(25, -4, 4).Weight().fill(x2)

# Create comparison plot
fig, ax_main, ax_comp = mh.comp.hists(
 h1,
 h2,
 comparison='ratio',
 xlabel='Observable [GeV]',
 ylabel='Events',
 h1_label='h1',
 h2_label='h2'
)
txt_obj = mh.add_text('plothist', loc='over left', ax=ax_main)
# Generate sample data and model
x1 = np.random.normal(0, 1, 1000)
x2 = np.random.normal(0, 1.05, 1000)
h1 = hist.new.Reg(25, -4, 4).Weight().fill(x1)
h2 = hist.new.Reg(25, -4, 4).Weight().fill(x2)

# Create comparison plot
fig, ax_main, ax_comp = mh.comp.hists(
 h1,
 h2,
 comparison='split_ratio',
 xlabel='Observable [GeV]',
 ylabel='Events',
 h1_label='h1',
 h2_label='h2'
)
txt_obj = mh.add_text('plothist', loc='over left', ax=ax_main)
# Generate sample data and model
x1 = np.random.normal(0, 1, 1000)
x2 = np.random.normal(0, 1.05, 1000)
h1 = hist.new.Reg(25, -4, 4).Weight().fill(x1)
h2 = hist.new.Reg(25, -4, 4).Weight().fill(x2)

# Create comparison plot
fig, ax_main, ax_comp = mh.comp.hists(
 h1,
 h2,
 comparison='pull',
 xlabel='Observable [GeV]',
 ylabel='Events',
 h1_label='h1',
 h2_label='h2'
)
txt_obj = mh.add_text('plothist', loc='over left', ax=ax_main)
# Generate sample data and model
x1 = np.random.normal(0, 1, 1000)
x2 = np.random.normal(0, 1.05, 1000)
h1 = hist.new.Reg(25, -4, 4).Weight().fill(x1)
h2 = hist.new.Reg(25, -4, 4).Weight().fill(x2)

# Create comparison plot
fig, ax_main, ax_comp = mh.comp.hists(
 h1,
 h2,
 comparison='difference',
 xlabel='Observable [GeV]',
 ylabel='Events',
 h1_label='h1',
 h2_label='h2'
)
txt_obj = mh.add_text('plothist', loc='over left', ax=ax_main)
# Generate sample data and model
x1 = np.random.normal(0, 1, 1000)
x2 = np.random.normal(0, 1.05, 1000)
h1 = hist.new.Reg(25, -4, 4).Weight().fill(x1)
h2 = hist.new.Reg(25, -4, 4).Weight().fill(x2)

# Create comparison plot
fig, ax_main, ax_comp = mh.comp.hists(
 h1,
 h2,
 comparison='relative_difference',
 xlabel='Observable [GeV]',
 ylabel='Events',
 h1_label='h1',
 h2_label='h2'
)
txt_obj = mh.add_text('plothist', loc='over left', ax=ax_main)
# Generate sample data and model
x1 = np.random.normal(0, 1, 1000)
x2 = np.random.normal(0, 1.05, 1000)
h1 = hist.new.Reg(25, -4, 4).Weight().fill(x1)
h2 = hist.new.Reg(25, -4, 4).Weight().fill(x2)

# Create comparison plot
fig, ax_main, ax_comp = mh.comp.hists(
 h1,
 h2,
 comparison='asymmetry',
 xlabel='Observable [GeV]',
 ylabel='Events',
 h1_label='h1',
 h2_label='h2'
)
txt_obj = mh.add_text('plothist', loc='over left', ax=ax_main)
# Generate sample data and model
x2 = np.random.normal(0, 1, 1000)
x1 = np.random.choice(x2, size=500, replace=False)
h1 = hist.new.Reg(25, -4, 4).Weight().fill(x1) # h1 needs to be a subset of h2
h2 = hist.new.Reg(25, -4, 4).Weight().fill(x2)

# Create comparison plot
fig, ax_main, ax_comp = mh.comp.hists(
 h1,
 h2,
 comparison='efficiency',
 xlabel='Observable [GeV]',
 ylabel='Events',
 h1_label='h1',
 h2_label='h2'
)
txt_obj = mh.add_text('plothist', loc='over left', ax=ax_main)
# Generate sample data and model
x1 = np.random.normal(0, 1, 1000)
x2 = np.random.normal(0, 1.05, 1000)
h1 = hist.new.Reg(25, -4, 4).Weight().fill(x1)
h2 = hist.new.Reg(25, -4, 4).Weight().fill(x2)

# Create comparison plot
fig, ax_main, ax_comp = mh.comp.hists(
 h1,
 h2,
 comparison='ratio',
 xlabel='Observable [GeV]',
 ylabel='Events',
 h1_label='h1',
 h2_label='h2'
)
mh.cms.label(data=True, ax=ax_main)
# Generate sample data and model
x1 = np.random.normal(0, 1, 1000)
x2 = np.random.normal(0, 1.05, 1000)
h1 = hist.new.Reg(25, -4, 4).Weight().fill(x1)
h2 = hist.new.Reg(25, -4, 4).Weight().fill(x2)

# Create comparison plot
fig, ax_main, ax_comp = mh.comp.hists(
 h1,
 h2,
 comparison='split_ratio',
 xlabel='Observable [GeV]',
 ylabel='Events',
 h1_label='h1',
 h2_label='h2'
)
mh.cms.label(data=True, ax=ax_main)
# Generate sample data and model
x1 = np.random.normal(0, 1, 1000)
x2 = np.random.normal(0, 1.05, 1000)
h1 = hist.new.Reg(25, -4, 4).Weight().fill(x1)
h2 = hist.new.Reg(25, -4, 4).Weight().fill(x2)

# Create comparison plot
fig, ax_main, ax_comp = mh.comp.hists(
 h1,
 h2,
 comparison='pull',
 xlabel='Observable [GeV]',
 ylabel='Events',
 h1_label='h1',
 h2_label='h2'
)
mh.cms.label(data=True, ax=ax_main)
# Generate sample data and model
x1 = np.random.normal(0, 1, 1000)
x2 = np.random.normal(0, 1.05, 1000)
h1 = hist.new.Reg(25, -4, 4).Weight().fill(x1)
h2 = hist.new.Reg(25, -4, 4).Weight().fill(x2)

# Create comparison plot
fig, ax_main, ax_comp = mh.comp.hists(
 h1,
 h2,
 comparison='difference',
 xlabel='Observable [GeV]',
 ylabel='Events',
 h1_label='h1',
 h2_label='h2'
)
mh.cms.label(data=True, ax=ax_main)
# Generate sample data and model
x1 = np.random.normal(0, 1, 1000)
x2 = np.random.normal(0, 1.05, 1000)
h1 = hist.new.Reg(25, -4, 4).Weight().fill(x1)
h2 = hist.new.Reg(25, -4, 4).Weight().fill(x2)

# Create comparison plot
fig, ax_main, ax_comp = mh.comp.hists(
 h1,
 h2,
 comparison='relative_difference',
 xlabel='Observable [GeV]',
 ylabel='Events',
 h1_label='h1',
 h2_label='h2'
)
mh.cms.label(data=True, ax=ax_main)
# Generate sample data and model
x1 = np.random.normal(0, 1, 1000)
x2 = np.random.normal(0, 1.05, 1000)
h1 = hist.new.Reg(25, -4, 4).Weight().fill(x1)
h2 = hist.new.Reg(25, -4, 4).Weight().fill(x2)

# Create comparison plot
fig, ax_main, ax_comp = mh.comp.hists(
 h1,
 h2,
 comparison='asymmetry',
 xlabel='Observable [GeV]',
 ylabel='Events',
 h1_label='h1',
 h2_label='h2'
)
mh.cms.label(data=True, ax=ax_main)
# Generate sample data and model
x2 = np.random.normal(0, 1, 1000)
x1 = np.random.choice(x2, size=500, replace=False)
h1 = hist.new.Reg(25, -4, 4).Weight().fill(x1) # h1 needs to be a subset of h2
h2 = hist.new.Reg(25, -4, 4).Weight().fill(x2)

# Create comparison plot
fig, ax_main, ax_comp = mh.comp.hists(
 h1,
 h2,
 comparison='efficiency',
 xlabel='Observable [GeV]',
 ylabel='Events',
 h1_label='h1',
 h2_label='h2'
)
mh.cms.label(data=True, ax=ax_main)
# Generate sample data and model
x1 = np.random.normal(0, 1, 1000)
x2 = np.random.normal(0, 1.05, 1000)
h1 = hist.new.Reg(25, -4, 4).Weight().fill(x1)
h2 = hist.new.Reg(25, -4, 4).Weight().fill(x2)

# Create comparison plot
fig, ax_main, ax_comp = mh.comp.hists(
 h1,
 h2,
 comparison='ratio',
 xlabel='Observable [GeV]',
 ylabel='Events',
 h1_label='h1',
 h2_label='h2'
)
mh.atlas.label(data=True, ax=ax_main)
mh.mpl_magic(soft_fail=True)
# Generate sample data and model
x1 = np.random.normal(0, 1, 1000)
x2 = np.random.normal(0, 1.05, 1000)
h1 = hist.new.Reg(25, -4, 4).Weight().fill(x1)
h2 = hist.new.Reg(25, -4, 4).Weight().fill(x2)

# Create comparison plot
fig, ax_main, ax_comp = mh.comp.hists(
 h1,
 h2,
 comparison='split_ratio',
 xlabel='Observable [GeV]',
 ylabel='Events',
 h1_label='h1',
 h2_label='h2'
)
mh.atlas.label(data=True, ax=ax_main)
mh.mpl_magic(soft_fail=True)
# Generate sample data and model
x1 = np.random.normal(0, 1, 1000)
x2 = np.random.normal(0, 1.05, 1000)
h1 = hist.new.Reg(25, -4, 4).Weight().fill(x1)
h2 = hist.new.Reg(25, -4, 4).Weight().fill(x2)

# Create comparison plot
fig, ax_main, ax_comp = mh.comp.hists(
 h1,
 h2,
 comparison='pull',
 xlabel='Observable [GeV]',
 ylabel='Events',
 h1_label='h1',
 h2_label='h2'
)
mh.atlas.label(data=True, ax=ax_main)
mh.mpl_magic(soft_fail=True)
# Generate sample data and model
x1 = np.random.normal(0, 1, 1000)
x2 = np.random.normal(0, 1.05, 1000)
h1 = hist.new.Reg(25, -4, 4).Weight().fill(x1)
h2 = hist.new.Reg(25, -4, 4).Weight().fill(x2)

# Create comparison plot
fig, ax_main, ax_comp = mh.comp.hists(
 h1,
 h2,
 comparison='difference',
 xlabel='Observable [GeV]',
 ylabel='Events',
 h1_label='h1',
 h2_label='h2'
)
mh.atlas.label(data=True, ax=ax_main)
mh.mpl_magic(soft_fail=True)
# Generate sample data and model
x1 = np.random.normal(0, 1, 1000)
x2 = np.random.normal(0, 1.05, 1000)
h1 = hist.new.Reg(25, -4, 4).Weight().fill(x1)
h2 = hist.new.Reg(25, -4, 4).Weight().fill(x2)

# Create comparison plot
fig, ax_main, ax_comp = mh.comp.hists(
 h1,
 h2,
 comparison='relative_difference',
 xlabel='Observable [GeV]',
 ylabel='Events',
 h1_label='h1',
 h2_label='h2'
)
mh.atlas.label(data=True, ax=ax_main)
mh.mpl_magic(soft_fail=True)
# Generate sample data and model
x1 = np.random.normal(0, 1, 1000)
x2 = np.random.normal(0, 1.05, 1000)
h1 = hist.new.Reg(25, -4, 4).Weight().fill(x1)
h2 = hist.new.Reg(25, -4, 4).Weight().fill(x2)

# Create comparison plot
fig, ax_main, ax_comp = mh.comp.hists(
 h1,
 h2,
 comparison='asymmetry',
 xlabel='Observable [GeV]',
 ylabel='Events',
 h1_label='h1',
 h2_label='h2'
)
mh.atlas.label(data=True, ax=ax_main)
mh.mpl_magic(soft_fail=True)
# Generate sample data and model
x2 = np.random.normal(0, 1, 1000)
x1 = np.random.choice(x2, size=500, replace=False)
h1 = hist.new.Reg(25, -4, 4).Weight().fill(x1) # h1 needs to be a subset of h2
h2 = hist.new.Reg(25, -4, 4).Weight().fill(x2)

# Create comparison plot
fig, ax_main, ax_comp = mh.comp.hists(
 h1,
 h2,
 comparison='efficiency',
 xlabel='Observable [GeV]',
 ylabel='Events',
 h1_label='h1',
 h2_label='h2'
)
mh.atlas.label(data=True, ax=ax_main)
mh.mpl_magic(soft_fail=True)
# Generate sample data and model
x1 = np.random.normal(0, 1, 1000)
x2 = np.random.normal(0, 1.05, 1000)
h1 = hist.new.Reg(25, -4, 4).Weight().fill(x1)
h2 = hist.new.Reg(25, -4, 4).Weight().fill(x2)

# Create comparison plot
fig, ax_main, ax_comp = mh.comp.hists(
 h1,
 h2,
 comparison='ratio',
 xlabel='Observable [GeV]',
 ylabel='Events',
 h1_label='h1',
 h2_label='h2'
)
mh.lhcb.label(data=True, ax=ax_main)
# Generate sample data and model
x1 = np.random.normal(0, 1, 1000)
x2 = np.random.normal(0, 1.05, 1000)
h1 = hist.new.Reg(25, -4, 4).Weight().fill(x1)
h2 = hist.new.Reg(25, -4, 4).Weight().fill(x2)

# Create comparison plot
fig, ax_main, ax_comp = mh.comp.hists(
 h1,
 h2,
 comparison='split_ratio',
 xlabel='Observable [GeV]',
 ylabel='Events',
 h1_label='h1',
 h2_label='h2'
)
mh.lhcb.label(data=True, ax=ax_main)