def boxcox_transform(
    R, metadata=None, Lambda=None, threshold=None, zerovalue=None, inverse=False
):
    """
    The one-parameter Box-Cox transformation.

    The Box-Cox transform is a well-known power transformation introduced by
    Box and Cox (1964). In its one-parameter version, the Box-Cox transform
    takes the form T(x) = ln(x) for Lambda = 0,
    or T(x) = (x**Lambda - 1)/Lambda otherwise.

    Default parameters will produce a log transform (i.e. Lambda=0).

    Parameters
    ----------
    R: array-like
        Array of any shape to be transformed.
    metadata: dict, optional
        Metadata dictionary containing the transform, zerovalue and threshold
        attributes as described in the documentation of
        :py:mod:`pysteps.io.importers`.
    Lambda: float, optional
        Parameter Lambda of the Box-Cox transformation.
        It is 0 by default, which produces the log transformation.

        Choose Lambda < 1 for positively skewed data, Lambda > 1 for negatively
        skewed data.
    threshold: float, optional
        The value that is used for thresholding with the same units as R.
        If None, the threshold contained in metadata is used.
        If no threshold is found in the metadata,
        a value of 0.1 is used as default.
    zerovalue: float, optional
        The value to be assigned to no rain pixels as defined by the threshold.
        It is equal to the threshold - 1 by default.
    inverse: bool, optional
        If set to True, it performs the inverse transform. False by default.

    Returns
    -------
    R: array-like
        Array of any shape containing the (back-)transformed units.
    metadata: dict
        The metadata with updated attributes.

    References
    ----------
    Box, G. E. and Cox, D. R. (1964), An Analysis of Transformations. Journal
    of the Royal Statistical Society: Series B (Methodological), 26: 211-243.
    doi:10.1111/j.2517-6161.1964.tb00553.x
    """

    R = R.copy()

    if metadata is None:
        if inverse:
            metadata = {"transform": "BoxCox"}
        else:
            metadata = {"transform": None}

    else:
        metadata = metadata.copy()

    if not inverse:
        if metadata["transform"] == "BoxCox":
            return R, metadata

        if Lambda is None:
            Lambda = metadata.get("BoxCox_lambda", 0.0)

        if threshold is None:
            threshold = metadata.get("threshold", 0.1)

        zeros = R < threshold

        # Apply Box-Cox transform
        if Lambda == 0.0:
            R[~zeros] = np.log(R[~zeros])
            threshold = np.log(threshold)

        else:
            R[~zeros] = (R[~zeros] ** Lambda - 1) / Lambda
            threshold = (threshold**Lambda - 1) / Lambda

        # Set value for zeros
        if zerovalue is None:
            zerovalue = threshold - 1  # TODO: set to a more meaningful value
        R[zeros] = zerovalue

        metadata["transform"] = "BoxCox"
        metadata["BoxCox_lambda"] = Lambda
        metadata["zerovalue"] = zerovalue
        metadata["threshold"] = threshold

    elif inverse:
        if metadata["transform"] not in ["BoxCox", "log"]:
            return R, metadata

        if Lambda is None:
            Lambda = metadata.pop("BoxCox_lambda", 0.0)
        if threshold is None:
            threshold = metadata.get("threshold", -10.0)
        if zerovalue is None:
            zerovalue = 0.0

        # Apply inverse Box-Cox transform
        if Lambda == 0.0:
            R = np.exp(R)
            threshold = np.exp(threshold)

        else:
            R = np.exp(np.log(Lambda * R + 1) / Lambda)
            threshold = np.exp(np.log(Lambda * threshold + 1) / Lambda)

        R[R < threshold] = zerovalue

        metadata["transform"] = None
        metadata["zerovalue"] = zerovalue
        metadata["threshold"] = threshold

    return R, metadata
The one-parameter Box-Cox transformation.

The Box-Cox transform is a well-known power transformation introduced by
Box and Cox (1964). In its one-parameter version, the Box-Cox transform
takes the form T(x) = ln(x) for Lambda = 0,
or T(x) = (x**Lambda - 1)/Lambda otherwise.

Default parameters will produce a log transform (i.e. Lambda=0).

Parameters
----------
R: array-like
Array of any shape to be transformed.
metadata: dict, optional
Metadata dictionary containing the transform, zerovalue and threshold
attributes as described in the documentation of
:py:mod:`pysteps.io.importers`.
Lambda: float, optional
Parameter Lambda of the Box-Cox transformation.
It is 0 by default, which produces the log transformation.

Choose Lambda < 1 for positively skewed data, Lambda > 1 for negatively
skewed data.
threshold: float, optional
The value that is used for thresholding with the same units as R.
If None, the threshold contained in metadata is used.
If no threshold is found in the metadata,
a value of 0.1 is used as default.
zerovalue: float, optional
The value to be assigned to no rain pixels as defined by the threshold.
It is equal to the threshold - 1 by default.
inverse: bool, optional
If set to True, it performs the inverse transform. False by default.

Returns
-------
R: array-like
Array of any shape containing the (back-)transformed units.
metadata: dict
The metadata with updated attributes.

References
----------
Box, G. E. and Cox, D. R. (1964), An Analysis of Transformations. Journal
of the Royal Statistical Society: Series B (Methodological), 26: 211-243.
doi:10.1111/j.2517-6161.1964.tb00553.x
pysteps/utils/transformation.py