Skip to content

Commit b44cc0d

Browse files
authored
Merge pull request #3 from rchristie/fix-alignment
Improve segment automatic alignment
2 parents 18fcac0 + ef7c059 commit b44cc0d

8 files changed

Lines changed: 1357 additions & 514 deletions

File tree

src/segmentationstitcher/annotation.py

Lines changed: 97 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
from cmlibs.utils.zinc.field import get_group_list
66
from cmlibs.utils.zinc.group import group_get_highest_dimension, groups_have_same_local_contents
77
from cmlibs.zinc.field import Field
8+
import logging
9+
10+
11+
logger = logging.getLogger(__name__)
812

913

1014
class AnnotationCategory(Enum):
@@ -24,9 +28,18 @@ def get_group_name(self):
2428
"""
2529
return '.' + self.name
2630

31+
def get_lower_name(self):
32+
"""
33+
:return: Lower case category name.
34+
"""
35+
return self.name.lower()
36+
2737
def is_connectable(self):
2838
return self in (self.INDEPENDENT_NETWORK, self.NETWORK_GROUP_1, self.NETWORK_GROUP_2)
2939

40+
def is_connectable_different_annotation(self):
41+
return self.is_connectable() and not (self == self.INDEPENDENT_NETWORK)
42+
3043

3144
class Annotation:
3245
"""
@@ -56,8 +69,8 @@ def decode_settings(self, settings_in: dict):
5669
assert (settings_in.get("name") == self._name) and (settings_in.get("term") == self._term)
5770
settings_dimension = settings_in.get("dimension")
5871
if settings_dimension != self._dimension:
59-
print("WARNING: Segmentation Stitcher. Annotation with name", self._name, "term", self._term,
60-
"was dimension ", settings_dimension, "in settings, is now ", self._dimension,
72+
logger.warning("Segmentation Stitcher. Annotation with name " + self._name, " term " + str(self._term) +
73+
" was dimension " + str(settings_dimension), "in settings, is now " + str(self._dimension) +
6174
". Have input files changed?")
6275
settings_in["dimension"] = self._dimension
6376
# update current settings to gain new ones and override old ones
@@ -125,6 +138,31 @@ def set_term(self, term):
125138
assert self._term is None
126139
self._term = term
127140

141+
def clear_term(self):
142+
"""
143+
Clear term to None, call in cases of mismatched terms for the same group name.
144+
"""
145+
self._term = None
146+
147+
def is_connectable(self):
148+
"""
149+
:return: True if annotation's category is connectable.
150+
"""
151+
return self._category.is_connectable()
152+
153+
def is_connectable_with(self, other_annotation):
154+
"""
155+
Query whether ends annotated with self and other_annotation can be connected.
156+
:param other_annotation: Another Annotation object.
157+
:return: True if self and other_annotation are allowed to be connected by a link.
158+
"""
159+
if self._category.is_connectable() and (self._category == other_annotation.get_category()):
160+
if other_annotation is self:
161+
return True
162+
elif self._category.is_connectable_different_annotation():
163+
return True
164+
return False
165+
128166

129167
def region_get_annotations(region, network_group1_keywords, network_group2_keywords, term_keywords):
130168
"""
@@ -146,6 +184,17 @@ def region_get_annotations(region, network_group1_keywords, network_group2_keywo
146184
annotations = []
147185
term_annotations = []
148186
datapoints = fieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_DATAPOINTS)
187+
# these terms have had slight mismatches with contents of url group, so explicitly matching:
188+
segment_name = region.getParent().getName()
189+
known_terms = {
190+
"epineurium": "http://uri.interlex.org/base/ilx_0103892",
191+
"left cervical vagus nerve": "http://uri.interlex.org/base/ilx_0794142",
192+
"right cervical vagus nerve": "http://uri.interlex.org/base/ilx_0794141",
193+
"left thoracic vagus nerve": "http://uri.interlex.org/base/ilx_0787543",
194+
"right thoracic vagus nerve": "http://uri.interlex.org/base/ilx_0786664",
195+
"left vagus x nerve trunk": "http://uri.interlex.org/base/ilx_0736691",
196+
"right vagus x nerve trunk": "http://uri.interlex.org/base/ilx_0730515"
197+
}
149198
for group in groups:
150199
# clean up name to remove case and leading/trailing whitespace
151200
name = group.getName().strip()
@@ -159,7 +208,9 @@ def region_get_annotations(region, network_group1_keywords, network_group2_keywo
159208
continue # empty group
160209
if lower_name.isdigit():
161210
continue # ignore as these can never be valid annotation names
162-
category = AnnotationCategory.GENERAL
211+
if '<property name=' in lower_name:
212+
continue # don't want these groups output by mbfxml2ex
213+
category = AnnotationCategory.EXCLUDE if ('_' in lower_name) else AnnotationCategory.GENERAL
163214
for keyword in network_group1_keywords:
164215
if keyword in lower_name:
165216
category = AnnotationCategory.NETWORK_GROUP_1
@@ -169,9 +220,10 @@ def region_get_annotations(region, network_group1_keywords, network_group2_keywo
169220
if keyword in lower_name:
170221
category = AnnotationCategory.NETWORK_GROUP_2
171222
break
172-
annotation = Annotation(name, None, dimension, category)
223+
term = known_terms.get(lower_name)
224+
annotation = Annotation(name, term, dimension, category)
173225
is_term = False
174-
if category == AnnotationCategory.GENERAL:
226+
if category in (AnnotationCategory.GENERAL, AnnotationCategory.EXCLUDE):
175227
for keyword in term_keywords:
176228
if keyword in lower_name:
177229
is_term = True
@@ -180,23 +232,55 @@ def region_get_annotations(region, network_group1_keywords, network_group2_keywo
180232
term_annotations.append(annotation)
181233
else:
182234
annotations.append(annotation)
235+
236+
# sort annotations to have networks first, then general, lastly EXCLUDE to associate terms with earlier ones first
237+
ordered_categories = (
238+
AnnotationCategory.NETWORK_GROUP_1,
239+
AnnotationCategory.NETWORK_GROUP_2,
240+
AnnotationCategory.INDEPENDENT_NETWORK,
241+
AnnotationCategory.GENERAL,
242+
AnnotationCategory.EXCLUDE)
243+
assert len(ordered_categories) == len(AnnotationCategory) # in case new categories added, expand the above
244+
sorted_annotations = []
245+
for category in ordered_categories:
246+
for annotation in annotations:
247+
if annotation.get_category() == category:
248+
sorted_annotations.append(annotation)
249+
183250
for term_annotation in term_annotations:
184251
term = term_annotation.get_name()
185252
term_group = fieldmodule.findFieldByName(term).castGroup()
186253
dimension = term_annotation.get_dimension()
187-
for annotation in annotations:
188-
if annotation.get_term() is not None:
189-
continue
254+
term_matched = False
255+
for annotation in sorted_annotations:
190256
if annotation.get_dimension() != dimension:
191257
continue
258+
if annotation.get_category() == AnnotationCategory.EXCLUDE:
259+
continue
192260
name = annotation.get_name()
193261
name_group = fieldmodule.findFieldByName(name).castGroup()
194262
if groups_have_same_local_contents(name_group, term_group):
195-
annotation.set_term(term)
196-
break
197-
else:
198-
print("WARNING: Segmentation Stitcher. Did not find matching annotation name for term", term,
199-
". Adding separate annotation.")
263+
old_term = annotation.get_term()
264+
if old_term:
265+
if old_term != term:
266+
logger.warning("Segment " + segment_name + ": " +
267+
"Annotation name " + name + " already has term " + old_term +
268+
" but matched group with term " + term + ". Keeping original term.")
269+
else:
270+
# logger.info("Segment " + segment_name + ": " + "Annotation name " + name +
271+
# " discovered term " + term + ".")
272+
annotation.set_term(term)
273+
term_matched = True
274+
# do not break to allow all groups with matching contents to get the term
275+
else:
276+
known_term = known_terms.get(name.lower())
277+
if known_term == term:
278+
logger.warning("Segment " + segment_name + ": " +
279+
"Known annotation name " + name + " and term " + term + " groups differ. Using name group.")
280+
term_matched = True
281+
if not term_matched:
282+
logger.warning("Segment " + segment_name + ": " +
283+
". Did not find matching annotation name for term " + term + ". Adding separate annotation.")
200284
term_annotation.set_term(term)
201285
index = 0
202286
for annotation in annotations:

0 commit comments

Comments
 (0)