Skip to content

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