MatchTimeline

MatchTimeline is the central time-indexed container for 60 FPS match dynamics, coupling frame-by-frame FrameState snapshots with static domain metadata (Court, EnvironmentConditions, BallProperties, SurfaceMaterials, and Match) for lossless serialization to Apache Parquet (.parquet), CSV, and Pandas DataFrames.

Properties

  • Name
    frames
    Type
    list[FrameState]
    Description

    Chronological sequence of FrameState snapshots.

  • Name
    fps
    Type
    float
    Description

    Nominal sampling frequency in frames per second.

  • Name
    court
    Type
    Court | None
    Description

    Court geometry, enclosure, turf color, and CourtLocation metadata associated with the recording.

  • Name
    environment
    Type
    EnvironmentConditions | None
    Description

    Atmospheric and environmental parameters (temperature_c, relative_humidity, altitude_m, wind_velocity, air_density, gravity).

  • Name
    ball_properties
    Type
    BallProperties | None
    Description

    Physical ball properties (mass, radius, cor_normal, fuzz_factor, spin_decay_tau).

  • Name
    surface_materials
    Type
    SurfaceMaterials | None
    Description

    Friction and restitution parameters for the court floor, glass walls, fence, and net.

  • Name
    match
    Type
    Match | None
    Description

    Associated Match domain entity (teams, players, MatchConfiguration, and score_history).

  • Name
    metadata
    Type
    dict[str, Any]
    Description

    Arbitrary user-defined JSON-serializable key-value metadata preserved in .parquet headers.

  • Name
    duration
    Type
    float
    Description

    Total elapsed duration in seconds (frames[-1].timestamp - frames[0].timestamp).

  • Name
    has_skeletal_poses
    Type
    bool
    Description

    Returns True if any player in any frame contains 17-joint 3D skeletal keypoints (keypoints_3d).


methodtimeline.to_parquet()

Export to Universal Parquet

Writes the timeline to a single self-contained .parquet file. Static domain entities (court, environment, ball_properties, surface_materials, match, metadata) are serialized as JSON inside the Parquet schema header under b"padelkit_metadata", while frame dynamics are stored as columnar float32 / int16 / string arrays.

Arguments

  • Name
    path
    Type
    str | Path
    Description

    Destination .parquet file path.

  • Name
    compression
    Type
    str
    Description

    Parquet compression codec ("zstd", "snappy", "gzip", or "none").

  • Name
    bake_skeleton
    Type
    bool
    Description

    If True and not timeline.has_skeletal_poses, automatically calls bake_skeletal_poses() before writing so all 204 3D joint columns (p1_j0_x..p4_j16_z) are included.

  • Name
    animation_library_dir
    Type
    str | Path | None
    Description

    Optional path to a padelkit-animator library folder used when bake_skeleton=True.

Save to Parquet

method
to_parquet
from padelkit import Court, EnvironmentConditions, MatchTimeline

timeline = MatchTimeline.demo_rally(
    court=Court.fip_standard(),
    environment=EnvironmentConditions.from_atmosphere(
        temperature_c=22.0,
        altitude_m=650.0,
        relative_humidity=0.45,
    ),
)

path = timeline.to_parquet(
    "rally_recording.parquet",
    compression="zstd",
    bake_skeleton=True,
)
print(f"Saved {len(timeline.frames)} frames to {path}")

classmethodMatchTimeline.from_parquet()

Load from Universal Parquet

Reads a .parquet file written by to_parquet(), reconstructs all attached domain objects (court, environment, ball_properties, surface_materials, match) from the padelkit_metadata schema header, and restores all FrameState objects (including 17-joint keypoints_3d when present).

Arguments

  • Name
    path
    Type
    str | Path
    Description

    Source .parquet file path.

Load from Parquet

classmethod
from_parquet
from padelkit import MatchTimeline

timeline = MatchTimeline.from_parquet("rally_recording.parquet")

