diff --git a/_pages/plugins/andi-j/index.md b/_pages/plugins/andi-j/index.md new file mode 100644 index 0000000000..ee8cd87534 --- /dev/null +++ b/_pages/plugins/andi-j/index.md @@ -0,0 +1,170 @@ +--- +title: AnDi-J +name: AnDi-J +description: Anomalous-diffusion analysis of single-particle tracking (SPT) data in Fiji, combining statistical and machine-learning methods. +categories: [Analysis, Tracking, Track analysis, Machine Learning] +icon: /media/plugins/andi-j/logo.png +update-site: AnDi-J +nav-title: Overview +nav-links: +- title: Overview + url: /plugins/andi-j +- title: Input data + url: /plugins/andi-j/input-data +- title: Trajectory Analysis + url: /plugins/andi-j/trajectory-analysis +- title: Trajectory Segmentation + url: /plugins/andi-j/trajectory-segmentation +- title: ML models + url: /plugins/andi-j/ml-models +source-url: https://github.com/gorkamunoz/andi-j +release-url: https://github.com/gorkamunoz/andi-j/releases/latest +dev-status: Active +support-status: Active +team-founders: 'Gorka Muñoz-Gil | https://github.com/gorkamunoz' +team-maintainers: 'Gorka Muñoz-Gil | https://github.com/gorkamunoz' +--- + +{% include img align="center" src="/media/plugins/andi-j/logo.png" alt="AnDi-J logo" width="160" %} + +**AnDi-J** is a [Fiji](/software/fiji)/ImageJ plugin for **anomalous-diffusion analysis of single-particle tracking (SPT) data**. Given input trajectories, it provides state-of-the-art machinery to analyse them, combining statistical and machine learning (ML) analysis. The plugin works at two scales: from single-trajectory analysis, returning properties for each of the input trajectories, to "*per-frame*" predictions, allowing for a fine-grained analysis and the segmentation of trajectories with expected diffusion changes. + +{% include notice icon="info" content=" +An up-to-date version of this wiki is available in [**Github**](https://github.com/gorkamunoz/andi-j/wiki). We strongly suggest following that, as it is more regularly updated. +" %} + + + +## Overview + +AnDi-J is organised around two menu commands under {% include bc path="Plugins|AnDi-J" %}: + +| Command | Purpose | +|---|---| +| [**Trajectory Analysis**](/plugins/andi-j/trajectory-analysis) | Per-trajectory observables: mean squared displacement (MSD) analysis, diffusion coefficient *D*, anomalous exponent *α*, the *D*–*α* plane, diffusion-model classification, turning angles and PSD. | +| [**Trajectory Segmentation**](/plugins/andi-j/trajectory-segmentation) | Per-frame predictions of *α* and *D* along each trajectory, change-point detection that splits it into homogeneous segments, and the diffusive state (immobile, confined, free diffusion, or directed) of each segment. | + +Both commands share the same [Data Manager](/plugins/andi-j/input-data#data-manager) for loading and grouping data, and both can analyse several experiments (conditions) at once, each with its own colour, overlaid for comparison. + +## Documentation + +| Page | Contents | +|---|---| +| [Input data](/plugins/andi-j/input-data) | Expected `.csv` layout, the [Data Manager](/plugins/andi-j/input-data#data-manager) ([loading trajectories](/plugins/andi-j/input-data#loading-trajectories), [units](/plugins/andi-j/input-data#units)), and [selecting the segmentation model](/plugins/andi-j/input-data#selecting-the-segmentation-model). | +| [Trajectory Analysis](/plugins/andi-j/trajectory-analysis) | [tMSD](/plugins/andi-j/trajectory-analysis#tmsd-visualization), [diffusion coefficient](/plugins/andi-j/trajectory-analysis#diffusion-coefficient), [anomalous exponent](/plugins/andi-j/trajectory-analysis#anomalous-exponent), [*D* vs *α*](/plugins/andi-j/trajectory-analysis#d-vs-alpha), [diffusion model](/plugins/andi-j/trajectory-analysis#diffusion-model), [turning angles](/plugins/andi-j/trajectory-analysis#turning-angles) and [PSD](/plugins/andi-j/trajectory-analysis#psd). | +| [Trajectory Segmentation](/plugins/andi-j/trajectory-segmentation) | [Visualization](/plugins/andi-j/trajectory-segmentation#visualization), [*D* vs *α* density](/plugins/andi-j/trajectory-segmentation#d-vs-alpha), [segment stats](/plugins/andi-j/trajectory-segmentation#segment-stats) and [diffusive state](/plugins/andi-j/trajectory-segmentation#diffusive-state). | +| [ML models](/plugins/andi-j/ml-models) | The bundled models, the ONNX contract, how to plug in your own models, and how to [contribute them](/plugins/andi-j/ml-models#contributing-a-model). | + +## Installation + +### From the update site + +The easiest way to install AnDi-J, and to keep it up to date, is to [follow](/update-sites/following) the **AnDi-J** [update site](/update-sites): + +1. Start [Fiji](/software/fiji) (or [download and install it](/software/fiji/downloads) first). +2. Select {% include bc path="Help|Update..." %} from the menu bar. +3. Click on the {% include button label="Manage update sites" %} button. +4. Scroll down the list and tick the checkbox for the **AnDi-J** update site, then click {% include button label="Close" %}. If **AnDi-J** is not in the list, click {% include button label="Add unlisted site" %} and enter the name `AnDi-J` and the URL `https://sites.imagej.net/AnDi-J/`. +5. Click {% include button label="Apply changes" %} to install the plugin. +6. Restart Fiji. + +The plugin is then available under {% include bc path="Plugins|AnDi-J" %}. + +{% include notice icon="note" content=" +The update site installs AnDi-J together with the **CPU** build of ONNX Runtime. For GPU (CUDA) acceleration, available only on Windows and Linux, replace `onnxruntime-1.26.0.jar` with `onnxruntime_gpu-1.26.0.jar` ([download link](https://repo1.maven.org/maven2/com/microsoft/onnxruntime/onnxruntime_gpu/1.26.0/onnxruntime_gpu-1.26.0.jar)) in the `Fiji.app/jars/` folder (see the requirements below). +" %} + +### Manual installation + +1. Go to the [Releases](https://github.com/gorkamunoz/andi-j/releases) page of the AnDi-J repository. +2. Under the latest plugin release, download the file `andi-j-X.Y.Z.jar`. It already contains the two default ML models. +3. AnDi-J uses **ONNX Runtime** for its machine-learning predictions, on **CPU** or **GPU** (CUDA). The GPU is much faster, and needs CUDA Toolkit 12.x and cuDNN 9.x for CUDA 12 (see [Other CUDA versions](#other-cuda-versions) otherwise). Download **one** of the two ONNX Runtime jars from Maven Central: + * CPU: [`onnxruntime-1.26.0.jar`](https://repo1.maven.org/maven2/com/microsoft/onnxruntime/onnxruntime/1.26.0/onnxruntime-1.26.0.jar) + * GPU/CUDA (Windows and Linux only): [`onnxruntime_gpu-1.26.0.jar`](https://repo1.maven.org/maven2/com/microsoft/onnxruntime/onnxruntime_gpu/1.26.0/onnxruntime_gpu-1.26.0.jar) +4. Copy the `andi-j` jar and the ONNX Runtime jar into the `Fiji.app/jars/` folder. Keep a single ONNX Runtime jar in that folder. +5. Restart Fiji. +6. The plugin is now available under {% include bc path="Plugins|AnDi-J" %}. + +With the GPU jar, AnDi-J runs the models on the GPU when CUDA is available and on the CPU otherwise. Without CUDA, Fiji's console shows an error line such as `[E:onnxruntime…] Failed to load library libonnxruntime_providers_cuda.so` when a model loads; it is harmless, and the models then run on the CPU. + +### Build from source + +```bash +git clone https://github.com/gorkamunoz/andi-j.git +``` + +Download the two default ML models from the latest model release on the [Releases](https://github.com/gorkamunoz/andi-j/releases) page and place them in `andi-j/src/main/resources/models/`. The plugin loads them by name, so rename the files, if needed, to exactly: + +* `andi-j-analysis-latest.onnx` (Trajectory Analysis model) +* `andi-j-seg-latest.onnx` (Trajectory Segmentation model) + +Then: + +```bash +cd andi-j +mvn clean package +cp target/andi-j-X.Y.Z.jar Fiji.app/jars/ # not the -sources.jar +``` + +The build downloads the **GPU** build of ONNX Runtime (Windows and Linux only) into your local Maven cache, so you can copy it from there: + +```bash +cp ~/.m2/repository/com/microsoft/onnxruntime/onnxruntime_gpu/1.26.0/onnxruntime_gpu-1.26.0.jar Fiji.app/jars/ +``` + +For the CPU build, download `onnxruntime-1.26.0.jar` as in [Manual installation](#manual-installation). + +Requires Java 8+ and [Maven](/develop/maven). The build uses the [pom-scijava](https://github.com/scijava/pom-scijava) parent POM. + +{% capture debug-mode %} +**Debug mode.** AnDi-J keeps its diagnostics quiet by default. To see them, enable ImageJ's debug mode at {% include bc path="Edit|Options|Misc..." %} and open {% include bc path="Window|Console" %}. With debug mode on, the plugin prints information about the ML models (ONNX model input/output tensor shapes and CPU/GPU usage). Genuine anomalies (e.g. a custom model returning an unexpected output type) are always reported, debug mode or not. +{% endcapture %} +{% include notice icon="tech" content=debug-mode %} + +### Other CUDA versions + +If your machine has a different CUDA toolkit than the one ONNX Runtime 1.26.0 needs, use the matching `onnxruntime_gpu` release instead: + +1. Check your installed CUDA version: `nvcc --version`. +2. Look up which `onnxruntime_gpu` release supports that CUDA version in the [ONNX Runtime CUDA Execution Provider compatibility table](https://onnxruntime.ai/docs/execution-providers/CUDA-ExecutionProvider.html). +3. Download the matching jar from Maven Central: `https://repo1.maven.org/maven2/com/microsoft/onnxruntime/onnxruntime_gpu//onnxruntime_gpu-.jar` +4. Put it in `Fiji.app/jars/` in place of the ONNX Runtime jar that is there. +5. Restart Fiji. + +The plugin uses whichever ONNX Runtime jar is in `Fiji.app/jars/`, so no rebuild is needed. AnDi-J is tested with ONNX Runtime 1.26.0. + +## Citing AnDi-J + +If you use AnDi-J in your work, please cite: + +> G. Muñoz-Gil, *AnDi-J: diffusion analysis of single-particle tracking data in Fiji*, bioRxiv (2026). [https://doi.org/10.64898/2026.10.14.756868](https://doi.org/10.64898/2026.10.14.756868) + +{% raw %} +```bibtex +@article{andij_paper, + author = {Mu{\~n}oz-Gil, Gorka}, + title = {{AnDi-J}: diffusion analysis of single-particle tracking data in Fiji}, + year = {2026}, + doi = {10.64898/2026.10.14.756868}, + publisher = {Cold Spring Harbor Laboratory}, + url = {https://www.biorxiv.org/content/early/2026/10/14/2026.10.14.756868}, + journal = {bioRxiv} +} +``` +{% endraw %} + +## More resources + +AnDi-J relies on previous work done in the context of the AnDi Challenge and related projects. To learn more about them, you can use the following references: + +* [`andi_datasets`](https://github.com/AnDiChallenge/andi_datasets): Python library used as backbone for many of the methods underlying AnDi-J. +* [Objective comparison of methods to decode anomalous diffusion, G. Muñoz-Gil et al. (2021)](https://www.nature.com/articles/s41467-021-26320-w): paper gathering the results of the 1st AnDi Challenge. Related to the analysis performed in [Trajectory Analysis](/plugins/andi-j/trajectory-analysis). +* [Quantitative evaluation of methods to analyze motion changes in single-particle experiments, G. Muñoz-Gil et al. (2025)](https://www.nature.com/articles/s41467-025-61949-x): paper gathering the results of the 2nd AnDi Challenge. Related to the analysis performed in [Trajectory Segmentation](/plugins/andi-j/trajectory-segmentation). +* [Single-particle diffusion characterization by deep learning, N. Granik et al. (2019)](https://doi.org/10.1016/j.bpj.2019.06.015): convolutional networks for single-trajectory analysis. The default model of the Trajectory Analysis tab is built on their architecture. +* [Inferring pointwise diffusion properties of single trajectories with deep learning, B. Requena et al. (2023)](https://www.cell.com/biophysj/fulltext/S0006-3495(23)00651-3): paper proposing step-wise prediction of anomalous diffusion trajectories. +* [U-Net 3+ for anomalous diffusion analysis enhanced with mixture estimates (U-AnD-ME) in particle-tracking data, S. Asghar et al. (2025)](https://iopscience.iop.org/article/10.1088/2515-7647/adf9aa): paper of the winners of the 2nd AnDi Challenge. The default model of the segmentation tab is a direct update of their model. + +## See also + +* [TrackMate](/plugins/trackmate) — produces the `.csv` trajectory files AnDi-J reads. +* [TraJClassifier](/plugins/trajclassifier) — another Fiji tool for classifying diffusion trajectories. diff --git a/_pages/plugins/andi-j/input-data.md b/_pages/plugins/andi-j/input-data.md new file mode 100644 index 0000000000..7141325b29 --- /dev/null +++ b/_pages/plugins/andi-j/input-data.md @@ -0,0 +1,74 @@ +--- +title: AnDi-J › Input data +name: AnDi-J +icon: /media/plugins/andi-j/logo.png +description: The CSV layout AnDi-J expects, and how to load and group trajectories with the Data Manager. +nav-title: Input data +nav-links: +- title: Overview + url: /plugins/andi-j +- title: Input data + url: /plugins/andi-j/input-data +- title: Trajectory Analysis + url: /plugins/andi-j/trajectory-analysis +- title: Trajectory Segmentation + url: /plugins/andi-j/trajectory-segmentation +- title: ML models + url: /plugins/andi-j/ml-models +--- + +AnDi-J takes as input `.csv` files containing the trajectories of a given experiment. To ease integration with existing tools, the expected `.csv` must follow the standard layout of a [TrackMate](/plugins/trackmate) output: a header row, three further description/units rows, then one row per spot. The required columns are: + +| Column | Meaning | +|---|---| +| `TRACK_ID` | trajectory identifier | +| `POSITION_X`, `POSITION_Y` | spot coordinates | +| `FRAME` | frame index | +| `POSITION_T` | time (optional; with its unit, gives the frame interval, see [Units](#units)) | + +Spots are grouped by `TRACK_ID` and sorted by frame; gaps in `FRAME` are handled where relevant (e.g. MSD and eMSD lookups are gap-aware). + +{% include notice icon="info" content=" +**Generating test data.** The [`pythons_helpers`](https://github.com/gorkamunoz/andi-j/tree/main/utils/pythons_helpers) folder of the repository provides scripts that use Python and the [`andi_datasets`](https://github.com/AnDiChallenge/andi_datasets) library to produce example test `csv` files. +" %} + +## Data Manager + +The Data Manager is an independent window that lets you select the data to be processed by the plugin. [Trajectory Analysis](/plugins/andi-j/trajectory-analysis) and [Trajectory Segmentation](/plugins/andi-j/trajectory-segmentation) have a similar Data Manager, although each opens in its own window. + +### Loading trajectories + +This part of the manager is the same for both Trajectory Analysis and Trajectory Segmentation. + +* **Load as Separate / Merge** — whether the chosen files are merged into a single experiment for analysis or loaded as separate ones. Only applies if more than one file is selected. +* **Choose Files…** — choose the CSV files (multi-select allowed). +* **Tag** — the name by which the experiment will be tagged in the analysis. If left blank, the tag is set to the file name. If several files are merged without a tag, the experiment is named `Exp N`. +* **Min. length** / **Max. length** — per-file trajectory-length filters: trajectories with fewer frames than **Min. length** are left out; longer than **Max. length** are cut to their first **Max. length** frames. Blank means no filter; setting both to *N* keeps exactly *N* frames of every trajectory with at least *N*. +* **Load Data** — loads the files into the table. +* The table shows, per file: colour, tag, file name, **Length range** (shortest – longest trajectory in the file), **Min. length**, **Max. length**, **Trajectories** (kept by **Min. length** / in the file, updated as you edit) and the [units](#units). **Tag, Min. length, Max. length and the units are editable.** +* **Perform Analysis** — assembles the experiments and opens the analysis window. For Trajectory Analysis this is almost instantaneous. For Trajectory Segmentation, the ML models that predict the per-frame properties are run at this point, so it takes longer; see [Selecting the segmentation model](#selecting-the-segmentation-model) below for details. + +The Data Manager can be accessed at any time during analysis, allowing you to add or remove experiments at will. + +### Units + +The fourth header row of a TrackMate export holds the unit of each column, e.g. `(micron)` for the positions and `(sec)` for `POSITION_T`, or `(pixel)` and `(frame)` when the image was not calibrated. The Data Manager reads them into two editable columns of the table: + +* **Space unit (μm)** — the size of one position unit in μm: 1 for positions in μm, the pixel size for positions in pixels. +* **Frame interval (μs)** — the time between frames in μs, from `POSITION_T` and its unit. + +An empty cell means unknown; double-click it to fill in or correct the value. When the experiments have these values, the **Units** button of the analysis tabs shows the results in physical units (nm to m, ns to s); without them, the analysis is in pixels and frames. + +All experiments must be either calibrated or not (separately for space and time), and files merged into one experiment must share their values: otherwise **Perform Analysis** shows a warning and does not run, since values in μm and in pixels, or in seconds and in frames, cannot be compared. α, turning angles, diffusion models and diffusive states do not depend on the units. + +{% include img align="center" name="Data Manager" src="/media/plugins/andi-j/data-manager.png" caption="**Data Manager.** Four test files loaded into three experiments. exp 1 keeps the trajectories of at least 10 frames and cuts them to 200 (557 of its 3005 trajectories are kept); the two files tagged exp 2 are merged into one experiment; exp 3 cuts its trajectories to 20 frames." %} + +## Selecting the segmentation model + +This part of the manager exists only in [Trajectory Segmentation](/plugins/andi-j/trajectory-segmentation). By default a pre-trained model is already selected, so the analysis can be run as is. + +* You can also **load your own models** for the predictions, either one model producing all outputs (**Combined model**) or one model per output (**Per output**). For a combined model, the **Model segments** checkbox (ticked by default) uses the segments the model reports in its `seg_*` outputs; unticked, the plugin builds the segments from the change points. See [Custom models for Trajectory Segmentation](/plugins/andi-j/ml-models#custom-models-for-trajectory-segmentation) for the input/output contract your model must follow. + +As a reference for runtime, the bundled default model processes 500 trajectories of 200 frames in about 90 s on an 8-core CPU (no GPU), running 4 trajectories in parallel. With a CUDA GPU and the GPU build of ONNX Runtime, inference runs on the GPU (see [Installation](/plugins/andi-j#installation)). The bundled model averages its predictions over 8 rotations and reflections of each trajectory; see [ML models](/plugins/andi-j/ml-models#andi-j-segmentation). + +{% include img align="center" name="ML model options" src="/media/plugins/andi-j/data-manager-ml.png" caption="**ML model options** in the Trajectory Segmentation Data Manager." %} diff --git a/_pages/plugins/andi-j/ml-models.md b/_pages/plugins/andi-j/ml-models.md new file mode 100644 index 0000000000..41222a3d70 --- /dev/null +++ b/_pages/plugins/andi-j/ml-models.md @@ -0,0 +1,324 @@ +--- +title: AnDi-J › ML models +name: AnDi-J +icon: /media/plugins/andi-j/logo.png +description: The deep-learning models bundled with AnDi-J, the ONNX contract they follow, and how to plug in your own models. +nav-title: ML models +nav-links: +- title: Overview + url: /plugins/andi-j +- title: Input data + url: /plugins/andi-j/input-data +- title: Trajectory Analysis + url: /plugins/andi-j/trajectory-analysis +- title: Trajectory Segmentation + url: /plugins/andi-j/trajectory-segmentation +- title: ML models + url: /plugins/andi-j/ml-models +--- + +AnDi-J uses deep-learning models at different levels: + +* [Trajectory Analysis](/plugins/andi-j/trajectory-analysis) — ML is optional for computing the anomalous exponent *α* and required for predicting the diffusion model. +* [Trajectory Segmentation](/plugins/andi-j/trajectory-segmentation) — all predictions here are made with ML models: per-frame *α*, log₁₀(*D*), diffusive state and change-point detection along each trajectory. + +Both tasks come with bundled default models that work out of the box. You can also use your own models for any of the tasks above (see [Custom models for Trajectory Analysis](#custom-models-for-trajectory-analysis) and [Custom models for Trajectory Segmentation](#custom-models-for-trajectory-segmentation)). + +{% include notice icon="info" content="Benchmark your custom models with this [online tool](https://gorkamunoz.github.io/andi-j/)." %} + +## Bundled models + +Two models ship with AnDi-J: + +| Model | Used in | Output | Reference | +|---|---|---|---| +| **andi-j-analysis** | Anomalous exponent (ML), Diffusion Model | one *α* per trajectory **and** the diffusion-model class (two networks in one model file) | Based on the convolutional networks of [Granik et al. (2019)](https://doi.org/10.1016/j.bpj.2019.06.015). | +| **andi-j-segmentation** | Trajectory Segmentation | per-frame *α*, *D* and diffusive state, plus change points | Based on [U-AnD-ME](https://iopscience.iop.org/article/10.1088/2515-7647/adf9aa). | + +Inference runs on **CPU** or **GPU**. See [Installation](/plugins/andi-j#installation) for details. + +### andi-j-analysis + +Two convolutional networks with the same architecture, after [Granik et al. (2019)](https://doi.org/10.1016/j.bpj.2019.06.015): five parallel blocks of dilated causal convolutions, max-pooled over time and followed by dense layers. One predicts the **anomalous exponent α** as a probability distribution over the 40 values 0.05, 0.10, …, 2.00; the other the **diffusion-model class** (ATTM, CTRW, FBM, LW, SBM). Both ship in a single `.onnx` file that follows the same input contract as custom models (raw `(1, T, 2)` positions) and returns two outputs, `alpha` `(1, 1)` and `model` `(1, 5)`. + +Inside the model, each trajectory is: + +1. cut to its last 1000 positions and shifted to start at the origin; +2. zero-padded at the front, turned into displacements and divided by the mean step size; +3. run through both networks for the 8 symmetric views of the trajectory (sign flips of *x* and *y*, and swapping *x* and *y*), whose probabilities are averaged; +4. read out: *α* is the median of the exponent distribution; the class scores of ATTM and CTRW are multiplied by the probability that *α* ≤ 1, and that of LW by the probability that *α* > 1. + +On the 2D trajectories of the 1st AnDi Challenge benchmark it reaches an *α* MAE of 0.137 and a classification F1 of 0.892, above every challenge participant in both tasks. Compute grows with the trajectory length, and the plugin runs one trajectory per CPU core in parallel (on an 8-core CPU, about 35 ms per trajectory for lengths of 10–400 frames). + +### andi-j-segmentation + +A 1-D **U-Net 3+** ([U-AnD-ME](https://iopscience.iop.org/article/10.1088/2515-7647/adf9aa)): an encoder–decoder with full-scale skip connections (6 depth levels) on the trajectory's displacements, with dedicated heads for *α* (including a temporal branch of dilated convolutions), log₁₀(*D*) and the diffusive state. It follows the same contract as custom models: raw `(1, T, 2)` positions in, every output below out, with all processing inside the model: + +* **Test-time augmentation, always on:** the network runs on the 8 symmetric views of the trajectory (4 rotations × 2 reflections) and the per-frame predictions are averaged, so the result does not depend on the orientation of your data. +* **Per frame:** *α* (clipped to [0, 1.999]), log₁₀(*D*) and the probabilities of the four diffusive states (0 = immobile, 1 = confined, 2 = free diffusion, 3 = directed); frames with *α* > 1.9 are directed. +* **Change points:** the local maxima of the change-point probability above 0.32, one flag at the first frame of each new segment. +* **Segments** (`seg_*` outputs): each segment's *α*, log₁₀(*D*) and diffusive-state probabilities are the **median** over its frames; its state is the most probable one. +* **Immobile segments** have *α* = 0, for the segment and for each of its frames, as in the labels of the 2nd AnDi Challenge. Their *D* is the predicted one: the apparent diffusion coefficient of the remaining motion, typically localization noise. + +On the challenge-phase data of the 2nd AnDi Challenge (single-trajectory task) it reaches JI (CP) 0.684, RMSE (CP) 1.755, MAE (*α*) 0.175, MSLE (*D*) 0.018 and F1 (diffusive state) 0.919, second in the overall ranking (see the [benchmark website](https://gorkamunoz.github.io/andi-j/)). + +The plugin runs 4 trajectories at a time in parallel. On an 8-core CPU this takes about 175 ms per trajectory of 10–400 frames; compute grows with the trajectory length. + +## What is ONNX (and why) + +**ONNX** (Open Neural Network Exchange) is a portable, framework-independent file format for a trained neural network: the graph of operations plus the learned weights, in a single `.onnx` file. It allows you to train in whichever Python framework you like (PyTorch, TensorFlow, scikit-learn…), then *export* the trained model to ONNX. + +The bundled models have all been trained using PyTorch. However, AnDi-J runs `.onnx` files with **ONNX Runtime** (the Java build), so at inference time **no Python is needed** — the model runs inside Fiji. This also means that when developing a custom model, you must export it to `.onnx` afterwards. Below you will find how to do that for the different options available. + +## Custom models for Trajectory Analysis + +AnDi-J ships with a default deep-learning model, but you can plug in **your own** model for either per-trajectory prediction task: + +* **Anomalous exponent** (*Anomalous exponent* tab → **Type: Load**) — a model that predicts the exponent *α* for a trajectory. +* **Diffusion model classification** (*Diffusion Model* tab → **Type: Load**) — a model that classifies a trajectory into one of the five diffusion models. + +{% include notice icon="note" content=" +The bundled **Default** model predicts α *and* the diffusion model in one run. A model you **Load** is single-purpose: an α model updates only α; a classifier model updates only the diffusion-model tab. +" %} + +### Input + +For every trajectory the plugin builds one input tensor and calls your model: + +| | | +|---|---| +| **Shape** | `(1, T, 2)` — batch 1, one row per **frame**, two features | +| **Type** | `float32` | +| **Dynamic axis** | the `T` (sequence-length) axis **must be dynamic** | + +The two features are the **raw trajectory coordinates**: + +* column `0` = `x` +* column `1` = `y` + +i.e. exactly the (x, y) positions from your loaded data, one row per frame. The plugin feeds these directly — it does **no** preprocessing. + +{% include notice icon="info" content=" +**Choose your own representation inside the model.** If your method works on displacements, relative-polar features `(dr, dθ)`, images, etc., compute that transform as the first layers of your model (or in the exported graph). That way training and inference stay identical and the plugin's contract stays simple. The bundled *Default* model, for example, shifts each trajectory to the origin and converts it to normalised displacements internally. That choice lives inside the model, not the plugin. +" %} + +### Output + +**Anomalous-exponent model** + +| | | +|---|---| +| **Shape** | `(1, 1)` (or `(1,)`) | +| **Meaning** | the predicted exponent α; the plugin reads element `[0]` | + +α should lie in `[0, 2]` (values outside are dropped from the histogram). The α prediction is a single value for the 2D trajectory, so the X / Y component buttons are disabled while ML α results are shown. + +**Diffusion-model classifier** + +| | | +|---|---| +| **Shape** | `(1, K)` — one score/logit per class | +| **Meaning** | predicted class = `argmax(output)` | + +`K = 5` and the class order **must** be: + +``` +0 = ATTM 1 = CTRW 2 = FBM 3 = LW 4 = SBM +``` + +(A scalar output `(1, 1)` is accepted too and taken as a rounded class index.) + +### Exporting an analysis model to ONNX (PyTorch example) + +```python +import torch + +model = MyModel() # your trained nn.Module +model.load_state_dict(torch.load("my_weights.pth", map_location="cpu")) +model.eval() + +dummy = torch.zeros(1, 50, 2) # (1, T, 2) raw (x, y); 50 is arbitrary here + +torch.onnx.export( + model, dummy, "my_alpha.onnx", + input_names=["input"], + output_names=["output"], + dynamic_axes={"input": {0: "batch", 1: "seq_len"}, # length must be dynamic! + "output": {0: "batch"}}, + opset_version=13, + do_constant_folding=True, +) +``` + +The **`dynamic_axes`** entry for the sequence-length axis is essential — trajectories have different lengths, and without it the exported graph is locked to `50`. + +{% include notice icon="warning" content=" +**Watch out: values derived from the sequence length.** If your `forward` uses the length as a Python integer — e.g. `T = x.shape[1]` then `math.log(T)`, `1/T`, or slicing like `x[:, T//2:]` — the ONNX tracer **bakes those in as constants** for the dummy length, and the model is then wrong for other lengths. Fixes: derive such quantities from the tensor shape at runtime (e.g. build a length tensor with `torch.ones_like(...).sum(dim=1)` and a position index with `torch.cumsum(torch.ones_like(...), dim=1) - 1`, then use masks instead of fixed slices), or expose the extra scalar as an additional model input. +" %} + +### Verify an analysis model before loading + +Check the exported graph in Python with ONNX Runtime, at **two different lengths**, before loading it in Fiji: + +```python +import numpy as np, onnxruntime as ort + +sess = ort.InferenceSession("my_alpha.onnx") +for T in (12, 137): # different trajectory lengths + x = np.random.randn(1, T, 2).astype(np.float32) # (1, T, 2) raw (x, y) + out = sess.run(["output"], {"input": x})[0] + print(T, out.shape, out.ravel()[:5]) +``` + +You want the output shape to be `(1, 1)` for an α model or `(1, 5)` for a classifier, and no error at either length. + +A ready-made pair of **test models** (an α estimator and a classifier) is provided in `utils/pythons_helpers/make_traj_analysis_test_onnx_models.py`: + +```bash +python make_traj_analysis_test_onnx_models.py # -> test_alpha.onnx, test_model.onnx +``` + +Use them to confirm the Load path works end-to-end before wiring your own model. + +### Loading an analysis model in the plugin + +1. Run **Perform Analysis** so the trajectories are loaded. +2. Open the relevant tab: + * **Anomalous exponent** → set **Type: Load** → **Choose model…** → pick your α `.onnx` → **Compute α**. + * **Diffusion Model** → set **Type: Load** → **Choose model…** → pick your classifier `.onnx` → **Compute models (ML)**. +3. Each runs with a progress bar over the number of trajectories. + +Switching **Type** back to **Default** restores the bundled model (which fills both α and the diffusion model, and keeps the two tabs in sync). + +## Custom models for Trajectory Segmentation + +Trajectory Segmentation can run your own ONNX model(s) instead of the bundled one. Pick **Load** in the *ML model options* box of the [segmentation Data Manager](/plugins/andi-j/input-data#selecting-the-segmentation-model), then either: + +* **Combined model** — one `.onnx` that outputs α, log₁₀(*D*), change points and the diffusive state, and optionally its own segments (see [Model segments](#optional-outputs-segment-level-predictions)), or +* **Per output** — one `.onnx` per output (**α**, **D**, **Change points**, **Diffusive state**); any of α, D or change points you leave as *default* is produced by the bundled model. The diffusive state is the exception: it is only backed by the bundled model when the bundled model is *already* running for one of the other three; if you supply custom α, D and change-point models and simply leave diffusive state unset, segments get no diffusive state rather than triggering an extra model run just for that. + +The plugin does no pre- or post-processing for your model: it feeds the raw trajectory in and reads your outputs out verbatim. Any processing must be added within your `.onnx` file. + +### Input: the raw trajectory + +| name | shape | dtype | meaning | +|------|-------|-------|---------| +| `input` | `(1, T, 2)` | float32 | raw positions — column 0 = x, column 1 = y, one row per frame | + +`T` (the number of frames) is **dynamic** — export the length axis as dynamic so your model accepts any trajectory length. If your architecture needs displacements, a fixed length, or padding, do it **inside** your model. + +### Required outputs: per-frame α, log D, change points and diffusive state + +All four outputs below are **required**. Each is **per frame**, length `T`, in the same frame order as the input. Shape `(1, T)` or `(1, T, 1)` are both accepted (`(1, T, 4)` for `diffusive_state`, see below). + +| output | shape | meaning | used as-is? | +|--------|-------|---------|-------------| +| `alpha` | `(1, T)` | anomalous exponent α per frame | yes, verbatim (the plots cover α in `[0, 2]`) | +| `logD` | `(1, T)` | **log₁₀(D)** per frame | yes, verbatim (use `NaN` for undefined/immobile) | +| `cp` | `(1, T)` | change-point flag per frame, **0 or 1** | the plugin marks a change point at every interior frame where `cp ≥ 0.5` | +| `diffusive_state` | `(1, T, 4)` or `(1, T)` | per-frame diffusive state: either class probabilities over the four states (`0 = immobile, 1 = confined, 2 = free diffusion, 3 = directed`), or the class index directly | `(1, T, 4)` → per-frame `argmax`; `(1, T)` → per-frame rounded value | + +Notes: + +* **D must be output as log₁₀(D)**, not linear D — that is exactly what the plugin stores and plots, so nothing is transformed. If a frame has no meaningful D (immobile / trapped), emit `NaN`; it will be shown as a gap and left out of segment means. +* **`cp` is a 0/1 flag**, one per frame. Frame 0 and the last frame are ignored (they are trajectory ends, not change points). Emit `1` at the first frame of each new segment, and apply whatever peak-picking or thresholding your method needs *inside* the model. +* **`diffusive_state` is shown per frame** in the *Visualization* tab's state strip, so every predicted state is visible even when it is short-lived. + +**Output names.** Name the outputs `alpha`, `logD`, `cp` and `diffusive_state`. If unnamed, the plugin falls back to output order 0 = alpha, 1 = logD, 2 = cp, 3 = diffusive_state. A per-output model exposes a single output and its name does not matter. + +### Optional outputs: segment-level predictions + +A combined model may also report its own segments, for methods whose segment-level values are not a simple summary of the per-frame ones. The **Model segments** checkbox, shown under **Combined model** in the *ML model options* box and ticked by default, decides how segments are built: + +* **ticked:** the plugin reads the `seg_*` outputs below and uses them verbatim as the segments. `seg_start` and `seg_length` must be present; if either is missing, the plugin derives the segments from `cp` as when unticked. +* **unticked:** the plugin ignores any `seg_*` output and derives the segments from `cp`, taking each segment's α and log₁₀(D) as the interval mean and its state as the majority vote of the frames it covers. + +*Per output* mode always derives the segments from `cp`. `S` is the number of segments and is dynamic. + +| output | shape | meaning | +|--------|-------|---------| +| `seg_start` | `(1, S)` | first frame of each segment, 0-based | +| `seg_length` | `(1, S)` | number of frames in each segment | +| `seg_alpha` | `(1, S)` | anomalous exponent α of each segment | +| `seg_logD` | `(1, S)` | **log₁₀(D)** of each segment | +| `seg_state` | `(1, S)` | diffusive-state class index of each segment, 0–3 | + +* `seg_start` and `seg_length` are what identify a segment; a row whose `seg_length` is `≤ 0`, or whose `seg_start` falls outside the trajectory, is skipped, so the arrays may be padded to a fixed length. A segment that runs past the last frame is cut at the end of the trajectory. +* `seg_alpha`, `seg_logD` and `seg_state` are optional: a missing value is left empty for that segment (not plotted, no diffusive state). +* `seg_state` is rounded to the nearest class and limited to 0–3. +* Integer (`int32`/`int64`) or float arrays are both accepted. + +Inference runs one trajectory per call, so the batch axis is always 1. + +### Exporting a segmentation model to ONNX (PyTorch example) + +```python +import torch, torch.nn as nn + +class CombinedSeg(nn.Module): + def forward(self, x): # x: (1, T, 2) raw x,y + # ... your architecture; must handle a dynamic T ... + alpha = ... # (1, T) + logD = ... # (1, T) = log10(D) + cp = ... # (1, T) in {0,1} + diffusive_state = ... # (1, T, 4) softmax over the 4 states + return alpha, logD, cp, diffusive_state + +m = CombinedSeg().eval() +dummy = torch.zeros(1, 200, 2) # any length; the axis is dynamic +torch.onnx.export( + m, dummy, "my_seg.onnx", + input_names=["input"], + output_names=["alpha", "logD", "cp", "diffusive_state"], + dynamic_axes={"input": {1: "T"}, "alpha": {1: "T"}, "logD": {1: "T"}, + "cp": {1: "T"}, "diffusive_state": {1: "T"}}, + opset_version=13, do_constant_folding=True, +) +``` + +A model that also reports its own segments returns the `seg_*` tensors after these four, naming them in `output_names` and marking their length axis dynamic with `{1: "S"}`. + +For a **per-output** model, return a single `(1, T)` (or `(1, T, 4)` for the diffusive-state slot) tensor and give it one `output_names` / `dynamic_axes` entry. + +{% include notice icon="warning" content=" +**Length-derived-constants pitfall.** Do not bake the dummy length (200 in the example above) into any reshape or constant. Derive `T` from the input at runtime (`x.shape[1]`) so the exported graph is truly length-agnostic. +" %} + +### Verify a segmentation model before loading + +```python +import numpy as np, onnxruntime as ort +s = ort.InferenceSession("my_seg.onnx", providers=["CPUExecutionProvider"]) +for T in (37, 128, 240): + out = s.run(None, {"input": np.random.randn(1, T, 2).astype("float32")}) + for name, arr in zip([o.name for o in s.get_outputs()], out): + print(T, name, arr.shape) # (1, T) or (1, T, 1); (1, T, 4) for diffusive_state +``` + +If every output is length `T` for every `T`, it will load in the plugin. + +`utils/pythons_helpers/make_traj_seg_test_onnx_models.py` builds small **dummy** models (`seg_alpha.onnx`, `seg_logd.onnx`, `seg_cp.onnx`, `seg_state.onnx`, and `seg_combined.onnx`, the last with all four required outputs) that follow this contract, so you can exercise both the *Combined* and *Per output* Load modes before dropping in your real models. + +## Troubleshooting + +Applies to both analysis and segmentation models. + +| Symptom | Likely cause | +|---|---| +| "Output '…' not found" / wrong values | output not named as expected, or wrong shape | +| "Output '…' has N values for a trajectory of T frames" | a per-frame output is not length `T`: e.g. one value per displacement (`T−1`) or a length fixed at export | +| Works for one dataset, wrong for another | sequence-length axis not dynamic, or length-derived constants baked in | +| Classes look shuffled | classifier class order ≠ `ATTM, CTRW, FBM, LW, SBM` | +| α histogram empty | α outside `[0, 2]`, or NaNs — the plugin uses custom α verbatim, so clip/validate it inside your model | +| Load fails immediately | not a valid `.onnx`, or exported with an opset newer than the bundled ONNX Runtime 1.26 supports — re-export with a lower `opset_version` | + +## Contributing a model + +Models developed for AnDi-J can be shared with the community: once approved, they are listed with the bundled models in [`contributions/list.md`](https://github.com/gorkamunoz/andi-j/blob/main/contributions/list.md), together with their scores and download links, and shown on the [benchmark website](https://gorkamunoz.github.io/andi-j/). The maintainers review every contribution. + +1. Export your model to ONNX following the contract of its module ([analysis](#custom-models-for-trajectory-analysis) or [segmentation](#custom-models-for-trajectory-segmentation)), and check that it runs in Fiji with **Load**. +2. Score it on the Submit pages of the [benchmark website](https://gorkamunoz.github.io/andi-j/). +3. Upload the `.onnx` file(s) to a public record with a DOI (for example [Zenodo](https://zenodo.org)). The code of the method must be open source. +4. Copy [`contributions/template.yml`](https://github.com/gorkamunoz/andi-j/blob/main/contributions/template.yml) to `contributions/.yml`, fill it in, and open a pull request that adds it. The file gives the method's id and version, authors, contact, license, code repository, optional reference, the ONNX record(s) and the scores, named `TA.alpha_mae`, `TA.model_f1` (Trajectory Analysis) and `TS.cp_ji`, `TS.cp_rmse`, `TS.alpha_mae`, `TS.D_msle`, `TS.state_f1` (Trajectory Segmentation). The pull request template lists the checks. + +The maintainers then download and benchmark the model, and add it to the list, the [GitHub wiki](https://github.com/gorkamunoz/andi-j/wiki) and the benchmark website. diff --git a/_pages/plugins/andi-j/trajectory-analysis.md b/_pages/plugins/andi-j/trajectory-analysis.md new file mode 100644 index 0000000000..574ed48393 --- /dev/null +++ b/_pages/plugins/andi-j/trajectory-analysis.md @@ -0,0 +1,138 @@ +--- +title: AnDi-J › Trajectory Analysis +name: AnDi-J +icon: /media/plugins/andi-j/logo.png +description: Per-trajectory anomalous-diffusion observables in AnDi-J - tMSD, diffusion coefficient, anomalous exponent, D vs α, diffusion model, turning angles and PSD. +nav-title: Trajectory Analysis +nav-links: +- title: Overview + url: /plugins/andi-j +- title: Input data + url: /plugins/andi-j/input-data +- title: Trajectory Analysis + url: /plugins/andi-j/trajectory-analysis +- title: Trajectory Segmentation + url: /plugins/andi-j/trajectory-segmentation +- title: ML models + url: /plugins/andi-j/ml-models +--- + +This tool allows to perform single-trajectory analysis of the input experiments. Every tab has a side **Experiments** panel where each experiment can be toggled on/off and, where relevant, restricted to the **2D**, **X**, or **Y** component. + +{% include notice icon="info" content="**Saving data.** Every tab has a **Save plot** button that exports its plot as a vector image (`svg`), which you can edit in tools such as Inkscape or Illustrator. The **Diffusion coefficient**, **Anomalous exponent**, **Diffusion Model**, **Turning Angles** and **PSD** tabs also save their values as a `csv` file for further analysis (**Save D…**, **Save α…**, **Save models…**, **Save angles…** and **Save PSD…**). Their first columns are `experiment` and, for per-trajectory values, `track_id`; commas in experiment names are written as semicolons. In **D vs α**, tagged populations can be saved as trajectory files (see [Population tagging](#d-vs-alpha))." %} + +{% include notice icon="info" content="**Units.** The **Units** button of the tMSD Visualization, Diffusion coefficient, D vs α and PSD tabs opens a window to choose the time (frames, ns, μs, ms, s) and space (nm, μm, mm, m) units of the plots and `csv` exports, whose column headers name them. Physical units need the calibration of the [Data Manager](/plugins/andi-j/input-data#units); without it, the window shows px and frames and cannot change them." %} + +## tMSD Visualization + +This tab shows the time-averaged MSD curves for each experiment, allowing for an initial visual inspection of the diffusive properties of the loaded experiments. + +* Per-experiment selectors for **Avg** (the average tMSD), **All** (every individual trajectory, faint), and **eMSD** (ensemble MSD, dashed). +* The lag axis is controlled by **Min lag**, **Max lag** (in frames) and **Log-spaced**. The number of lag points is chosen automatically (every integer lag when linear; capped, log-spaced sampling when log-spaced is selected). When the window opens, the tMSD is computed with min lag 1, max lag a quarter of the longest trajectory length and linear lags, the values shown in the fields. +* **Draw line** lets you place a reference line and read its slope live; in log–log mode the slope is labelled *α*, since it corresponds to the anomalous exponent. +* **eMSD vs tMSD as an ergodicity test:** comparing the eMSD curve to the Avg tMSD shows whether the process is ergodic (the two coincide) or non-ergodic (they differ). + +{% include img align="center" name="tMSD tab" src="/media/plugins/andi-j/tmsd-tab.png" caption="**tMSD Visualization** tab with the eMSD overlay." %} + +## Diffusion coefficient + +Estimates the diffusion coefficient *D* per trajectory from a linear fit of the tMSD vs lag-time (mirroring `andi_datasets`' `get_diff_coeff`), shown as a histogram. Dashed lines show the mean over the experiment. + +You can configure the time lags at will, depending on the conditions of your experiment. Three formats are accepted: + +1. **`[min, max]` — a fixed integer range.** When the second value is an integer ≥ 1 and larger than the first, the fit uses every lag from `min` to `max`, the **same for all trajectories**. Example: `[1, 20]` uses lags 1, 2, …, 20. + +2. **`[min, fraction]` — a per-trajectory (adaptive) range.** When the second value is between 0 and 1, it is read as a *fraction of each trajectory's length*: the fit uses lags from `min` up to `floor(fraction × length)` (with a small lower bound of 4), computed **independently for every trajectory**, so short trajectories automatically get a shorter maximum lag. Example (and default): `[1, 0.1]` fits from lag 1 up to 10 % of each trajectory's length. + +3. **`[t₁, t₂, t₃, …]` — an explicit list.** Any comma-separated list of positive integers is used verbatim as the set of lags for every trajectory. Example: `[1, 2, 4, 8]`. + +For guidance on what to choose, we recommend: + +* Kepten, E., Weron, A., Sikora, G., Burnecki, K., & Garini, Y. (2015). Guidelines for the fitting of anomalous diffusion mean square displacement graphs from single particle tracking experiments. [PLOS ONE, 10(2), e0117722](https://journals.plos.org/plosone/article?id=10.1371/journal.pone.0117722). + +You can analyse the **2D / X / Y** components independently, which makes it possible, for instance, to detect anisotropic diffusion in your experiment. The values shown when the window opens use the default time lags `[1,2]`. The histogram toolbar has **Normalize (%)** and **Log D axis**; the latter shows *D* on a logarithmic axis with log-spaced bins (values *D* ≤ 0 are left out). + +{% include img align="center" name="Diffusion coefficient tab" src="/media/plugins/andi-j/diff-coeff-tab.png" caption="**Diffusion coefficient** histogram." %} + +## Anomalous exponent + +Estimates the anomalous exponent *α* with **two interchangeable methods**, selected from the **Method** drop-down: + +
+TMSD — log–log fit of the tMSD curve (click to expand) + +The anomalous exponent is obtained from a **log–log fit** of the time-averaged MSD (tMSD) versus the time lag Δ: α is the slope of `log(tMSD)` vs `log(Δ)`. The **Time lags** field controls which lags enter that fit, and follows the same format as for [*D*](#diffusion-coefficient) above. + +**How to choose.** The key trade-off is statistics versus bias. At a lag Δ, the tMSD of a trajectory of length `L` is averaged over only `L − Δ` time origins, so **large lags are noisy** and can distort the slope; conversely you need enough points to define a slope reliably. + +* **Keep the maximum lag small relative to the trajectory length** (roughly 10–25 %). The adaptive form `[1, 0.1]` (the default) is the safest general choice because it scales automatically with each trajectory — recommended when your dataset mixes different lengths. +* **Use a fixed `[min, max]`** only when all trajectories are of similar length and you want identical lags across them (e.g. for reproducibility). +* **Start at lag 1** for clean/simulated data. For experimental data affected by localization noise or motion blur at the shortest lag, starting at 2 (e.g. `[2, 0.1]`) can give a cleaner slope. +* Make sure the range spans **at least a few lags** (two is the minimum for a slope, but more gives a more stable fit). +* Because the fit is in log–log space, the **frame interval does not affect α** (it only rescales the lag axis); the interval matters for *D*, not for the exponent. + +
+ +
+ML — deep-learning prediction (click to expand) + +Uses a neural network to predict the exponent, typically a much more accurate technique than the tMSD approach (as shown in the [1st AnDi Challenge](https://arxiv.org/abs/2105.06766)). Two options: + +1. **Default** — uses a pre-trained model that outperforms every method of the 1st AnDi Challenge on 2D trajectories (see [ML models](/plugins/andi-j/ml-models#andi-j-analysis)). This model internally also predicts the diffusion model, so running it automatically populates the [Diffusion Model](#diffusion-model) tab (see below). +2. **Load** — allows you to load a custom α predictor. See [ML models](/plugins/andi-j/ml-models#custom-models-for-trajectory-analysis) for details. + +
+ +Once the exponent is calculated, a histogram of the exponent per trajectory is shown. The table below it reports the exponent computed from an ensemble MSD fit, the most robust method **if** the dataset is homogeneous. If ML is used to predict α, a new column appears with the average over those predictions. + +{% include img align="center" name="Anomalous exponent tab" src="/media/plugins/andi-j/anomalous-exponent-tab.png" caption="**Anomalous exponent** histogram, computed with the ML method." %} + +## D vs α +{: #d-vs-alpha} + +A scatter of **one point per trajectory** in the *D*–*α* plane, or a density of the same points. Both quantities are taken from the *last* computation in their respective tabs; change the parameters or methods there and this tab updates too. + +The dropdown at the start of the toolbar chooses the view: + +* **Scatter** — one point per trajectory, with the **Select** tool for population tagging (below). +* **Density** — a 2-D histogram of the same points, overlaid per experiment and tagged population in their colours, as in the [Trajectory Segmentation D vs α tab](/plugins/andi-j/trajectory-segmentation#d-vs-alpha), with **α bins**, **D bins** and **Log count scale**; the legend gives the number of trajectories of each. Selection and tagging are not available in this view; tagged populations appear as their own colour. + +Features: + +* **Marginal KDEs** — the plots along the top and right edges show a kernel density estimate of the population for α and *D*, respectively. +* **Population tagging** — in **Select** mode, *circle* (lasso) a cluster of points (see blue area in the figure below), type a name in **Population tag:** and click **Tag population**. The enclosed trajectories are recoloured to a shade of their parent colour and added as a new dataset to the [Turning Angles](#turning-angles) and [Diffusion Model](#diffusion-model) tabs. A management table below the plot lists each population (tag, source datasets, colour — click the colour to change it). Click **Save…** in the **Save** column to export the population's trajectories as a `csv` in the [input format](/plugins/andi-j/input-data) (`TRACK_ID, POSITION_X, POSITION_Y, POSITION_T, FRAME`), plus an `EXPERIMENT` column naming the experiment each trajectory comes from. The file can be loaded again in the Data Manager, which ignores the extra column; with a calibration, positions are written in μm and `POSITION_T` in seconds, so the file loads back calibrated. `TRACK_ID` keeps the trajectory's id when the population comes from one experiment and is renumbered from 0 when it mixes several, so ids stay unique; commas in experiment names are written as semicolons. +* **Plot manipulation** — Log *D* axis toggle, rubber-band **Zoom**, **Pan**, **Reset view**, in both views. + +{% include img align="center" name="D vs alpha tab" src="/media/plugins/andi-j/d-vs-alpha-tab.png" caption="**D vs α** in Scatter view, with marginal KDEs and a tagged population (top), and in Density view (bottom)." %} + +## Diffusion Model + +Classifies each trajectory into one of the five canonical anomalous-diffusion models: **ATTM, CTRW, FBM, LW, SBM** (see [Muñoz-Gil et al. (2021)](https://arxiv.org/abs/2105.06766) for more details). The predictions are done through an [ML model](/plugins/andi-j/ml-models), and shown as a **grouped bar chart** of the percentage of trajectories per experiment assigned to each model. + +{% include notice icon="info" content="If a population was selected in the [D vs α](#d-vs-alpha) plot, it will appear as its own experiment in this tab." %} + +{% include img align="center" name="Diffusion Model tab" src="/media/plugins/andi-j/diffusion-model-tab.png" caption="**Diffusion Model** classification bar chart." %} + +## Turning Angles + +A **polar rose histogram** of turning angles between successive displacement vectors, pooled per experiment and normalised to a fraction, so that experiments with different track counts are comparable. + +{% include notice icon="info" content="If a population was selected in the [D vs α](#d-vs-alpha) plot, it will appear as its own experiment in this tab. In the example below, `population_normal_fast` is a population containing a few trajectories from `exp_FBM_normal`." %} + +{% include img align="center" name="Turning Angles tab" src="/media/plugins/andi-j/turning-angles-tab.png" caption="**Turning Angles** polar rose." %} + +## PSD + +Ensemble-averaged **power spectral density** of the trajectories, based on [`andi_datasets.analysis.psd`](https://andichallenge.github.io/andi_datasets/lib_nbs/analysis.html#psd) (which wraps `scipy.signal.periodogram` with its defaults: unit sampling, boxcar window, constant detrend, one-sided, density scaling). + +* Each shown periodogram is averaged over all trajectories of an experiment on a shared log-frequency grid (from `1/max-length` up to the Nyquist frequency 0.5). Only the **global average** is shown — no per-track curves — with independent **2D / X / Y** selectors per experiment. +* **Freq. points** sets the number of frequency bins; **Log–log** toggles the axes. +* A **Draw line** tool (as in the [tMSD](#tmsd-visualization) tab) reports the slope of a reference line — useful since the PSD of an anomalous process scales as a power law in frequency (the spectral slope is related to the anomalous exponent). + +To learn about the PSD for anomalous diffusion analysis, we recommend reading the following publications: + +* Krapf, D., et al. (2018). Power spectral density of a single Brownian trajectory: what one can and cannot learn from it. [New Journal of Physics, 20(2), 023029](https://iopscience.iop.org/article/10.1088/1367-2630/aaa67c). +* Krapf, D., Lukat, N., Marinari, E., Metzler, R., Oshanin, G., Selhuber-Unkel, C., … & Xu, X. (2019). Spectral content of a single non-Brownian trajectory. [Physical Review X, 9(1), 011019](https://journals.aps.org/prx/abstract/10.1103/PhysRevX.9.011019). +* Sposini, V., Krapf, D., Marinari, E., Sunyer, R., Ritort, F., Taheri, F., … & Oshanin, G. (2022). Towards a robust criterion of anomalous diffusion. [Communications Physics, 5(1), 305](https://www.nature.com/articles/s42005-022-01079-8). + +{% include img align="center" name="PSD tab" src="/media/plugins/andi-j/psd-tab.png" caption="**PSD** tab with a drawn slope line." %} diff --git a/_pages/plugins/andi-j/trajectory-segmentation.md b/_pages/plugins/andi-j/trajectory-segmentation.md new file mode 100644 index 0000000000..637845c1bb --- /dev/null +++ b/_pages/plugins/andi-j/trajectory-segmentation.md @@ -0,0 +1,98 @@ +--- +title: AnDi-J › Trajectory Segmentation +name: AnDi-J +icon: /media/plugins/andi-j/logo.png +description: Per-frame predictions of alpha, D and diffusive state along each trajectory, with change-point detection and segment statistics. +nav-title: Trajectory Segmentation +nav-links: +- title: Overview + url: /plugins/andi-j +- title: Input data + url: /plugins/andi-j/input-data +- title: Trajectory Analysis + url: /plugins/andi-j/trajectory-analysis +- title: Trajectory Segmentation + url: /plugins/andi-j/trajectory-segmentation +- title: ML models + url: /plugins/andi-j/ml-models +--- + +This tool runs a per-frame segmentation model that predicts, **for every frame** of every trajectory, the local anomalous exponent *α*, the diffusion coefficient *D* (shown on a logarithmic scale, due to its wide range of values) and the **diffusive state** — immobile, confined, free diffusion, or directed. It then detects **change points** to split each trajectory into homogeneous segments, each with its own α, *D* and diffusive state (see [ML models](/plugins/andi-j/ml-models#andi-j-segmentation) for how the default model computes them; it gives immobile segments α = 0). The window has four tabs: [Visualization](#visualization), [D vs α](#d-vs-alpha), [Segment Stats](#segment-stats) and [Diffusive state](#diffusive-state). + +{% include notice icon="info" content="**Saving data.** Per-frame predictions and per-segment statistics can be exported as `csv` files from the [Visualization](#visualization) tab (see below). The **D vs α**, **Segment Stats** and **Diffusive state** tabs have a **Save plot** button that exports the plot, with all its panels, as a vector image (`svg`)." %} + +{% include notice icon="info" content="**Units.** Each tab has a **Units** button to choose the time and space units (see [Units](/plugins/andi-j/input-data#units)). *D* and segment lengths are shown in the chosen units, named in the *D* axis labels of the **D vs α** and **Segment Stats** tabs and in the `csv` headers; the log₁₀(*D*) axis of the **Visualization** tab does not repeat the unit." %} + +## Visualization + +A **4 × 4 grid** of prediction plots, one per trajectory. Each plot shows the per-frame predictions for one trajectory: + +1. Two lines showcasing **α** (red, right axis, range [0, 2]) and **log₁₀(D)** (blue, left axis, auto-scaled). +2. A coloured strip showing the predicted diffusive state, with colour code: + Immobile, + Confined, + Free diffusion and + Directed. + +For α and D, two layers are overlaid: + +* The **raw per-frame prediction**, whose opacity is controlled by the **Raw α/D** slider. +* The **segment step-line**, i.e. the value of that variable for each detected segment, toggled independently with **α_seg** / **D_seg**. + +The **CP** toggle shows/hides the dashed vertical lines marking the detected change points; the **State** toggle shows/hides the diffusive-state strip. + +Tools: + +* **Sample random 16** picks 16 random trajectories; **Choose trajectories** opens a popup to enter specific `TRACK_ID`s. +* **Save raw preds.** exports every trajectory's per-frame α, D and diffusive state to a `csv` (`experiment, track_id, frame, alpha, D [unit], state`); `frame` is the `FRAME` of the input file and `state` is the per-frame diffusive state, coded as `0 = immobile, 1 = confined, 2 = free diffusion, 3 = directed`. +* **Save segments** exports the detected segments, with starting frame, length, α, D, and state (`experiment, track_id, segment, start_frame, length, alpha, D [unit], state`); `length` is the number of frames; `start_frame` is the `FRAME` of the input file at which the segment starts. + +{% include img align="center" name="Visualization tab" src="/media/plugins/andi-j/seg-visualization-tab.png" caption="**Visualization** grid with the raw prediction and segment step-line overlaid." %} + +## D vs α +{: #d-vs-alpha} + +This tab shows a **2-D density heatmap** of (α, *D*). The dropdown at the start of the toolbar chooses whether each **frame** or each **segment** counts once; the colour scale, the side plots and the legend count the same. Each selected experiment is overlaid as its own semi-transparent colour. + +**Show immobile** (off by default): immobile segments, and in frame mode the frames of immobile segments, are left out of the plot, so that immobile data at α ≈ 0 do not hide the distribution of the moving ones. The legend has one row per experiment: its number of frames or segments and how many of them are immobile, marked *(hidden)* while they are left out. While immobile data is hidden, the checkbox has a soft orange highlight, which pulses for a few seconds when the tab is opened or the plot updates; once the box has been ticked, it is no longer highlighted until the next **Perform Analysis**. Immobile segments keep their predicted *D*: the apparent diffusion coefficient of the remaining motion, typically localization noise. + +**Log D axis** (on by default): *D* on a logarithmic axis with log-spaced bins, as in the [Trajectory Analysis](/plugins/andi-j/trajectory-analysis#d-vs-alpha) **D vs α** tab; untick it for a linear axis. + +The side plots show the **marginal histograms + KDEs** along the top (α) and right (*D*) edges. Drag the plot's top or right border to resize either marginal strip. + +Tools: + +* Hovering the heatmap shows the (α, *D*) value under the cursor. +* Rubber-band **Zoom**, **Pan**, **Reset view**; a draggable **legend**. +* Experiment multi-select in the side panel. + +{% include img align="center" name="D vs alpha tab" src="/media/plugins/andi-j/seg-dvsa-tab.png" caption="**D vs α** density heatmap of the predictions." %} + +## Segment Stats + +This tab shows the temporal statistics of the identified segments, together with their relation to the extracted α and *D*. + +Plots: + +* **Segment-length histogram** — the distribution of segment lengths separated per experiment. +* **Segment length vs α** and **Segment length vs D** — 2-D density heatmaps, overlaid per experiment, each with a side marginal KDE of the *y* variable (α on the left, *D* on the right). + +Tools: + +* **Length bins**, **α bins** and **D bins** are set independently; all three plots share the segment-length *x* axis. +* **Log D axis** (on by default): the **Segment length vs D** plot shows *D* on a logarithmic axis with log-spaced bins; untick it for a linear axis. +* **Show immobile** (off by default): the **Segment length vs α** and **Segment length vs D** plots leave out immobile segments; each gives the number of segments (*N*, immobile included) and, below, how many are immobile and their share. The length histogram always includes them. The checkbox is highlighted as in the **D vs α** tab. +* Rubber-band **Zoom**, **Pan**, **Reset view** on every plot. + +{% include img align="center" name="Segment Stats tab" src="/media/plugins/andi-j/seg-stats-tab.png" caption="**Segment Stats** tab." %} + +## Diffusive state + +This tab gathers the diffusive-state analysis. It contains two plots: + +* **Top** — a grouped bar chart of the **percentage of segments** in each diffusive state, per experiment. +* **Bottom** — the **segment-length distribution**, one colour-coded line per diffusive state, pooled over the selected experiments. A **Normalize (%)** checkbox switches between raw segment counts and each state's distribution normalised to its own total (useful to compare the *shape* of the length distributions regardless of how many segments each state has). + +The right-hand column mirrors that split: it lets you select the **Experiments** as well as which **Diffusive states** are shown in the segment-length plot. A state with no segments draws a flat line at zero. + +{% include img align="center" name="Diffusive state tab" src="/media/plugins/andi-j/seg-diffusive-state-tab.png" caption="**Diffusive state** tab." %} diff --git a/media/plugins/andi-j/anomalous-exponent-tab.png b/media/plugins/andi-j/anomalous-exponent-tab.png new file mode 100644 index 0000000000..35aec89fb8 Binary files /dev/null and b/media/plugins/andi-j/anomalous-exponent-tab.png differ diff --git a/media/plugins/andi-j/d-vs-alpha-tab.png b/media/plugins/andi-j/d-vs-alpha-tab.png new file mode 100644 index 0000000000..10be63c957 Binary files /dev/null and b/media/plugins/andi-j/d-vs-alpha-tab.png differ diff --git a/media/plugins/andi-j/data-manager-ml.png b/media/plugins/andi-j/data-manager-ml.png new file mode 100644 index 0000000000..9441d83477 Binary files /dev/null and b/media/plugins/andi-j/data-manager-ml.png differ diff --git a/media/plugins/andi-j/data-manager.png b/media/plugins/andi-j/data-manager.png new file mode 100644 index 0000000000..cf0673c321 Binary files /dev/null and b/media/plugins/andi-j/data-manager.png differ diff --git a/media/plugins/andi-j/diff-coeff-tab.png b/media/plugins/andi-j/diff-coeff-tab.png new file mode 100644 index 0000000000..7ce8f3b8fa Binary files /dev/null and b/media/plugins/andi-j/diff-coeff-tab.png differ diff --git a/media/plugins/andi-j/diffusion-model-tab.png b/media/plugins/andi-j/diffusion-model-tab.png new file mode 100644 index 0000000000..6d2db77707 Binary files /dev/null and b/media/plugins/andi-j/diffusion-model-tab.png differ diff --git a/media/plugins/andi-j/logo.png b/media/plugins/andi-j/logo.png new file mode 100644 index 0000000000..be5c06f8c7 Binary files /dev/null and b/media/plugins/andi-j/logo.png differ diff --git a/media/plugins/andi-j/psd-tab.png b/media/plugins/andi-j/psd-tab.png new file mode 100644 index 0000000000..b5520556d6 Binary files /dev/null and b/media/plugins/andi-j/psd-tab.png differ diff --git a/media/plugins/andi-j/seg-diffusive-state-tab.png b/media/plugins/andi-j/seg-diffusive-state-tab.png new file mode 100644 index 0000000000..3e4dd50c56 Binary files /dev/null and b/media/plugins/andi-j/seg-diffusive-state-tab.png differ diff --git a/media/plugins/andi-j/seg-dvsa-tab.png b/media/plugins/andi-j/seg-dvsa-tab.png new file mode 100644 index 0000000000..27480a13d7 Binary files /dev/null and b/media/plugins/andi-j/seg-dvsa-tab.png differ diff --git a/media/plugins/andi-j/seg-stats-tab.png b/media/plugins/andi-j/seg-stats-tab.png new file mode 100644 index 0000000000..b6adbc4bb6 Binary files /dev/null and b/media/plugins/andi-j/seg-stats-tab.png differ diff --git a/media/plugins/andi-j/seg-visualization-tab.png b/media/plugins/andi-j/seg-visualization-tab.png new file mode 100644 index 0000000000..9f4f1a2991 Binary files /dev/null and b/media/plugins/andi-j/seg-visualization-tab.png differ diff --git a/media/plugins/andi-j/tmsd-tab.png b/media/plugins/andi-j/tmsd-tab.png new file mode 100644 index 0000000000..e8baba4c15 Binary files /dev/null and b/media/plugins/andi-j/tmsd-tab.png differ diff --git a/media/plugins/andi-j/turning-angles-tab.png b/media/plugins/andi-j/turning-angles-tab.png new file mode 100644 index 0000000000..d172a62828 Binary files /dev/null and b/media/plugins/andi-j/turning-angles-tab.png differ