Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 24 additions & 23 deletions .github/workflows/test_pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,63 +11,64 @@ on:

jobs:
test:
name: ${{ matrix.platform }} ${{ matrix.python }} ${{ matrix.toxenv || matrix.backend }}
name: ${{ matrix.platform }} py${{ matrix.python }} ${{ matrix.backend }}
if: github.event.pull_request.draft == false
runs-on: ${{ matrix.platform }}
strategy:
fail-fast: false
matrix:
platform: [ubuntu-latest]
python: ["3.10", "3.12"]
backend: [pyqt5]
include:
# - python: 3.11
# platform: windows-latest
# backend: pyqt5
# - python: 3.11
# platform: macos-13 # latest not-arm version
# backend: pyside2
- python: 3.11 # only this run execute coverage
platform: ubuntu-latest
- platform: ubuntu-latest
python: "3.11"
backend: pyside6
coverage: true
- platform: ubuntu-latest
python: "3.12"
backend: pyqt5
- platform: ubuntu-latest
python: "3.13"
backend: pyqt5
- platform: macos-latest
python: "3.13"
backend: pyqt5
# - platform: windows-latest
# python: "3.13"
# backend: pyside6

steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.13.1
with:
access_token: ${{ github.token }}

- uses: actions/checkout@v6
- uses: actions/checkout@v4

# see https://github.com/actions/runner-images/issues/709#issuecomment-612569242
- name: Workaround to free up space on github runner
if: runner.os == 'Linux'
run: sudo rm -rf "$AGENT_TOOLSDIRECTORY"

- uses: prefix-dev/setup-pixi@v0.9.5
- name: Install uv
uses: astral-sh/setup-uv@v5
with:
pixi-version: v0.62.2
cache: true
python-version: ${{ matrix.python }}
enable-cache: true

- name: Setup headless screenL
- name: Setup headless display
if: runner.os == 'Linux'
uses: pyvista/setup-headless-display-action@5bc8de3bc71fcda7a96439571287a554901541a0 # v4.3
with:
qt: true
wm: herbstluftwm

- name: Install dependencies with pixi
run: pixi install -e test

- name: Run pre-commit
run: pixi run -e test pre-commit run --all-files
run: uvx pre-commit run --all-files

- name: Testing
run: pixi run -e test test --cov-report=xml
run: uv run --extra test --extra ml --with "${{ matrix.backend }}" pytest -v --color=yes --cov=ultrack --cov-report=xml --durations=15 .
env:
PLATFORM: ${{ matrix.platform }}
BACKEND: ${{ matrix.backend }}
TOXENV: ${{ matrix.toxenv }}

- name: Coverage
if: ${{ matrix.coverage }}
Expand Down
6 changes: 3 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ repos:
- id: absolufy-imports
# sorting imports
- repo: https://github.com/pycqa/isort
rev: 7.0.0
rev: 8.0.1
hooks:
- id: isort
args: ["--profile", "black", "--filter-files"]
Expand All @@ -29,7 +29,7 @@ repos:
args: ["--py38-plus", "--keep-runtime-typing"]
# syntax linting and formatting
- repo: https://github.com/myint/autoflake
rev: v2.3.1
rev: v2.3.3
hooks:
- id: autoflake
args: [--in-place, --remove-all-unused-imports,
Expand All @@ -45,7 +45,7 @@ repos:
--min-python-version, '3.9']
additional_dependencies: [flake8-typing-imports==1.12.0]
- repo: https://github.com/psf/black
rev: 25.11.0
rev: 26.3.1
hooks:
- id: black

