Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
ba15742
first anywidget attempt
TeunHuijben Apr 22, 2025
bb8e201
left sidebar solved
TeunHuijben Apr 22, 2025
471793d
time slider no longer behind sidebar
TeunHuijben Apr 22, 2025
f7f1daf
last working commit after time slider fix, images are a problem....
TeunHuijben Apr 22, 2025
ffa5cdc
working test widget
TeunHuijben Apr 29, 2025
7f794b8
improved test_widget with direct image loading
TeunHuijben Apr 29, 2025
471098d
logo and spark work in anywidget!!
TeunHuijben Apr 29, 2025
2647219
reverted App.tsx back to normal/main
TeunHuijben Apr 30, 2025
d3ad488
deleted unnec.file
TeunHuijben Apr 30, 2025
9ec08e9
FIXED image issue again, need widget.tsx
TeunHuijben Apr 30, 2025
cd7dafd
fixed styling of toggles and sliders
TeunHuijben Apr 30, 2025
9772589
custom dataUrl as input to Widget
TeunHuijben May 1, 2025
e7ac582
precommit fixes
TeunHuijben May 1, 2025
175fdbf
df_2_browser function has option to not open the browser and return t…
TeunHuijben May 1, 2025
53216eb
w.selected_tracks gives list of track_ids that are currently selected
TeunHuijben May 1, 2025
9cb2003
deleted test widget with logo loading
TeunHuijben May 1, 2025
c2b4313
removed shareable-url button, since this doesnt work from within a no…
TeunHuijben May 1, 2025
e7ed22c
renamed get_selected_tracks
TeunHuijben May 2, 2025
6921cf7
try 1, only see useEffect, no callback1
TeunHuijben May 2, 2025
7409f1b
working! but only once
TeunHuijben May 2, 2025
b7b1449
fixed react state > remove selected_cells in selectedPointIds useeffe…
TeunHuijben May 2, 2025
38963f8
fixed selecting bug after clearing tracks
TeunHuijben May 13, 2025
383913c
lint fix
TeunHuijben May 13, 2025
24e67c2
fix initial dataset isssue, by moving initialViewerState into widget
TeunHuijben May 13, 2025
fe160f7
lint fix
TeunHuijben May 13, 2025
5ef9a60
disable copy URL button
TeunHuijben May 13, 2025
499e4a4
sync widget.js and app.tsx
TeunHuijben May 13, 2025
0125a9f
sync with app.tsx
TeunHuijben May 13, 2025
53e6c4f
fix get_selected does not show box-selected cells, because useEffect …
TeunHuijben May 13, 2025
9abf854
cleanup example scripts
TeunHuijben May 14, 2025
c3ae50e
fixed selection error, that numCells shows zero, after clearing cells…
TeunHuijben May 15, 2025
c9e0a50
lint changes
TeunHuijben May 15, 2025
95a521c
lint fixes
TeunHuijben May 15, 2025
3836f66
Merge branch 'anywidget-fix-selection' into anywidget
TeunHuijben May 15, 2025
a038d6c
minor example notebook edits
TeunHuijben May 16, 2025
346b5fc
updated noteboooks anywidget
TeunHuijben May 21, 2025
a92dfab
solve selection error
TeunHuijben May 21, 2025
a2f7b4e
merge conflict
TeunHuijben May 21, 2025
cd539f6
moved widget to python package
TeunHuijben May 22, 2025
34acb19
widget to python package + precommit fixes
TeunHuijben May 22, 2025
fd37aac
select/get cells by actual track_id
TeunHuijben May 23, 2025
65c4aba
update notebook_widget.py
TeunHuijben May 24, 2025
6109988
updated example script 3
TeunHuijben May 24, 2025
815522f
update example 3
TeunHuijben May 24, 2025
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
852 changes: 471 additions & 381 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"coverage": "vitest --coverage"
},
"dependencies": {
"@anywidget/react": "^0.2.0",
"@czi-sds/components": "^21.6.3",
"@emotion/css": "^11.11.2",
"@emotion/react": "^11.11.4",
Expand Down
2 changes: 1 addition & 1 deletion python/src/intracktive/_tests/test_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import napari
import pandas as pd
import pytest
from intracktive.widget import IntracktiveWidget
from intracktive.napari_widget import IntracktiveWidget


def test_intracktive_widget_2D(
Expand Down
73 changes: 58 additions & 15 deletions python/src/intracktive/convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,20 +290,10 @@ def convert_dataframe_to_zarr(
n_time_points = df["t"].max() + 1
max_values_per_time_point = df.groupby("t").size().max()

uniq_track_ids = df["track_id"].unique()
extended_uniq_track_ids = np.append(
uniq_track_ids, -1
) # include -1 for orphaned tracklets
fwd_map = ArrayMap(
extended_uniq_track_ids, np.append(np.arange(1, 1 + len(uniq_track_ids)), -1)
)

# relabeling from 0 to N-1
df["track_id"] = fwd_map[df["track_id"].to_numpy()]
# orphaned are set to 0 according to skimage convention
df["parent_track_id"] = fwd_map[df["parent_track_id"].to_numpy()]

# Replace the manual remapping code with the new function call
df = make_track_ids_consecutive(df, inplace=True)
n_tracklets = df["track_id"].nunique()

# (z, y, x) + extra_cols
num_values_per_point = 4 if add_radius else 3

Expand Down Expand Up @@ -595,8 +585,26 @@ def dataframe_to_browser(
pre_normalized=pre_normalized,
)

# Use the new zarr_to_browser function
zarr_to_browser(zarr_dir_with_storename, flag_open_browser)
hostURL = serve_directory(
path=zarr_dir,
threaded=True,
)

LOG.info("localhost successfully launched, serving: %s", zarr_dir_with_storename)
baseUrl = "https://intracktive.sf.czbiohub.org" # inTRACKtive application
dataUrl = (
hostURL + "/" + zarr_path.name + "/"
) # exact path of the data (on localhost)
fullUrl = baseUrl + generate_viewer_state_hash(
data_url=str(dataUrl)
) # full hash that encodes viewerState
LOG.info("Copy the following URL into the Google Chrome browser:")
LOG.info("full URL: %s", fullUrl)

if flag_open_browser:
webbrowser.open(fullUrl)
else:
return dataUrl


def check_if_columns_exist(
Expand Down Expand Up @@ -647,6 +655,41 @@ def get_col_type(column: pd.Series) -> str:
return "continuous"


def make_track_ids_consecutive(df: pd.DataFrame, inplace: bool = False) -> pd.DataFrame:
"""
Remap track IDs to be consecutive starting from 1, preserving parent-child relationships.
Uses ArrayMap from skimage for efficient array-based mapping.

Parameters
----------
df : pd.DataFrame
DataFrame containing 'track_id' and 'parent_track_id' columns
inplace : bool, optional
If True, modifies the dataframe in place. If False, returns a copy.

Returns
-------
pd.DataFrame
DataFrame with remapped consecutive track IDs
"""
if not inplace:
df = df.copy()

uniq_track_ids = df["track_id"].unique()
extended_uniq_track_ids = np.append(
uniq_track_ids, -1
) # include -1 for orphaned tracklets
fwd_map = ArrayMap(
extended_uniq_track_ids, np.append(np.arange(1, 1 + len(uniq_track_ids)), -1)
)

# relabeling from 1 to N
df["track_id"] = fwd_map[df["track_id"].to_numpy()]
df["parent_track_id"] = fwd_map[df["parent_track_id"].to_numpy()]

return df


@click.command(name="convert")
@click.argument(
"input_file",
Expand Down
141 changes: 141 additions & 0 deletions python/src/intracktive/examples/anywidget_example.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "8dee98d4-c8b1-4ba9-8c10-8e326db0a138",
"metadata": {},
"outputs": [],
"source": [
"%env ANYWIDGET_HMR=1\n",
"import anywidget\n",
"import traitlets\n",
"\n",
"\n",
"class Widget(anywidget.AnyWidget):\n",
" get_selected_tracks = traitlets.List().tag(sync=True)\n",
" dataset_url = traitlets.Unicode(\n",
" \"https://public.czbiohub.org/royerlab/zoo/Zebrafish/tracks_zebrafish_bundle.zarr/\"\n",
" ).tag(sync=True)\n",
" selected_cells = traitlets.List().tag(sync=True)\n",
"\n",
" def select_tracks(self, cell_ids):\n",
" print(\"in class widget1, cell_ids = \", self.selected_cells)\n",
" self.selected_cells = cell_ids\n",
" print(\"in class widget2, cell_ids = \", self.selected_cells)\n",
"\n",
" _esm = \"static/widget.js\"\n",
" _css = \"static/widget.css\""
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1ebd6233-decd-434f-87d7-7648f962e5dc",
"metadata": {},
"outputs": [],
"source": [
"# default widget has zebrafish\n",
"w = Widget()\n",
"w"
]
},
{
"cell_type": "markdown",
"id": "59317ec0",
"metadata": {},
"source": [
"# get/set data"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "555439b3-5509-4743-bee3-2400712d15f9",
"metadata": {},
"outputs": [],
"source": [
"w = Widget(\n",
" dataset_url=\"https://public.czbiohub.org/royerlab/zoo/Ascidian/tracks_ascidian_attributes_bundle.zarr/\"\n",
")\n",
"w"
]
},
{
"cell_type": "markdown",
"id": "12f4f980-7c9f-4247-8989-be73971a9f26",
"metadata": {},
"source": [
"Get track_ids of selected cells"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b187affc-bc62-46dd-a531-4c84d0aeae2a",
"metadata": {},
"outputs": [],
"source": [
"print(\"tracks:\", w.get_selected_tracks)\n",
"print(len(w.get_selected_tracks), \"tracks selected\")"
]
},
{
"cell_type": "markdown",
"id": "08962eca-f237-4597-93b5-7bd6b9ca1d7b",
"metadata": {},
"source": [
"Select tracks progammatically"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "72729521-3c62-42dc-80e7-a4743c24ed31",
"metadata": {},
"outputs": [],
"source": [
"w.select_tracks([39])"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b971a2d0-4d83-46bb-afab-6bac63d8765f",
"metadata": {},
"outputs": [],
"source": [
"w.select_tracks([40, 1, 39])"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "03099cc5-7e0e-4466-97bc-249499fc01d9",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.7"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
126 changes: 126 additions & 0 deletions python/src/intracktive/examples/anywidget_example2.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "217c2911-87bc-4e7c-8198-1a8d252904e9",
"metadata": {},
"source": [
"# Dependencies"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "f06c4f19-d756-44f1-8559-9f5e79f68081",
"metadata": {},
"outputs": [],
"source": [
"import traitlets\n",
"import anywidget\n",
"import pandas as pd\n",
"\n",
"from pathlib import Path\n",
"from IPython.display import clear_output\n",
"from intracktive.convert import dataframe_to_browser\n",
"\n",
"\n",
"class Widget(anywidget.AnyWidget):\n",
" selected_points = traitlets.List().tag(sync=True)\n",
" dataset_url = traitlets.Unicode(\n",
" \"https://public.czbiohub.org/royerlab/zoo/Zebrafish/tracks_zebrafish_bundle.zarr/\"\n",
" ).tag(sync=True)\n",
"\n",
" _esm = \"static/widget.js\"\n",
" _css = \"static/widget.css\""
]
},
{
"cell_type": "markdown",
"id": "8f416127-f17e-4816-b2ce-03317fee1605",
"metadata": {},
"source": [
"# Define data"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c19cf75c-5bb5-4c29-ab83-6c29d0d6b4c7",
"metadata": {},
"outputs": [],
"source": [
"df = pd.read_csv(\"https://public.czbiohub.org/royerlab/zoo/C_elegans/tracks.csv\")\n",
"df"
]
},
{
"cell_type": "markdown",
"id": "0d23d870-b89b-4b3a-a228-3c52646a6469",
"metadata": {},
"source": [
"# Open inTRACKtive within notebook"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "127be4fb-3e81-4583-aa1a-0a5d205129fb",
"metadata": {},
"outputs": [],
"source": [
"zarr_data_url = dataframe_to_browser(df, Path(), flag_open_browser=False)\n",
"clear_output()\n",
"\n",
"wid = Widget(dataset_url=zarr_data_url)\n",
"wid"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0d6b86bf-cd77-4f8d-8fd2-ce6040f00f62",
"metadata": {},
"outputs": [],
"source": [
"wid.selected_points"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ee233f4a-74bf-400d-aaba-4036d2c73066",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "9db1b2a0-f304-429a-9e5e-db7685912e10",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.7"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Loading