Skip to content

tracksdata

A common data structure and basic tools for multi-object tracking.

Modules:

  • array

    Array representation of graphical data.

  • attrs

    Module to compose attribute expressions for attribute filtering or value evaluation.

  • constants

    Module to define default and often global values used through tracksdata.

  • edges

    Edge operators for creating connections between nodes of a graph.

  • functional

    Functional utilities for graph operations.

  • graph

    Graph backends for representing tracking data as directed graphs in memory or on disk.

  • io

    Input/output utilities for loading and saving tracking data in various formats.

  • metrics

    Evaluation metrics for tracking performance, including the CTC benchmark metrics.

  • nodes

    Node operators for creating nodes and their respective attributes (e.g. masks) in a graph.

  • options

    Global options system for TracksData.

  • solvers

    Solvers for finding a valid tracking solution from a candidate graph.

  • utils

    Utility functions for data processing, type conversions, and progress tracking.

Classes:

  • EdgeAttr

    Wrapper of Attr to represent an edge attribute.

  • NodeAttr

    Wrapper of Attr to represent a node attribute.

EdgeAttr

EdgeAttr(value: ExprInput)

Bases: Attr

Wrapper of Attr to represent an edge attribute.

See Also

Attr: The base class for all attributes.

Methods:

  • evaluate

    Evaluate the expression on a DataFrame returning a numeric result.

  • has_inf

    Check if any column in the expression is multiplied by infinity or negative infinity.

  • has_neg_inf

    Check if any column in the expression is multiplied by negative infinity.

  • has_pos_inf

    Check if any column in the expression is multiplied by positive infinity.

Attributes:

Source code in src/tracksdata/attrs.py
def __init__(self, value: ExprInput) -> None:
    self._inf_exprs = []  # expressions multiplied by +inf
    self._neg_inf_exprs = []  # expressions multiplied by -inf

    if isinstance(value, str):
        self.expr = pl.col(value)
    elif isinstance(value, Attr):
        self.expr = value.expr
        # Copy infinity tracking from the other AttrExpr
        self._inf_exprs = value.inf_exprs
        self._neg_inf_exprs = value.neg_inf_exprs
    elif isinstance(value, AttrComparison):
        attr = value.to_attr()
        self.expr = attr.expr
        self._inf_exprs = attr.inf_exprs
        self._neg_inf_exprs = attr.neg_inf_exprs
    elif isinstance(value, Expr):
        self.expr = value
    else:
        self.expr = pl.lit(value)

expr_columns property

expr_columns: list[str]

Get the names of columns in the expression.

inf_columns property

inf_columns: list[str]

Get the names of columns multiplied by positive infinity.

inf_exprs property

inf_exprs: list[Attr]

Get the expressions multiplied by positive infinity.

neg_inf_columns property

neg_inf_columns: list[str]

Get the names of columns multiplied by negative infinity.

neg_inf_exprs property

neg_inf_exprs: list[Attr]

Get the expressions multiplied by negative infinity.

_delegate_comparison_operator

_delegate_comparison_operator(other: ExprInput, op: Callable, reverse: bool = False) -> AttrComparison | Attr

Simplified version of _delegate_operator for comparison operators. AttrComparison has a limited scope and it's mainly used for filtering. If creating an AttrComparison object is not possible, it will return an Attr object.

Parameters:

  • other

    (ExprInput) –

    The other expression to delegate the operator to.

  • op

    (Callable) –

    The operator to delegate.

  • reverse

    (bool, default: False ) –

    Whether the operator is reversed.

Returns:

Source code in src/tracksdata/attrs.py
def _delegate_comparison_operator(
    self,
    other: ExprInput,
    op: Callable,
    reverse: bool = False,
) -> "AttrComparison | Attr":
    """
    Simplified version of `_delegate_operator` for comparison operators.
    [AttrComparison][tracksdata.attrs.AttrComparison] has a limited scope and
    it's mainly used for filtering.
    If creating an [AttrComparison][tracksdata.attrs.AttrComparison] object is
    not possible, it will return an [Attr][tracksdata.attrs.Attr] object.

    Parameters
    ----------
    other : ExprInput
        The other expression to delegate the operator to.
    op : Callable
        The operator to delegate.
    reverse : bool, optional
        Whether the operator is reversed.

    Returns
    -------
    AttrComparison | Attr
        The result of the operator.
    """
    if reverse:
        lhs = Attr(other)
        rhs = self
    else:
        lhs = self
        rhs = other

    if isinstance(other, Attr):
        return self._delegate_operator(other, op, reverse=False)

    return AttrComparison(lhs, op, rhs)

