Skip to content

CSV Format

sleap-io supports multiple CSV formats for exporting pose tracking data. Each format has different structures suited for various analysis workflows.

Supported Formats

Format Description Best For
sleap SLEAP Analysis CSV Native SLEAP exports, one row per instance
dlc DeepLabCut format DLC compatibility, multi-header structure
points One row per point Database imports, normalized data
instances One row per instance Analysis pipelines
frames One row per frame Time series analysis, wide format

Format Details

SLEAP Format (sleap)

The default SLEAP Analysis CSV format produces one row per instance.

Columns:

Column Type Description
track string Track name (empty if untracked)
frame_idx int Frame index in video
instance.score float Instance confidence score
{node}.x float X coordinate for node
{node}.y float Y coordinate for node
{node}.score float Point confidence score

Example:

track,frame_idx,instance.score,nose.x,nose.y,nose.score,tail.x,tail.y,tail.score
mouse_1,0,0.95,100.5,200.3,0.98,150.2,250.1,0.92
mouse_1,1,0.94,102.1,198.5,0.97,148.8,248.3,0.91
mouse_2,0,0.93,300.2,400.1,0.96,350.5,450.8,0.89

DeepLabCut Format (dlc)

Multi-header format compatible with DeepLabCut analysis tools.

Structure:

  • Row 1: Scorer name (repeated)
  • Row 2: Body part names (repeated for x, y, likelihood)
  • Row 3: Coordinate type (x, y, likelihood)
  • Data rows: One per frame

Example:

scorer,MyModel,MyModel,MyModel,MyModel,MyModel,MyModel
bodyparts,nose,nose,nose,tail,tail,tail
coords,x,y,likelihood,x,y,likelihood
0,100.5,200.3,0.98,150.2,250.1,0.92
1,102.1,198.5,0.97,148.8,248.3,0.91

Multi-animal DLC format adds an individuals row:

scorer,MyModel,MyModel,MyModel,MyModel,MyModel,MyModel
individuals,mouse_1,mouse_1,mouse_1,mouse_2,mouse_2,mouse_2
bodyparts,nose,nose,nose,nose,nose,nose
coords,x,y,likelihood,x,y,likelihood
0,100.5,200.3,0.98,300.2,400.1,0.96

Points Format (points)

The most normalized format with one row per point. Ideal for database imports.

Columns:

Column Type Description
video_path string Path to video file
frame_idx int Frame index
track string Track name
instance_idx int Instance index within frame
instance_score float Instance confidence
node string Node/keypoint name
x float X coordinate
y float Y coordinate
score float Point confidence

Example:

video_path,frame_idx,track,instance_idx,instance_score,node,x,y,score
video.mp4,0,mouse_1,0,0.95,nose,100.5,200.3,0.98
video.mp4,0,mouse_1,0,0.95,tail,150.2,250.1,0.92
video.mp4,0,mouse_2,1,0.93,nose,300.2,400.1,0.96
video.mp4,0,mouse_2,1,0.93,tail,350.5,450.8,0.89

Instances Format (instances)

One row per instance with all node coordinates as columns.

Columns:

Column Type Description
video_path string Path to video file
frame_idx int Frame index
track string Track name
instance_idx int Instance index within frame
instance_score float Instance confidence
{node}.x float X coordinate for node
{node}.y float Y coordinate for node
{node}.score float Point confidence for node

Example:

video_path,frame_idx,track,instance_idx,instance_score,nose.x,nose.y,nose.score,tail.x,tail.y,tail.score
video.mp4,0,mouse_1,0,0.95,100.5,200.3,0.98,150.2,250.1,0.92
video.mp4,0,mouse_2,1,0.93,300.2,400.1,0.96,350.5,450.8,0.89
video.mp4,1,mouse_1,0,0.94,102.1,198.5,0.97,148.8,248.3,0.91

Frames Format (frames)

One row per frame with all instances multiplexed into columns. Best for time series analysis.

Columns:

Column Type Description
frame_idx int Frame index
video_path string Path to video file
inst{N}.{node}.x float X coordinate for instance N, node
inst{N}.{node}.y float Y coordinate for instance N, node
inst{N}.{node}.score float Point confidence for instance N, node

Example:

