Skip to content

Int eff

puma.integrated_eff.IntegratedEfficiency #

Bases: puma.plot_base.PlotLineObject

Represent a single IntegratedEfficiency curve.

Parameters:

Name Type Description Default
disc_sig numpy.ndarray

Discriminant values for signal

required
disc_bkg numpy.ndarray

Discriminant values for background

required
key str | None

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 | None

Tagger name, by default None

None
flavour str | ftag.Label

Flavour label of the jets, by default None

None
**kwargs typing.Any

Keyword arguments passed to puma.PlotLineObject

{}
Source code in puma/integrated_eff.py
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 | Label = None,
    **kwargs: Any,
) -> None:
    super().__init__(**kwargs)
    self.disc_sig = np.asarray(disc_sig)
    self.disc_bkg = np.asarray(disc_bkg)
    self.n_vals = n_vals
    self.tagger = cast(str, 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.

Parameters:

Name Type Description Default
grid bool

Set the grid for the plots.

True
**kwargs typing.Any

Keyword arguments from puma.PlotObject

{}
Source code in puma/integrated_eff.py
def __init__(self, grid: bool = True, **kwargs: Any) -> None:
    super().__init__(grid=grid, **kwargs)
    self.int_effs: dict[str, IntegratedEfficiency] = {}
    self.tagger_ls: dict[str, str] = {}
    self.label_colours: dict[str, str] = {}
    self.leg_tagger_labels: dict[str, str] = {}
    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_eff puma.integrated_eff.IntegratedEfficiency

IntegratedEfficiency curve

required
key str | None

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

    Parameters
    ----------
    int_eff : IntegratedEfficiency
        IntegratedEfficiency curve
    key : str | None, optional
        Unique identifier for IntegratedEfficiency curve, by default None

    Raises
    ------
    KeyError
        If unique identifier key is used twice
    """
    key = cast(str, key if key is not None else f"{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
    assert isinstance(int_eff.label, str)
    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
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
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
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 typing.Any

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
def plot(self, **kwargs: Any) -> mpl.lines.Line2D:
    """Plotting integrated efficiency curves.

    Parameters
    ----------
    **kwargs: Any
        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