_delegate_operator

_delegate_operator(other: ExprInput, op: Callable[[Expr, Expr], Expr], reverse: bool = False) -> Attr

Delegate the operator to the expression.

Parameters:

  • other

    (ExprInput) –

    The other expression to delegate the operator to.

  • op

    (Callable[[Expr, Expr], Expr]) –

    The operator to delegate.

  • reverse

    (bool, default: False ) –

    Whether the operator is reversed.

Returns:

  • Attr

    The result of the operator.

Source code in src/tracksdata/attrs.py
def _delegate_operator(self, other: ExprInput, op: Callable[[Expr, Expr], Expr], reverse: bool = False) -> "Attr":
    """
    Delegate the operator to the expression.

    Parameters
    ----------
    other : ExprInput
        The other expression to delegate the operator to.
    op : Callable[[Expr, Expr], Expr]
        The operator to delegate.
    reverse : bool, optional
        Whether the operator is reversed.

    Returns
    -------
    Attr
        The result of the operator.
    """
    # Special handling for multiplication with infinity
    if op == operator.mul:
        # Check if we're multiplying with infinity scalar
        # In both reverse and non-reverse cases, 'other' is the infinity value
        # and 'self' is the AttrExpr we want to track
        if isinstance(other, int | float) and math.isinf(other):
            result = Attr(pl.lit(0))  # Clean expression is zero (infinity term removed)

            # Copy existing infinity tracking
            result._inf_exprs = self._inf_exprs.copy()
            result._neg_inf_exprs = self._neg_inf_exprs.copy()

            # Add the expression to appropriate infinity list
            if other > 0:
                result._inf_exprs.append(self)
            else:
                result._neg_inf_exprs.append(self)

            return result

    # Regular operation - no infinity involved
    left = Attr(other).expr if reverse else self.expr
    right = self.expr if reverse else Attr(other).expr
    result = Attr(op(left, right))

    # Combine infinity tracking from both operands
    if isinstance(other, Attr):
        result._inf_exprs = self._inf_exprs + other._inf_exprs
        result._neg_inf_exprs = self._neg_inf_exprs + other._neg_inf_exprs

        # Special handling for subtraction: flip signs of the second operand's infinity terms
        if op == operator.sub and not reverse:
            # self - other: other's positive infinity becomes negative, negative becomes positive
            result._inf_exprs = self._inf_exprs + other._neg_inf_exprs
            result._neg_inf_exprs = self._neg_inf_exprs + other._inf_exprs
        elif op == operator.sub and reverse:
            # other - self: self's positive infinity becomes negative, negative becomes positive
            result._inf_exprs = other._inf_exprs + self._neg_inf_exprs
            result._neg_inf_exprs = other._neg_inf_exprs + self._inf_exprs
    else:
        result._inf_exprs = self._inf_exprs.copy()
        result._neg_inf_exprs = self._neg_inf_exprs.copy()

    return result

evaluate

evaluate(df: DataFrame) -> Series

Evaluate the expression on a DataFrame returning a numeric result.

Parameters:

  • df

    (DataFrame) –

    The DataFrame to evaluate the expression on.

Returns:

  • Series

    The evaluated expression.

Source code in src/tracksdata/attrs.py
def evaluate(self, df: DataFrame) -> Series:
    """
    Evaluate the expression on a DataFrame returning a numeric result.

    Parameters
    ----------
    df : DataFrame
        The DataFrame to evaluate the expression on.

    Returns
    -------
    Series
        The evaluated expression.
    """
    return df.select(self.expr).to_series()

has_inf

has_inf() -> bool

Check if any column in the expression is multiplied by infinity or negative infinity.

Returns:

  • bool

    True if any column is multiplied by infinity, False otherwise.

Source code in src/tracksdata/attrs.py
def has_inf(self) -> bool:
    """
    Check if any column in the expression is multiplied by infinity or negative infinity.

    Returns
    -------
    bool
        True if any column is multiplied by infinity, False otherwise.
    """
    return self.has_pos_inf() or self.has_neg_inf()

has_neg_inf

has_neg_inf() -> bool

Check if any column in the expression is multiplied by negative infinity.