frame_idx,video_path,inst0.nose.x,inst0.nose.y,inst0.nose.score,inst0.tail.x,inst0.tail.y,inst0.tail.score,inst1.nose.x,inst1.nose.y,inst1.nose.score,inst1.tail.x,inst1.tail.y,inst1.tail.score
0,video.mp4,100.5,200.3,0.98,150.2,250.1,0.92,300.2,400.1,0.96,350.5,450.8,0.89
1,video.mp4,102.1,198.5,0.97,148.8,248.3,0.91,,,,,,

Empty Frames

When all_frames=True (or include_empty=True), frames without instances are included with NaN values for all coordinates.

Frame Padding

By default, CSV export only includes frames with instances. To include all frames:

import sleap_io as sio

labels = sio.load_slp("predictions.slp")

# Include empty frames (padded with NaN)
sio.save_csv(labels, "all_frames.csv", include_empty=True)

# Only frames with instances (sparse)
sio.save_csv(labels, "sparse.csv", include_empty=False)

# Specific frame range
sio.save_csv(labels, "clip.csv", start_frame=100, end_frame=500)

When include_empty=True and no explicit end_frame is given, padding spans the full video length when it is known (e.g. instances stopping at frame 1000 in a 2000-frame video still export rows through frame 1999). This matches the Analysis HDF5 export. If the video length cannot be resolved, padding falls back to the last labeled frame.

Metadata Sidecar

CSV files cannot store all Labels information (skeleton edges, symmetries, suggestions). To enable full round-trip reconstruction, use save_metadata=True:

sio.save_csv(labels, "data.csv", save_metadata=True)
# Creates: data.csv and data.json

Metadata JSON Structure

{
    "version": "1.0",
    "videos": [
        {
            "filename": "video.mp4",
            "backend_metadata": {}
        }
    ],
    "skeletons": [
        {
            "name": "Skeleton-0",
            "nodes": ["nose", "head", "neck", "tail"],
            "edges": [[0, 1], [1, 2], [2, 3]],
            "symmetries": []
        }
    ],
    "tracks": ["mouse_1", "mouse_2"],
    "suggestions": [],
    "provenance": {}
}
Field Description
version Metadata schema version (currently "1.0")
videos Video metadata; each entry has filename and a backend-specific backend_metadata object (e.g. shape, dataset, grayscale)
skeletons List of skeleton definitions, each with nodes, edges, and symmetries
tracks Track names in order
suggestions Suggested frame indices
provenance Source-file / creation metadata, mirroring labels.provenance

Loading CSV Files

import sleap_io as sio

# Load CSV (auto-detects format)
labels = sio.load_csv("data.csv")

# If metadata sidecar exists, it's loaded automatically
# data.json provides skeleton edges, symmetries, etc.

CLI Usage

# Export to CSV
sio export predictions.slp -o analysis.csv

# Specify format
sio export predictions.slp -o dlc.csv --csv-format dlc --scorer MyModel

# Include all frames
sio export predictions.slp -o all.csv --empty-frames

# Frame range
sio export predictions.slp -o clip.csv --start 100 --end 500

# With metadata sidecar
sio export predictions.slp -o data.csv --save-metadata

API Reference

sleap_io.io.main.load_csv(filename, format='auto', video=None, skeleton=None, **kwargs)

Load pose data from a CSV file.

Parameters:

Name Type Description Default
filename str

Path to CSV file.

required
format str

CSV format. One of "auto", "sleap", "dlc", "points", "instances", "frames". Default "auto" detects format from file content.

'auto'
video Video | str | None

Video to associate with data. Can be Video object or path string.

None
skeleton Skeleton | None

Skeleton to use. If None, inferred from columns or metadata.

None
**kwargs

Additional loader keyword arguments forwarded by load_file (e.g. open_videos, lazy). They are accepted but ignored; this format does not use them.

required

Returns:

Type Description
Labels

Labels object.

Notes

If a metadata JSON file exists alongside the CSV (same base name with .json extension), it will be automatically loaded to restore full Labels context including skeleton edges, symmetries, and provenance.

See Also

save_csv: Save Labels to CSV file.

