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
2 changes: 1 addition & 1 deletion .copier-answers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ _src_path: https://github.com/napari/napari-plugin-template
display_name: Cotcotcot
email: romain.guiet@epfl.ch
full_name: Romain Guiet
github_repository_url: provide later
github_repository_url: https://github.com/BIOP/napari-cotcotcot
github_username_or_organization: romainGuiet
include_reader_plugin: true
include_sample_data_plugin: true
Expand Down
8 changes: 5 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ dependencies = [
"pandas",
"tqdm",
"tifffile",
"napari", # Add this since your plugin is for napari
"torch", # See note below about PyTorch
"napari",
"torch",
]

[project.optional-dependencies]
Expand All @@ -56,7 +56,7 @@ dev = [
[project.entry-points."napari.manifest"]
napari-cotcotcot = "napari_cotcotcot:napari.yaml"

# to enable command line interface
# to enable command line interface, starting rom terminal with naparicot
[project.scripts]
naparicot = "napari_cotcotcot:main"

Expand All @@ -72,6 +72,8 @@ where = ["src"]

[tool.setuptools.package-data]
"*" = ["*.yaml"]
# to enable package data inclusion
"napari_cotcotcot" = ["/data/Gallus_gallus_domesticus/chicken-run.gif" , "/data/Gallus_gallus_domesticus/seed_Chicken1.csv" ]

[tool.setuptools_scm]
write_to = "src/napari_cotcotcot/_version.py"
Expand Down
73 changes: 0 additions & 73 deletions src/napari_cotcotcot/_reader.py

This file was deleted.

95 changes: 79 additions & 16 deletions src/napari_cotcotcot/_sample_data.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,85 @@
"""
This module is an example of a barebones sample data provider for napari.

It implements the "sample data" specification.
see: https://napari.org/stable/plugins/building_a_plugin/guides.html#sample-data
from pathlib import Path
from typing import List

Replace code below according to your needs.
"""
import numpy as np
import pandas as pd
from skimage.io import imread
from napari.types import LayerData

from __future__ import annotations
def _load_seed_from_csv_standalone(csv_path: str) -> np.ndarray:
"""
Load seed points from a CSV file.

import numpy
Parameters
----------
csv_path : str
Path to the CSV file containing seed point coordinates.

Returns
-------
np.ndarray
Array of shape (n_points, 3) containing seed point coordinates.

def make_sample_data():
"""Generates an image"""
# Return list of tuples
# [(data1, add_image_kwargs1), (data2, add_image_kwargs2)]
# Check the documentation for more information about the
# add_image_kwargs
# https://napari.org/stable/api/napari.Viewer.html#napari.Viewer.add_image
return [(numpy.random.rand(512, 512), {})]
Raises
------
ValueError
If the CSV format is invalid (missing required columns).
"""
df = pd.read_csv(csv_path)

required_cols = ["axis-0", "axis-1", "axis-2"]
if not all(col in df.columns for col in required_cols):
if all(col in df.columns for col in ["t", "y", "x"]):
df = df.rename(columns={"t": "axis-0", "y": "axis-1", "x": "axis-2"})
else:
raise ValueError("CSV must contain columns: axis-0, axis-1, axis-2 (or t, y, x)")

return df[["axis-0", "axis-1", "axis-2"]].values

def load_sample_data() -> List[LayerData]:
"""
Loads sample data for demonstration in napari.

This function loads:
- A GIF image ("chicken-run.gif") from a remote URL:
https://raw.githubusercontent.com/BIOP/napari-cotcotcot/refs/heads/main/src/napari_cotcotcot/data/Gallus_gallus_domesticus/chicken-run.gif
- Seed points from a local CSV file ("seed_Chicken1.csv") if available at:
<package_dir>/data/Gallus_gallus_domesticus/seed_Chicken1.csv

Returns
-------
List[LayerData]
A list of tuples (data, metadata, layer_type) suitable for napari, where:
- The first tuple contains the image data, metadata with name "cotcotcot", and layer_type "image".
- The second tuple (if CSV is found and loaded) contains the seed points, metadata with name "seed_Chicken1", and layer_type "points".

Data Sources
-----------
- GIF image: downloaded from the above URL.
- Seed points: loaded from a local CSV file.

Exceptions
----------
- If the CSV file is missing, empty, or malformed, an error is printed and only the image is returned.
- If the GIF image cannot be downloaded or read, an exception may be raised by skimage.io.imread.
"""
URL = "https://raw.githubusercontent.com/BIOP/napari-cotcotcot/refs/heads/main/src/napari_cotcotcot/data/Gallus_gallus_domesticus/chicken-run.gif"
print(f"Downloading sample data from {URL}...")
try:
gif_data = imread(URL)
print("Downloading completed!")
sample_datasets = [(gif_data, {"name": "cotcotcot"}, "image")]
except (IOError, ValueError, Exception) as e:
print(f"Error downloading or reading image from {URL}: {e}")
sample_datasets = []
# Load CSV
csv_data_path = Path(__file__).parent / "data" / "Gallus_gallus_domesticus" / "seed_Chicken1.csv"
if csv_data_path.exists():
try:
csv_data = _load_seed_from_csv_standalone(str(csv_data_path))
sample_datasets.append((csv_data, {"name": "seed_Chicken1"}, "points"))
except (FileNotFoundError, ValueError, pd.errors.EmptyDataError, pd.errors.ParserError) as e:
print(f"Error loading CSV data: {e}")

return sample_datasets
34 changes: 33 additions & 1 deletion src/napari_cotcotcot/_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from pathlib import Path
from typing import TYPE_CHECKING


import napari
import numpy as np
import pandas as pd
from magicgui.widgets import (
Expand Down Expand Up @@ -292,6 +292,24 @@ def __init__(
# Auto-initialize if we have an image
if self._get_image_layers():
self.image_selector.value = self._get_image_layers()[0]

# Auto-initialize seed manager if seed layers are already present
self._check_and_auto_initialize()

def _check_and_auto_initialize(self):
"""Check for existing seed layers and auto-initialize if found."""
if self.seed_manager is None:
seed_like_layers = [
layer.name for layer in self.viewer.layers
if isinstance(layer, napari.layers.Points) and
(layer.name.startswith("seed_") or "seed" in layer.name.lower())
]

if seed_like_layers:
print(f"Auto-initializing seed manager on startup due to detected seed layers: {seed_like_layers}")
self._ensure_seed_manager_initialized()
self._refresh_seed_list()
self._check_enable_tracking()

def _pick_custom_color(self):
"""Open color picker dialog for custom color selection."""
Expand Down Expand Up @@ -389,6 +407,20 @@ def _disconnect_seed_layer_events(self, layer_name):
def _on_layer_change(self, event):
"""Handle layer changes in viewer."""
self.image_selector.choices = self._get_image_layers()

# Auto-initialize seed manager if we detect seed layers but manager is None
if self.seed_manager is None:
# Check if there are any layers that look like seed layers
seed_like_layers = [
layer.name for layer in self.viewer.layers
if isinstance(layer, napari.layers.Points) and
(layer.name.startswith("seed_") or "seed" in layer.name.lower())
]

if seed_like_layers:
print(f"Auto-initializing seed manager due to detected seed layers: {seed_like_layers}")
self._ensure_seed_manager_initialized()

if self.seed_manager:
self._refresh_seed_list()
# Check if tracking buttons should be enabled
Expand Down
66 changes: 0 additions & 66 deletions src/napari_cotcotcot/_writer.py

This file was deleted.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
index,axis-0,axis-1,axis-2
0.0,0.0,92.83061471930142,59.76071319110557
1.0,23.0,163.09295583101897,78.5809831317442
2.0,10.0,93.00985538540276,73.9207258131099
3.0,18.0,128.6787479395655,85.57136910969572
22 changes: 3 additions & 19 deletions src/napari_cotcotcot/napari.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,15 @@ visibility: public
# categories: []
contributions:
commands:
- id: napari-cotcotcot.get_reader
python_name: napari_cotcotcot._reader:napari_get_reader
title: Open data with CoTracker
- id: napari-cotcotcot.write_image
python_name: napari_cotcotcot._writer:napari_write_image
title: Save image data with CoTracker
- id: napari-cotcotcot.make_sample_data
python_name: napari_cotcotcot._sample_data:make_sample_data
- id: napari-cotcotcot.load_sample_data
python_name: napari_cotcotcot._sample_data:load_sample_data
title: Load sample data from CoTracker
- id: napari-cotcotcot.cotracker_widget
python_name: napari_cotcotcot._widget:cotracker_widget
title: CoTracker Control Panel

readers:
- command: napari-cotcotcot.get_reader
accepts_directories: false
filename_patterns: ['*.tif', '*.tiff']

writers:
- command: napari-cotcotcot.write_image
layer_types: ['image']
filename_extensions: ['.tif', '.tiff']

sample_data:
- command: napari-cotcotcot.make_sample_data
- command: napari-cotcotcot.load_sample_data
display_name: CoTracker sample
key: unique_id.1

Expand Down
Loading