siibra 1.0a14__py3-none-any.whl → 1.0.1a0__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.

Files changed (80) hide show
  1. siibra/VERSION +1 -1
  2. siibra/__init__.py +15 -5
  3. siibra/commons.py +3 -48
  4. siibra/configuration/__init__.py +1 -1
  5. siibra/configuration/configuration.py +1 -1
  6. siibra/configuration/factory.py +164 -127
  7. siibra/core/__init__.py +1 -1
  8. siibra/core/assignment.py +1 -1
  9. siibra/core/atlas.py +24 -17
  10. siibra/core/concept.py +18 -9
  11. siibra/core/parcellation.py +76 -55
  12. siibra/core/region.py +163 -183
  13. siibra/core/space.py +3 -1
  14. siibra/core/structure.py +1 -2
  15. siibra/exceptions.py +17 -1
  16. siibra/experimental/contour.py +6 -6
  17. siibra/experimental/patch.py +2 -2
  18. siibra/experimental/plane3d.py +8 -8
  19. siibra/explorer/__init__.py +1 -1
  20. siibra/explorer/url.py +15 -0
  21. siibra/explorer/util.py +1 -1
  22. siibra/features/__init__.py +1 -1
  23. siibra/features/anchor.py +13 -14
  24. siibra/features/connectivity/__init__.py +1 -1
  25. siibra/features/connectivity/functional_connectivity.py +1 -1
  26. siibra/features/connectivity/regional_connectivity.py +7 -5
  27. siibra/features/connectivity/streamline_counts.py +1 -1
  28. siibra/features/connectivity/streamline_lengths.py +1 -1
  29. siibra/features/connectivity/tracing_connectivity.py +1 -1
  30. siibra/features/dataset/__init__.py +1 -1
  31. siibra/features/dataset/ebrains.py +1 -1
  32. siibra/features/feature.py +50 -28
  33. siibra/features/image/__init__.py +1 -1
  34. siibra/features/image/image.py +18 -13
  35. siibra/features/image/sections.py +1 -1
  36. siibra/features/image/volume_of_interest.py +1 -1
  37. siibra/features/tabular/__init__.py +1 -1
  38. siibra/features/tabular/bigbrain_intensity_profile.py +2 -2
  39. siibra/features/tabular/cell_density_profile.py +102 -66
  40. siibra/features/tabular/cortical_profile.py +5 -3
  41. siibra/features/tabular/gene_expression.py +1 -1
  42. siibra/features/tabular/layerwise_bigbrain_intensities.py +1 -1
  43. siibra/features/tabular/layerwise_cell_density.py +8 -25
  44. siibra/features/tabular/receptor_density_fingerprint.py +5 -3
  45. siibra/features/tabular/receptor_density_profile.py +5 -3
  46. siibra/features/tabular/regional_timeseries_activity.py +7 -5
  47. siibra/features/tabular/tabular.py +5 -3
  48. siibra/livequeries/__init__.py +1 -1
  49. siibra/livequeries/allen.py +46 -20
  50. siibra/livequeries/bigbrain.py +9 -9
  51. siibra/livequeries/ebrains.py +1 -1
  52. siibra/livequeries/query.py +1 -2
  53. siibra/locations/__init__.py +10 -10
  54. siibra/locations/boundingbox.py +77 -38
  55. siibra/locations/location.py +12 -4
  56. siibra/locations/point.py +14 -9
  57. siibra/locations/{pointset.py → pointcloud.py} +69 -27
  58. siibra/retrieval/__init__.py +1 -1
  59. siibra/retrieval/cache.py +1 -1
  60. siibra/retrieval/datasets.py +1 -1
  61. siibra/retrieval/exceptions/__init__.py +1 -1
  62. siibra/retrieval/repositories.py +10 -27
  63. siibra/retrieval/requests.py +20 -3
  64. siibra/vocabularies/__init__.py +1 -1
  65. siibra/volumes/__init__.py +2 -2
  66. siibra/volumes/parcellationmap.py +121 -94
  67. siibra/volumes/providers/__init__.py +1 -1
  68. siibra/volumes/providers/freesurfer.py +1 -1
  69. siibra/volumes/providers/gifti.py +1 -1
  70. siibra/volumes/providers/neuroglancer.py +68 -42
  71. siibra/volumes/providers/nifti.py +18 -28
  72. siibra/volumes/providers/provider.py +2 -2
  73. siibra/volumes/sparsemap.py +128 -247
  74. siibra/volumes/volume.py +252 -65
  75. {siibra-1.0a14.dist-info → siibra-1.0.1a0.dist-info}/METADATA +17 -4
  76. siibra-1.0.1a0.dist-info/RECORD +84 -0
  77. {siibra-1.0a14.dist-info → siibra-1.0.1a0.dist-info}/WHEEL +1 -1
  78. siibra-1.0a14.dist-info/RECORD +0 -84
  79. {siibra-1.0a14.dist-info → siibra-1.0.1a0.dist-info}/LICENSE +0 -0
  80. {siibra-1.0a14.dist-info → siibra-1.0.1a0.dist-info}/top_level.txt +0 -0