Source code in sleap_io/io/main.py
def load_csv(
    filename: str,
    format: str = "auto",
    video: "Video | str | None" = None,
    skeleton: "Skeleton | None" = None,
    **kwargs,
) -> "Labels":
    """Load pose data from a CSV file.

    Args:
        filename: Path to CSV file.
        format: CSV format. One of "auto", "sleap", "dlc", "points", "instances",
            "frames". Default "auto" detects format from file content.
        video: Video to associate with data. Can be Video object or path string.
        skeleton: Skeleton to use. If None, inferred from columns or metadata.
        **kwargs: Additional loader keyword arguments forwarded by `load_file`
            (e.g. ``open_videos``, ``lazy``). They are accepted but ignored; this
            format does not use them.

    Returns:
        Labels object.

    Notes:
        If a metadata JSON file exists alongside the CSV (same base name with
        .json extension), it will be automatically loaded to restore full
        Labels context including skeleton edges, symmetries, and provenance.

    See Also:
        save_csv: Save Labels to CSV file.
    """
    from sleap_io.io import csv

    return csv.read_labels(filename, format=format, video=video, skeleton=skeleton)

sleap_io.io.main.save_csv(labels, filename, format='sleap', video=None, include_score=True, include_empty=False, start_frame=None, end_frame=None, scorer='sleap-io', save_metadata=False, chunk_size=None, video_id='path')

Save pose data to a CSV file.

Parameters:

Name Type Description Default
labels Labels

Labels to save.

required
filename str

Output path.

required
format str

CSV format. One of "sleap" (default), "dlc", "points", "instances", "frames".

'sleap'
video Video | int | None

Video to filter to. Can be Video object or integer index. If None, includes all videos.

None
include_score bool

Include confidence scores in output. Default True.

True
include_empty bool

Include frames with no instances (filled with NaN values). Default False. Only applies to "frames" and "instances" formats.

False
start_frame int | None

Start frame index (inclusive) for output. If None, starts from 0 when include_empty=True, or from first labeled frame otherwise.

None
end_frame int | None

End frame index (exclusive) for output. If None, ends at the full video length when known, otherwise at last labeled frame + 1.

None
scorer str

Scorer name for DLC format. Default "sleap-io".

'sleap-io'
save_metadata bool

Save JSON metadata file alongside CSV that enables full round-trip reconstruction. Default False.

False
chunk_size int | None

Number of rows per chunk for memory-efficient writing. If None (default), writes entire DataFrame at once. Useful for large datasets. Not supported for DLC format.

None
video_id str

How to represent videos in the CSV. Options: "path" (default), "index", or "name".

'path'
See Also

load_csv: Load Labels from CSV file.

Source code in sleap_io/io/main.py
def save_csv(
    labels: "Labels",
    filename: str,
    format: str = "sleap",
    video: "Video | int | None" = None,
    include_score: bool = True,
    include_empty: bool = False,
    start_frame: int | None = None,
    end_frame: int | None = None,
    scorer: str = "sleap-io",
    save_metadata: bool = False,
    chunk_size: int | None = None,
    video_id: str = "path",
) -> None:
    """Save pose data to a CSV file.

    Args:
        labels: Labels to save.
        filename: Output path.
        format: CSV format. One of "sleap" (default), "dlc", "points",
            "instances", "frames".
        video: Video to filter to. Can be Video object or integer index.
            If None, includes all videos.
        include_score: Include confidence scores in output. Default True.
        include_empty: Include frames with no instances (filled with NaN values).
            Default False. Only applies to "frames" and "instances" formats.
        start_frame: Start frame index (inclusive) for output. If None, starts
            from 0 when include_empty=True, or from first labeled frame otherwise.
        end_frame: End frame index (exclusive) for output. If None, ends at the
            full video length when known, otherwise at last labeled frame + 1.
        scorer: Scorer name for DLC format. Default "sleap-io".
        save_metadata: Save JSON metadata file alongside CSV that enables
            full round-trip reconstruction. Default False.
        chunk_size: Number of rows per chunk for memory-efficient writing. If None
            (default), writes entire DataFrame at once. Useful for large datasets.
            Not supported for DLC format.
        video_id: How to represent videos in the CSV. Options: "path" (default),
            "index", or "name".

    See Also:
        load_csv: Load Labels from CSV file.
    """
    from sleap_io.io import csv

    csv.write_labels(
        labels,
        filename,
        format=format,
        video=video,
        include_score=include_score,
        include_empty=include_empty,
        start_frame=start_frame,
        end_frame=end_frame,
        scorer=scorer,
        save_metadata=save_metadata,
        chunk_size=chunk_size,
        video_id=video_id,
    )