siibra 1.0a1__1-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 (84) hide show
  1. siibra/VERSION +1 -0
  2. siibra/__init__.py +164 -0
  3. siibra/commons.py +823 -0
  4. siibra/configuration/__init__.py +17 -0
  5. siibra/configuration/configuration.py +189 -0
  6. siibra/configuration/factory.py +589 -0
  7. siibra/core/__init__.py +16 -0
  8. siibra/core/assignment.py +110 -0
  9. siibra/core/atlas.py +239 -0
  10. siibra/core/concept.py +308 -0
  11. siibra/core/parcellation.py +387 -0
  12. siibra/core/region.py +1223 -0
  13. siibra/core/space.py +131 -0
  14. siibra/core/structure.py +111 -0
  15. siibra/exceptions.py +63 -0
  16. siibra/experimental/__init__.py +19 -0
  17. siibra/experimental/contour.py +61 -0
  18. siibra/experimental/cortical_profile_sampler.py +57 -0
  19. siibra/experimental/patch.py +98 -0
  20. siibra/experimental/plane3d.py +256 -0
  21. siibra/explorer/__init__.py +17 -0
  22. siibra/explorer/url.py +222 -0
  23. siibra/explorer/util.py +87 -0
  24. siibra/features/__init__.py +117 -0
  25. siibra/features/anchor.py +224 -0
  26. siibra/features/connectivity/__init__.py +33 -0
  27. siibra/features/connectivity/functional_connectivity.py +57 -0
  28. siibra/features/connectivity/regional_connectivity.py +494 -0
  29. siibra/features/connectivity/streamline_counts.py +27 -0
  30. siibra/features/connectivity/streamline_lengths.py +27 -0
  31. siibra/features/connectivity/tracing_connectivity.py +30 -0
  32. siibra/features/dataset/__init__.py +17 -0
  33. siibra/features/dataset/ebrains.py +90 -0
  34. siibra/features/feature.py +970 -0
  35. siibra/features/image/__init__.py +27 -0
  36. siibra/features/image/image.py +115 -0
  37. siibra/features/image/sections.py +26 -0
  38. siibra/features/image/volume_of_interest.py +88 -0
  39. siibra/features/tabular/__init__.py +24 -0
  40. siibra/features/tabular/bigbrain_intensity_profile.py +77 -0
  41. siibra/features/tabular/cell_density_profile.py +298 -0
  42. siibra/features/tabular/cortical_profile.py +322 -0
  43. siibra/features/tabular/gene_expression.py +257 -0
  44. siibra/features/tabular/layerwise_bigbrain_intensities.py +62 -0
  45. siibra/features/tabular/layerwise_cell_density.py +95 -0
  46. siibra/features/tabular/receptor_density_fingerprint.py +192 -0
  47. siibra/features/tabular/receptor_density_profile.py +110 -0
  48. siibra/features/tabular/regional_timeseries_activity.py +294 -0
  49. siibra/features/tabular/tabular.py +139 -0
  50. siibra/livequeries/__init__.py +19 -0
  51. siibra/livequeries/allen.py +352 -0
  52. siibra/livequeries/bigbrain.py +197 -0
  53. siibra/livequeries/ebrains.py +145 -0
  54. siibra/livequeries/query.py +49 -0
  55. siibra/locations/__init__.py +91 -0
  56. siibra/locations/boundingbox.py +454 -0
  57. siibra/locations/location.py +115 -0
  58. siibra/locations/point.py +344 -0
  59. siibra/locations/pointcloud.py +349 -0
  60. siibra/retrieval/__init__.py +27 -0
  61. siibra/retrieval/cache.py +233 -0
  62. siibra/retrieval/datasets.py +389 -0
  63. siibra/retrieval/exceptions/__init__.py +27 -0
  64. siibra/retrieval/repositories.py +769 -0
  65. siibra/retrieval/requests.py +659 -0
  66. siibra/vocabularies/__init__.py +45 -0
  67. siibra/vocabularies/gene_names.json +29176 -0
  68. siibra/vocabularies/receptor_symbols.json +210 -0
  69. siibra/vocabularies/region_aliases.json +460 -0
  70. siibra/volumes/__init__.py +23 -0
  71. siibra/volumes/parcellationmap.py +1279 -0
  72. siibra/volumes/providers/__init__.py +20 -0
  73. siibra/volumes/providers/freesurfer.py +113 -0
  74. siibra/volumes/providers/gifti.py +165 -0
  75. siibra/volumes/providers/neuroglancer.py +736 -0
  76. siibra/volumes/providers/nifti.py +266 -0
  77. siibra/volumes/providers/provider.py +107 -0
  78. siibra/volumes/sparsemap.py +468 -0
  79. siibra/volumes/volume.py +892 -0
  80. siibra-1.0.0a1.dist-info/LICENSE +201 -0
  81. siibra-1.0.0a1.dist-info/METADATA +160 -0
  82. siibra-1.0.0a1.dist-info/RECORD +84 -0
  83. siibra-1.0.0a1.dist-info/WHEEL +5 -0
  84. siibra-1.0.0a1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,20 @@
