Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
9a7de48
add reading slide-level info from provided csv
measty Feb 21, 2024
b811b62
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 21, 2024
a692c59
add documentation entry
measty Feb 21, 2024
79ab016
Merge branch 'add-slide-data' of https://github.com/TissueImageAnalyt…
measty Feb 21, 2024
bcd5131
fix typo
measty Feb 21, 2024
d0995cc
improve test coverage
measty Feb 21, 2024
8b24409
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 21, 2024
ad57393
Merge branch 'develop' into add-slide-data
shaneahmed Mar 1, 2024
2fd714d
Merge branch 'develop' into add-slide-data
shaneahmed Mar 12, 2024
cda3110
Merge branch 'develop' into add-slide-data
shaneahmed Mar 13, 2024
ab711ff
add simple plugins
measty Mar 13, 2024
e45fb3c
Merge branch 'add-slide-data' of https://github.com/TissueImageAnalyt…
measty Mar 13, 2024
8755f27
fix test
measty Mar 13, 2024
b7715f6
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 14, 2024
4ca17e1
change circle size->radius for bokeh 3.4 compatibility
measty Mar 14, 2024
3cec0aa
Merge branch 'add-slide-data' of https://github.com/TissueImageAnalyt…
measty Mar 14, 2024
1e8df62
remove refs to size
measty Mar 15, 2024
96ccd97
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 15, 2024
cd9e3bd
update img size
measty Mar 15, 2024
f52ee5e
Merge branch 'add-slide-data' of https://github.com/TissueImageAnalyt…
measty Mar 15, 2024
d2a6ec4
try dialog
measty Mar 15, 2024
1bec5b6
Merge branch 'develop' into add-slide-data
shaneahmed Mar 19, 2024
7b40965
replace dropdown with select
measty Mar 20, 2024
08fcb59
Merge branch 'develop' into add-slide-data
shaneahmed Mar 22, 2024
646848e
once and per slide options
measty Apr 4, 2024
4a2e48f
update tests for switch to layer select
measty Apr 8, 2024
27a9d1d
Merge branch 'develop' of https://github.com/TissueImageAnalytics/tia…
measty Apr 12, 2024
880e4a6
Merge branch 'add-slide-data' of https://github.com/TissueImageAnalyt…
measty Apr 12, 2024
c8ffd30
add missing docstrings
measty Apr 12, 2024
c5165be
Merge branch 'develop' into add-slide-data
shaneahmed Apr 19, 2024
721ad20
Merge branch 'develop' into add-slide-data
shaneahmed May 10, 2024
f849dee
Merge branch 'develop' into add-slide-data
shaneahmed May 17, 2024
e15f6bb
add tests
measty May 28, 2024
23796bc
Merge branch 'develop' into add-slide-data
shaneahmed Jun 14, 2024
90d69b3
Merge branch 'develop' into add-slide-data
shaneahmed Jun 21, 2024
7768414
Merge branch 'develop' into add-slide-data
shaneahmed Jun 28, 2024
12147da
Merge branch 'add-slide-data' of https://github.com/TissueImageAnalyt…
measty Oct 3, 2024
c9e7ea1
Merge branch 'develop' of https://github.com/TissueImageAnalytics/tia…
measty Oct 3, 2024
0bfb5f0
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 3, 2024
c39fe41
fix test
measty Oct 4, 2024
43cac84
Merge branch 'add-slide-data' of https://github.com/TissueImageAnalyt…
measty Oct 4, 2024
33a1068
Merge branch 'develop' into add-slide-data
shaneahmed Nov 22, 2024
59b4a2c
Merge branch 'develop' into add-slide-data
shaneahmed Jan 24, 2025
12b4d62
Merge branch 'develop' into add-slide-data
shaneahmed Feb 7, 2025
ab9451e
Merge branch 'develop' into add-slide-data
shaneahmed Feb 21, 2025
7adde6d
Merge branch 'develop' of https://github.com/TissueImageAnalytics/tia…
measty Oct 9, 2025
6d94488
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 9, 2025
bf50ee3
precommit
measty Oct 9, 2025
62dd99c
Merge branch 'add-slide-data' of https://github.com/TissueImageAnalyt…
measty Oct 9, 2025
de8723b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 9, 2025
5e8309c
Merge branch 'develop' into add-slide-data
shaneahmed Oct 10, 2025
b99f0e5
Merge branch 'develop' into add-slide-data
shaneahmed Oct 17, 2025
709c90f
Merge branch 'develop' into add-slide-data
shaneahmed Oct 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
9 changes: 7 additions & 2 deletions docs/visualization.rst
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,11 @@ Additional features can be added to nodes by adding extra keys to the dictionary

