Skip to content

create_bounds

Functions:

Name Description
create_bounds

Creates a 2D array of start and end times between the start and stop bounds.

create_bounds_from_labels

Functions#

create_bounds #

create_bounds(
    start: float | datetime64 | str,
    stop: float | datetime64 | str,
    interval: float | str,
    width: float | str | None = None,
    alignment: (
        Literal["left", "right", "center"] | float
    ) = "left",
) -> tuple[np.ndarray, np.ndarray]

Creates a 2D array of start and end times between the start and stop bounds. Returns both the 1D coordinate labels and the 2D array of coordinate bounds.

Parameters:

Name Type Description Default
start datetime64 | str

The starting time corresponding with the first bound (inclusive). Can be provided either as a numpy datetime64 scalar or as a yyyy-mm-dd hh🇲🇲ss string. Note the first value of the returned bounds array may be less than this if the bins are not left-aligned (see alignment parameter for more details.)

required
stop datetime64 | str

The ending point of the bounds (exclusive). The bounds array is guaranteed to end sometime before this point. Can be provided either as a numpy datetime64 scalar or as a yyyy-mm-dd hh🇲🇲ss string.

required
interval int | str

The gap between the centers of the output bounds in seconds. Can be provided as either a number or as a string (e.g., "30min")

required
width int | str | None

The difference between the end of each bound and the start of each bound in seconds. Can be provided as either a number or a string (e.g., "30min"). This can be set independently of the interval to make the bounds overlap (if the width is greater than the interval), introduce gaps (if the width is less than the interval - why, idk), or to make the bounds align perfectly (by setting width = interval, the default).

None
alignment float

Controls where the bounds are located relative to the label for each bin. Can be provided as a literal string ("left", "right", or "center"), or a value from 0.0 - 1.0 to specify an alignment in-between the two (left=0, right=1, center=0.5).

'left'

Raises:

Type Description
ValueError

Raises an error if the stop time is not greater than the start time.

Returns:

Type Description
ndarray

np.ndarray: The 1-dimensional array of labels for the bounds.

ndarray

np.ndarray: The 2-dimensional array of time bounds.

Source code in tsdat/transform_v2/utils/create_bounds.py
def create_bounds(
    start: float | np.datetime64 | str,
    stop: float | np.datetime64 | str,
    interval: float | str,
    width: float | str | None = None,
    alignment: Literal["left", "right", "center"] | float = "left",
) -> tuple[np.ndarray, np.ndarray]:
    """
    Creates a 2D array of start and end times between the start and stop bounds.
    Returns both the 1D coordinate labels and the 2D array of coordinate bounds.

    Args:
        start (np.datetime64 | str): The starting time corresponding with the first
            bound (inclusive). Can be provided either as a numpy datetime64 scalar or as
            a yyyy-mm-dd hh:mm:ss string. Note the first value of the returned bounds
            array may be less than this if the bins are not left-aligned (see alignment
            parameter for more details.)
        stop (np.datetime64 | str): The ending point of the bounds (exclusive). The
            bounds array is guaranteed to end sometime before this point. Can be
            provided either as a numpy datetime64 scalar or as a yyyy-mm-dd hh:mm:ss
            string.
        interval (int | str): The gap between the centers of the output bounds in
            seconds. Can be provided as either a number or as a string (e.g., "30min")
        width (int | str | None, optional): The difference between the end of each bound
            and the start of each bound in seconds. Can be provided as either a number
            or a string (e.g., "30min"). This can be set independently of the interval
            to make the bounds overlap (if the width is greater than the interval),
            introduce gaps (if the width is less than the interval - why, idk), or to
            make the bounds align perfectly (by setting width = interval, the default).
        alignment (float, optional): Controls where the bounds are located relative to
            the label for each bin. Can be provided as a literal string ("left",
            "right", or "center"), or a value from 0.0 - 1.0 to specify an alignment
            in-between the two (left=0, right=1, center=0.5).

    Raises:
        ValueError: Raises an error if the stop time is not greater than the start time.

    Returns:
        np.ndarray: The 1-dimensional array of labels for the bounds.
        np.ndarray: The 2-dimensional array of time bounds.
    """
    is_datetime_like = isinstance(start, (str, np.datetime64))

    if is_datetime_like:
        _start = 0.0
        _stop = (pd.to_datetime(stop) - pd.to_datetime(start)).total_seconds()
        _interval = pd.to_timedelta(interval).total_seconds()
        _width = _interval if width is None else pd.to_timedelta(width).total_seconds()
    else:
        # Casting just for the type checker since we know that these will all be numbers
        _start = cast(float, start)
        _stop = cast(float, stop)
        _interval = cast(float, interval)
        _width = cast(float, width)

    labels, bounds = _create_bounds(
        start=_start,
        stop=_stop,
        interval=_interval,
        width=_width,
        alignment=alignment,
    )

    if is_datetime_like:
        start_dt = pd.to_datetime(start)
        labels = (pd.to_timedelta(labels, unit="s") + start_dt).to_numpy(
            dtype="datetime64[ns]"
        )
        bound_starts = (pd.to_timedelta(bounds[:, 0], unit="s") + start_dt).to_numpy()
        bound_stops = (pd.to_timedelta(bounds[:, 1], unit="s") + start_dt).to_numpy()
        bounds = np.column_stack((bound_starts, bound_stops)).astype("datetime64[ns]")

    return labels, bounds

create_bounds_from_labels #

create_bounds_from_labels(
    labels: ndarray,
    width: float | str | None = None,
    alignment: (
        Literal["left", "right", "center"] | float
    ) = "left",
) -> np.ndarray
Source code in tsdat/transform_v2/utils/create_bounds.py
def create_bounds_from_labels(
    labels: np.ndarray,  # Can be datetime or float
    width: float | str | None = None,  # Can be str or float or None
    alignment: Literal["left", "right", "center"] | float = "left",  # Literal or 0 to 1
) -> np.ndarray:
    if isinstance(alignment, str):
        alignment = {"left": 0.0, "right": 1.0, "center": 0.5}[alignment]

    is_datetime_like = np.issubdtype(labels.dtype, np.datetime64)

    _width = width
    _labels = labels

    if is_datetime_like:
        np_timedeltas = labels - labels[0]
        _labels = pd.to_timedelta(np_timedeltas).total_seconds()  # type: ignore
        if width is not None:
            _width = pd.to_timedelta(width).total_seconds()

    _width = cast(float, _width)
    _labels = cast(np.ndarray, _labels)

    _bounds = _create_bounds_from_labels(
        labels=_labels,
        width=_width,
        alignment=alignment,
    )

    if is_datetime_like:
        start_dt = pd.to_datetime(labels[0])
        bound_starts = (pd.to_timedelta(_bounds[:, 0], unit="s") + start_dt).to_numpy()
        bound_stops = (pd.to_timedelta(_bounds[:, 1], unit="s") + start_dt).to_numpy()
        _bounds = np.column_stack((bound_starts, bound_stops)).astype("datetime64[ns]")

    return _bounds