funtracks.import_export
CSVTracksBuilder
CSVTracksBuilder()
Bases: TracksBuilder
Builder for importing tracks from CSV/DataFrame format.
Initialize CSV builder with CSV-specific required features.
load_source
load_source(
source: Path | DataFrame,
node_name_map: dict[str, str | list[str]],
) -> None
Load CSV and convert to InMemoryGeff format.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source
|
Path | DataFrame
|
Path to CSV file or DataFrame |
required |
node_name_map
|
dict[str, str | list[str]]
|
Maps standard keys to CSV column names |
required |
read_header
read_header(source: Path | DataFrame) -> None
Read CSV column names.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source
|
Path | DataFrame
|
Path to CSV file or DataFrame |
required |
GeffTracksBuilder
GeffTracksBuilder()
Bases: TracksBuilder
Builder for importing tracks from GEFF format.
construct_graph
construct_graph(
node_name_map: dict[str, str | list[str]] | None = None,
database: str | None = None,
) -> td.graph.GraphView
Construct graph and prepare embedded segmentation data.
The GEFF format serialises mask data as plain numeric arrays (zarr
cannot store arbitrary Python objects). After the base graph is built,
this override wraps each raw array back into a
:class:tracksdata.nodes.Mask instance and writes
segmentation_shape into the graph metadata so that
:class:~funtracks.data_model.tracks.Tracks.__init__ can reconstruct
the segmentation and create the
:class:~funtracks.annotators.RegionpropsAnnotator naturally.
infer_node_name_map
infer_node_name_map() -> dict[str, str | list[str]]
Derive time and position mapping from geff axes metadata.
When axes with typed metadata (type="time" / type="space") are present, uses them directly instead of falling back to fuzzy string matching, which can misassign properties when many non-spatiotemporal properties are present.
Falls back to the base-class fuzzy matching when axes metadata is absent.
Returns:
| Type | Description |
|---|---|
dict[str, str | list[str]]
|
Inferred node_name_map mapping standard keys to source property names |
load_source
load_source(
source_path: Path,
node_name_map: dict[str, str | list[str]],
) -> None
Load GEFF data and convert to InMemoryGeff format.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source_path
|
Path
|
Path to GEFF zarr store |
required |
node_name_map
|
dict[str, str | list[str]]
|
Maps standard keys to GEFF property names |
required |
read_header
read_header(source_path: Path) -> None
Read GEFF property names without loading arrays.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source_path
|
Path
|
Path to GEFF zarr store |
required |
TracksBuilder
TracksBuilder()
Bases: ABC
Abstract builder for importing tracks from various formats.
Defines the construction steps that all format-specific builders must implement, along with common logic shared across formats.
Initialize builder state.
axis_names
axis_names: list[str]
Position attribute names derived from ndim.
Returns ["z", "y", "x"] for 3D (ndim=4) or ["y", "x"] for 2D (ndim=3). If ndim is None, returns ["z", "y", "x"] as default.
build
build(
source: Path | DataFrame,
segmentation: Path | ndarray | None = None,
scale: list[float] | None = None,
node_name_map: dict[str, str | list[str]] | None = None,
database: str | None = None,
) -> SolutionTracks
Orchestrate the full construction process.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source
|
Path | DataFrame
|
Path to data source or DataFrame |
required |
segmentation
|
Path | ndarray | None
|
Optional path to segmentation or pre-loaded segmentation array |
None
|
scale
|
list[float] | None
|
Optional spatial scale |
None
|
node_name_map
|
dict[str, str | list[str]] | None
|
Optional node_name_map to override self.node_name_map |
None
|
database
|
str | None
|
Optional path to a SQLite database file for backing storage. If None (default), an in-memory/temp graph is used. |
None
|
Returns:
| Type | Description |
|---|---|
SolutionTracks
|
Fully constructed SolutionTracks object |
Raises:
| Type | Description |
|---|---|
ValueError
|
If self.node_name_map is not set or validation fails |
Example
Using prepare() to auto-infer node_name_map
builder = CSVTracksBuilder() builder.prepare("data.csv") tracks = builder.build("data.csv")
Or set node_name_map manually
builder = CSVTracksBuilder() builder.read_header("data.csv") builder.node_name_map = {"time": "t", "x": "x", "y": "y", "id": "id"} tracks = builder.build("data.csv")
construct_graph
construct_graph(
node_name_map: dict[str, str | list[str]] | None = None,
database: str | None = None,
) -> td.graph.GraphView
Construct Tracksdata graph from validated InMemoryGeff data.
Common logic shared across all formats.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
node_name_map
|
dict[str, str | list[str]] | None
|
Optional node name map used to infer default values per attribute dtype. |
None
|
database
|
str | None
|
Optional path to a SQLite database file for backing storage. If None (default), an in-memory/temp graph is used. |
None
|
Returns:
| Type | Description |
|---|---|
GraphView
|
Tracksdata GraphView with standard keys |
Raises:
| Type | Description |
|---|---|
ValueError
|
If data not loaded or validated |
enable_features
enable_features(
tracks: SolutionTracks,
name_map: dict[str, str | list[str]],
feature_type: Literal["node", "edge"] = "node",
) -> None
Enable and register features on tracks object from a name map.
For each key in name_map that is not structural (time, id, parent_id, seg_id) and not already registered in tracks.features: - If the key matches an annotator-managed feature and data was loaded for it, enable it via the annotator (recompute=False). - Otherwise, if data was loaded for it, register it as a static feature.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tracks
|
SolutionTracks
|
SolutionTracks object to add features to |
required |
name_map
|
dict[str, str | list[str]]
|
Mapping from standard funtracks keys to source property names (same format as node_name_map / edge_name_map). |
required |
feature_type
|
Literal['node', 'edge']
|
Type of features ("node" or "edge") |
'node'
|
handle_segmentation
handle_segmentation(
graph: GraphView,
segmentation: Path | ndarray | None,
scale: list[float] | None,
) -> tuple[
np.ndarray | None,
list[float] | None,
td.graph.GraphView,
]
Load, validate, and optionally relabel segmentation.
Common logic shared across all formats.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
graph
|
GraphView
|
Constructed Tracksdata graph for validation |
required |
segmentation
|
Path | ndarray | None
|
Path to segmentation data or pre-loaded segmentation array |
required |
scale
|
list[float] | None
|
Spatial scale for coordinate transformation |
required |
Returns:
| Type | Description |
|---|---|
ndarray | None
|
Tuple of (segmentation array, scale, graph). The graph may be relabeled |
list[float] | None
|
if node_id 0 exists in the original graph. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If segmentation validation fails |
infer_edge_name_map
infer_edge_name_map() -> dict[str, str | list[str]]
Infer edge_name_map by matching source properties to standard keys.
The edge_name_map maps standard funtracks keys to source property names
{standard_key: source_property_name}
For example: {"iou": "overlap"} - "iou" is the standard funtracks key - "overlap" is the property name from the source data
Uses difflib fuzzy matching with the following priority: 1. Exact matches to edge feature default keys 2. Fuzzy matches to edge feature default keys (case-insensitive, 40% similarity cutoff) 3. Exact matches to edge feature display names 4. Fuzzy matches to edge feature display names (case-insensitive, 40% cutoff) 5. Remaining properties map to themselves (custom properties)
Returns:
| Type | Description |
|---|---|
dict[str, str | list[str]]
|
Inferred edge_name_map mapping standard keys to source property names |
infer_node_name_map
infer_node_name_map() -> dict[str, str | list[str]]
Infer node_name_map by matching source properties to standard keys.
The node_name_map maps standard funtracks keys to source property names
{standard_key: source_property_name}
For example: {"time": "t", "pos": ["y", "x"], "seg_id": "label"} - "time", "pos", "seg_id" are standard funtracks keys - "t", "y", "x", "label" are property names from the source data
Uses difflib fuzzy matching with the following priority: 1. Exact matches to standard keys (time, seg_id, etc.) 2. Fuzzy matches to standard keys (case-insensitive, 40% similarity cutoff) 3. Exact matches to feature display names/value_names (including position z/y/x) 4. Fuzzy matches to feature display names (case-insensitive, 40% cutoff) 5. Remaining properties map to themselves (custom properties)
Position attributes (z, y, x) are matched via Position feature's value_names, resulting in a composite mapping like {"pos": ["z", "y", "x"]}.
Returns:
| Type | Description |
|---|---|
dict[str, str | list[str]]
|
Inferred node_name_map mapping standard keys to source property names |
Raises:
| Type | Description |
|---|---|
ValueError
|
If required features cannot be inferred |
load_source
load_source(
source: Path | DataFrame,
node_name_map: dict[str, str | list[str]],
) -> None
Load data from source file and convert to InMemoryGeff format.
Should populate self.in_memory_geff with all properties using standard keys.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source
|
Path | DataFrame
|
Path to data source (zarr store, CSV file, etc.) or DataFrame |
required |
node_name_map
|
dict[str, str | list[str]]
|
Maps standard keys to source property names |
required |
prepare
prepare(
source: Path | DataFrame,
segmentation: Path | ArrayLike | None = None,
) -> None
Prepare for building by reading headers and inferring name maps.
This method reads the data source headers/metadata and automatically infers both node_name_map and edge_name_map. After calling this, you can inspect and modify self.node_name_map and self.edge_name_map before calling build().
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source
|
Path | DataFrame
|
Path to data source or DataFrame |
required |
segmentation
|
Path | ArrayLike | None
|
Optional path to segmentation or array to infer ndim |
None
|
Example
builder = CSVTracksBuilder() builder.prepare("data.csv")
Optionally modify the inferred mappings
builder.node_name_map["circularity"] = "circ" builder.edge_name_map["iou"] = "overlap" tracks = builder.build("data.csv", segmentation_path="seg.tif")
read_header
read_header(source: Path | DataFrame) -> None
Read metadata/headers from source without loading data.
Should populate self.importable_node_props and self.importable_edge_props with property/column names.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source
|
Path | DataFrame
|
Path to data source (zarr store, CSV file, etc.) or DataFrame |
required |
validate
validate() -> None
Validate the loaded InMemoryGeff data.
Common validation logic shared across all formats. Validates: - Graph structure (unique nodes, valid edges, etc.) - Spatial_dims features have correct array shapes - Optional properties (lineage_id, tracklet_id) - removed with warning if invalid
Raises:
| Type | Description |
|---|---|
ValueError
|
If required validation fails |
validate_name_map
validate_name_map(has_segmentation: bool = False) -> None
Validate that node_name_map and edge_name_map contain valid mappings.
Checks for nodes: - No None values in required mappings - All required_features are mapped - Position ("pos") is mapped to coordinate columns (unless segmentation provided) - All mapped properties exist in importable_node_props - Features with spatial_dims=True have correct number of list elements
Checks for edges: - All mapped edge properties exist in importable_edge_props
Note: Array shapes for spatial_dims features are validated after loading via validate_spatial_dims().
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
has_segmentation
|
bool
|
If True, position can be computed from segmentation and is not required in name_map |
False
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If validation fails |
export_to_csv
export_to_csv(
tracks: SolutionTracks,
outfile: Path | str,
color_dict: dict[int, ndarray] | None = None,
node_ids: set[int] | None = None,
use_display_names: bool = False,
export_seg: bool = False,
seg_path: Path | str | None = None,
seg_relabel: Literal[
"tracklet", "lineage", None
] = "tracklet",
seg_file_format: Literal["zarr", "tiff"] = "zarr",
zarr_format: Literal[2, 3] = 2,
) -> None
Export tracks to a CSV file. TODO: export_all = False for backward compatibility - display names option shouldn't change which columns are exported, just using which names
Exports tracking data to CSV format with columns for node ID, parent ID, and all registered features. Optionally also exports the segmentation as zarr or tiff. If a color dictionary is provided, it will also export the tracklet colors.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tracks
|
SolutionTracks
|
SolutionTracks object containing the tracking data to export |
required |
outfile
|
Path | str
|
Path to output CSV file |
required |
color_dict
|
dict[int, ndarray] | None
|
dict[int, np.ndarray], optional. If provided, will be used to save the hex colors. |
None
|
node_ids
|
set[int] | None
|
Optional set of node IDs to include. If provided, only these nodes and their ancestors will be included in the output. |
None
|
use_display_names
|
bool
|
If True, use feature display names as column headers. If False (default), use raw feature keys for backward compatibility. |
False
|
export_seg
|
bool
|
Whether to export the segmentation alongside the CSV. |
False
|
seg_path
|
Path | str | None
|
Path to save the segmentation to. Required when export_seg=True. |
None
|
seg_relabel
|
Literal['tracklet', 'lineage', None]
|
How to relabel cells in the exported segmentation. "tracklet" (default): paint by tracklet ID. "lineage": paint by lineage ID. None: preserve original labels (node IDs). |
'tracklet'
|
seg_file_format
|
Literal['zarr', 'tiff']
|
Output format for the segmentation, either "zarr" or "tiff". Defaults to "zarr". |
'zarr'
|
zarr_format
|
Literal[2, 3]
|
Zarr format version. Only used when seg_file_format="zarr". Defaults to 2. |
2
|
Example
from funtracks.import_export import export_to_csv export_to_csv(tracks, "output.csv")
Export with display names
export_to_csv(tracks, "output.csv", use_display_names=True)
Export only specific nodes
export_to_csv(tracks, "filtered.csv", node_ids={1, 2, 3})
Export with segmentation as zarr painted by tracklet ID
export_to_csv(tracks, "out.csv", export_seg=True, seg_path="seg_zarr")
Export with segmentation as tiff, original labels
export_to_csv(tracks, "out.csv", export_seg=True, seg_path="seg.tif", ... seg_relabel=None, seg_file_format="tiff")
load_v1_tracks
load_v1_tracks(
directory: Path,
seg_required: bool = False,
solution: bool = False,
) -> Tracks | SolutionTracks
Load a Tracks object from the given directory. Looks for files in the format generated by Tracks.save.
TODO: retain loading capabilities for legacy tracks
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
directory
|
Path
|
The directory containing tracks to load |
required |
seg_required
|
bool
|
If true, raises a FileNotFoundError if the segmentation file is not present in the directory. Defaults to False. |
False
|
solution
|
bool
|
If true, returns a SolutionTracks object, otherwise returns a normal Tracks object. Defaults to False. |
False
|
Returns:
| Name | Type | Description |
|---|---|---|
Tracks |
Tracks | SolutionTracks
|
A tracks object loaded from the given directory |
tracks_from_df
tracks_from_df(
df: DataFrame,
segmentation: ndarray | None = None,
scale: list[float] | None = None,
node_name_map: dict[str, str | list[str]] | None = None,
) -> SolutionTracks
Import tracks from pandas DataFrame.
Turns a pandas DataFrame with columns
time, [z], y, x, id, parent_id, [seg_id], [optional custom attr 1], ...
into a SolutionTracks object.
Cells without a parent_id will have an empty string or a -1 for the parent_id.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
df
|
DataFrame
|
A pandas DataFrame containing columns time, [z], y, x, id, parent_id, [seg_id], [optional custom attr 1], ... |
required |
segmentation
|
ndarray | None
|
An optional accompanying segmentation. If provided, assumes that the seg_id column in the dataframe exists and corresponds to the label ids in the segmentation array. Defaults to None. |
None
|
scale
|
list[float] | None
|
The scale of the segmentation (including the time dimension). Defaults to None. |
None
|
node_name_map
|
dict[str, str | list[str]] | None
|
Optional mapping from standard funtracks keys to DataFrame column names: {standard_key: column_name}. For example: {"time": "t", "pos": ["y", "x"], "area": "Area"} - Keys are standard funtracks attribute names (e.g., "time", "pos", "seg_id") - Values are column names from the DataFrame (e.g., "t", "Area") - For multi-value features like position, use a list: {"pos": ["y", "x"]} If None, column names are auto-inferred using fuzzy matching. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
SolutionTracks |
SolutionTracks
|
a solution tracks object |
Raises:
| Type | Description |
|---|---|
ValueError
|
if the segmentation IDs in the dataframe do not match the provided segmentation |
Example
tracks = tracks_from_df(df, segmentation=seg, scale=[1.0, 1.0, 0.5, 0.5])
write_to_geff
write_to_geff(
tracks: Tracks,
path: Path,
overwrite: bool = False,
zarr_format: Literal[2, 3] = 2,
)
Write tracks directly to a geff store at the given path.
Unlike :func:export_to_geff (which creates a parent zarr container with
a tracks.geff subfolder and optional segmentation), this writes the
geff store directly to path. Intended for internal save/load workflows
where the user picks the .geff path.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tracks
|
Tracks
|
Tracks object containing a graph to save. |
required |
path
|
Path
|
Destination path for the geff store. |
required |
overwrite
|
bool
|
If True, overwrites an existing store at path. |
False
|
zarr_format
|
Literal[2, 3]
|
Zarr format version to use. Defaults to 2. |
2
|