1
+ # Copyright 2018-2024
2
+ # Institute of Neuroscience and Medicine (INM-1), Forschungszentrum Jülich GmbH
3
+
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ """Subpackage handling the digestion of different volume and mesh types"""
16
+
17
+ from .neuroglancer import NeuroglancerProvider, NeuroglancerMesh
18
+ from .nifti import NiftiProvider
19
+ from .gifti import GiftiSurfaceLabeling, GiftiMesh
20
+ from .freesurfer import ZippedFreesurferAnnot, FreesurferAnnot
@@ -0,0 +1,113 @@
1
+ # Copyright 2018-2024
2
+ # Institute of Neuroscience and Medicine (INM-1), Forschungszentrum Jülich GmbH
3
+
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ """Handles reading and preparing gii files."""
16
+
17
+ from . import provider as _provider
18
+
19
+ from ...retrieval.requests import HttpRequest, ZipfileRequest
20
+
21
+ import numpy as np
22
+ from typing import Union, Dict, TYPE_CHECKING
23
+
24
+ if TYPE_CHECKING:
25
+ from ...locations import boundingbox as _boundingbox
26
+
27
+
28
+ class FreesurferAnnot(_provider.VolumeProvider, srctype="freesurfer-annot"):
29
+ def __init__(self, url: Union[str, dict]):
30
+ self._init_url = url
31
+ if isinstance(url, str): # single mesh labelling
32
+ self._loaders = {None: HttpRequest(url)}
33
+ elif isinstance(url, dict): # named label fragments
34
+ self._loaders = {lbl: HttpRequest(u) for lbl, u in url.items()}
35
+ else:
36
+ raise NotImplementedError(f"Urls for {self.__class__.__name__} are expected to be of type str.")
37
+
38
+ def fetch(self, fragment: str = None, label: int = None, **kwargs):
39
+ """Returns a 1D numpy array of label indices."""
40
+ vertex_labels = []
41
+ if fragment is None:
42
+ matched_frags = list(self._loaders.keys())
43
+ else:
44
+ matched_frags = [frg for frg in self._loaders.keys() if fragment.lower() in frg.lower()]
45
+ if len(matched_frags) != 1:
46
+ raise ValueError(
47
+ f"Requested fragment '{fragment}' could not be matched uniquely "
48
+ f"to [{', '.join(self._loaders)}]"
49
+ )
50
+ for frag in matched_frags:
51
+ frag_labels, *_ = self._loaders[frag].data
52
+ if label is not None: # create the mask
53
+ selected_label = frag_labels == label
54
+ frag_labels[selected_label] = 1
55
+ frag_labels[~selected_label] = 0
56
+ else:
57
+ frag_labels[frag_labels == -1] = 0 # annot files store backgorund as -1 while siibra uses 0
58
+ vertex_labels.append(frag_labels)
59
+
60
+ return {"labels": np.hstack(vertex_labels)}
61
+
62
+ def get_boundingbox(self, clip=False, background=0.0) -> '_boundingbox.BoundingBox':
63
+ raise NotImplementedError(
64
+ f"Bounding box access to {self.__class__.__name__} objects not yet implemented."
65
+ )
66
+
67
+ @property
68
+ def _url(self) -> Union[str, Dict[str, str]]:
69
+ return self._init_url
70
+
71
+
72
+ class ZippedFreesurferAnnot(_provider.VolumeProvider, srctype="zip/freesurfer-annot"):
73
+ def __init__(self, url: Union[str, dict]):
74
+ self._init_url = url
75
+ if isinstance(url, str): # single mesh labelling
76
+ self._loaders = {None: ZipfileRequest(*url.split(" "))}
77
+ elif isinstance(url, dict): # named label fragments
78
+ self._loaders = {lbl: ZipfileRequest(*u.split(" ")) for lbl, u in url.items()}
79
+ else:
80
+ raise NotImplementedError(f"Urls for {self.__class__.__name__} are expected to be of type str.")
81
+
82
+ def fetch(self, fragment: str = None, label: int = None, **kwargs):
83
+ """Returns a 1D numpy array of label indices."""
84
+ vertex_labels = []
85
+ if fragment is None:
86
+ matched_frags = list(self._loaders.keys())
87
+ else:
88
+ matched_frags = [frg for frg in self._loaders.keys() if fragment.lower() in frg.lower()]
89
+ if len(matched_frags) != 1:
90
+ raise ValueError(
91
+ f"Requested fragment '{fragment}' could not be matched uniquely "
92
+ f"to [{', '.join(self._loaders)}]"
93
+ )
94
+ for frag in matched_frags:
95
+ frag_labels, *_ = self._loaders[frag].data
96
+ if label is not None: # create the mask
97
+ selected_label = frag_labels == label
98
+ frag_labels[selected_label] = 1
99
+ frag_labels[~selected_label] = 0
100
+ else:
101
+ frag_labels[frag_labels == -1] = 0 # annot files store backgorund as -1 while siibra uses 0
102
+ vertex_labels.append(frag_labels)
103
+
104
+ return {"labels": np.hstack(vertex_labels)}
105
+
106
+ def get_boundingbox(self, clip=False, background=0.0) -> '_boundingbox.BoundingBox':
107
+ raise NotImplementedError(
108
+ f"Bounding box access to {self.__class__.__name__} objects not yet implemented."
109
+ )
110
+
111
+ @property
112
+ def _url(self) -> Union[str, Dict[str, str]]:
113
+ return self._init_url
@@ -0,0 +1,165 @@
1
+ # Copyright 2018-2024
2
+ # Institute of Neuroscience and Medicine (INM-1), Forschungszentrum Jülich GmbH
3
+
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ """Handles reading and preparing gii files."""
16
+
17
+ from . import provider as _provider
18
+
19
+ from ...retrieval import requests
20
+ from ...commons import logger, merge_meshes
21
+ from ...locations import boundingbox as _boundingbox
22
+
23
+ import numpy as np
24
+ from typing import Union, Dict
25
+
26
+
27
+ class GiftiMesh(_provider.VolumeProvider, srctype="gii-mesh"):
28
+ """
29
+ One or more surface mesh fragments in Gifti format.
30
+ """
31
+
32
+ def __init__(self, url: Union[str, Dict[str, str]], volume=None):
33
+ self._init_url = url
34
+ self.volume = volume
35
+ # TODO duplicated code to NgMesh
36
+ if isinstance(url, str): # single mesh
37
+ self._loaders = {None: requests.HttpRequest(url)}
38
+ elif isinstance(url, dict): # named mesh fragments
39
+ self._loaders = {lbl: requests.HttpRequest(u) for lbl, u in url.items()}
40
+ else:
41
+ raise NotImplementedError(f"Urls for {self.__class__.__name__} are expected to be of type str or dict.")
42
+
43
+ @property
44
+ def _url(self) -> Union[str, Dict[str, str]]:
45
+ return self._init_url
46
+
47
+ def get_boundingbox(self, clip=False, background=0.0, **fetch_kwargs) -> '_boundingbox.BoundingBox':
48
+ """
49
+ Bounding box calculation is not yet implemented for meshes.
50
+ """
51
+ raise NotImplementedError(
52
+ f"Bounding box access to {self.__class__.__name__} objects not yet implemented."
53
+ )
54
+
55
+ @property
56
+ def fragments(self):
57
+ return [k for k in self._loaders if k is not None]
58
+
59
+ def fetch(self, fragment: str = None, **kwargs):
60
+ """
61
+ Returns the mesh as a dictionary with two numpy arrays.
62
+
63
+ Parameters
64
+ ----------
65
+ fragment: str, default: None
66
+ A fragment name can be specified to choose from multiple fragments.
67
+
68
+ Note
69
+ ----
70
+ If not specified, multiple fragments will be merged into one mesh.
71
+ In such a case, the verts and faces arrays of different fragments
72
+ are appended to one another.
73
+
74
+ Returns
75
+ -------
76
+ dict
77
+ - 'verts': An Nx3 array of vertex coordinates,
78
+ - 'faces': an Mx3 array of face definitions using row indices of the vertex array
79
+ """
80
+ for arg in ["resolution_mm", "voi"]:
81
+ if kwargs.get(arg):
82
+ raise NotImplementedError(f"Parameter {arg} ignored by {self.__class__}.")
83
+
84
+ fragments_included = []
85
+ meshes = []
86
+ for fragment_name, loader in self._loaders.items():
87
+ if fragment and fragment.lower() not in fragment_name.lower():
88
+ continue
89
+ assert len(loader.data.darrays) > 1
90
+ meshes.append({
91
+ "verts": loader.data.darrays[0].data,
92
+ "faces": loader.data.darrays[1].data
93
+ })
94
+ fragments_included.append(fragment_name)
95
+
96
+ if len(fragments_included) > 1:
97
+ logger.info(
98
+ f"The mesh fragments [{', '.join(fragments_included)}] were merged by "
99
+ "appending vertex information of fragments. "
100
+ f"You could select one with the 'fragment' parameter in fetch()."
101
+ )
102
+
103
+ return merge_meshes(meshes)
104
+
105
+ @property
106
+ def variants(self):
107
+ return list(self._loaders.keys())
108
+
109
+ def fetch_iter(self):
110
+ """
111
+ Iterator returning all submeshes
112
+
113
+ Returns
114
+ -------
115
+ dict
116
+ - 'verts': An Nx3 array of vertex coordinates,
117
+ - 'faces': an Mx3 array of face definitions using row indices of the vertex array
118
+ - 'name': Name of the of the mesh variant
119
+ """
120
+ return (self.fetch(v) for v in self.variants)
121
+
122
+
123
+ class GiftiSurfaceLabeling(_provider.VolumeProvider, srctype="gii-label"):
124
+ """
125
+ A mesh labeling, specified by a gifti file.
126
+ """
127
+
128
+ def __init__(self, url: Union[str, dict]):
129
+ self._init_url = url
130
+ if isinstance(url, str): # single mesh labelling
131
+ self._loaders = {None: requests.HttpRequest(url)}
132
+ elif isinstance(url, dict): # labelling for multiple mesh fragments
133
+ self._loaders = {lbl: requests.HttpRequest(u) for lbl, u in url.items()}
134
+ else:
135
+ raise NotImplementedError(f"Urls for {self.__class__.__name__} are expected to be of type str or dict.")
136
+
137
+ def fetch(self, fragment: str = None, label: int = None, **kwargs):
138
+ """Returns a 1D numpy array of label indices."""
139
+ labels = []
140
+ if fragment is None:
141
+ matched_frags = list(self._loaders.keys())
142
+ else:
143
+ matched_frags = [frg for frg in self._loaders.keys() if fragment.lower() in frg.lower()]
144
+ if len(matched_frags) != 1:
145
+ raise ValueError(
146
+ f"Requested fragment '{fragment}' could not be matched uniquely "
147
+ f"to [{', '.join(self._loaders)}]"
148
+ )
149
+ for frag in matched_frags:
150
+ assert len(self._loaders[frag].data.darrays) == 1
151
+ if label is not None:
152
+ labels.append((self._loaders[frag].data.darrays[0].data == label).astype('uint8'))
153
+ else:
154
+ labels.append(self._loaders[frag].data.darrays[0].data)
155
+
156
+ return {"labels": np.hstack(labels)}
157
+
158
+ def get_boundingbox(self, clip=False, background=0.0) -> '_boundingbox.BoundingBox':
159
+ raise NotImplementedError(
160
+ f"Bounding box access to {self.__class__.__name__} objects not yet implemented."
161
+ )
162
+
163
+ @property
164
+ def _url(self) -> Union[str, Dict[str, str]]:
165
+ return self._init_url