FreeClimber-FNG is a Python-based tool for automated detection of Failed Negative Geotaxis (FNG) events and calculation of fall distance in Drosophila melanogaster locomotor assays. It extends the FreeClimber platform (Spierer et al., 2020) with new functionality for identifying climb-to-fall transitions and quantifying recovery distance.
Note: This repository is a fork of adamspierer/FreeClimber. The core particle detection and climbing velocity pipeline is the work of Adam N. Spierer and colleagues. FreeClimber-FNG adds FNG-specific detection on top of that foundation.
The following capabilities were added by Jordan Vasu (2025):
- FNG detection — automated identification of climb-to-fall transitions (failed negative geotaxis events) within climbing assay videos
- Fall distance measurement — calculates the vertical distance between the position at fall initiation and the position at fall recovery; this metric captures the interval during which a fly falls and subsequently recovers, and can be interpreted as a proxy for fall severity
- Individual-fly tracking mode — an optional mode that links per-frame detections into per-fly trajectories using TrackPy (including predictive linking), in addition to the default cohort (mean-position) analysis
- Per-fly tortuosity / meandering metrics — when individual mode is enabled, computes path tortuosity, straightness, and mean turning angle per fly per climbing bout, quantifying how directly (or erratically) each fly climbs
These additions are implemented in detector_fng.py and are designed to integrate with the existing FreeClimber parameter configuration and batch processing workflow.
FreeClimber-FNG uses the same environment and dependencies as the base FreeClimber platform. We recommend running in an Anaconda virtual environment.
1. Create and activate a Python 3.6 environment:
conda create -n freeclimber python=3.6 anaconda
conda activate freeclimber2. Install dependencies:
pip install FreeClimber3. Clone this repository:
git clone https://github.com/jordanvasu/FreeClimber-FNG.git
cd FreeClimber-FNGFor full dependency details (FFmpeg, wxPython, trackpy, etc.), see the FreeClimber installation guide.
FreeClimber-FNG can be run via GUI or command line, following the same conventions as the base platform. See TUTORIAL.md for step-by-step instructions on parameter configuration and batch processing (covers base FreeClimber workflow). FNG-specific detection is handled by detector_fng.py and is described in the paper.
GUI:
pythonw ./scripts/FreeClimber_gui.py --video_file ./example/<video_file.suffix>Command line:
python FreeClimber_main.py --config_file ./example/example.cfgA single shared .cfg can be reused across folders whose videos have different
vial counts. Drop a plain-text file named vials.txt into a folder containing
just the integer count (e.g. 3), and it overrides the vials value in the
.cfg for every video in that folder. Accepted contents: a non-blank,
non-#-comment line as a bare integer (3) or vials=3 / vials: 3. A
missing or unparseable file leaves the .cfg value unchanged, so batch runs
never break.
When only some vials remain in a video — say the set b31-35 was reduced to
just vials 33, 34 and 35 — add an id = line listing which physical vials are
present, left to right:
id = 33, 34, 35
These IDs label the vials in every per-vial output (the vial_ID in
*.slopes.csv/results.csv, and the vial column of *.fng.csv,
*.tracks.csv and the tortuosity CSVs) instead of the default positional
1, 2, 3. The vial count is taken from how many IDs are listed, so the id =
line alone is enough — a separate count line is optional, and if it disagrees
with the number of IDs the ID count wins. Accepted separators are = or :,
the key may be id or ids, and non-numeric labels are allowed too. The vials
are still detected by their left-to-right position in the frame, so list the IDs
in that same left-to-right order.
By default FreeClimber-FNG runs in cohort mode: it analyzes the mean
position of all flies in a vial, exactly as the base FreeClimber platform does.
An optional individual mode additionally links per-frame detections into
per-fly trajectories using TrackPy,
including predictive linking (trackpy.predict.NearestVelocityPredict).
Individual mode is opt-in and fully backward compatible — when analysis_mode
is unset or 'cohort', output is byte-identical to previous behavior. To enable
it, set analysis_mode='individual' in the configuration (.cfg) file. When
enabled, a <video>.tracks.csv file is written alongside the other outputs
containing the columns particle, frame, t, vial, x, y plus the naming-convention
fields. Each vial is linked independently so particle IDs never swap across vials.
The five new configuration keys (defaults shown) are:
| Key | Default | Description |
|---|---|---|
analysis_mode |
'cohort' |
'cohort' (mean-position analysis) or 'individual' (per-fly linking) |
link_search_range |
15 |
Maximum inter-frame displacement, in pixels |
link_memory |
3 |
Frames a particle may be lost before it is treated as a new track |
link_predictor |
'nearest_velocity' |
'nearest_velocity' (predictive) or 'none' (plain nearest-neighbor) |
link_min_track_length |
5 |
Minimum track length, in frames; shorter tracks are dropped |
All five keys are optional. Existing .cfg files that omit them keep working
unchanged. See example/example.cfg for the keys as commented-out defaults.
Note: Individual mode is currently command-line only. GUI exposure is deferred until linking is validated on real multi-fly data.
When individual mode is enabled, three tortuosity metrics are additionally
computed per fly, per climbing bout, and written to <video>.tortuosity.csv:
| Metric | Definition | Range |
|---|---|---|
tortuosity |
path length / net displacement | >= 1 (NaN for closed bouts) |
straightness |
net displacement / path length | [0, 1] |
mean_turning_angle_rad |
mean absolute turning angle between consecutive step vectors | [0, pi] |
A climbing bout is the contiguous frame window from the previous FNG event's
fall-end (or the start of the recording, for the first event) up to and
including the current event's peak frame. Bouts are defined per vial using
the same FNG events emitted to <video>.fng.csv, and metrics are then
computed per linked particle inside each window. One row is emitted per
(vial, event_idx, particle) tuple. See scripts/tortuosity.py for the
formal definitions and degenerate-case handling, and dashboard/ for a
small exploratory plot script.
| File/Folder | Description |
|---|---|
detector_fng.py |
Core FNG detection logic (FreeClimber-FNG additions) |
scripts/ |
GUI and command line interface wrappers |
example/ |
Example video and configuration files |
paper.md |
JOSS manuscript |
TUTORIAL.md |
Usage walkthrough |
A synthetic single-fly negative geotaxis video is included in the repository for regression testing against known ground truth. The video was generated with 5 scripted fall events at peak frames 150, 280, 410, 540, and 660 in a 750-frame, 25 fps recording (30 s). Event parameters (rise magnitude, fall distance, recovery duration) are fully specified in the ground-truth CSV.
All synthetic validation assets live under tests/fixtures/synthetic_validation/:
| File | Description |
|---|---|
freeclimber_fng_validation_video.mp4 |
Synthetic test video (750 frames, 25 fps) |
freeclimber_fng_validation_video_ground_truth.csv |
Ground-truth fall events (5 events, peak frames 150/280/410/540/660) |
freeclimber_fng_validation_video.raw.csv |
Raw TrackPy output used by the regression test |
freeclimber_fng_validation_video.fng.csv |
Expected FNG output from the fixed pipeline |
freeclimber_fng_test_validation_README.txt |
Full description of video parameters and detection notes |
The regression test (tests/test_fng_bounds_and_detection.py) loads the raw CSV, runs the FNG detection pipeline, and asserts that exactly 5 events are detected with peak frames within ±5 frames of ground truth and no impossible (out-of-bounds) frame indices.
Run the regression test:
pip install pytest numpy pandas scipy
pytest tests/test_fng_bounds_and_detection.py -vNo video decoding or FFmpeg is required — the test operates on the pre-computed raw CSV.
If you use FreeClimber-FNG in your research, please cite both this tool and the original FreeClimber platform:
FreeClimber-FNG:
Vasu, J. (2026). FreeClimber-FNG (v1.0.4). Zenodo. https://doi.org/10.5281/zenodo.18090957
Original FreeClimber:
Spierer, A. N., Zhuo, L., Zhu, C. T., & Rand, D. M. (2020). FreeClimber: Automated quantification of climbing performance in Drosophila. Journal of Experimental Biology, 223, jeb229377. https://doi.org/10.1242/jeb.229377
This project is licensed under the MIT License, consistent with the original FreeClimber license. Modifications by Jordan Vasu are open-source under the same terms, with attribution to the original authors.
FreeClimber-FNG modifications: Jordan Vasu
Original FreeClimber: Adam N. Spierer, Lei Zhuo, and colleagues — Brown University Computational Biology Core