File size: 5,064 Bytes
ef1df2a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
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