Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added skeleton path length example to docs #945

Merged
merged 8 commits into from
Sep 21, 2023
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: 2 additions & 0 deletions docs/mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ nav:
- webknossos-py/examples/skeleton_synapse_candidates.md
- webknossos-py/examples/calculate_segment_sizes.md
- webknossos-py/examples/download_segments.md
- webknossos-py/examples/load_annotation_from_file.md
- webknossos-py/examples/skeleton_path_length.md
- Administration Examples:
- webknossos-py/examples/user_times.md
- webknossos-py/examples/annotation_project_administration.md
Expand Down
11 changes: 11 additions & 0 deletions docs/src/webknossos-py/examples/load_annotation_from_file.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Annotation File to OME-TIFF

This example shows how to turn a volume annotation downloaded from WEBKNOSSOS into a OME-TIFF. When [manually downloading a WEBKNOSSOS annotation](/webknossos/export.html#data-export-through-the-ui) through the UI you end up with a ZIP file containing the volume segmentation in the WKW-format (and potentially any skeleton annotation).

As an alternative to manually downloading annotation files, have a look at streaming the data directly from the remote serve, e.g., in [this example](./download_segments.html).

```python
--8<--
webknossos/examples/load_annotation_from_file.py
--8<--
```
9 changes: 9 additions & 0 deletions docs/src/webknossos-py/examples/skeleton_path_length.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Skeleton Path Length

This example shows how to downloaded a skeleton annotation from WEBKNOSSOS and calcuate the total path length along all edges of each tree.

```python
--8<--
webknossos/examples/skeleton_path_length.py
--8<--
```
37 changes: 37 additions & 0 deletions webknossos/examples/load_annotation_from_file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from pathlib import Path

from tifffile import imwrite

import webknossos as wk

# Specify a bounding box for cutouts
# (topleft_x, topleft_y, topleft_z), (width, height, depth)
BOUNDING_BOX = wk.BoundingBox((0, 0, 0), (500, 500, 50))


def load_annotation(annotation_file: Path) -> None:
# Read the WEBKNOSSOS annotation file (a zipped WKW)
annotation = wk.Annotation.load(annotation_file)

# Treat it as a regular WK volume layer
with annotation.temporary_volume_layer_copy() as segmentation_layer:
# Do any standard layer operation, e.g. reading a cutout as a numpy array
mag_view = segmentation_layer.get_finest_mag()
segments = mag_view.read(absolute_bounding_box=BOUNDING_BOX)

# Write segmentation IDs to an OME Tiff file
imwrite(
"segmentation.ome.tiff",
segments.T, # note, the tiff lib use different channel order
ome=True,
metadata={
"axes": "ZYXC",
},
)


if __name__ == "__main__":
# Path to annotation file on your computer
ANNOTATION_FILE = Path("my_annotation_file.zip")

load_annotation(ANNOTATION_FILE)
55 changes: 55 additions & 0 deletions webknossos/examples/skeleton_path_length.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
from typing import Tuple

import numpy as np

import webknossos as wk


def calculate_path_length(annotation_url: str, auth_token: str) -> None:
with wk.webknossos_context(token=auth_token):
# Download a annotation directly from the WEBKNOSSOS server
annotation = wk.Annotation.download(
annotation_url,
)

skeleton = annotation.skeleton
voxel_size = annotation.voxel_size

# Iterate over all the tree in a skeleton and calculate their path length
for tree in skeleton.flattened_trees():
path_length = calculate_path_length_for_tree(tree, voxel_size)

# Log the results :-)
print(f"Tree {tree.name} has a path length of {path_length:.2f} nm")


def calculate_path_length_for_tree(
tree: wk.Tree, voxel_size: Tuple[float, float, float]
) -> float:
# Auxillary method calculate the maximum path length of a given tree
# Assumes that the annotation does not contain any cycles

assert (
len(tree.nodes) > 1
), "Each tree should have at least two nodes to calculate the path length"
result = 0

# Iterate over all edges
for source_node, target_node in tree.edges:
diff_vector = np.array(source_node.position) - np.array(target_node.position)
scaled_diff_vector = diff_vector * voxel_size
edge_length = np.sqrt(scaled_diff_vector.dot(scaled_diff_vector))
result += edge_length

return result


if __name__ == "__main__":
# Authentication and API token for your account
# Get it at https://webknossos.org/auth/token
TOKEN = "YOUR-token"

# A WEBKNOSOS URL containing the skeleton annotation
ANNOTATION_URL = "https://webknossos.org/annotations/12345678"

calculate_path_length(ANNOTATION_URL, TOKEN)
Binary file not shown.
22 changes: 22 additions & 0 deletions webknossos/tests/test_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -326,3 +326,25 @@ def test_download_tiff_stack() -> None:
len(list(output_path.iterdir()))
== mag_view.bounding_box.size.z / mag_view.mag.z
)


@pytest.mark.block_network(allowed_hosts=[".*"])
@pytest.mark.vcr(ignore_hosts=["webknossos.org", "data-humerus.webknossos.org"])
def test_skeleton_path_length() -> None:
from examples.skeleton_path_length import calculate_path_length

# Public skeleton annotation by MH Lab
annotation_id = "https://webknossos.org/annotations/62b191ef010000e80033e7c0"
token = "123"
calculate_path_length(annotation_id, token)


def test_load_annotation_file() -> None:
from examples.load_annotation_from_file import load_annotation

annotation_file = Path(
"./tests/example_files/l4dense_motta_et_al_demo_v2__explorational.zip"
).resolve()

with tmp_cwd():
load_annotation(annotation_file)