Skip to content

Integrated Efficiency

puma.integrated_eff.IntegratedEfficiency #

Bases: puma.plot_base.PlotLineObject

Represent a single IntegratedEfficiency curve.

Initialise properties of IntegratedEfficiency object.

Parameters:

Name Type Description Default
disc_sig numpy.array

Discriminant values for signal

required
disc_bkg numpy.array

Discriminant values for background

required
key str

Identifier for IntegratedEfficiency e.g. tagger, by default None

None
n_vals int

Number of values to calculate the efficiency at, by default 500

500
tagger str

Tagger name, by default None

None
flavour str or ftag.Flavour

Flavour of the jets, by default None

None
**kwargs kwargs

Keyword arguments passed to puma.PlotLineObject

{}

Raises:

Type Description
ValueError

If sig_eff and bkg_rej have a different shape

Source code in puma/integrated_eff.py
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
def __init__(
    self,
    disc_sig: np.ndarray,
    disc_bkg: np.ndarray,
    key: str | None = None,
    n_vals: int = 500,
    tagger: str | None = None,
    flavour: str | Flavour = None,
    **kwargs,
) -> None:
    """Initialise properties of IntegratedEfficiency object.

    Parameters
    ----------
    disc_sig : np.array
        Discriminant values for signal
    disc_bkg : np.array
        Discriminant values for background
    key : str
        Identifier for IntegratedEfficiency e.g. tagger, by default None
    n_vals : int, optional
        Number of values to calculate the efficiency at, by default 500
    tagger : str, optional
        Tagger name, by default None
    flavour : str or Flavour, optional
        Flavour of the jets, by default None
    **kwargs : kwargs
        Keyword arguments passed to `puma.PlotLineObject`

    Raises
    ------
    ValueError
        If `sig_eff` and `bkg_rej` have a different shape
    """
    super().__init__(**kwargs)
    self.disc_sig = np.asarray(disc_sig)
    self.disc_bkg = np.asarray(disc_bkg)
    self.n_vals = n_vals
    self.tagger = tagger
    self.key = key
    self.flavour = Flavours[flavour] if isinstance(flavour, str) else flavour
    if self.label is None and self.flavour is not None:
        self.label = self.flavour.label
    self._calc_profile()

puma.integrated_eff.IntegratedEfficiencyPlot #

Bases: puma.plot_base.PlotBase

IntegratedEfficiencyPlot class.

IntegratedEfficiency plot properties.

Parameters:

Name Type Description Default
grid bool

Set the grid for the plots.

True
**kwargs kwargs

Keyword arguments from puma.PlotObject

{}
Source code in puma/integrated_eff.py
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
def __init__(self, grid: bool = True, **kwargs) -> None:
    """IntegratedEfficiency plot properties.

    Parameters
    ----------
    grid : bool, optional
        Set the grid for the plots.
    **kwargs : kwargs
        Keyword arguments from `puma.PlotObject`
    """
    super().__init__(grid=grid, **kwargs)
    self.int_effs = {}
    self.tagger_ls = {}
    self.label_colours = {}
    self.leg_tagger_labels = {}
    self.initialise_figure()
    self.disc_min, self.disc_max = (1e3, -1e3)
    self.default_linestyles = get_good_linestyles()
    self.legend_flavs = None
    self.leg_tagger_loc = "lower left"

    self.ymin = 0
    self.ymax = 1.2

add #

Adding puma.Roc object to figure.

Parameters:

Name Type Description Default
int_effs puma.IntegratedEfficiency

IntegratedEfficiency curve

required
key str

Unique identifier for IntegratedEfficiency curve, by default None

None

Raises:

Type Description
KeyError

If unique identifier key is used twice

Source code in puma/integrated_eff.py
 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
def add(self, int_eff: object, key: str | None = None):
    """Adding puma.Roc object to figure.

    Parameters
    ----------
    int_effs : puma.IntegratedEfficiency
        IntegratedEfficiency curve
    key : str, optional
        Unique identifier for IntegratedEfficiency curve, by default None

    Raises
    ------
    KeyError
        If unique identifier key is used twice
    """
    if key is None:
        key = len(self.int_effs) + 1
    if key in self.int_effs:
        raise KeyError(f"Duplicated key {key} already used for roc unique identifier.")

    self.int_effs[key] = int_eff
    # set linestyle
    if int_eff.tagger not in self.tagger_ls:
        self.tagger_ls[int_eff.tagger] = (
            self.default_linestyles[len(self.tagger_ls)]
            if int_eff.linestyle is None
            else int_eff.linestyle
        )
    elif int_eff.linestyle != self.tagger_ls[int_eff.tagger] and int_eff.linestyle is not None:
        logger.warning(
            "You specified a different linestyle for the same tagger"
            " %s. This will lead to a mismatch in the line colours"
            " and the legend.",
            int_eff.tagger,
        )
    if int_eff.linestyle is None:
        int_eff.linestyle = self.tagger_ls[int_eff.tagger]

    # set colours
    if int_eff.label not in self.label_colours:
        if int_eff.flavour is not None:
            self.label_colours[int_eff.label] = int_eff.flavour.colour
        else:
            curr_colours = set(self.label_colours.values())
            possible_colours = set(get_good_colours()) - curr_colours
            self.label_colours[int_eff.label] = (
                possible_colours.pop() if int_eff.colour is None else int_eff.colour
            )
    elif int_eff.colour != self.label_colours[int_eff.label] and int_eff.colour is not None:
        logger.warning(
            "You specified a different colour for the same label"
            " %s. This will lead to a mismatch in the line colours"
            " and the legend.",
            int_eff.label,
        )
    if int_eff.colour is None:
        int_eff.colour = self.label_colours[int_eff.label]