Source code in src/tracksdata/attrs.py
def has_neg_inf(self) -> bool:
    """
    Check if any column in the expression is multiplied by negative infinity.
    """
    return len(self._neg_inf_exprs) > 0

has_pos_inf

has_pos_inf() -> bool

Check if any column in the expression is multiplied by positive infinity.

Source code in src/tracksdata/attrs.py
def has_pos_inf(self) -> bool:
    """
    Check if any column in the expression is multiplied by positive infinity.
    """
    return len(self._inf_exprs) > 0

NodeAttr

NodeAttr(value: ExprInput)

Bases: Attr

Wrapper of Attr to represent a node attribute.

See Also

Attr: The base class for all attributes.

Methods:

  • evaluate

    Evaluate the expression on a DataFrame returning a numeric result.

  • has_inf

    Check if any column in the expression is multiplied by infinity or negative infinity.

  • has_neg_inf

    Check if any column in the expression is multiplied by negative infinity.

  • has_pos_inf

    Check if any column in the expression is multiplied by positive infinity.

Attributes:

Source code in src/tracksdata/attrs.py
def __init__(self, value: ExprInput) -> None:
    self._inf_exprs = []  # expressions multiplied by +inf
    self._neg_inf_exprs = []  # expressions multiplied by -inf

    if isinstance(value, str):
        self.expr = pl.col(value)
    elif isinstance(value, Attr):
        self.expr = value.expr
        # Copy infinity tracking from the other AttrExpr
        self._inf_exprs = value.inf_exprs
        self._neg_inf_exprs = value.neg_inf_exprs
    elif isinstance(value, AttrComparison):
        attr = value.to_attr()
        self.expr = attr.expr
        self._inf_exprs = attr.inf_exprs
        self._neg_inf_exprs = attr.neg_inf_exprs
    elif isinstance(value, Expr):
        self.expr = value
    else:
        self.expr = pl.lit(value)

expr_columns property

expr_columns: list[str]

Get the names of columns in the expression.

inf_columns property

inf_columns: list[str]

Get the names of columns multiplied by positive infinity.

inf_exprs property

inf_exprs: list[Attr]

Get the expressions multiplied by positive infinity.

neg_inf_columns property

neg_inf_columns: list[str]

Get the names of columns multiplied by negative infinity.

neg_inf_exprs property

neg_inf_exprs: list[Attr]

Get the expressions multiplied by negative infinity.

_delegate_comparison_operator

_delegate_comparison_operator(other: ExprInput, op: Callable, reverse: bool = False) -> AttrComparison | Attr

Simplified version of _delegate_operator for comparison operators. AttrComparison has a limited scope and it's mainly used for filtering. If creating an AttrComparison object is not possible, it will return an Attr object.

Parameters:

  • other

    (ExprInput) –

    The other expression to delegate the operator to.

  • op

    (Callable) –

    The operator to delegate.

  • reverse

    (bool, default: False ) –

    Whether the operator is reversed.

Returns:

Source code in src/tracksdata/attrs.py
def _delegate_comparison_operator(
    self,
    other: ExprInput,
    op: Callable,
    reverse: bool = False,
) -> "AttrComparison | Attr":
    """
    Simplified version of `_delegate_operator` for comparison operators.
    [AttrComparison][tracksdata.attrs.AttrComparison] has a limited scope and
    it's mainly used for filtering.
    If creating an [AttrComparison][tracksdata.attrs.AttrComparison] object is
    not possible, it will return an [Attr][tracksdata.attrs.Attr] object.

    Parameters
    ----------
    other : ExprInput
        The other expression to delegate the operator to.
    op : Callable
        The operator to delegate.
    reverse : bool, optional
        Whether the operator is reversed.

    Returns
    -------
    AttrComparison | Attr
        The result of the operator.
    """
    if reverse:
        lhs = Attr(other)
        rhs = self
    else:
        lhs = self
        rhs = other

    if isinstance(other, Attr):
        return self._delegate_operator(other, op, reverse=False)

    return AttrComparison(lhs, op, rhs)

_delegate_operator

_delegate_operator(other: ExprInput, op: Callable[[Expr, Expr], Expr], reverse: bool = False) -> Attr

Delegate the operator to the expression.