print("Frames:", len(timeline.frames), "@", timeline.fps, "FPS")
print("Has 3D skeletons:", timeline.has_skeletal_poses)
print("Court turf:", timeline.court.turf_color)
print("Air density:", timeline.environment.air_density)

methodtimeline.bake_skeletal_poses()

Bake 3D Skeletal Poses

Populates PlayerPose.keypoints_3d (shape (17, 3) in the H36M_17 convention) for every player in every frame of the timeline.

If animation_library_dir is provided and contains .npz or .glb clips matching PlayerPose.animation, their motion-captured 3D joint trajectories are phase-aligned via contact_swing_phase and rotated by PlayerPose.yaw_deg. Otherwise, PadelKit synthesizes an anatomically accurate 17-joint athletic padel rig driven by the player's locomotion cycle and stroke swing_phase.

Arguments

  • Name
    animation_library_dir
    Type
    str | Path | None
    Description

    Optional directory containing manifest.json and 3D clips from padelkit-animator.

  • Name
    overwrite
    Type
    bool
    Description

    When False, preserves existing PlayerPose.keypoints_3d arrays (e.g., from camera pose estimation) and only bakes missing players/frames.

Bake 17-Joint Skeletons

method
bake_skeletal_poses
from padelkit import MatchTimeline

timeline = MatchTimeline.demo_rally(fps=60.0)
assert not timeline.has_skeletal_poses

timeline.bake_skeletal_poses(
    animation_library_dir="../padelkit-animator/data/animations"
)
assert timeline.has_skeletal_poses

p1_pose = timeline.frames[30].players["P1"]
print("Root-relative (17 joints):", len(p1_pose.keypoints_3d))
print("World Pelvis (X, Y, Z):", p1_pose.world_keypoints_3d[0])

methodsto_dataframe / from_dataframe / to_csv / from_csv

DataFrame & CSV Conversion

Converts between MatchTimeline and tabular Pandas DataFrame or .csv files. All structured score columns, 9D ball state columns, and optional 204 skeletal columns (p1_j0_x..p4_j16_z) are supported in both DataFrames and CSV files.

Methods

  • Name
    to_dataframe(include_skeleton=None)
    Type
    pd.DataFrame
    Description

    Converts all frames into a flat Pandas DataFrame. By default (include_skeleton=None), includes the 204 skeletal columns automatically if has_skeletal_poses is True.

  • Name
    from_dataframe(df, fps=60.0, ...)
    Type
    MatchTimeline
    Description

    Classmethod that reconstructs a MatchTimeline from a Pandas DataFrame, automatically detecting p{1..4}_j{0..16}_{x,y,z} columns when present.

  • Name
    to_csv(path, include_skeleton=False)
    Type
    Path
    Description

    Writes the timeline to a .csv file (defaults to compact root-pose columns unless include_skeleton=True).

  • Name
    from_csv(path, fps=60.0)
    Type
    MatchTimeline
    Description

    Classmethod that loads a MatchTimeline from a .csv file.

  • Name
    build_metadata_envelope()
    Type
    dict[str, Any]
    Description

    Returns the serializable metadata dictionary stored in the padelkit_metadata Parquet header.

  • Name
    demo_rally(court=None, fps=60.0, ..., bake_skeleton=False)
    Type
    MatchTimeline
    Description

    Classmethod that generates a physics-driven 6-shot padel rally (Serve, Return, Volley,Chiquita, Lob, Bandeja) with 9D ball aerodynamics and 4 players.

DataFrame Roundtrip

method
to_dataframe
from padelkit import MatchTimeline

timeline = MatchTimeline.demo_rally(bake_skeleton=True)
df = timeline.to_dataframe()

print("Rows:", len(df), "| Columns:", len(df.columns))
restored = MatchTimeline.from_dataframe(df, fps=timeline.fps)
assert restored.has_skeletal_poses

Was this page helpful?