It will be possible to color the nodes by these features in the interface, and the top 10 will appear in a tooltip when hovering over a node (you will have to turn on the hovertool in the small toolbar to the right of the main window to enable this, it is disabled by default).

Slide Level Information
^^^^^^^^^^^^^^^^^^^^^^^

If you have slide-level predictions, ground truth labels, or other metadata you wish to be able to see associated with slides in the interface, this can be provided as a .csv formatted table placed in the slides folder, with "Image File" as the first column. The other columns can be anything you like. When loading a slide in the UI, if the slide name appears in the "Image File" column of the provided .csv, any other entries in that row will be displayed in the interface below the main view window when the slide is selected.

.. _examples:

4. Annotation Store Examples
Expand Down Expand Up @@ -460,7 +465,7 @@ and the ability to toggle on or off specific UI elements:

::

"UI_elements_1": { # controls which UI elements are visible
"ui_elements_1": { # controls which UI elements are visible
"slide_select": 1, # slide select box
"layer_drop": 1, # overlay select drop down
"slide_row": 1, # slide alpha toggle and slider
Expand All @@ -475,7 +480,7 @@ and the ability to toggle on or off specific UI elements:

::

"UI_elements_2": { # controls visible UI elements on second tab in UI
"ui_elements_2": { # controls visible UI elements on second tab in UI
"opt_buttons": 1, # UI elements providing a few options including if annotations should be filled/outline only
"pt_size_spinner": 1, # control for point size and graph node size
"edge_size_spinner": 1, # control for edge thickness
Expand Down
1 change: 1 addition & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -622,6 +622,7 @@ def data_path(tmp_path_factory: pytest.TempPathFactory) -> dict[str, object]:
"""Set up a temporary data directory for testing visualization UI."""
tmp_path = tmp_path_factory.mktemp("data")
(tmp_path / "slides").mkdir()
(tmp_path / "slides" / "CMU-1_files").mkdir()
(tmp_path / "overlays").mkdir()
return {"base_path": tmp_path}

Expand Down
21 changes: 19 additions & 2 deletions tests/test_app_bokeh.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ def annotation_path(data_path: dict[str, Path]) -> dict[str, object]:
"patch-extraction-vf",
data_path["base_path"] / "slides",
)
data_path["meta"] = _fetch_remote_sample(
"test_meta",
data_path["base_path"] / "slides",
)
data_path["annotations"] = _fetch_remote_sample(
"annotation_store_svs_1",
data_path["base_path"] / "overlays",
Expand Down Expand Up @@ -134,6 +138,14 @@ def annotation_path(data_path: dict[str, Path]) -> dict[str, object]:
"config_2",
data_path["base_path"] / "overlays",
)
data_path["plugin_img"] = _fetch_remote_sample(
"stainnorm-source",
data_path["base_path"] / "slides" / "CMU-1_files",
)
data_path["plugin_csv"] = _fetch_remote_sample(
"test_csv",
data_path["base_path"] / "slides" / "CMU-1_files",
)
return data_path


Expand Down Expand Up @@ -186,8 +198,8 @@ def test_get_level_by_extent() -> None:

def test_roots(doc: Document) -> None:
"""Test that the document has the correct number of roots."""
# should be 4 roots: main window, controls, slide_info, popup table
assert len(doc.roots) == 4
# should be 5 roots: main window, controls, slide_info, popup, extra_layout
assert len(doc.roots) == 5


def test_config_loaded(data_path: pytest.TempPathFactory) -> None:
Expand Down Expand Up @@ -215,6 +227,11 @@ def test_slide_select(doc: Document, data_path: pytest.TempPathFactory) -> None:
slide_select.value = ["CMU-1.ndpi"]
assert main.UI["vstate"].slide_path == data_path["slide2"]

# check the slide metadata is loaded from csv
desc = doc.get_model_by_name("description")
assert "valA" in desc.text
assert "valB" not in desc.text

# check selecting nothing has no effect
slide_select.value = []
assert main.UI["vstate"].slide_path == data_path["slide2"]
Expand Down
14 changes: 14 additions & 0 deletions tests/test_json_config_bokeh.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from threading import Thread
from typing import TYPE_CHECKING

import pandas as pd
import pytest
import requests
from bokeh.client.session import ClientSession, pull_session
Expand All @@ -29,6 +30,15 @@ def annotation_path(data_path: dict[str, Path]) -> dict[str, Path]:
"ndpi-1",
data_path["base_path"] / "slides",
)
data_path["meta"] = _fetch_remote_sample(
"test_meta",
data_path["base_path"] / "slides",
)
meta_df = pd.read_csv(data_path["meta"])
# change 'Image File' column name to 'Wrong Name'
meta_df = meta_df.rename(columns={"Image File": "Wrong Name"})
# save so we can test behaviour if required column isn't there
meta_df.to_csv(data_path["meta"], index=False)
data_path["annotations"] = _fetch_remote_sample(
"annotation_store_svs_1",
data_path["base_path"] / "overlays",
Expand Down Expand Up @@ -82,6 +92,10 @@ def test_slides_available(bk_session: ClientSession) -> None:
slide_select.value = ["CMU-1.ndpi"]
assert len(layer_drop.menu) == 2

# check the metadata wasnt found as the column name was wrong
desc = doc.get_model_by_name("description")
assert "Metadata:" not in desc.text

bk_session.document.clear()
assert len(bk_session.document.roots) == 0
bk_session.close()
Expand Down
12 changes: 11 additions & 1 deletion tiatoolbox/cli/visualize.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,14 @@ def run_bokeh(img_input: list[str], port: int, *, noshow: bool) -> None:
This option must be used in conjunction with --slides.
The --base-path option should not be used in this case.""",
)
@click.option(
"--plugin",
multiple=True,
help=r"""Path to a file to define an extra layout containing extra
resources such as graphs below each slide. Some pre-built plugins are
available in the tiatoolbox\visualization\templates folder. Can pass
multiple instances of this option to add multiple ui additions.""",
)
@click.option(
"--port",
type=int,
Expand All @@ -88,6 +96,7 @@ def visualize(
base_path: str,
slides: str,
overlays: str,
plugin: list[str],
port: int,
*,
noshow: bool,
Expand All @@ -101,6 +110,7 @@ def visualize(
base_path (str): Path to base directory containing images to be displayed.
slides (str): Path to directory containing slides to be displayed.
overlays (str): Path to directory containing overlays to be displayed.
plugin (list): Paths to files containing ui plugins.
port (int): Port to launch the visualization tool on.
noshow (bool): Do not launch in browser (mainly intended for testing).

Expand All @@ -109,7 +119,7 @@ def visualize(
if base_path is None and (slides is None or overlays is None):
msg = "Must specify either base-path or both slides and overlays."
raise ValueError(msg)
img_input = [base_path, slides, overlays]
img_input = [base_path, slides, overlays, *list(plugin)]
img_input = [p for p in img_input if p is not None]
# check that the input paths exist
for input_path in img_input:
Expand Down
4 changes: 4 additions & 0 deletions tiatoolbox/data/remote_samples.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,10 @@ files:
url: [*testdata, "annotation/test1_config.json"]
config_2:
url: [*testdata, "annotation/test2_config.json"]
test_meta:
url: [*testdata, "annotation/test_meta.csv"]
test_csv:
url: [*testdata, "annotation/metrics_10.csv"]
patch_annotations:
url: [*testdata, "annotation/sample_wsi_patch_preds.db"]
nuclick-output:
Expand Down
Loading
Loading