siibra/core/atlas.py CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright 2018-2021
1
+ # Copyright 2018-2024
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");
@@ -30,14 +30,15 @@ class Atlas(concept.AtlasConcept, configuration_folder="atlases"):
30
30
  spaces, as well as common functionalities of those.
31
31
  """
32
32
 
33
- def __init__(self, identifier: str, name: str, species: Species):
33
+ def __init__(self, identifier: str, name: str, species: Species, **kwargs):
34
34
  """Construct an empty atlas object with a name and identifier."""
35
35
 
36
36
  concept.AtlasConcept.__init__(
37
37
  self,
38
38
  identifier=identifier,
39
39
  name=name,
40
- species=species
40
+ species=species,
41
+ **kwargs
41
42
  )
42
43
  self._parcellation_ids: List[str] = []
43
44
  self._space_ids: List[str] = []
@@ -196,27 +197,29 @@ class Atlas(concept.AtlasConcept, configuration_folder="atlases"):
196
197
 
197
198
  def find_regions(
198
199
  self,
199
- regionspec,
200
- all_versions=False,
201
- filter_children=True,
202
- **kwargs
200
+ regionspec: str,
201
+ all_versions: bool = False,
202
+ filter_children: bool = True,
203
+ find_topmost: bool = False
203
204
  ):
204
205
  """
205
- Find regions with the given specification in all
206
- parcellations offered by the atlas. Additional kwargs
207
- are passed on to Parcellation.find().
206
+ Find regions with the given specification in all parcellations offered
207
+ by the atlas.
208
208
 
209
209
  Parameters
210
210
  ----------
211
- regionspec: str, regex, int, Region, MapIndex
211
+ regionspec: str, regex
212
212
  - a string with a possibly inexact name (matched both against the name and the identifier key)
213
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)
214
214
  - a regex applied to region names
215
- - a Region object
216
215
  all_versions : Bool, default: False
217
216
  If True, matched regions for all versions of a parcellation are returned.
218
217
  filter_children : bool, default: True
219
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.
220
223
 
221
224
  Returns
222
225
  -------
@@ -224,9 +227,13 @@ class Atlas(concept.AtlasConcept, configuration_folder="atlases"):
224
227
  list of regions matching to the regionspec
225
228
  """
226
229
  result = []
227
- for p in self._parcellation_ids:
228
- parcobj = _parcellation.Parcellation.get_instance(p)
229
- if parcobj.is_newest_version or all_versions:
230
- match = parcobj.find(regionspec, filter_children=filter_children, **kwargs)
231
- result.extend(match)
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
+ )
232
239
  return result
siibra/core/concept.py CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright 2018-2021
1
+ # Copyright 2018-2024
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");
@@ -67,7 +67,8 @@ class AtlasConcept:
67
67
  modality: str = "",
68
68
  publications: List[TypePublication] = [],
69
69
  datasets: List['TypeDataset'] = [],
70
- spec=None
70
+ spec=None,
71
+ prerelease: bool = False,
71
72
  ):
72
73
  """
73
74
  Construct a new atlas concept base object.
@@ -94,7 +95,7 @@ class AtlasConcept:
94
95
  The preconfigured specification.
95
96
  """
96
97
  self._id = identifier
97
- self.name = name
98
+ self.name = name if not prerelease else f"[PRERELEASE] {name}"
98
99
  self._species_cached = None if species is None \
99
100
  else Species.decode(species) # overwritable property implementation below
100
101
  self.shortname = shortname
@@ -104,6 +105,7 @@ class AtlasConcept:
104
105
  self.datasets = datasets
105
106
  self._spec = spec
106
107
  self._CACHED_MATCHES = {} # we cache match() function results
108
+ self._prerelease = prerelease
107
109
 
108
110
  @property
109
111
  def description(self):
@@ -116,12 +118,19 @@ class AtlasConcept:
116
118
 
117
119
  @property
118
120
  def LICENSE(self) -> str:
119
- licenses = {ds.LICENSE for ds in self.datasets if ds.LICENSE}
120
- if not licenses:
121
- return "No license information is found."
122
- if len(licenses) == 1:
123
- return next(iter(licenses))
124
- logger.info("Found multiple licenses corresponding to datasets.")
121
+ licenses = []
122
+ for ds in self.datasets:
123
+ if ds.LICENSE is None or ds.LICENSE == "No license information is found.":
124
+ continue
125
+ if isinstance(ds.LICENSE, str):
126
+ licenses.append(ds.LICENSE)
127
+ if isinstance(ds.LICENSE, list):
128
+ licenses.extend(ds.LICENSE)
129
+ if len(licenses) == 0:
130
+ logger.warning("No license information is found.")
131
+ return ""
132
+ if len(licenses) > 1:
133
+ logger.info("Found multiple licenses corresponding to datasets.")
125
134
  return '\n'.join(licenses)
126
135
 
127
136
  @property
@@ -1,4 +1,4 @@
1
- # Copyright 2018-2023
1
+ # Copyright 2018-2024
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 NoMapMatchingValues
20
21
 
21
- from typing import Union, List, Dict
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,
@@ -82,6 +90,7 @@ class Parcellation(region.Region, configuration_folder="parcellations"):
82
90
  modality: str = None,
83
91
  publications: list = [],
84
92
  datasets: list = [],
93
+ prerelease: bool = False,
85
94
  ):
86
95
  """
87
96
  Constructs a new parcellation object.
@@ -118,7 +127,8 @@ class Parcellation(region.Region, configuration_folder="parcellations"):
118
127
  description=description,
119
128
  publications=publications,
120
129
  datasets=datasets,
121
- modality=modality
130
+ modality=modality,
131
+ prerelease=prerelease,
122
132
  )
123
133
  self._species_cached = Species.decode(species)
124
134
  self._id = identifier
@@ -138,7 +148,12 @@ class Parcellation(region.Region, configuration_folder="parcellations"):
138
148
  self._CACHED_MATCHES[spec] = True
139
149
  return super().matches(spec)
140
150
 
141
- def get_map(self, space=None, maptype: Union[str, MapType] = MapType.LABELLED, spec: str = ""):
151
+ def get_map(
152
+ self,
153
+ space: Union[str, "Space"],
154
+ maptype: Union[Literal['labelled', 'statistical'], MapType] = MapType.LABELLED,
155
+ spec: str = ""
156
+ ):
142
157
  """
143
158
  Get the maps for the parcellation in the requested template space.
144
159
 
@@ -151,8 +166,8 @@ class Parcellation(region.Region, configuration_folder="parcellations"):
151
166
  Parameters
152
167
  ----------
153
168
  space: Space or str
154
- template space specification
155
- maptype: MapType
169
+ reference space specification such as name, id, or a `Space` instance.
170
+ maptype: MapType or str
156
171
  Type of map requested (e.g., statistical or labelled).
157
172
  Use MapType.STATISTICAL to request probability maps.
158
173
  Defaults to MapType.LABELLED.
@@ -167,26 +182,24 @@ class Parcellation(region.Region, configuration_folder="parcellations"):
167
182
  A ParcellationMap representing the volumetric map or
168
183
  a SparseMap representing the list of statistical maps.
169
184
  """
170
- if not isinstance(maptype, MapType):
185
+ if isinstance(maptype, str):
171
186
  maptype = MapType[maptype.upper()]
187
+ assert isinstance(maptype, MapType), "Possible values of `maptype` are `MapType`s, 'labelled', 'statistical'."
172
188
 
173
189
  candidates = [
174
190
  m for m in parcellationmap.Map.registry()
175
191
  if m.space.matches(space)
176
192
  and m.maptype == maptype
177
- and m.parcellation
178
193
  and m.parcellation.matches(self)
179
194
  ]
180
195
  if len(candidates) == 0:
181
- logger.error(f"No {maptype} map in {space} available for {str(self)}")
182
- return None
196
+ raise NoMapMatchingValues(f"No '{maptype}' map in '{space}' available for {str(self)}")
183
197
  if len(candidates) > 1:
184
198
  spec_candidates = [
185
- c for c in candidates if all(w.lower() in c.name.lower() for w in spec.split())
199
+ c for c in candidates if all(w.lower() in c.id.lower() for w in spec.split())
186
200
  ]
187
201
  if len(spec_candidates) == 0:
188
- logger.warning(f"'{spec}' does not match any options from {[c.name for c in candidates]}.")
189
- return None
202
+ raise NoMapMatchingValues(f"'{spec}' does not match any options from {[c.name for c in candidates]}.")
190
203
  if len(spec_candidates) > 1:
191
204
  logger.warning(
192
205
  f"Multiple maps are available in this specification of space, parcellation, and map type.\n"
@@ -195,43 +208,6 @@ class Parcellation(region.Region, configuration_folder="parcellations"):
195
208
  return spec_candidates[0]
196
209
  return candidates[0]
197
210
 
198
- @staticmethod
199
- def find_regions(region_spec: str, parents_only=True):
200
- """
201
- Find regions that match the given region specification in the subtree
202
- headed by each parcellation in the registry.
203
- Note
204
- ----
205
- Use Region.find() to search for a region in an instance of a
206
- parcellation.
207
-
208
- Parameters
209
- ----------
210
- regionspec: str
211
- a string with a possibly inexact name, which is matched both
212
- against the name and the identifier key,
213
- parents_only: bool
214
- If true, children of matched parents will not be returned
215
- Returns
216
- -------
217
- List[Region]
218
- list of matching regions
219
- """
220
- MEM = Parcellation._CACHED_REGION_SEARCHES
221
- if region_spec not in MEM:
222
- MEM[region_spec] = [
223
- r
224
- for p in Parcellation.registry()
225
- for r in p.find(regionspec=region_spec)
226
- ]
227
- if parents_only:
228
- return [
229
- r for r in MEM[region_spec]
230
- if (r.parent is None) or (r.parent not in MEM[region_spec])
231
- ]
232
- else:
233
- return MEM[region_spec]
234
-
235
211
  @property
236
212
  def is_newest_version(self):
237
213
  return (self.version is None) or (self.version.next_id is None)
@@ -261,7 +237,7 @@ class Parcellation(region.Region, configuration_folder="parcellations"):
261
237
  def get_region(
262
238
  self,
263
239
  regionspec: Union[str, region.Region],
264
- find_topmost: bool = True,
240
+ find_topmost: bool = False,
265
241
  allow_tuple: bool = False
266
242
  ):
267
243
  """
@@ -279,7 +255,7 @@ class Parcellation(region.Region, configuration_folder="parcellations"):
279
255
  regionspec: str, Region
280
256
  - a string with a possibly inexact name (matched both against the name and the identifier key)
281
257
  - a Region object
282
- find_topmost: bool, default: True
258
+ find_topmost: bool, default: False
283
259
  If True, will automatically return the parent of a decoded region
284
260
  the decoded region is its only child.
285
261
  allow_tuple: bool, default: False
@@ -309,7 +285,11 @@ class Parcellation(region.Region, configuration_folder="parcellations"):
309
285
 
310
286
  # if there exist an exact match of region spec to region name, return
311
287
  if isinstance(regionspec, str):
312
- exact_match = [region for region in self if hasattr(region, "name") and region.name == regionspec]
288
+ exact_match = [
289
+ region
290
+ for region in self
291
+ if region.name == regionspec or region.key == regionspec
292
+ ]
313
293
  if len(exact_match) == 1:
314
294
  return exact_match[0]
315
295
  if len(exact_match) > 1:
@@ -364,3 +344,44 @@ class Parcellation(region.Region, configuration_folder="parcellations"):
364
344
  )
365
345
  return self.name < other.name
366
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 registery.
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