Expand Down
17 changes: 2 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,30 +42,17 @@ Zebrafish imaged using [DaXi](https://www.nature.com/articles/s41592-022-01417-2

## Installation

Install or update [conda](https://docs.conda.io/projects/conda/en/latest/user-guide/install/index.html).

To avoid conflicts between different packages, we recommend using conda to create an isolated environment:

```bash
conda create -n ultrack python=3.11 higra gurobi pytorch pyqt -c pytorch -c gurobi -c conda-forge
conda activate ultrack
pip install ultrack
```

The installation should take a few minutes, depending on your internet speed and conda.

NOTE: `gurobi` and `-c gurobi` are optional but recommended; they can be installed later, as shown below.
We recommend installing into a virtual environment to avoid package conflicts.
`gurobi` is optional but recommended for best performance; see the [installation guide](https://ultrack.readthedocs.io/en/latest/install.html) for details on Gurobi setup and GPU acceleration.

Optionally, we provide multiple Docker images. For instructions, see the [docker folder](https://github.com/royerlab/ultrack/tree/main/docker).

## Usage

**ATTENTION**: every time you need to run this software, you'll have to activate this environment

```bash
conda activate ultrack
```

Here is a basic example to get you started:

```python
Expand Down
80 changes: 41 additions & 39 deletions docs/source/install.rst
Original file line number Diff line number Diff line change
@@ -1,27 +1,38 @@
Installation
============

The recommended way to install the package is to use the conda (or mamba) package manager.
The simplest way to install ``ultrack`` is with pip:

We also provide a `pixi <https://pixi-docs.com/>`_ configuration for the package, which allows you to setup an environment with all the dependencies in a single command. See the section :ref:`pixi_install` for more details.
.. code-block:: bash

If you do not have conda installed, we recommend to install mamba first, which is a faster alternative to conda.
You can find mamba installation instructions `here <https://mamba.readthedocs.io/en/latest/installation/mamba-installation.html>`_.
pip install ultrack

Once you have conda (mamba) installed, you should create an environment for ``ultrack`` as follows:
We recommend installing into a virtual environment to avoid package conflicts.
With Python's built-in ``venv`` on Linux / macOS:

.. code-block:: bash

conda create -n ultrack python=3.11 higra gurobi pytorch pyqt -c pytorch -c gurobi -c conda-forge
python -m venv ultrack-env
source ultrack-env/bin/activate
pip install ultrack

On Windows:

.. code-block:: bat

python -m venv ultrack-env
ultrack-env\Scripts\activate
pip install ultrack

Then, you can activate the environment and install ``ultrack``:
Or with `conda <https://docs.conda.io/projects/conda/en/latest/>`_:

.. code-block:: bash

conda create -n ultrack python=3.11
conda activate ultrack
pip install ultrack

You can check if the installation was successful by running:
You can verify the installation by running:

.. code-block:: bash

Expand All @@ -31,54 +42,43 @@ You can check if the installation was successful by running:
GPU acceleration
----------------

Ultrack makes use of GPU for image processing operations.
You can install the additional packages required for GPU acceleration by running (Linux and Windows only):
Ultrack uses the GPU for image processing operations.
Install the additional packages for GPU acceleration (Linux and Windows only):

.. code-block:: bash

conda install pytorch-cuda -c pytorch -c nvidia
conda install cupy -c conda-forge
# linux only
conda install cucim -c rapidsai
# for windows, you can install cucim using pip
pip install "git+https://github.com/rapidsai/cucim.git@v22.04.00#egg=cucim&subdirectory=python/cucim"
# Install PyTorch with CUDA — pick the right version at https://pytorch.org/get-started/locally/
pip install torch --index-url https://download.pytorch.org/whl/cu124
pip install cupy-cuda12x
# Linux only
pip install cucim-cu12

See the `PyTorch website <https://pytorch.org/get-started/locally/>`_ for more information on how to install PyTorch with GPU support.
See the `PyTorch website <https://pytorch.org/get-started/locally/>`_ for the full list of CUDA builds.

.. _gurobi_install:

Gurobi setup
------------

Gurobi is a commercial optimization solver that is used in the tracking module of ``ultrack``.
While it is not a requirement, it is recommended to install it for the best performance.

To use it, you need to obtain a license (free for academics) and activate it.

Install gurobi using conda
``````````````````````````

You can skip this step if you have already installed Gurobi.

In your existing Conda environment, install Gurobi with the following command:

.. code-block:: bash
Gurobi is a commercial optimization solver used in the tracking module of ``ultrack``.
While not required, it is recommended for best performance.

conda install -c gurobi gurobi
``gurobipy`` is installed automatically with ``ultrack`` — no extra install step is needed.
To use the solver, you must obtain and activate a license (free for academics).

Obtain and activate an academic license
```````````````````````````````````````

**Obtaining a license:** register for an account using your academic email at `Gurobi's website <https://portal.gurobi.com/iam/login>`_.
Navigate to the Gurobi's `named academic license page <https://www.gurobi.com/features/academic-named-user-license/>`_, and follow the instructions to get your academic license key.

**Activating license:** In your Conda environment, run:
**Activating license:** run:

.. code-block:: bash

grbgetkey YOUR_LICENSE_KEY

Replace YOUR_LICENSE_KEY with the key you received. Follow the prompts to complete activation.
Replace ``YOUR_LICENSE_KEY`` with the key you received. Follow the prompts to complete activation.

Test the installation
`````````````````````
Expand All @@ -92,26 +92,28 @@ Verify Gurobi's installation by running:
Troubleshooting
```````````````

Depending on the operating system, the gurobi library might be missing and you need to install it from `here <https://www.gurobi.com/downloads/gurobi-software>`_.
Depending on the operating system, the Gurobi library might be missing.
Download it from `Gurobi's website <https://www.gurobi.com/downloads/gurobi-software>`_.

If you're still having trouble, with the installation we recommend reaching out to us or using the docker image, see :doc:`Docker instructions <docker/README>`.
If you're still having trouble, reach out to us or use the Docker image — see :doc:`Docker instructions <docker/README>`.

.. _pixi_install:

Ultrack environment with pixi
-----------------------------

This is an alternative to the conda installation for environment management, using the `pixi <https://pixi-docs.com/>`_ package manager.
For contributors and advanced users, we provide a `pixi <https://pixi.sh/>`_ configuration
that sets up a full development environment in a single command.

First, install ``pixi`` following the instructions for your operating system:
Install ``pixi`` following the instructions for your operating system:

For Linux and OSX:
For Linux and macOS:

.. code-block:: bash

curl -fsSL https://pixi.sh/install.sh | bash

For Windows, using PowerShell:
For Windows (PowerShell):

.. code-block:: powershell

Expand Down
7 changes: 3 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ dynamic = ["version"]
description = "Large-scale multi-hypotheses cell tracking"
readme = "README.md"
license = "BSD-3-Clause"
requires-python = ">=3.9,<3.13"
requires-python = ">=3.11,<3.14"
authors = [
{ name = "Jordao Bragantini", email = "jordao.bragantini@czbiohub.org" },
]
Expand All @@ -17,10 +17,9 @@ classifiers = [
"Intended Audience :: Science/Research",
"License :: OSI Approved :: BSD License",
"Programming Language :: Python",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Scientific/Engineering",
"Topic :: Scientific/Engineering :: Image Processing",
"Topic :: Scientific/Engineering :: Artificial Intelligence",
Expand Down Expand Up @@ -82,10 +81,10 @@ test = [
"asv >=0.5.1",
"pre-commit >=3.2.2",
"pytest >=7.3.1",
"pytest-cov >=6.0.0",
"pytest-qt >=4.2.0",
"pytrackmate >=1.3.4",
"napari[testing] >0.4.18",
"pyqt5 >=5.15.4",
]
ml = [
"catboost >=1.2.7",
Expand Down
2 changes: 1 addition & 1 deletion ultrack/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
# ignoring small float32/64 zero flush warning
warnings.filterwarnings("ignore", message="The value of the smallest subnormal for")

__version__ = "0.7.2"
__version__ = "0.7.3"

from ultrack.config.config import MainConfig, load_config
from ultrack.core.export.ctc import to_ctc
Expand Down
8 changes: 4 additions & 4 deletions ultrack/core/export/_test/test_ctc.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@ def dataframe_forest() -> pd.DataFrame:
def dataframe_forest_with_time(dataframe_forest: pd.DataFrame) -> pd.DataFrame:
df = dataframe_forest.copy()
df["t"] = -1
df["t"].values[:10] = np.arange(10)
df["t"].values[10:20] = np.arange(10, 20)
df["t"].values[20:30] = np.arange(10, 20)
df["t"].values[30:40] = np.arange(5, 15)
df.iloc[:10, df.columns.get_loc("t")] = np.arange(10)
df.iloc[10:20, df.columns.get_loc("t")] = np.arange(10, 20)
df.iloc[20:30, df.columns.get_loc("t")] = np.arange(10, 20)
df.iloc[30:40, df.columns.get_loc("t")] = np.arange(5, 15)
return df


Expand Down
9 changes: 7 additions & 2 deletions ultrack/core/export/ctc.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
tracks_df_forest,
)
from ultrack.tracks.stats import estimate_drift
from ultrack.utils.array import make_array_writeable
from ultrack.utils.constants import NO_PARENT
from ultrack.utils.data import validate_and_overwrite_path

Expand Down Expand Up @@ -370,9 +371,13 @@ def condition(node: Node) -> bool:
stitch_tracks=stitch_tracks,
)

df["track_id"], fw, _ = relabel_sequential(df["track_id"].values)
df["track_id"], fw, _ = relabel_sequential(
make_array_writeable(df["track_id"].values)
)
mask = df["parent_track_id"] != NO_PARENT
df.loc[mask, "parent_track_id"] = fw[df.loc[mask, "parent_track_id"].values]
df.loc[mask, "parent_track_id"] = fw[
make_array_writeable(df.loc[mask, "parent_track_id"].values)
]

# convert to CTC format and write output
tracks_df = ctc_compress_forest(df)
Expand Down
2 changes: 1 addition & 1 deletion ultrack/core/segmentation/hierarchy.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def create_hierarchies(
# This is mainly for lonely cells.
morphology.remove_small_objects(
labels,
min_size=int(kwargs["min_area"] / kwargs.get("min_area_factor", 4.0)),
max_size=int(kwargs["min_area"] / kwargs.get("min_area_factor", 4.0)) - 1,
out=labels,
)

Expand Down
Loading
Loading