Closure to determine the bin associated with a value on an axis.

        It can apply a function to an axis if necessary to determine the proper bin.  Otherwise,
        it can just return a stored value.

        Note:
            To properly determine the value, carefully note the information below. In many cases,
            such as when we want values [2, 5), the values need to be shifted by a small epsilon
            to retrieve the proper bin. This is done automatically in ``SetRangeUser()``.

            >>> hist = ROOT.TH1D("test", "test", 10, 0, 10)
            >>> x = 2, y = 5
            >>> hist.FindBin(x)
            2
            >>> hist.FindBin(x+epsilon)
            2
            >>> hist.FindBin(y)
            6
            >>> hist.FindBin(y-epsilon)
            5

            Note that the bin + epsilon on the lower bin is not strictly necessary, but it is
            used for consistency with the upper bound.

        Args:
            func (Callable): Function to apply to the histogram axis. If it is None, the value
                will be returned.
            values (int or float): Value to pass to the function. Default: None (in which case,
                it won't be passed).
        Returns:
            Function to be called with an axis to determine the desired bin on that axis.

def apply_func_to_find_bin(
        func: Union[None, Callable[..., Union[float, int, Any]]],
        values: Optional[float] = None
    ) -> Callable[[Any], Union[float, int]]:
        """ Closure to determine the bin associated with a value on an axis.

        It can apply a function to an axis if necessary to determine the proper bin.  Otherwise,
        it can just return a stored value.

        Note:
            To properly determine the value, carefully note the information below. In many cases,
            such as when we want values [2, 5), the values need to be shifted by a small epsilon
            to retrieve the proper bin. This is done automatically in ``SetRangeUser()``.

            >>> hist = ROOT.TH1D("test", "test", 10, 0, 10)
            >>> x = 2, y = 5
            >>> hist.FindBin(x)
            2
            >>> hist.FindBin(x+epsilon)
            2
            >>> hist.FindBin(y)
            6
            >>> hist.FindBin(y-epsilon)
            5

            Note that the bin + epsilon on the lower bin is not strictly necessary, but it is
            used for consistency with the upper bound.

        Args:
            func (Callable): Function to apply to the histogram axis. If it is None, the value
                will be returned.
            values (int or float): Value to pass to the function. Default: None (in which case,
                it won't be passed).
        Returns:
            Function to be called with an axis to determine the desired bin on that axis.
        """
        def return_func(axis) -> Any:
            """ Apply the stored function and value to a given axis.

            Args:
                axis (TAxis or similar): Axis to which the function should be applied.
            Returns:
                any: The value returned by the function. Often a float or int, but not necessarily.
            """
            #logger.debug(f"func: {func}, values: {values}")
            if func:
                if values is not None:
                    return func(axis, values)
                else:
                    return func(axis)
            else:
                return values

        return return_func