Skip to content

Commit ab635e2

Browse files
[wk-libs] Skeleton: allow comparison of graphs and other types, fix node-order for equality check (#593)
* allow comparison of graphs and other types, fix node-order for equality check * remove unused import * remove temp test line * add changelog entry * add testcase from bugreport * Update webknossos/tests/test_skeleton.py Co-authored-by: Philipp Otto <[email protected]> * add explaining comment for node order * formatting Co-authored-by: Philipp Otto <[email protected]>
1 parent a984fa7 commit ab635e2

File tree

5 files changed

+64
-11
lines changed

5 files changed

+64
-11
lines changed

webknossos/Changelog.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@ For upgrade instructions, please check the respective *Breaking Changes* section
1616
### Changed
1717

1818
### Fixed
19-
19+
- Skeleton: Fixed a bug when comparing `Graph` instances, this fixes failing loads which had the error message `Can only compare wk.Graph to another wk.Graph.` before. [#593](https://github.com/scalableminds/webknossos-libs/pull/593)
2020

2121
## [0.9.4](https://github.com/scalableminds/webknossos-libs/releases/tag/v0.9.4) - 2022-02-09
2222
[Commits](https://github.com/scalableminds/webknossos-libs/compare/v0.9.3...v0.9.4)
2323

2424
### Added
25-
- Added AnnotationInfo, Project and Task classes for handling annotation information and annotation project administration. [#574](https://github.com/scalableminds/webknossos-libs/pull/574):
25+
- Added AnnotationInfo, Project and Task classes for handling annotation information and annotation project administration. [#574](https://github.com/scalableminds/webknossos-libs/pull/574)
2626

2727
### Changed
2828
- Lifted the restriction that `BoundingBox` cannot have a negative topleft (introduced in v0.9.0). Also, negative size dimensions are flipped, so that the topleft <= bottomright,
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<things>
2+
<parameters>
3+
<experiment name="ds_name" organization="orga" description="" />
4+
<scale x="4.0" y="4.0" z="35.0" />
5+
<offset x="0" y="0" z="0" />
6+
<time ms="1644425515615" />
7+
<editPosition x="199480" y="199906" z="3593" />
8+
<editRotation xRot="0.0" yRot="0.0" zRot="0.0" />
9+
<zoomLevel zoom="2.0" />
10+
<activeNode id="3" />
11+
</parameters>
12+
<thing id="3" color.r="0.8509804010391235" color.g="0.5215686559677124" color.b="0.07058823853731155" color.a="1.0" name="003" groupId="2">
13+
<nodes>
14+
<node id="3" radius="1.0" x="199480" y="199906" z="3593" rotX="0.0" rotY="0.0" rotZ="0.0" inVp="0" inMag="1" bitDepth="8" interpolation="true" time="1644425546725" />
15+
</nodes>
16+
<edges />
17+
</thing>
18+
<thing id="2" color.r="0.0" color.g="0.0" color.b="1.0" color.a="1.0" name="002" groupId="2">
19+
<nodes>
20+
<node id="2" radius="1.0" x="199355" y="199679" z="3593" rotX="0.0" rotY="0.0" rotZ="0.0" inVp="0" inMag="1" bitDepth="8" interpolation="true" time="1644425544361" />
21+
</nodes>
22+
<edges />
23+
</thing>
24+
<thing id="1" color.r="0.6784313917160034" color.g="0.1411764770746231" color.b="0.05098039284348488" color.a="1.0" name="001">
25+
<nodes>
26+
<node id="1" radius="1.0" x="199196" y="199290" z="3593" rotX="0.0" rotY="0.0" rotZ="0.0" inVp="0" inMag="1" bitDepth="8" interpolation="true" time="1644425520594" />
27+
</nodes>
28+
<edges />
29+
</thing>
30+
<branchpoints />
31+
<comments />
32+
<groups>
33+
<group name="Group 1" id="1">
34+
<group name="Group 2" id="2" />
35+
</group>
36+
</groups>
37+
</things>

webknossos/tests/test_skeleton.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,16 @@ def test_export_to_nml(tmp_path: Path) -> None:
131131
diff_files(output_path, snapshot_path)
132132

133133

134+
def test_import_from_nml() -> None:
135+
nml = create_dummy_skeleton()
136+
snapshot_path = TESTDATA_DIR / "nmls" / "generated_snapshot.nml"
137+
loaded_nml = wk.Skeleton.load(snapshot_path)
138+
139+
assert (
140+
nml == loaded_nml
141+
), "NML created by create_dummy_skeleton() should equal NML loaded from disk."
142+
143+
134144
def test_simple_initialization_and_representations(tmp_path: Path) -> None:
135145
nml = wk.Skeleton(name="my_skeleton", scale=(0.5, 0.5, 0.5), time=12345)
136146
nml_path = tmp_path / "my_skeleton.nml"
@@ -248,3 +258,11 @@ def test_volume_dump_round_trip(tmp_path: Path) -> None:
248258
volume_out = __parse_volume(next(tree.iter()))
249259

250260
assert volume_in == volume_out
261+
262+
263+
def test_load_nml(tmp_path: Path) -> None:
264+
input_path = TESTDATA_DIR / "nmls" / "test_a.nml"
265+
output_path = tmp_path / "test_a.nml"
266+
skeleton_a = wk.Skeleton.load(input_path)
267+
skeleton_a.save(output_path)
268+
assert skeleton_a == wk.Skeleton.load(output_path)

webknossos/webknossos/skeleton/graph.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from collections.abc import MutableMapping
2-
from typing import TYPE_CHECKING, Any, Dict, Iterator, Optional, Tuple, Union, cast
2+
from typing import TYPE_CHECKING, Any, Dict, Iterator, Optional, Tuple, Union
33

44
import networkx as nx
55
import numpy as np
@@ -144,12 +144,8 @@ def __to_tuple_for_comparison(self) -> Tuple:
144144
)
145145

146146
def __eq__(self, o: object) -> bool:
147-
assert isinstance(
148-
o, type(self)
149-
), "Can only compare wk.Graph to another wk.Graph."
150-
return (
151-
self.__to_tuple_for_comparison()
152-
== cast("Graph", o).__to_tuple_for_comparison()
147+
return isinstance(o, Graph) and (
148+
self.__to_tuple_for_comparison() == o.__to_tuple_for_comparison()
153149
)
154150

155151
@property

webknossos/webknossos/skeleton/node.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@
88
Vector3 = Tuple[float, float, float]
99

1010

11-
@attr.define()
11+
# Defining an order on nodes is necessary to allow to sort them,
12+
# which is used in the graph's equality check, see Graph.__eq__().
13+
@attr.define(order=True)
1214
class Node:
1315
position: Vector3
14-
_skeleton: "Skeleton" = attr.ib(eq=False, repr=False)
16+
_skeleton: "Skeleton" = attr.ib(eq=False, repr=False, order=False)
1517
_id: int = attr.ib(init=False)
1618
comment: Optional[str] = None
1719
radius: Optional[float] = None

0 commit comments

Comments
 (0)