tracksdata.functional
Functional utilities for graph operations.
Classes:
-
TilingScheme–Tiling scheme for the graph.
Functions:
-
ancestral_connected_edges–Let an ancestral path be any sequence from (target, source)-edges in the
reference_graph. -
apply_tiled–Apply a function to a graph tiled by the tiling scheme.
-
join_node_attrs_to_edges–Add node attributes to edge attributes by joining on the node ID.
-
rx_digraph_to_napari_dict–Convert a tracklet graph to a napari-ready dictionary.
-
shift_division–Move a dividing node forward or backward in time by the given number of frames.
-
to_napari_format–Convert the subgraph of solution nodes to a napari-ready format.
TilingScheme
dataclass
TilingScheme(
tile_shape: tuple[S, ...],
overlap_shape: tuple[S, ...],
attrs: list[str] | None = None,
)
Tiling scheme for the graph. Graph will be sliced with 'tile_shape' + 2 * 'overlap_shape' per axis.
Parameters:
-
(tile_shapetuple[S, ...]) –The shape of the tile.
-
(overlap_shapetuple[S, ...]) –The overlap between tiles PER SIDE.
-
(attrslist[str] | None, default:None) –The attributes to include in the tile. If None, all attributes will be included. By default DEFAULT_ATTR_KEYS.T, DEFAULT_ATTR_KEYS.Z, DEFAULT_ATTR_KEYS.Y, DEFAULT_ATTR_KEYS.X are included. If some columns are not present, they will be ignored.
ancestral_connected_edges
ancestral_connected_edges(
input_graph: BaseGraph,
reference_graph: BaseGraph,
match: bool = True,
) -> list[int]
Let an ancestral path be any sequence from (target, source)-edges in the reference_graph.
This function returns the subset of edges in the input_graph that are
part of an ancestral path in the reference graph.
IMPORTANT: This function updates the input_graph in place when matching
with the reference_graph.
Parameters:
-
(input_graphBaseGraph) –The input graph.
-
(reference_graphBaseGraph) –The reference graph.
-
(matchbool, default:True) –Whether to match the input graph with the reference graph.
Source code in src/tracksdata/functional/_labeling.py
apply_tiled
apply_tiled(
graph: BaseGraph,
tiling_scheme: TilingScheme,
func: MapFunc,
*,
agg_func: ReduceFunc | None = None,
) -> Iterator[T] | R
Apply a function to a graph tiled by the tiling scheme. Graph will be sliced with 'tile_shape' + 2 * 'overlap_shape' per axis.
Parameters:
-
(graphBaseGraph) –The graph to apply the function to.
-
(tiling_schemeTilingScheme) –The tiling scheme to use.
-
(funcMapFunc) –The function to apply to each tile. It takes two arguments: - filtered_graph_with_overlap: the subgraph inside the tile with the overlap - filtered_graph: the subgraph inside the tile without the overlap If all overlaps are 0, filtered_graph_with_overlap == filtered_graph with minimal overhead.
-
(agg_funcReduceFunc | None, default:None) –The function to reduce the results of the function. If None, the results will be yielded.
Returns:
-
Iterator[T] | R–The results of the function. If agg_func is provided, the results will be reduced. Otherwise, the results will be yielded.
Source code in src/tracksdata/functional/_apply.py
join_node_attrs_to_edges
join_node_attrs_to_edges(
node_attrs: DataFrame,
edge_attrs: DataFrame,
node_id_key: str = DEFAULT_ATTR_KEYS.NODE_ID,
source_key: str = DEFAULT_ATTR_KEYS.EDGE_SOURCE,
target_key: str = DEFAULT_ATTR_KEYS.EDGE_TARGET,
source_prefix: str = "source_",
target_prefix: str = "target_",
how: JoinStrategy = "left",
) -> pl.DataFrame
Add node attributes to edge attributes by joining on the node ID.
Parameters:
-
(node_attrsDataFrame) –Node attributes.
-
(edge_attrsDataFrame) –Edge attributes.
-
(node_id_keystr, default:NODE_ID) –The key of the node ID column.
-
(source_keystr, default:EDGE_SOURCE) –The key of the source column.
-
(target_keystr, default:EDGE_TARGET) –The key of the target column.
-
(source_prefixstr, default:'source_') –The prefix of the source column.
-
(target_prefixstr, default:'target_') –The prefix of the target column.
-
(howJoinStrategy, default:'left') –The join type, where the "left" dataframe is the edge attributes and the "right" dataframe is the node attributes.
Returns:
-
DataFrame–Edge attributes with node attributes added.
Examples:
node_attrs = pl.DataFrame({"node_id": [1, 2, 3], "a": [1, 2, 3], "b": [4, 5, 6]})
edge_attrs = pl.DataFrame({"source": [1, 2], "target": [2, 3]})
node_attr_to_edges(node_attrs, edge_attrs)
# shape: (2, 5)
# ┌──────────┬──────────┬──────────┬──────────┬────────────────┬────────────────┐
# │ source_a ┆ source_b ┆ target_a ┆ target_b ┆ source_node_id ┆ target_node_id │
# │ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │
# │ i64 ┆ i64 ┆ i64 ┆ i64 ┆ i64 ┆ i64 │
# ╞══════════╪══════════╪══════════╪══════════╪════════════════╪════════════════╡
# │ 1 ┆ 4 ┆ 2 ┆ 5 ┆ 1 ┆ 2 │
# │ 2 ┆ 5 ┆ 3 ┆ 6 ┆ 2 ┆ 3 │
# └──────────┴──────────┴──────────┴──────────┴────────────────┴────────────────┘
Source code in src/tracksdata/functional/_edges.py
rx_digraph_to_napari_dict
Convert a tracklet graph to a napari-ready dictionary. The input is a (child -> parent) graph (forward in time) and it is converted to a (parent -> child) dictionary (backward in time).
Parameters
tracklet_graph : rx.PyDiGraph The tracklet graph to convert.
Returns
dict[int, list[int]] A dictionary of parent -> child relationships.
Source code in src/tracksdata/functional/_napari.py
shift_division
shift_division(
graph: BaseGraph,
node_id: int,
frames: int,
on_conflict: Literal["raise", "merge"] = "raise",
) -> BaseGraph
Move a dividing node forward or backward in time by the given number of frames.
A dividing node is a node with exactly two successors (children).
Moving ahead (positive frames):
The two children are merged into a single averaged node linked to the
original dividing node, while the original children are removed.
Their successors are inherited by the merged node, which becomes the new
dividing position for the next iteration.
Moving behind (negative frames):
Two new nodes replace the original dividing node. Their attributes are
linearly interpolated between the parent (predecessor) and each
respective child (successor). The parent then becomes the new dividing
position for the next iteration.
Parameters:
-
(graphBaseGraph) –The input graph. It is not modified.
-
(node_idint) –The ID of the dividing node to shift.
-
(framesint) –Number of frames to move the division. Positive shifts ahead in time, negative shifts behind.
-
(on_conflict('raise', 'merge'), default:"raise") –Action when the shift encounters an existing division "in the way":
- Shift ahead conflict: both children are themselves dividing nodes, so merging them would produce a node with more than 2 successors.
-
Shift behind conflict: the parent is already a dividing node (has other children), so shifting behind would give it more than 2 children.
-
"raise"(default): raise :exc:ValueErroron conflict. -
"merge": resolve the conflict by collapsing the moving division into the existing one. -
Ahead: proceed without raising; the merged node inherits all grandchildren, producing a >2-way division.
- Behind: replace the moving node with two interpolated nodes (each averaged between the moving node and one child) and attach them to the parent alongside its existing children.
Returns:
-
BaseGraph–A copy of the input graph with the division shifted.
Raises:
-
ValueError–If the node does not have exactly 2 children, or if shifting behind and the node does not have exactly 1 parent, or if a conflict is detected and
on_conflict="raise".
Examples:
Move a division one frame earlier:
Move a division two frames later:
Move a division ahead, merging into an existing division if encountered:
Source code in src/tracksdata/functional/_division.py
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 | |
to_napari_format
to_napari_format(
graph: BaseGraph,
shape: tuple[int, ...] | None = None,
solution_key: str | None = DEFAULT_ATTR_KEYS.SOLUTION,
output_tracklet_id_key: str = DEFAULT_ATTR_KEYS.TRACKLET_ID,
mask_key: str | None = None,
chunk_shape: tuple[int] | None = None,
buffer_cache_size: int | None = None,
) -> (
tuple[pl.DataFrame, dict[int, int], GraphArrayView]
| tuple[pl.DataFrame, dict[int, int]]
)
Convert the subgraph of solution nodes to a napari-ready format.
This includes:
- a tracks layer with the solution tracks
- a graph with the parent-child relationships for the solution tracks
- a labels layer with the solution nodes if mask_key is provided.
IMPORTANT: This function will reset the track ids if they already exist.
Parameters:
-
(graphBaseGraph) –The graph to convert.
-
(shapetuple[int, ...] | None, default:None) –The shape of the labels layer. If None, the shape is inferred from the graph metadata
shapekey. -
(solution_keystr, default:SOLUTION) –The key of the solution attribute. If None, the graph is not filtered by the solution attribute.
-
(output_tracklet_id_keystr, default:TRACKLET_ID) –The key of the output track id attribute.
-
(mask_keystr | None, default:None) –The key of the mask attribute.
-
(chunk_shapetuple[int] | None, default:None) –The chunk shape for the labels layer. If None, the default chunk size is used.
-
(buffer_cache_sizeint, default:None) –The maximum number of buffers to keep in the cache for the labels layer. If None, the default buffer cache size is used.
Examples:
labels = ...
graph = ...
tracks_data, dict_graph, array_view = to_napari_format(graph, labels.shape, mask_key="mask")
Returns:
-
tuple[DataFrame, dict[int, int], GraphArrayView] | tuple[DataFrame, dict[int, int]]–- tracks_data: The tracks data as a polars DataFrame.
- dict_graph: A dictionary of parent -> child relationships.
- array_view: The array view of the solution graph if
mask_keyis provided.
Source code in src/tracksdata/functional/_napari.py
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | |