siibra 1.0a19__py3-none-any.whl → 1.0.1a1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of siibra might be problematic. Click here for more details.
- siibra/VERSION +1 -1
- siibra/__init__.py +7 -7
- siibra/commons.py +8 -53
- siibra/configuration/__init__.py +1 -1
- siibra/configuration/configuration.py +1 -1
- siibra/configuration/factory.py +11 -21
- siibra/core/__init__.py +1 -1
- siibra/core/assignment.py +1 -1
- siibra/core/atlas.py +21 -15
- siibra/core/concept.py +3 -3
- siibra/core/parcellation.py +69 -54
- siibra/core/region.py +178 -158
- siibra/core/space.py +1 -1
- siibra/core/structure.py +2 -2
- siibra/exceptions.py +13 -1
- siibra/experimental/__init__.py +1 -1
- siibra/experimental/contour.py +8 -8
- siibra/experimental/cortical_profile_sampler.py +1 -1
- siibra/experimental/patch.py +3 -3
- siibra/experimental/plane3d.py +12 -12
- siibra/explorer/__init__.py +1 -1
- siibra/explorer/url.py +2 -2
- siibra/explorer/util.py +1 -1
- siibra/features/__init__.py +1 -1
- siibra/features/anchor.py +14 -15
- siibra/features/connectivity/__init__.py +1 -1
- siibra/features/connectivity/functional_connectivity.py +1 -1
- siibra/features/connectivity/regional_connectivity.py +4 -4
- siibra/features/connectivity/streamline_counts.py +1 -1
- siibra/features/connectivity/streamline_lengths.py +1 -1
- siibra/features/connectivity/tracing_connectivity.py +1 -1
- siibra/features/dataset/__init__.py +1 -1
- siibra/features/dataset/ebrains.py +1 -1
- siibra/features/feature.py +24 -26
- siibra/features/image/__init__.py +1 -1
- siibra/features/image/image.py +2 -2
- siibra/features/image/sections.py +1 -1
- siibra/features/image/volume_of_interest.py +1 -1
- siibra/features/tabular/__init__.py +1 -1
- siibra/features/tabular/bigbrain_intensity_profile.py +2 -2
- siibra/features/tabular/cell_density_profile.py +98 -64
- siibra/features/tabular/cortical_profile.py +3 -3
- siibra/features/tabular/gene_expression.py +1 -1
- siibra/features/tabular/layerwise_bigbrain_intensities.py +1 -1
- siibra/features/tabular/layerwise_cell_density.py +4 -23
- siibra/features/tabular/receptor_density_fingerprint.py +13 -10
- siibra/features/tabular/receptor_density_profile.py +1 -1
- siibra/features/tabular/regional_timeseries_activity.py +4 -4
- siibra/features/tabular/tabular.py +7 -5
- siibra/livequeries/__init__.py +1 -1
- siibra/livequeries/allen.py +42 -19
- siibra/livequeries/bigbrain.py +21 -12
- siibra/livequeries/ebrains.py +1 -1
- siibra/livequeries/query.py +2 -3
- siibra/locations/__init__.py +11 -11
- siibra/locations/boundingbox.py +30 -29
- siibra/locations/location.py +1 -1
- siibra/locations/point.py +7 -7
- siibra/locations/{pointset.py → pointcloud.py} +36 -33
- siibra/retrieval/__init__.py +1 -1
- siibra/retrieval/cache.py +1 -1
- siibra/retrieval/datasets.py +4 -4
- siibra/retrieval/exceptions/__init__.py +1 -1
- siibra/retrieval/repositories.py +13 -30
- siibra/retrieval/requests.py +25 -8
- siibra/vocabularies/__init__.py +1 -1
- siibra/volumes/__init__.py +2 -2
- siibra/volumes/parcellationmap.py +119 -91
- siibra/volumes/providers/__init__.py +1 -1
- siibra/volumes/providers/freesurfer.py +3 -3
- siibra/volumes/providers/gifti.py +1 -1
- siibra/volumes/providers/neuroglancer.py +67 -41
- siibra/volumes/providers/nifti.py +12 -26
- siibra/volumes/providers/provider.py +1 -1
- siibra/volumes/sparsemap.py +125 -246
- siibra/volumes/volume.py +150 -61
- {siibra-1.0a19.dist-info → siibra-1.0.1a1.dist-info}/METADATA +26 -4
- siibra-1.0.1a1.dist-info/RECORD +84 -0
- {siibra-1.0a19.dist-info → siibra-1.0.1a1.dist-info}/WHEEL +1 -1
- siibra-1.0a19.dist-info/RECORD +0 -84
- {siibra-1.0a19.dist-info → siibra-1.0.1a1.dist-info}/LICENSE +0 -0
- {siibra-1.0a19.dist-info → siibra-1.0.1a1.dist-info}/top_level.txt +0 -0
siibra/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.
|
|
1
|
+
1.0.1-alpha.1
|
siibra/__init__.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright 2018-
|
|
1
|
+
# Copyright 2018-2025
|
|
2
2
|
# Institute of Neuroscience and Medicine (INM-1), Forschungszentrum Jülich GmbH
|
|
3
3
|
|
|
4
4
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -39,7 +39,7 @@ from . import configuration
|
|
|
39
39
|
from . import experimental
|
|
40
40
|
from .configuration import factory
|
|
41
41
|
from . import features, livequeries
|
|
42
|
-
from siibra.locations import Point,
|
|
42
|
+
from siibra.locations import Point, PointCloud
|
|
43
43
|
|
|
44
44
|
import os as _os
|
|
45
45
|
logger.info(f"Version: {__version__}")
|
|
@@ -51,7 +51,7 @@ logger.info(
|
|
|
51
51
|
# forward access to some functions
|
|
52
52
|
set_ebrains_token = _EbrainsRequest.set_token
|
|
53
53
|
fetch_ebrains_token = _EbrainsRequest.fetch_token
|
|
54
|
-
find_regions = _parcellation.
|
|
54
|
+
find_regions = _parcellation.find_regions
|
|
55
55
|
from_json = factory.Factory.from_json
|
|
56
56
|
|
|
57
57
|
|
|
@@ -108,7 +108,7 @@ def set_feasible_download_size(maxsize_gbyte):
|
|
|
108
108
|
|
|
109
109
|
def set_cache_size(maxsize_gbyte: int):
|
|
110
110
|
"""
|
|
111
|
-
siibra runs
|
|
111
|
+
siibra runs maintenance on its local cache to keep it under a predetermined
|
|
112
112
|
size of 2 gigabytes. This method changes the cache size.
|
|
113
113
|
|
|
114
114
|
Parameters
|
|
@@ -129,9 +129,9 @@ def warm_cache(level=WarmupLevel.INSTANCE):
|
|
|
129
129
|
Preload preconfigured siibra concepts.
|
|
130
130
|
|
|
131
131
|
Siibra relies on preconfigurations that simplify integrating various
|
|
132
|
-
concepts such as parcellations,
|
|
132
|
+
concepts such as parcellations, reference spaces, and multimodal data
|
|
133
133
|
features. By preloading the instances, siibra commits all preconfigurations
|
|
134
|
-
to the memory at once instead of
|
|
134
|
+
to the memory at once instead of committing them when required.
|
|
135
135
|
"""
|
|
136
136
|
Warmup.warmup(level)
|
|
137
137
|
|
|
@@ -150,7 +150,7 @@ def __dir__():
|
|
|
150
150
|
"get_template",
|
|
151
151
|
"MapType",
|
|
152
152
|
"Point",
|
|
153
|
-
"
|
|
153
|
+
"PointCloud",
|
|
154
154
|
"QUIET",
|
|
155
155
|
"VERBOSE",
|
|
156
156
|
"fetch_ebrains_token",
|
siibra/commons.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright 2018-
|
|
1
|
+
# Copyright 2018-2025
|
|
2
2
|
# Institute of Neuroscience and Medicine (INM-1), Forschungszentrum Jülich GmbH
|
|
3
3
|
|
|
4
4
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -139,7 +139,7 @@ class InstanceTable(Generic[T], Iterable):
|
|
|
139
139
|
return (w for w in self._elements.values())
|
|
140
140
|
|
|
141
141
|
def __contains__(self, key: Union[str, T]) -> bool:
|
|
142
|
-
"""Test
|
|
142
|
+
"""Test whether the given key or element is defined by the registry."""
|
|
143
143
|
if isinstance(key, str):
|
|
144
144
|
return key in self._elements
|
|
145
145
|
return key in [item for _, item in self._elements.values()]
|
|
@@ -366,9 +366,6 @@ class MapType(Enum):
|
|
|
366
366
|
STATISTICAL = 2
|
|
367
367
|
|
|
368
368
|
|
|
369
|
-
SIIBRA_DEFAULT_MAPTYPE = MapType.LABELLED
|
|
370
|
-
SIIBRA_DEFAULT_MAP_THRESHOLD = 0.0
|
|
371
|
-
|
|
372
369
|
REMOVE_FROM_NAME = [
|
|
373
370
|
"hemisphere",
|
|
374
371
|
" -",
|
|
@@ -539,7 +536,8 @@ def resample_img_to_img(
|
|
|
539
536
|
resampled_img = resample_to_img(
|
|
540
537
|
source_img=source_img,
|
|
541
538
|
target_img=target_img,
|
|
542
|
-
interpolation=interpolation
|
|
539
|
+
interpolation=interpolation,
|
|
540
|
+
force_resample=True, # False is intended for testing. see nilearn docs
|
|
543
541
|
)
|
|
544
542
|
return resampled_img
|
|
545
543
|
|
|
@@ -557,7 +555,7 @@ def connected_components(
|
|
|
557
555
|
|
|
558
556
|
Note
|
|
559
557
|
----
|
|
560
|
-
`Uses skimage.measure.label()` to determine foreground
|
|
558
|
+
`Uses skimage.measure.label()` to determine foreground components.
|
|
561
559
|
|
|
562
560
|
Parameters
|
|
563
561
|
----------
|
|
@@ -571,7 +569,7 @@ def connected_components(
|
|
|
571
569
|
Yields
|
|
572
570
|
------
|
|
573
571
|
Generator[Tuple[int, np.ndarray], None, None]
|
|
574
|
-
tuple of integer label of the component and component as an
|
|
572
|
+
tuple of integer label of the component and component as an ndarray in
|
|
575
573
|
the shape of the original image.
|
|
576
574
|
"""
|
|
577
575
|
from skimage import measure
|
|
@@ -586,49 +584,6 @@ def connected_components(
|
|
|
586
584
|
)
|
|
587
585
|
|
|
588
586
|
|
|
589
|
-
class PolyLine:
|
|
590
|
-
"""Simple polyline representation which allows equidistant sampling.."""
|
|
591
|
-
|
|
592
|
-
def __init__(self, pts):
|
|
593
|
-
self.pts = pts
|
|
594
|
-
self.lengths = [
|
|
595
|
-
np.sqrt(np.sum((pts[i, :] - pts[i - 1, :]) ** 2))
|
|
596
|
-
for i in range(1, pts.shape[0])
|
|
597
|
-
]
|
|
598
|
-
|
|
599
|
-
def length(self):
|
|
600
|
-
return sum(self.lengths)
|
|
601
|
-
|
|
602
|
-
def sample(self, d):
|
|
603
|
-
|
|
604
|
-
# if d is interable, we assume a list of sample positions
|
|
605
|
-
try:
|
|
606
|
-
iter(d)
|
|
607
|
-
except TypeError:
|
|
608
|
-
positions = [d]
|
|
609
|
-
else:
|
|
610
|
-
positions = d
|
|
611
|
-
|
|
612
|
-
samples = []
|
|
613
|
-
for s_ in positions:
|
|
614
|
-
s = min(max(s_, 0), 1)
|
|
615
|
-
target_distance = s * self.length()
|
|
616
|
-
current_distance = 0
|
|
617
|
-
for i, length in enumerate(self.lengths):
|
|
618
|
-
current_distance += length
|
|
619
|
-
if current_distance >= target_distance:
|
|
620
|
-
p1 = self.pts[i, :]
|
|
621
|
-
p2 = self.pts[i + 1, :]
|
|
622
|
-
r = (target_distance - current_distance + length) / length
|
|
623
|
-
samples.append(p1 + (p2 - p1) * r)
|
|
624
|
-
break
|
|
625
|
-
|
|
626
|
-
if len(samples) == 1:
|
|
627
|
-
return samples[0]
|
|
628
|
-
else:
|
|
629
|
-
return np.array(samples)
|
|
630
|
-
|
|
631
|
-
|
|
632
587
|
def unify_stringlist(L: list):
|
|
633
588
|
"""Adds asterisks to strings that appear multiple times, so the resulting
|
|
634
589
|
list has only unique strings but still the same length, order, and meaning.
|
|
@@ -690,11 +645,11 @@ def MI(arr1, arr2, nbins=100, normalized=True):
|
|
|
690
645
|
assert (all(arr.size > 0) for arr in [arr1, arr2])
|
|
691
646
|
|
|
692
647
|
# compute the normalized joint 2D histogram as an
|
|
693
|
-
# empirical measure of the joint
|
|
648
|
+
# empirical measure of the joint probability of arr1 and arr2
|
|
694
649
|
pxy, _, _ = np.histogram2d(arr1.ravel(), arr2.ravel(), bins=nbins)
|
|
695
650
|
pxy /= pxy.sum()
|
|
696
651
|
|
|
697
|
-
# extract the empirical
|
|
652
|
+
# extract the empirical probabilities of intensities
|
|
698
653
|
# from the joint histogram
|
|
699
654
|
px = np.sum(pxy, axis=1) # marginal for x over y
|
|
700
655
|
py = np.sum(pxy, axis=0) # marginal for y over x
|
siibra/configuration/__init__.py
CHANGED
siibra/configuration/factory.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright 2018-
|
|
1
|
+
# Copyright 2018-2025
|
|
2
2
|
# Institute of Neuroscience and Medicine (INM-1), Forschungszentrum Jülich GmbH
|
|
3
3
|
|
|
4
4
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -24,7 +24,7 @@ from ..features.tabular import (
|
|
|
24
24
|
)
|
|
25
25
|
from ..features.image import sections, volume_of_interest
|
|
26
26
|
from ..core import atlas, parcellation, space, region
|
|
27
|
-
from ..locations import point,
|
|
27
|
+
from ..locations import point, pointcloud, boundingbox
|
|
28
28
|
from ..retrieval import datasets, repositories
|
|
29
29
|
from ..volumes import volume, sparsemap, parcellationmap
|
|
30
30
|
from ..volumes.providers.provider import VolumeProvider
|
|
@@ -302,25 +302,18 @@ class Factory:
|
|
|
302
302
|
@build_type("siibra/map/v0.0.1")
|
|
303
303
|
def build_map(cls, spec):
|
|
304
304
|
# maps have no configured identifier - we require the spec filename to build one
|
|
305
|
-
|
|
306
|
-
basename = path.splitext(path.basename(spec["filename"]))[0]
|
|
307
|
-
name = (
|
|
308
|
-
basename.replace("-", " ")
|
|
309
|
-
.replace("_", " ")
|
|
310
|
-
.replace("continuous", "statistical")
|
|
311
|
-
)
|
|
312
|
-
identifier = f"{spec['@type'].replace('/', '-')}_{basename}"
|
|
305
|
+
identifier = spec.get("@id")
|
|
313
306
|
volumes = cls.extract_volumes(
|
|
314
|
-
spec, space_id=spec["space"].get("@id"), name_prefix=
|
|
307
|
+
spec, space_id=spec["space"].get("@id"), name_prefix=identifier
|
|
315
308
|
)
|
|
316
309
|
|
|
317
|
-
if spec.get("
|
|
310
|
+
if spec.get("represented_as_sparsemap", False):
|
|
318
311
|
Maptype = sparsemap.SparseMap
|
|
319
312
|
else:
|
|
320
313
|
Maptype = parcellationmap.Map
|
|
321
314
|
return Maptype(
|
|
322
|
-
identifier=
|
|
323
|
-
name=spec.get("name"
|
|
315
|
+
identifier=identifier,
|
|
316
|
+
name=spec.get("name"),
|
|
324
317
|
space_spec=spec.get("space", {}),
|
|
325
318
|
parcellation_spec=spec.get("parcellation", {}),
|
|
326
319
|
indices=spec.get("indices", {}),
|
|
@@ -363,18 +356,18 @@ class Factory:
|
|
|
363
356
|
|
|
364
357
|
@classmethod
|
|
365
358
|
@build_type("tmp/poly")
|
|
366
|
-
@build_type("siibra/location/
|
|
367
|
-
def
|
|
359
|
+
@build_type("siibra/location/pointcloud/v0.1")
|
|
360
|
+
def build_pointcloud(cls, spec):
|
|
368
361
|
if spec.get("@type") == "tmp/poly":
|
|
369
362
|
space_id = spec["coordinateSpace"]["@id"]
|
|
370
363
|
coords = []
|
|
371
364
|
for coord in spec["coordinates"]:
|
|
372
365
|
assert all(c["unit"]["@id"] == "id.link/mm" for c in coord)
|
|
373
366
|
coords.append(list(np.float16(c["value"]) for c in coord))
|
|
374
|
-
elif spec.get("@type") == "siibra/location/
|
|
367
|
+
elif spec.get("@type") == "siibra/location/pointcloud/v0.1":
|
|
375
368
|
space_id = spec.get("space").get("@id")
|
|
376
369
|
coords = [tuple(c) for c in spec.get("coordinates")]
|
|
377
|
-
return
|
|
370
|
+
return pointcloud.PointCloud(coords, space=space_id)
|
|
378
371
|
|
|
379
372
|
@classmethod
|
|
380
373
|
@build_type("siibra/location/boundingbox/v0.1")
|
|
@@ -584,11 +577,8 @@ class Factory:
|
|
|
584
577
|
|
|
585
578
|
if isinstance(spec, str):
|
|
586
579
|
if path.isfile(spec):
|
|
587
|
-
fname = spec
|
|
588
580
|
with open(spec, "r") as f:
|
|
589
581
|
spec = json.load(f)
|
|
590
|
-
assert "filename" not in spec
|
|
591
|
-
spec["filename"] = fname
|
|
592
582
|
else:
|
|
593
583
|
spec = json.loads(spec)
|
|
594
584
|
|
siibra/core/__init__.py
CHANGED
siibra/core/assignment.py
CHANGED
siibra/core/atlas.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright 2018-
|
|
1
|
+
# Copyright 2018-2025
|
|
2
2
|
# Institute of Neuroscience and Medicine (INM-1), Forschungszentrum Jülich GmbH
|
|
3
3
|
|
|
4
4
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -197,27 +197,29 @@ class Atlas(concept.AtlasConcept, configuration_folder="atlases"):
|
|
|
197
197
|
|
|
198
198
|
def find_regions(
|
|
199
199
|
self,
|
|
200
|
-
regionspec,
|
|
201
|
-
all_versions=False,
|
|
202
|
-
filter_children=True,
|
|
203
|
-
|
|
200
|
+
regionspec: str,
|
|
201
|
+
all_versions: bool = False,
|
|
202
|
+
filter_children: bool = True,
|
|
203
|
+
find_topmost: bool = False
|
|
204
204
|
):
|
|
205
205
|
"""
|
|
206
|
-
Find regions with the given specification in all
|
|
207
|
-
|
|
208
|
-
are passed on to Parcellation.find().
|
|
206
|
+
Find regions with the given specification in all parcellations offered
|
|
207
|
+
by the atlas.
|
|
209
208
|
|
|
210
209
|
Parameters
|
|
211
210
|
----------
|
|
212
|
-
regionspec: str, regex
|
|
211
|
+
regionspec: str, regex
|
|
213
212
|
- a string with a possibly inexact name (matched both against the name and the identifier key)
|
|
214
213
|
- a string in '/pattern/flags' format to use regex search (acceptable flags: aiLmsux, see at https://docs.python.org/3/library/re.html#flags)
|
|
215
214
|
- a regex applied to region names
|
|
216
|
-
- a Region object
|
|
217
215
|
all_versions : Bool, default: False
|
|
218
216
|
If True, matched regions for all versions of a parcellation are returned.
|
|
219
217
|
filter_children : bool, default: True
|
|
220
218
|
If False, children of matched parents will be returned.
|
|
219
|
+
find_topmost : bool, default: False
|
|
220
|
+
If True (requires `filter_children=True`), will return parent
|
|
221
|
+
structures if all children are matched, even though the parent
|
|
222
|
+
itself might not match the specification.
|
|
221
223
|
|
|
222
224
|
Returns
|
|
223
225
|
-------
|
|
@@ -225,9 +227,13 @@ class Atlas(concept.AtlasConcept, configuration_folder="atlases"):
|
|
|
225
227
|
list of regions matching to the regionspec
|
|
226
228
|
"""
|
|
227
229
|
result = []
|
|
228
|
-
for p in self.
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
230
|
+
for p in self.parcellations:
|
|
231
|
+
if p.is_newest_version or all_versions:
|
|
232
|
+
result.extend(
|
|
233
|
+
p.find(
|
|
234
|
+
regionspec=regionspec,
|
|
235
|
+
filter_children=filter_children,
|
|
236
|
+
find_topmost=find_topmost
|
|
237
|
+
)
|
|
238
|
+
)
|
|
233
239
|
return result
|
siibra/core/concept.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright 2018-
|
|
1
|
+
# Copyright 2018-2025
|
|
2
2
|
# Institute of Neuroscience and Medicine (INM-1), Forschungszentrum Jülich GmbH
|
|
3
3
|
|
|
4
4
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -145,9 +145,9 @@ class AtlasConcept:
|
|
|
145
145
|
@property
|
|
146
146
|
def authors(self):
|
|
147
147
|
return [
|
|
148
|
-
|
|
148
|
+
contributor['name']
|
|
149
149
|
for ds in self.datasets
|
|
150
|
-
for
|
|
150
|
+
for contributor in ds.contributors
|
|
151
151
|
]
|
|
152
152
|
|
|
153
153
|
@property
|
siibra/core/parcellation.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright 2018-
|
|
1
|
+
# Copyright 2018-2025
|
|
2
2
|
# Institute of Neuroscience and Medicine (INM-1), Forschungszentrum Jülich GmbH
|
|
3
3
|
|
|
4
4
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -17,11 +17,21 @@ from . import region
|
|
|
17
17
|
|
|
18
18
|
from ..commons import logger, MapType, Species
|
|
19
19
|
from ..volumes import parcellationmap
|
|
20
|
+
from ..exceptions import MapNotFound
|
|
20
21
|
|
|
21
|
-
from
|
|
22
|
+
from functools import lru_cache
|
|
22
23
|
import re
|
|
24
|
+
from typing import Union, List, TYPE_CHECKING
|
|
25
|
+
try:
|
|
26
|
+
from typing import Literal
|
|
27
|
+
except ImportError:
|
|
28
|
+
# support python 3.7
|
|
29
|
+
from typing_extensions import Literal
|
|
23
30
|
|
|
24
31
|
|
|
32
|
+
if TYPE_CHECKING:
|
|
33
|
+
from .space import Space
|
|
34
|
+
|
|
25
35
|
# NOTE : such code could be used to automatically resolve
|
|
26
36
|
# multiple matching parcellations for a short spec to the newset version:
|
|
27
37
|
# try:
|
|
@@ -68,8 +78,6 @@ class ParcellationVersion:
|
|
|
68
78
|
|
|
69
79
|
class Parcellation(region.Region, configuration_folder="parcellations"):
|
|
70
80
|
|
|
71
|
-
_CACHED_REGION_SEARCHES: Dict[str, List[region.Region]] = {}
|
|
72
|
-
|
|
73
81
|
def __init__(
|
|
74
82
|
self,
|
|
75
83
|
identifier: str,
|
|
@@ -140,7 +148,12 @@ class Parcellation(region.Region, configuration_folder="parcellations"):
|
|
|
140
148
|
self._CACHED_MATCHES[spec] = True
|
|
141
149
|
return super().matches(spec)
|
|
142
150
|
|
|
143
|
-
def get_map(
|
|
151
|
+
def get_map(
|
|
152
|
+
self,
|
|
153
|
+
space: Union[str, "Space"],
|
|
154
|
+
maptype: Union[Literal['labelled', 'statistical'], MapType] = MapType.LABELLED,
|
|
155
|
+
spec: str = ""
|
|
156
|
+
):
|
|
144
157
|
"""
|
|
145
158
|
Get the maps for the parcellation in the requested template space.
|
|
146
159
|
|
|
@@ -153,8 +166,8 @@ class Parcellation(region.Region, configuration_folder="parcellations"):
|
|
|
153
166
|
Parameters
|
|
154
167
|
----------
|
|
155
168
|
space: Space or str
|
|
156
|
-
|
|
157
|
-
maptype: MapType
|
|
169
|
+
reference space specification such as name, id, or a `Space` instance.
|
|
170
|
+
maptype: MapType or str
|
|
158
171
|
Type of map requested (e.g., statistical or labelled).
|
|
159
172
|
Use MapType.STATISTICAL to request probability maps.
|
|
160
173
|
Defaults to MapType.LABELLED.
|
|
@@ -169,26 +182,24 @@ class Parcellation(region.Region, configuration_folder="parcellations"):
|
|
|
169
182
|
A ParcellationMap representing the volumetric map or
|
|
170
183
|
a SparseMap representing the list of statistical maps.
|
|
171
184
|
"""
|
|
172
|
-
if
|
|
185
|
+
if isinstance(maptype, str):
|
|
173
186
|
maptype = MapType[maptype.upper()]
|
|
187
|
+
assert isinstance(maptype, MapType), "Possible values of `maptype` are `MapType`s, 'labelled', 'statistical'."
|
|
174
188
|
|
|
175
189
|
candidates = [
|
|
176
190
|
m for m in parcellationmap.Map.registry()
|
|
177
191
|
if m.space.matches(space)
|
|
178
192
|
and m.maptype == maptype
|
|
179
|
-
and m.parcellation
|
|
180
193
|
and m.parcellation.matches(self)
|
|
181
194
|
]
|
|
182
195
|
if len(candidates) == 0:
|
|
183
|
-
|
|
184
|
-
return None
|
|
196
|
+
raise MapNotFound(f"No '{maptype}' map in '{space}' available for {str(self)}")
|
|
185
197
|
if len(candidates) > 1:
|
|
186
198
|
spec_candidates = [
|
|
187
|
-
c for c in candidates if all(w.lower() in c.
|
|
199
|
+
c for c in candidates if all(w.lower() in c.id.lower() for w in spec.split())
|
|
188
200
|
]
|
|
189
201
|
if len(spec_candidates) == 0:
|
|
190
|
-
|
|
191
|
-
return None
|
|
202
|
+
raise MapNotFound(f"'{spec}' does not match any options from {[c.name for c in candidates]}.")
|
|
192
203
|
if len(spec_candidates) > 1:
|
|
193
204
|
logger.warning(
|
|
194
205
|
f"Multiple maps are available in this specification of space, parcellation, and map type.\n"
|
|
@@ -197,43 +208,6 @@ class Parcellation(region.Region, configuration_folder="parcellations"):
|
|
|
197
208
|
return spec_candidates[0]
|
|
198
209
|
return candidates[0]
|
|
199
210
|
|
|
200
|
-
@staticmethod
|
|
201
|
-
def find_regions(region_spec: str, parents_only=True):
|
|
202
|
-
"""
|
|
203
|
-
Find regions that match the given region specification in the subtree
|
|
204
|
-
headed by each parcellation in the registry.
|
|
205
|
-
Note
|
|
206
|
-
----
|
|
207
|
-
Use Region.find() to search for a region in an instance of a
|
|
208
|
-
parcellation.
|
|
209
|
-
|
|
210
|
-
Parameters
|
|
211
|
-
----------
|
|
212
|
-
regionspec: str
|
|
213
|
-
a string with a possibly inexact name, which is matched both
|
|
214
|
-
against the name and the identifier key,
|
|
215
|
-
parents_only: bool
|
|
216
|
-
If true, children of matched parents will not be returned
|
|
217
|
-
Returns
|
|
218
|
-
-------
|
|
219
|
-
List[Region]
|
|
220
|
-
list of matching regions
|
|
221
|
-
"""
|
|
222
|
-
MEM = Parcellation._CACHED_REGION_SEARCHES
|
|
223
|
-
if region_spec not in MEM:
|
|
224
|
-
MEM[region_spec] = [
|
|
225
|
-
r
|
|
226
|
-
for p in Parcellation.registry()
|
|
227
|
-
for r in p.find(regionspec=region_spec)
|
|
228
|
-
]
|
|
229
|
-
if parents_only:
|
|
230
|
-
return [
|
|
231
|
-
r for r in MEM[region_spec]
|
|
232
|
-
if (r.parent is None) or (r.parent not in MEM[region_spec])
|
|
233
|
-
]
|
|
234
|
-
else:
|
|
235
|
-
return MEM[region_spec]
|
|
236
|
-
|
|
237
211
|
@property
|
|
238
212
|
def is_newest_version(self):
|
|
239
213
|
return (self.version is None) or (self.version.next_id is None)
|
|
@@ -247,7 +221,7 @@ class Parcellation(region.Region, configuration_folder="parcellations"):
|
|
|
247
221
|
"""
|
|
248
222
|
spec = re.sub(r'Group: *', '', spec)
|
|
249
223
|
for substr in re.findall(r'\(.*?\)', spec):
|
|
250
|
-
#
|
|
224
|
+
# temporarily replace commas inside brackets with a placeholder
|
|
251
225
|
# because these are not region spec delimiters
|
|
252
226
|
spec = spec.replace(substr, re.sub(r', *', '##', substr))
|
|
253
227
|
# process the comma separated substrings
|
|
@@ -263,7 +237,7 @@ class Parcellation(region.Region, configuration_folder="parcellations"):
|
|
|
263
237
|
def get_region(
|
|
264
238
|
self,
|
|
265
239
|
regionspec: Union[str, region.Region],
|
|
266
|
-
find_topmost: bool =
|
|
240
|
+
find_topmost: bool = False,
|
|
267
241
|
allow_tuple: bool = False
|
|
268
242
|
):
|
|
269
243
|
"""
|
|
@@ -281,7 +255,7 @@ class Parcellation(region.Region, configuration_folder="parcellations"):
|
|
|
281
255
|
regionspec: str, Region
|
|
282
256
|
- a string with a possibly inexact name (matched both against the name and the identifier key)
|
|
283
257
|
- a Region object
|
|
284
|
-
find_topmost: bool, default:
|
|
258
|
+
find_topmost: bool, default: False
|
|
285
259
|
If True, will automatically return the parent of a decoded region
|
|
286
260
|
the decoded region is its only child.
|
|
287
261
|
allow_tuple: bool, default: False
|
|
@@ -370,3 +344,44 @@ class Parcellation(region.Region, configuration_folder="parcellations"):
|
|
|
370
344
|
)
|
|
371
345
|
return self.name < other.name
|
|
372
346
|
return self.version.__lt__(other.version)
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
@lru_cache(maxsize=128)
|
|
350
|
+
def find_regions(
|
|
351
|
+
regionspec: str,
|
|
352
|
+
filter_children=True,
|
|
353
|
+
find_topmost=False
|
|
354
|
+
):
|
|
355
|
+
"""
|
|
356
|
+
Find regions matching the given region specification across all parcellation
|
|
357
|
+
instances in the registry.
|
|
358
|
+
|
|
359
|
+
Parameters
|
|
360
|
+
----------
|
|
361
|
+
regionspec: str, regex, Region
|
|
362
|
+
- a string with a possibly inexact name (matched both against the name and the identifier key)
|
|
363
|
+
- a string in '/pattern/flags' format to use regex search (acceptable flags: aiLmsux) (see https://docs.python.org/3/library/re.html#flags)
|
|
364
|
+
- a regex applied to region names
|
|
365
|
+
- a Region object
|
|
366
|
+
filter_children : bool, default: True
|
|
367
|
+
If True, children of matched parents will not be returned
|
|
368
|
+
find_topmost : bool, default: False
|
|
369
|
+
If True (requires `filter_children=True`), will return parent
|
|
370
|
+
structures if all children are matched, even though the parent
|
|
371
|
+
itself might not match the specification.
|
|
372
|
+
|
|
373
|
+
Returns
|
|
374
|
+
-------
|
|
375
|
+
list[Region]
|
|
376
|
+
list of regions matching to the regionspec
|
|
377
|
+
"""
|
|
378
|
+
result = []
|
|
379
|
+
for p in Parcellation.registry():
|
|
380
|
+
result.extend(
|
|
381
|
+
p.find(
|
|
382
|
+
regionspec=regionspec,
|
|
383
|
+
filter_children=filter_children,
|
|
384
|
+
find_topmost=find_topmost
|
|
385
|
+
)
|
|
386
|
+
)
|
|
387
|
+
return result
|