Containers
Spatial data structures for efficient nearest neighbor queries.
Containers module.
This module provides spatial data structures for efficient nearest neighbor queries, spatial indexing, and tracking containers.
Spatial Index Hierarchy
Most spatial index structures inherit from BaseSpatialIndex, which defines a common interface for k-nearest neighbor and radius queries. RTree is the exception: it indexes bounding boxes rather than points and counts entries rather than samples, so it stands outside the hierarchy:
BaseSpatialIndex (abstract)
├── KDTree - K-dimensional tree (Euclidean space)
├── BallTree - Ball tree variant of KD-tree
└── MetricSpatialIndex (abstract)
├── VPTree - Vantage point tree (any metric)
└── CoverTree - Cover tree (any metric)
RTree - Rectangle tree for bounding boxes (standalone)
K-D Tree
K-dimensional tree for spatial queries.
K-D Tree implementation.
A k-dimensional tree (k-d tree) is a space-partitioning data structure for organizing points in k-dimensional space. Useful for efficient nearest neighbor searches in tracking applications.
References
J. L. Bentley, “Multidimensional binary search trees used for associative searching,” Communications of the ACM, 1975.
J. H. Friedman, J. L. Bentley, R. A. Finkel, “An Algorithm for Finding Best Matches in Logarithmic Expected Time,” ACM TOMS, 1977.
- class pytcl.containers.kd_tree.KDNode(point, index, split_dim, bucket=None)[source]
Bases:
objectA node in the k-d tree.
- Variables:
point (ndarray) – The point stored at this node.
index (int) – Original index of this point in the data array.
split_dim (int) – The dimension used for splitting at this node.
left (KDNode or None) – Left child (points with smaller split dimension value).
right (KDNode or None) – Right child (points with larger split dimension value).
bucket (ndarray or None) – For a leaf node, the indices of every point it holds (
pointandindexare the first of them). None for an internal node.
- point
- index
- split_dim
- bucket
Indices of every point held by this node when it is a leaf, or None for an internal node. A leaf is scanned exhaustively rather than split further; see
KDTree.leaf_size.
- pytcl.containers.kd_tree.NearestNeighborResult
alias of
NeighborResult
- class pytcl.containers.kd_tree.KDTree(data, leaf_size=10)[source]
Bases:
BaseSpatialIndexK-D Tree for efficient spatial queries.
A k-d tree recursively partitions space by splitting along different dimensions at each level. This enables O(log n) average-case nearest neighbor queries.
- Parameters:
data (array_like) – Data points of shape (n_samples, n_features).
leaf_size (int, optional) – Maximum number of points in a leaf node. Default 10.
Examples
>>> import numpy as np >>> points = np.array([[0, 0], [1, 0], [0, 1], [1, 1]]) >>> tree = KDTree(points) >>> result = tree.query(np.array([[0.1, 0.1]]), k=2) >>> result.indices array([[0, 1]])
Notes
The tree is balanced by choosing the median point along the split dimension at each level, giving O(n log n) construction time.
Query complexity is O(log n) on average for nearest neighbor search, though worst case is O(n) for highly unbalanced queries.
See also
BaseSpatialIndexAbstract base class defining the spatial index interface.
BallTreeAlternative spatial index using hyperspheres.
- query(X, k=1)[source]
Query the tree for k nearest neighbors.
- Parameters:
X (array_like) – Query points of shape (n_queries, n_features) or (n_features,).
k (int, optional) – Number of nearest neighbors. Default 1.
- Returns:
result – Indices and distances of k nearest neighbors for each query.
- Return type:
Examples
>>> tree = KDTree(np.array([[0, 0], [1, 1], [2, 2]])) >>> result = tree.query([[0.4, 0.4]], k=2) >>> result.indices array([[0, 1]])
- query_radius(X, r)[source]
Query the tree for all points within radius r.
- Parameters:
X (array_like) – Query points of shape (n_queries, n_features) or (n_features,).
r (float) – Query radius.
- Returns:
indices – For each query, a list of indices of points within radius r.
- Return type:
list of lists
Examples
>>> tree = KDTree(np.array([[0, 0], [1, 0], [0, 1], [5, 5]])) >>> sorted(tree.query_radius([[0, 0]], r=1.5)[0]) [0, 1, 2]
- class pytcl.containers.kd_tree.BallTree(data, leaf_size=10)[source]
Bases:
BaseSpatialIndexBall Tree for efficient spatial queries.
A ball tree partitions space using hyperspheres (balls), which can be more efficient than k-d trees for high-dimensional data or non-Euclidean metrics.
- Parameters:
data (array_like) – Data points of shape (n_samples, n_features).
leaf_size (int, optional) – Maximum number of points in a leaf node. Default 10.
Examples
>>> import numpy as np >>> points = np.array([[0, 0], [1, 0], [0, 1], [1, 1]]) >>> tree = BallTree(points) >>> result = tree.query(np.array([[0.1, 0.1]]), k=2)
Notes
Ball trees have O(n log n) construction and O(log n) average-case query time. They can outperform k-d trees in high dimensions.
See also
BaseSpatialIndexAbstract base class defining the spatial index interface.
KDTreeAlternative spatial index using axis-aligned splits.
- query(X, k=1)[source]
Query the tree for k nearest neighbors.
- Parameters:
X (array_like) – Query points of shape (n_queries, n_features) or (n_features,).
k (int, optional) – Number of nearest neighbors. Default 1.
- Returns:
result – Indices and distances of k nearest neighbors.
- Return type:
R-Tree
R-tree for spatial indexing.
R-tree implementation for spatial indexing of bounding boxes.
R-trees are tree data structures used for spatial access methods, i.e., for indexing multi-dimensional information such as geographical coordinates, rectangles, or polygons.
References
A. Guttman, “R-trees: A Dynamic Index Structure for Spatial Searching,” ACM SIGMOD, 1984.
N. Beckmann et al., “The R*-tree: An Efficient and Robust Access Method for Points and Rectangles,” ACM SIGMOD, 1990.
- pytcl.containers.rtree.SpatialQueryResult
alias of
NeighborResult
- class pytcl.containers.rtree.BoundingBox(min_coords, max_coords)[source]
Bases:
NamedTupleAxis-aligned bounding box.
- Variables:
min_coords (ndarray) – Minimum coordinates in each dimension.
max_coords (ndarray) – Maximum coordinates in each dimension.
- property volume: float
Volume (area in 2D) of the bounding box.
Zero if the box is degenerate in any dimension. A flat box such as
[0,0]-[2,0]encloses no volume, and this used to report2.0for it by multiplying only the nonzero extents (gh-22). That behavior belongs to the insertion heuristic below, which needs to distinguish degenerate boxes from one another; as a geometric property it was simply wrong.
- pytcl.containers.rtree.merge_boxes(boxes)[source]
Compute minimum bounding box containing all boxes.
- pytcl.containers.rtree.box_from_point(point)[source]
Create a zero-volume bounding box from a point.
- pytcl.containers.rtree.box_from_points(points)[source]
Create minimum bounding box containing all points.
- class pytcl.containers.rtree.RTreeNode(is_leaf=True)[source]
Bases:
objectNode in an R-tree.
- Variables:
bbox (BoundingBox) – Bounding box of this node.
is_leaf (bool) – Whether this is a leaf node.
children (list) – Child nodes (for internal nodes).
entries (list) – (bbox, data_index) pairs (for leaf nodes).
- is_leaf
- entries: List[Tuple[BoundingBox, int]]
- bbox: BoundingBox | None
- class pytcl.containers.rtree.RTreeResult(indices, boxes)[source]
Bases:
NamedTupleResult of R-tree query.
- Variables:
- boxes: List[BoundingBox]
Alias for field number 1
- class pytcl.containers.rtree.RTree(max_entries=10, min_entries=None)[source]
Bases:
objectR-tree for spatial indexing of bounding boxes.
An R-tree groups nearby objects and represents them with their minimum bounding rectangle. This allows efficient spatial queries.
Unlike KDTree and BallTree which only index points, RTree can index bounding boxes of arbitrary size. It also supports dynamic insertion.
- Parameters:
max_entries (int, optional) – Maximum entries per node. Default 10.
min_entries (int, optional) – Minimum entries a split leaves in a node, root excepted. Default
max_entries // 2. Must not exceed(max_entries + 1) // 2: a node splits atmax_entries + 1entries and the halves are as even as possible, so nothing larger is achievable, and an unsatisfiable value raises rather than being silently violated. This tree is insert-only, so there is no deletion underflow formin_entriesto govern.
- Variables:
Examples
>>> tree = RTree() >>> tree.insert(BoundingBox(np.array([0, 0]), np.array([1, 1])), 0) 0 >>> tree.insert(BoundingBox(np.array([2, 2]), np.array([3, 3])), 1) 1 >>> query_box = BoundingBox(np.array([0.5, 0.5]), np.array([2.5, 2.5])) >>> result = tree.query_intersect(query_box)
Notes
This implementation uses a simplified insertion algorithm. For production use, consider using R*-tree or packed R-tree variants.
See also
KDTreePoint-based spatial index using axis-aligned splits.
BallTreePoint-based spatial index using hyperspheres.
- classmethod from_points(data, max_entries=10, min_entries=None)[source]
Create an RTree from point data.
This factory method provides an interface similar to KDTree and BallTree, allowing RTree to be used interchangeably for point queries.
- Parameters:
- Returns:
tree – RTree with all points inserted.
- Return type:
Examples
>>> points = np.array([[0, 0], [1, 0], [0, 1], [1, 1]]) >>> tree = RTree.from_points(points) >>> result = tree.query([[0.1, 0.1]], k=2)
- insert(bbox, data_index=None)[source]
Insert a bounding box into the tree.
- Parameters:
bbox (BoundingBox) – Bounding box to insert.
data_index (int, optional) – Index to associate with this box. If None, uses next available.
- Returns:
index – Index of the inserted entry.
- Return type:
- query(X, k=1)[source]
Query the tree for k nearest neighbors.
This method provides API compatibility with KDTree and BallTree.
- Parameters:
X (array_like) – Query points of shape (n_queries, n_features) or (n_features,).
k (int, optional) – Number of nearest neighbors. Default 1.
- Returns:
result – Indices and distances of k nearest neighbors for each query.
- Return type:
Examples
>>> tree = RTree.from_points(np.array([[0, 0], [1, 1], [2, 2]])) >>> result = tree.query([[0.5, 0.5]], k=2) >>> result.indices array([[0, 1]])
- query_radius(X, r)[source]
Query the tree for all points within radius r.
This method provides API compatibility with KDTree and BallTree.
- Parameters:
X (array_like) – Query points of shape (n_queries, n_features) or (n_features,).
r (float) – Query radius.
- Returns:
indices – For each query, a list of indices of points within radius r.
- Return type:
list of lists
Examples
>>> tree = RTree.from_points(np.array([[0, 0], [1, 0], [0, 1], [5, 5]])) >>> tree.query_radius([[0, 0]], r=1.5) [[0, 1, 2]]
- query_ball_point(X, r)[source]
Query the tree for all points within radius r.
This is an alias for
query_radius()provided for compatibility with scipy.spatial.KDTree.- Parameters:
X (array_like) – Query points of shape (n_queries, n_features) or (n_features,).
r (float) – Search radius.
- Returns:
indices – For each query point, a list of indices of data points within distance r.
- Return type:
See also
query_radiusThe underlying implementation.
- query_intersect(query_bbox)[source]
Find all entries intersecting a query box.
- Parameters:
query_bbox (BoundingBox) – Query bounding box.
- Returns:
result – Indices and boxes of intersecting entries.
- Return type:
- query_contains(query_bbox)[source]
Find all entries contained within a query box.
- Parameters:
query_bbox (BoundingBox) – Query bounding box.
- Returns:
result – Indices and boxes of contained entries.
- Return type:
- query_point(point)[source]
Find all entries containing a point.
- Parameters:
point (array_like) – Query point.
- Returns:
result – Indices and boxes of entries containing the point.
- Return type:
VP-Tree
Vantage-point tree for metric spaces.
Vantage Point Tree (VP-tree) implementation.
VP-trees are metric trees that partition data based on distance to selected vantage points. They are effective for nearest neighbor search in metric spaces, particularly with high-dimensional data.
References
P. N. Yianilos, “Data structures and algorithms for nearest neighbor search in general metric spaces,” SODA 1993.
- pytcl.containers.vptree.VPTreeResult
alias of
NeighborResult
- class pytcl.containers.vptree.VPNode(index, radius=0.0)[source]
Bases:
objectNode in a VP-tree.
- Variables:
- index
- radius
- class pytcl.containers.vptree.VPTree(data, metric=None)[source]
Bases:
MetricSpatialIndexVantage Point Tree for metric space nearest neighbor search.
A VP-tree recursively partitions space by selecting a vantage point and dividing remaining points into those closer than a threshold (median distance) and those farther.
- Parameters:
data (array_like) – Data points of shape (n_samples, n_features).
metric (callable, optional) – Distance function metric(x, y) -> float. Default is Euclidean distance.
Examples
>>> import numpy as np >>> points = np.random.rand(100, 3) >>> tree = VPTree(points) >>> result = tree.query(points[:5], k=3) >>> result.indices.shape (5, 3)
Notes
VP-trees can use any metric distance function, making them useful for non-Euclidean spaces (e.g., edit distance for strings, geodesic distance on manifolds).
Query complexity is O(log n) on average but can degrade to O(n) for pathological distance distributions.
See also
MetricSpatialIndexAbstract base class for metric-based spatial indices.
CoverTreeAlternative metric space index with theoretical guarantees.
Cover Tree
Cover tree for approximate nearest neighbors.
Cover Tree implementation for nearest neighbor search.
Cover trees are data structures for nearest neighbor search in metric
spaces. The reference algorithm carries a theoretical O(c^12 log n)
query-time guarantee, where c is the expansion constant of the data –
but that bound assumes the strict cover invariant (d(parent, child) <=
base^level) is maintained during insertion. This implementation’s
insertion is simplified and does not maintain that invariant (see the
covering-radii comment in __init__, where covering radii are computed
from actual descendant distances precisely because the level bound cannot
be trusted). Queries still return correct results, since pruning falls
back to the exact computed radii, but the O(c^12 log n) bound does not
apply to this implementation.
References
A. Beygelzimer, S. Kakade, J. Langford, “Cover trees for nearest neighbor,” ICML 2006.
- pytcl.containers.covertree.CoverTreeResult
alias of
NeighborResult
- class pytcl.containers.covertree.CoverTreeNode(index, level)[source]
Bases:
objectNode in a Cover tree.
- Variables:
index (int) – Index of the point in the original data.
level (int) – Level in the tree (determines covering radius 2^level).
children (dict) – Children organized by level.
max_desc (float) – Covering radius: maximum distance from this node’s point to any point in its subtree. Used for exact query pruning.
- index
- level
- children: dict[int, List[CoverTreeNode]]
- max_desc
- class pytcl.containers.covertree.CoverTree(data, metric=None, base=2.0)[source]
Bases:
MetricSpatialIndexCover Tree for metric space nearest neighbor search.
A cover tree maintains a hierarchy of nested coverings of the data, where points at level i are a subset of points at level i-1 and cover all points within distance 2^i.
- Parameters:
data (array_like) – Data points of shape (n_samples, n_features).
metric (callable, optional) – Distance function metric(x, y) -> float. Default is Euclidean distance.
base (float, optional) – Base for the exponential scale. Default 2.0.
Examples
>>> import numpy as np >>> points = np.random.rand(100, 3) >>> tree = CoverTree(points) >>> result = tree.query(points[:5], k=3)
Notes
The classical cover tree’s guarantees (O(c^12 log n) queries in the expansion constant c) do NOT apply to this implementation – the module docstring details the simplifications: insertion does not maintain the strict cover invariant, and query pruning uses a per-node max-descendant bound instead of the level radius. Results are exact; the guarantees that are lost are about running time. For well-distributed data, queries are efficient even in high dimensions.
The implementation uses a simplified version of the original algorithm for clarity.
See also
MetricSpatialIndexAbstract base class for metric-based spatial indices.
VPTreeAlternative metric space index using vantage points.
- root: CoverTreeNode | None
Base
Base classes for spatial data structures.
This module provides abstract base classes that define the common interface for spatial indexing data structures like KD-trees, VP-trees, R-trees, and Cover trees.
The unified interface ensures all spatial indices provide consistent: - Constructor patterns (data, optional parameters) - Query methods (query, query_radius, query_ball_point) - Return types (NeighborResult)
- class pytcl.containers.base.NeighborResult(indices, distances)[source]
Bases:
NamedTupleUnified result type for spatial index queries.
All spatial index implementations (KDTree, BallTree, VPTree, CoverTree, RTree) return this type from their query methods, ensuring a consistent interface across the library.
- Variables:
indices (ndarray of shape (n_queries, k) or (n_queries,)) – Indices of the k nearest neighbors in the original data array. For k=1, may be 1D. For k>1, shape is (n_queries, k).
distances (ndarray of shape (n_queries, k) or (n_queries,)) – Distances to the k nearest neighbors. Same shape as indices.
Examples
>>> from pytcl.containers import KDTree >>> import numpy as np >>> points = np.array([[0, 0], [1, 0], [0, 1], [1, 1]]) >>> tree = KDTree(points) >>> result = tree.query([[0.1, 0.2]], k=2) >>> result.indices array([[0, 2]]) >>> result.distances array([[0.2236068 , 0.80622577]])
See also
BaseSpatialIndexAbstract base class for spatial indices.
- class pytcl.containers.base.BaseSpatialIndex(data)[source]
Bases:
ABCAbstract base class for spatial indexing data structures.
All spatial index implementations (KDTree, VPTree, RTree, CoverTree) should inherit from this class and implement the required methods.
This provides a consistent interface for: - Building the index from point data - k-nearest neighbor queries - Range/radius queries - Dimension and size introspection
- Parameters:
data (array_like) – Data points of shape (n_samples, n_features).
- Variables:
- abstractmethod query(X, k=1)[source]
Query the index for k nearest neighbors.
- Parameters:
X (array_like) – Query points of shape (n_queries, n_features) or (n_features,).
k (int, optional) – Number of nearest neighbors to return. Default is 1.
- Returns:
result – Named tuple with indices and distances of k nearest neighbors for each query point.
- Return type:
- query_ball_point(X, r)[source]
Query the index for all points within radius r.
This is an alias for
query_radius()provided for compatibility with scipy.spatial.KDTree.- Parameters:
X (array_like) – Query points of shape (n_queries, n_features) or (n_features,).
r (float) – Search radius.
- Returns:
indices – For each query point, a list of indices of data points within distance r.
- Return type:
See also
query_radiusThe underlying implementation.
- class pytcl.containers.base.MetricSpatialIndex(data, metric=None)[source]
Bases:
BaseSpatialIndexBase class for metric space spatial indices.
Extends BaseSpatialIndex with support for custom distance metrics. Used by VP-trees and Cover trees which can work with any metric.
- Parameters:
data (array_like) – Data points of shape (n_samples, n_features).
metric (callable, optional) – Distance function with signature metric(x, y) -> float. Default is Euclidean distance.
- pytcl.containers.base.validate_query_input(X, n_features)[source]
Validate and reshape query input.
- Parameters:
X (array_like) – Query points.
n_features (int) – Expected number of features.
- Returns:
X – Validated query array of shape (n_queries, n_features).
- Return type:
ndarray
- Raises:
ValueError – If query has wrong number of features.
- pytcl.containers.base.validate_neighbor_count(k, n_samples)[source]
Reject a request for more neighbors than the index holds.
Every index here used to pad the shortfall with index
0and an infinite distance. Zero is a valid index, so a caller who read the indices without also checking the distances got point 0 returned as a neighbor – silently, and as many times as the request overshot (gh-22).Raising instead matches
sklearn.neighbors, which is where most callers’ expectations come from, and turns a wrong answer into a message at the call site. A caller who genuinely wants “up to k” can ask formin(k, index.n_samples).- Parameters:
- Raises:
ValueError – If
kis not a positive integer, or exceedsn_samples.
- pytcl.containers.base.SpatialQueryResult
alias of
NeighborResult
- pytcl.containers.base.NearestNeighborResult
alias of
NeighborResult
- pytcl.containers.base.VPTreeResult
alias of
NeighborResult
- pytcl.containers.base.CoverTreeResult
alias of
NeighborResult
- pytcl.containers.base.RTreeResult
alias of
NeighborResult
Cluster Set
Cluster set container.
This module provides a container for managing groups of tracks that move together (formations, convoys, etc.).
- class pytcl.containers.cluster_set.TrackCluster(id, track_ids, centroid, covariance, time)[source]
Bases:
NamedTupleA cluster of related tracks.
- Variables:
- class pytcl.containers.cluster_set.ClusterSet(clusters=None)[source]
Bases:
objectCollection of track clusters.
Provides: - Cluster creation from tracks - Cluster queries - Cluster merging/splitting
- Parameters:
clusters (Iterable[TrackCluster], optional) – Initial clusters to add.
Examples
>>> import numpy as np >>> from pytcl.trackers.multi_target import Track, TrackStatus >>> from pytcl.containers.track_list import TrackList >>> # Create some tracks in two groups >>> t1 = Track(id=0, state=np.array([0, 0, 0, 0]), ... covariance=np.eye(4), status=TrackStatus.CONFIRMED, ... hits=5, misses=0, time=1.0) >>> t2 = Track(id=1, state=np.array([1, 0, 1, 0]), ... covariance=np.eye(4), status=TrackStatus.CONFIRMED, ... hits=5, misses=0, time=1.0) >>> t3 = Track(id=2, state=np.array([10, 0, 10, 0]), ... covariance=np.eye(4), status=TrackStatus.CONFIRMED, ... hits=5, misses=0, time=1.0) >>> tracks = TrackList([t1, t2, t3]) >>> # Cluster using DBSCAN >>> clusters = cluster_tracks_dbscan(tracks, eps=5.0, min_samples=2)
- classmethod from_tracks(tracks, method='dbscan', **kwargs)[source]
Create a ClusterSet by clustering tracks.
- Parameters:
- Returns:
New ClusterSet containing the computed clusters.
- Return type:
Examples
>>> clusters = ClusterSet.from_tracks(tracks, method='dbscan', eps=2.0) >>> clusters = ClusterSet.from_tracks(tracks, method='kmeans', n_clusters=3)
- __getitem__(idx)[source]
Get cluster by index or slice.
- Parameters:
- Returns:
Single cluster if int, ClusterSet if slice.
- Return type:
- get_cluster(cluster_id)[source]
Get cluster by ID.
- Parameters:
cluster_id (int) – Cluster ID to find.
- Returns:
The cluster if found, None otherwise.
- Return type:
TrackCluster or None
- get_cluster_for_track(track_id)[source]
Get the cluster containing a specific track.
- Parameters:
track_id (int) – Track ID to find.
- Returns:
The cluster containing the track, or None if not found.
- Return type:
TrackCluster or None
- clusters_in_region(center, radius)[source]
Get clusters with centroids within a spatial region.
- Parameters:
center (array_like) – Center point [x, y].
radius (float) – Radius of the region.
- Returns:
Clusters within the region.
- Return type:
list of TrackCluster
- cluster_stats(cluster_id, tracks=None, state_indices=(0, 2), velocity_indices=(1, 3))[source]
Compute statistics for a cluster.
- Parameters:
cluster_id (int) – ID of the cluster.
tracks (TrackList, optional) – TrackList containing the tracks. Required for velocity coherence.
state_indices (tuple of int, optional) – Indices of x and y in state vector (default: (0, 2)).
velocity_indices (tuple of int, optional) – Indices of vx and vy in state vector (default: (1, 3)).
- Returns:
Statistics for the cluster, or None if cluster not found.
- Return type:
ClusterStats or None
- all_stats(tracks=None, state_indices=(0, 2), velocity_indices=(1, 3))[source]
Compute statistics for all clusters.
- Parameters:
- Returns:
Mapping from cluster ID to ClusterStats.
- Return type:
- add_cluster(cluster)[source]
Add a cluster and return a new ClusterSet.
- Parameters:
cluster (TrackCluster) – Cluster to add.
- Returns:
New ClusterSet with the cluster added.
- Return type:
- remove_cluster(cluster_id)[source]
Remove a cluster by ID and return a new ClusterSet.
- Parameters:
cluster_id (int) – ID of cluster to remove.
- Returns:
New ClusterSet without the specified cluster.
- Return type:
- merge_clusters(id1, id2, new_id=None)[source]
Merge two clusters into one.
- Parameters:
- Returns:
New ClusterSet with merged cluster.
- Return type:
- Raises:
ValueError – If either cluster ID is not found.
- split_cluster(cluster_id, track_ids_1, track_ids_2, new_id_1=None, new_id_2=None, tracks=None, state_indices=(0, 2))[source]
Split a cluster into two.
- Parameters:
cluster_id (int) – ID of cluster to split.
track_ids_1 (Iterable[int]) – Track IDs for first new cluster.
track_ids_2 (Iterable[int]) – Track IDs for second new cluster.
new_id_1 (int, optional) – ID for first new cluster. Defaults to cluster_id.
new_id_2 (int, optional) – ID for second new cluster. Defaults to max(cluster_ids) + 1.
tracks (TrackList, optional) – TrackList for computing centroids. If None, uses existing centroid.
state_indices (tuple of int, optional) – Indices of x and y in state vector (default: (0, 2)).
- Returns:
New ClusterSet with split clusters.
- Return type:
- Raises:
ValueError – If cluster ID is not found.
- class pytcl.containers.cluster_set.ClusterStats(n_tracks, mean_separation, max_separation, velocity_coherence)[source]
Bases:
NamedTupleStatistics for a cluster.
- Variables:
n_tracks (int) – Number of tracks in the cluster.
mean_separation (float) – Average distance between tracks and centroid.
max_separation (float) – Maximum distance from any track to centroid.
velocity_coherence (float) – Measure of how aligned velocities are (0-1). 1.0 means perfectly aligned, 0.0 means random directions.
- pytcl.containers.cluster_set.cluster_tracks_dbscan(tracks, eps, min_samples=2, state_indices=(0, 2))[source]
Cluster tracks using DBSCAN algorithm.
- Parameters:
- Returns:
Set of track clusters.
- Return type:
- pytcl.containers.cluster_set.cluster_tracks_kmeans(tracks, n_clusters, state_indices=(0, 2), rng=None)[source]
Cluster tracks using K-means algorithm.
- Parameters:
tracks (TrackList) – Tracks to cluster.
n_clusters (int) – Number of clusters to form.
state_indices (tuple of int, optional) – Indices of x and y in state vector (default: (0, 2)).
rng (numpy.random.Generator, optional) – Random number generator for reproducibility.
- Returns:
Set of track clusters.
- Return type:
- pytcl.containers.cluster_set.compute_cluster_centroid(tracks, state_indices=(0, 2))[source]
Compute the centroid of a group of tracks.
- Parameters:
- Returns:
centroid – Centroid position [x, y].
- Return type:
ndarray
Examples
>>> from pytcl.trackers.multi_target import Track, TrackStatus >>> import numpy as np >>> def make_track(tid, state): ... return Track(id=tid, state=np.asarray(state), covariance=np.eye(4), ... status=TrackStatus.CONFIRMED, hits=1, misses=0, time=0.0) >>> # Create sample tracks with [x, vx, y, vy] state vectors >>> tracks = [make_track(0, [0.0, 1.0, 0.0, 1.0]), ... make_track(1, [2.0, 1.0, 2.0, 1.0]), ... make_track(2, [4.0, 1.0, 4.0, 1.0])] >>> centroid = compute_cluster_centroid(tracks) >>> centroid array([2., 2.])
See also
compute_cluster_covarianceCompute covariance of track positions.
Measurement Set
Measurement set container.
This module provides a time-indexed collection of measurements with spatial query support.
- class pytcl.containers.measurement_set.Measurement(value, time, covariance=None, sensor_id=0, id=-1)[source]
Bases:
NamedTupleSingle measurement with metadata.
- Variables:
- class pytcl.containers.measurement_set.MeasurementSet(measurements=None)[source]
Bases:
objectCollection of measurements with time and spatial indexing.
Provides: - Time-windowed queries - Spatial region queries - Sensor filtering - Batch value extraction
- Parameters:
measurements (Iterable[Measurement], optional) – Initial measurements to add.
Examples
>>> import numpy as np >>> # Create measurements >>> m1 = Measurement(value=np.array([1.0, 2.0]), time=0.0, id=0) >>> m2 = Measurement(value=np.array([3.0, 4.0]), time=0.0, id=1) >>> m3 = Measurement(value=np.array([5.0, 6.0]), time=1.0, id=2) >>> # Create measurement set >>> mset = MeasurementSet([m1, m2, m3]) >>> len(mset) 3 >>> # Filter by time >>> at_t0 = mset.at_time(0.0) >>> len(at_t0) 2 >>> # Get values >>> values = mset.values() >>> values.shape (3, 2)
- classmethod from_arrays(values, times, covariances=None, sensor_ids=None)[source]
Create MeasurementSet from arrays.
- Parameters:
values (array_like) – Array of shape (n_meas, meas_dim) containing measurement values.
times (array_like) – Array of length n_meas containing measurement times.
covariances (array_like, optional) – Array of shape (n_meas, meas_dim, meas_dim) containing covariances.
sensor_ids (array_like, optional) – Array of length n_meas containing sensor IDs.
- Returns:
New MeasurementSet containing the measurements.
- Return type:
- __getitem__(idx)[source]
Get measurement by index or slice.
- Parameters:
- Returns:
Single measurement if int, MeasurementSet if slice.
- Return type:
- at_time(time, tolerance=1e-09)[source]
Get measurements at a specific time.
- Parameters:
- Returns:
Measurements at the specified time.
- Return type:
- in_time_window(start, end)[source]
Get measurements in a time window.
- Parameters:
- Returns:
Measurements within the time window.
- Return type:
- in_region(center, radius)[source]
Get measurements within a spatial region.
- Parameters:
center (array_like) – Center point of the region.
radius (float) – Radius of the region.
- Returns:
Measurements within the region.
- Return type:
- by_sensor(sensor_id)[source]
Get measurements from a specific sensor.
- Parameters:
sensor_id (int) – Sensor ID to filter by.
- Returns:
Measurements from the specified sensor.
- Return type:
- nearest_to(point, k=1)[source]
Find k nearest measurements to a point.
- Parameters:
point (array_like) – Query point.
k (int, optional) – Number of nearest neighbors (default: 1).
- Returns:
Query result with measurements and indices.
- Return type:
Notes
This method builds a spatial index on first call if not already built.
- values()[source]
Extract all measurement values as array.
- Returns:
Array of shape (n_meas, meas_dim).
- Return type:
ndarray
- add(measurement)[source]
Add a measurement and return a new MeasurementSet.
- Parameters:
measurement (Measurement) – Measurement to add.
- Returns:
New MeasurementSet with the measurement added.
- Return type:
- add_batch(measurements)[source]
Add multiple measurements and return a new MeasurementSet.
- Parameters:
measurements (Iterable[Measurement]) – Measurements to add.
- Returns:
New MeasurementSet with the measurements added.
- Return type:
- merge(other)[source]
Merge with another MeasurementSet.
- Parameters:
other (MeasurementSet) – MeasurementSet to merge with.
- Returns:
New MeasurementSet containing measurements from both.
- Return type:
- class pytcl.containers.measurement_set.MeasurementQuery(measurements, indices)[source]
Bases:
NamedTupleResult of a measurement set query.
- Variables:
measurements (List[Measurement]) – List of measurements matching the query.
indices (List[int]) – Original indices of the matching measurements.
- measurements: List[Measurement]
Alias for field number 0
Track List
Track list container.
This module provides a collection class for managing multiple tracks with filtering, querying, and batch operations.
- class pytcl.containers.track_list.TrackList(tracks=None)[source]
Bases:
objectCollection of tracks with query and filter capabilities.
Provides: - Filtering by status, time, region - Iteration and indexing - Batch state extraction - Statistics computation
- Parameters:
tracks (Iterable[Track], optional) – Initial tracks to add to the list.
Examples
>>> import numpy as np >>> from pytcl.trackers.multi_target import Track, TrackStatus >>> # Create some tracks >>> t1 = Track(id=0, state=np.array([1, 0, 2, 0]), ... covariance=np.eye(4), status=TrackStatus.CONFIRMED, ... hits=5, misses=0, time=1.0) >>> t2 = Track(id=1, state=np.array([5, 0, 6, 0]), ... covariance=np.eye(4), status=TrackStatus.TENTATIVE, ... hits=2, misses=1, time=1.0) >>> # Create track list >>> tracks = TrackList([t1, t2]) >>> len(tracks) 2 >>> # Filter by status >>> confirmed = tracks.confirmed >>> len(confirmed) 1 >>> # Get positions >>> positions = tracks.positions(indices=(0, 2)) >>> positions.shape (2, 2)
- classmethod from_tracker(tracker)[source]
Create a TrackList from a MultiTargetTracker.
- Parameters:
tracker (MultiTargetTracker) – The tracker to extract tracks from.
- Returns:
A new TrackList containing the tracker’s current tracks.
- Return type:
- filter_by_status(status)[source]
Filter tracks by status.
- Parameters:
status (TrackStatus) – Status to filter by.
- Returns:
New TrackList containing only tracks with the given status.
- Return type:
- filter_by_predicate(predicate)[source]
Filter tracks using a custom predicate.
- Parameters:
predicate (callable) – Function that takes a Track and returns True to include it.
- Returns:
New TrackList containing tracks that pass the predicate.
- Return type:
- states()[source]
Extract all track states as array.
- Returns:
Array of shape (n_tracks, state_dim) containing all states.
- Return type:
ndarray
- covariances()[source]
Extract all track covariances as array.
- Returns:
Array of shape (n_tracks, state_dim, state_dim).
- Return type:
ndarray
- stats()[source]
Compute statistics about the track list.
- Returns:
Statistics about the tracks.
- Return type:
- merge(other)[source]
Merge with another TrackList.
- Parameters:
other (TrackList) – TrackList to merge with.
- Returns:
New TrackList containing tracks from both lists.
- Return type:
Notes
Duplicate track IDs are not handled specially - both tracks will be included. Use get_by_id on the result to access specific tracks.
- class pytcl.containers.track_list.TrackQuery(tracks, indices)[source]
Bases:
NamedTupleResult of a track list query.
- Variables:
- class pytcl.containers.track_list.TrackListStats(n_tracks, n_confirmed, n_tentative, n_deleted, mean_hits, mean_misses)[source]
Bases:
NamedTupleStatistics about a track list.
- Variables: