Sound production in philodoptera#

Stridulation in crickets (e.g. Pholidoptera littoralis) is a great animal model to study motor control/ sound production. Below is a tutorial on how we can create a trials.nc. Note that we have a video, audio and DeepLabCut pose file, meaning we can look at movement and sound features in the GUI!

../_images/cricket1.png ../_images/cricket2.png

Made in Slovenia, 2025.

%load_ext autoreload
%autoreload 2

import pandas as pd
from pathlib import Path
from audioio import AudioLoader
from movement.io import load_poses
from movement.kinematics import compute_velocity, compute_speed, compute_acceleration

import ethograph as eto
from ethograph.utils.download import download_example_dataset
from ethograph.io.nwb_alignment import align_media_per_trial
The autoreload extension is already loaded. To reload it, use:
  %reload_ext autoreload

Download example data#

try:
    _here = Path(__vsc_ipynb_file__).parent
except NameError:
    _here = Path().resolve()

data_folder = _here.parent / "data" / "philodoptera"
download_example_dataset("philodoptera", data_folder)
print(f"\ndata_folder: {data_folder}")
Downloading philodoptera.nc... (1/4)
Downloading philodoptera.mp4... (2/4)
Downloading philodoptera.wav... (3/4)
  philodoptera.csv (4/4)

data_folder: d:\Akseli\Code\ethograph\data\philodoptera

Build NWB alignment#

video_path = data_folder / "philodoptera.mp4"
audio_path = data_folder / "philodoptera.wav"
poses_csv_path = data_folder / "philodoptera.csv"
fps = 240

# Probe audio sample rate from file
with AudioLoader(str(audio_path)) as f:
    audio_sr = f.rate

# Single-session dataset: one row in the session table
session_table = pd.DataFrame({
    "trial":   ["session"],
    "video_0": [str(video_path)],
    "audio_0": [str(audio_path)],
    "pose_0":  [str(poses_csv_path)],
})

nwb_path = data_folder / ".ethograph" / "alignment.nwb"
align_media_per_trial(
    trial_table=session_table,
    stream_rates={"video": float(fps), "audio": float(audio_sr), "pose": float(fps)},
    output_path=nwb_path,
    pose_fps=float(fps),
)

Create dataset#

# Load pose data and compute kinematics
ds = load_poses.from_dlc_file(poses_csv_path, fps=fps)
ds["velocity"] = compute_velocity(ds.position)
ds["speed"] = compute_speed(ds.position)
ds["acceleration"] = compute_acceleration(ds.position)

ds["individuals"] = ["Pholidoptera_littoralis_1"]
ds.attrs["Recording info"] = (
    "This cricket species Pholidoptera littoralis was recorded on a field trip "
    "in Slovenia in 2025. The video was recorded with an iPhone and the audio "
    "with a Zoom recorder. Synchronization may not be perfect."
)


ds.to_netcdf(data_folder / "philodoptera.nc")
print(f"Saved to {data_folder / 'philodoptera.nc'}")
Saved to d:\Akseli\Code\ethograph\data\philodoptera\philodoptera.nc