Parameters:

  • other

    (ExprInput) –

    The other expression to delegate the operator to.

  • op

    (Callable[[Expr, Expr], Expr]) –

    The operator to delegate.

  • reverse

    (bool, default: False ) –

    Whether the operator is reversed.

Returns:

  • Attr

    The result of the operator.

Source code in src/tracksdata/attrs.py
def _delegate_operator(self, other: ExprInput, op: Callable[[Expr, Expr], Expr], reverse: bool = False) -> "Attr":
    """
    Delegate the operator to the expression.

    Parameters
    ----------
    other : ExprInput
        The other expression to delegate the operator to.
    op : Callable[[Expr, Expr], Expr]
        The operator to delegate.
    reverse : bool, optional
        Whether the operator is reversed.

    Returns
    -------
    Attr
        The result of the operator.
    """
    # Special handling for multiplication with infinity
    if op == operator.mul:
        # Check if we're multiplying with infinity scalar
        # In both reverse and non-reverse cases, 'other' is the infinity value
        # and 'self' is the AttrExpr we want to track
        if isinstance(other, int | float) and math.isinf(other):
            result = Attr(pl.lit(0))  # Clean expression is zero (infinity term removed)

            # Copy existing infinity tracking
            result._inf_exprs = self._inf_exprs.copy()
            result._neg_inf_exprs = self._neg_inf_exprs.copy()

            # Add the expression to appropriate infinity list
            if other > 0:
                result._inf_exprs.append(self)
            else:
                result._neg_inf_exprs.append(self)

            return result

    # Regular operation - no infinity involved
    left = Attr(other).expr if reverse else self.expr
    right = self.expr if reverse else Attr(other).expr
    result = Attr(op(left, right))

    # Combine infinity tracking from both operands
    if isinstance(other, Attr):
        result._inf_exprs = self._inf_exprs + other._inf_exprs
        result._neg_inf_exprs = self._neg_inf_exprs + other._neg_inf_exprs

        # Special handling for subtraction: flip signs of the second operand's infinity terms
        if op == operator.sub and not reverse:
            # self - other: other's positive infinity becomes negative, negative becomes positive
            result._inf_exprs = self._inf_exprs + other._neg_inf_exprs
            result._neg_inf_exprs = self._neg_inf_exprs + other._inf_exprs
        elif op == operator.sub and reverse:
            # other - self: self's positive infinity becomes negative, negative becomes positive
            result._inf_exprs = other._inf_exprs + self._neg_inf_exprs
            result._neg_inf_exprs = other._neg_inf_exprs + self._inf_exprs
    else:
        result._inf_exprs = self._inf_exprs.copy()
        result._neg_inf_exprs = self._neg_inf_exprs.copy()

    return result

evaluate

evaluate(df: DataFrame) -> Series

Evaluate the expression on a DataFrame returning a numeric result.

Parameters:

  • df

    (DataFrame) –

    The DataFrame to evaluate the expression on.

Returns:

  • Series

    The evaluated expression.

Source code in src/tracksdata/attrs.py
def evaluate(self, df: DataFrame) -> Series:
    """
    Evaluate the expression on a DataFrame returning a numeric result.

    Parameters
    ----------
    df : DataFrame
        The DataFrame to evaluate the expression on.

    Returns
    -------
    Series
        The evaluated expression.
    """
    return df.select(self.expr).to_series()

has_inf

has_inf() -> bool

Check if any column in the expression is multiplied by infinity or negative infinity.

Returns:

  • bool

    True if any column is multiplied by infinity, False otherwise.

Source code in src/tracksdata/attrs.py
def has_inf(self) -> bool:
    """
    Check if any column in the expression is multiplied by infinity or negative infinity.

    Returns
    -------
    bool
        True if any column is multiplied by infinity, False otherwise.
    """
    return self.has_pos_inf() or self.has_neg_inf()

has_neg_inf

has_neg_inf() -> bool

Check if any column in the expression is multiplied by negative infinity.

Source code in src/tracksdata/attrs.py
def has_neg_inf(self) -> bool:
    """
    Check if any column in the expression is multiplied by negative infinity.
    """
    return len(self._neg_inf_exprs) > 0

has_pos_inf

has_pos_inf() -> bool

Check if any column in the expression is multiplied by positive infinity.

Source code in src/tracksdata/attrs.py
def has_pos_inf(self) -> bool:
    """
    Check if any column in the expression is multiplied by positive infinity.
    """
    return len(self._inf_exprs) > 0