draw #

Draw plotting.

Parameters:

Name Type Description Default
x_label str

x-axis label, by default Discriminant

'Discriminant'
Source code in puma/integrated_eff.py
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
def draw(
    self,
    x_label: str = "Discriminant",
):
    """Draw plotting.

    Parameters
    ----------
    x_label : str, optional
        x-axis label, by default Discriminant
    """
    plt_handles = self.plot()
    xmin, xmax = self.get_xlim_auto()

    self.set_xlim(
        xmin if self.xmin is None else self.disc_min,
        xmax if self.xmax is None else self.disc_max,
    )
    self.set_title()
    self.set_y_lim()
    # self.set_log()
    self.set_y_lim()
    self.set_xlabel(label=x_label)
    self.set_ylabel(self.axis_top, label="Integrated efficiency")

    self.make_legend(plt_handles)

    self.plotting_done = True
    if self.apply_atlas_style is True:
        self.atlasify()
        # atlasify can only handle one legend. Therefore, we remove the frame of
        # the second legend by hand
        if self.legend_flavs is not None:
            self.legend_flavs.set_frame_on(False)

get_xlim_auto #

Returns min and max efficiency values.

Returns:

Type Description
float

Min and max efficiency values

Source code in puma/integrated_eff.py
157
158
159
160
161
162
163
164
165
166
167
168
169
def get_xlim_auto(self):
    """Returns min and max efficiency values.

    Returns
    -------
    float
        Min and max efficiency values
    """
    for elem in self.int_effs.values():
        self.disc_min = min(np.min(elem.x), self.disc_min)
        self.disc_max = max(np.max(elem.x), self.disc_max)

    return self.disc_min, self.disc_max

make_legend #

Make legend.

Parameters:

Name Type Description Default
handles list

List of handles

required
Source code in puma/integrated_eff.py
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
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
def make_legend(self, handles: list):
    """Make legend.

    Parameters
    ----------
    handles : list
        List of handles
    """
    line_list_tagger = [
        mpl.lines.Line2D(
            [],
            [],
            color="k",
            linestyle=self.tagger_ls[tagger],
            label=tagger,
        )
        for tagger in self.tagger_ls
    ]
    self.legend_flavs = self.axis_top.legend(
        handles=line_list_tagger,
        labels=[handle.get_label() for handle in line_list_tagger],
        loc=self.leg_tagger_loc,
        fontsize=self.leg_fontsize,
        ncol=self.leg_ncol,
    )
    self.axis_top.add_artist(self.legend_flavs)
    # Get the labels for the legends
    labels_list = []
    lines_list = []

    for line in handles:
        if line.get_label() not in labels_list:
            labels_list.append(line.get_label())
            lines_list.append(line)

    # Define the legend
    self.axis_top.legend(
        handles=lines_list,
        labels=labels_list,
        loc=self.leg_loc,
        fontsize=self.leg_fontsize,
        ncol=self.leg_ncol,
    )

plot #

Plotting integrated efficiency curves.

Parameters:

Name Type Description Default
**kwargs

Keyword arguments passed to plt.axis.plot

{}

Returns:

Type Description
puma.line_plot_2d.Line2D

matplotlib Line2D object

Source code in puma/integrated_eff.py
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
def plot(self, **kwargs) -> mpl.lines.Line2D:
    """Plotting integrated efficiency curves.

    Parameters
    ----------
    **kwargs: kwargs
        Keyword arguments passed to plt.axis.plot

    Returns
    -------
    Line2D
        matplotlib Line2D object
    """
    plt_handles = []
    for key, elem in self.int_effs.items():
        plt_handles += self.axis_top.plot(
            elem.x,
            elem.eff,
            linestyle=elem.linestyle,
            color=elem.colour,
            label=elem.label if elem is not None else key,
            zorder=2,
            **kwargs,
        )
    return plt_handles