cmpatino's picture
Setup first version
ef1df2a
from typing import List, Tuple
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.figure import Figure
def hist_n_particles(q: List[int], label: str) -> Figure:
"""Generate histogram for particle counts on events.
:param q: Count per event.
:type q: List[int]
:param label: Plot title.
:type label: str
:return: Figure with histogram and histogram ratio.
:rtype: Figure
"""
fig, ax = plt.subplots(nrows=1, figsize=(15, 8))
bins, edges = np.histogram(q, bins=15, range=(0, 15))
for idx, val in enumerate(bins[::-1]):
if val > 0:
max_idx = len(bins) - idx - 1
edges = edges[:max_idx]
bins = bins[:max_idx]
break
ax.bar(edges, bins, width=1, alpha=0.6)
ax.set_title(label, fontsize=20, y=1.04)
ax.set_xticks(edges)
return fig
def hist_var(q: List[float], ax: plt.Axes, **kwargs) -> plt.Axes:
"""Create histogram with error bars.
:param q: Values to create histogram.
:type q: List[float]
:param ax: Axes in which histrogram is plotted.
:type ax: plt.Axes
:return: Axes with histogram.
:rtype: plt.Axes
"""
bins, edges, _ = ax.hist(
q, alpha=0.6, histtype="step", align="left", linewidth=4, **kwargs
)
errors = np.sqrt(bins)
bin_width = edges[1] - edges[0]
ax.bar(
x=edges[:-1],
bottom=bins,
height=errors,
width=bin_width,
alpha=0.0,
color="w",
hatch="/",
)
ax.bar(
x=edges[:-1],
bottom=bins,
height=-errors,
width=bin_width,
alpha=0.0,
color="w",
hatch="/",
)
return ax
def ratio_hist(
processes_q: List[List[float]],
hist_labels: List[str],
reference_label: str,
n_bins: int,
hist_range: Tuple[int, int],
title: str,
figsize=(15, 8),
) -> Figure:
"""Generate histrograms with ratio pad
:param processes_q: Quantity for each event and process
:type processes_q: List[List[float]]
:param hist_labels: Labels for each process
:type hist_labels: List[str]
:param reference_label: Label of process taken as the denominator of ratios
:type reference_label: str
:param n_bins: Number of bins for histograms
:type n_bins: int
:param hist_range: Range for histogram bins
:type hist_range: Tuple[int]
:param title: Plot title
:type title: str
:param figsize: Figure size for output plot
:type figsize: Tuple[int]
:return: Figure with histogram and histogram ratio.
:rtype: Figure
"""
fig, ax = plt.subplots(
nrows=len(processes_q),
ncols=1,
gridspec_kw={"height_ratios": [3] + [1] * (len(processes_q) - 1)},
sharex=True,
figsize=figsize,
)
legends = []
p_bins = {}
p_edges = {}
p_errors = {}
edges = None
for p, label in zip(processes_q, hist_labels):
bins = n_bins
if edges is not None:
bins = edges
bins, edges, _ = ax[0].hist(
x=p,
bins=bins,
range=hist_range,
fill=False,
label=label,
align="left",
histtype="step",
linewidth=4,
)
p_bins[label] = bins
p_edges[label] = edges
p_errors[label] = np.sqrt(bins)
legends += [label]
bin_width = edges[1] - edges[0]
for label in hist_labels:
ax[0].bar(
x=p_edges[label][:-1],
bottom=p_bins[label],
height=p_errors[label],
width=bin_width,
alpha=0.0,
color="w",
hatch="/",
)
ax[0].bar(
x=p_edges[label][:-1],
bottom=p_bins[label],
height=-p_errors[label],
width=bin_width,
alpha=0.0,
color="w",
hatch="/",
)
legends += ["_", "_"]
ax[0].set_ylabel("Events", fontsize=15)
ax[0].set_title(title, fontsize=20)
legends[-1] = "Stat. Uncertainty"
ax[0].legend(legends)
plot_idx = 1
ref_bins = p_bins[reference_label]
ref_edges = p_edges[reference_label]
ref_frac_error = p_errors[reference_label] / ref_bins
for label in hist_labels:
if label == reference_label:
continue
ratios = p_bins[label] / ref_bins
error_ratio = ratios * (ref_frac_error + p_errors[label] / p_bins[label])
ax[plot_idx].bar(
bottom=1.0,
height=error_ratio,
x=ref_edges[:-1],
width=bin_width,
alpha=0.3,
color="blue",
)
ax[plot_idx].bar(
bottom=1.0,
height=-error_ratio,
x=ref_edges[:-1],
width=bin_width,
alpha=0.3,
color="blue",
)
ax[plot_idx].scatter(ref_edges[:-1], ratios, marker="o", color="black")
ax[plot_idx].set_ylabel(f"{label}/{reference_label}")
plot_idx += 1
return fig