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,322 @@
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
+
16
+ from . import tabular
17
+ from ..feature import Compoundable
18
+
19
+ from .. import anchor as _anchor
20
+
21
+ import pandas as pd
22
+ from typing import Union, Dict, Tuple, List
23
+ from textwrap import wrap
24
+ import numpy as np
25
+
26
+
27
+ class CorticalProfile(tabular.Tabular, Compoundable):
28
+ """
29
+ Represents a 1-dimensional profile of measurements along cortical depth,
30
+ measured at relative depths between 0 representing the pial surface,
31
+ and 1 corresponding to the gray/white matter boundary.
32
+
33
+ Mandatory attributes are the list of depth coordinates and the list of
34
+ corresponding measurement values, which have to be of equal length,
35
+ as well as a unit and description of the measurements.
36
+
37
+ Optionally, the depth coordinates of layer boundaries can be specified.
38
+
39
+ Most attributes are modelled as properties, so dervide classes are able
40
+ to implement lazy loading instead of direct initialiation.
41
+
42
+ """
43
+
44
+ LAYERS = {0: "0", 1: "I", 2: "II", 3: "III", 4: "IV", 5: "V", 6: "VI", 7: "WM"}
45
+ BOUNDARIES = list(zip(list(LAYERS.keys())[:-1], list(LAYERS.keys())[1:]))
46
+
47
+ _filter_attrs = ["modality"]
48
+ _compound_attrs = ["modality"]
49
+
50
+ def __init__(
51
+ self,
52
+ description: str,
53
+ modality: str,
54
+ anchor: _anchor.AnatomicalAnchor,
55
+ depths: Union[list, np.ndarray] = None,
56
+ values: Union[list, np.ndarray] = None,
57
+ unit: str = None,
58
+ boundary_positions: Dict[Tuple[int, int], float] = None,
59
+ datasets: list = [],
60
+ id: str = None,
61
+ prerelease: bool = False,
62
+ ):
63
+ """Initialize profile.
64
+
65
+ Parameters
66
+ ----------
67
+ description: str
68
+ Human-readable of the modality of the measurements.
69
+ modality: str
70
+ Short textual description of the modality of measurements.
71
+ anchor: AnatomicalAnchor
72
+ depths: list, default: None
73
+ List of cortical depth positions corresponding to each
74
+ measurement, all in the range [0..1]
75
+ values: list, default: None
76
+ List of the actual measurements at each depth position.
77
+ Length must correspond to 'depths'.
78
+ unit: str, default: None
79
+ Textual identifier for the unit of measurements.
80
+ boundary_positions: dict, default: None
81
+ Dictionary of depths at which layer boundaries were identified.
82
+ Keys are tuples of layer numbers, e.g. (1,2), and values are
83
+ cortical depth positions in the range [0..1].
84
+ datasets : list[Dataset]
85
+ list of datasets corresponding to this feature
86
+ """
87
+
88
+ # cached properties will be revealed as property functions,
89
+ # so derived classes may choose to override for lazy loading.
90
+ self._unit = unit
91
+ self._depths_cached = depths
92
+ self._values_cached = values
93
+ self._boundary_positions = boundary_positions
94
+
95
+ tabular.Tabular.__init__(
96
+ self,
97
+ modality=modality,
98
+ description=description,
99
+ anchor=anchor,
100
+ data=None, # lazy loader below
101
+ datasets=datasets,
102
+ id=id,
103
+ prerelease=prerelease,
104
+ )
105
+
106
+ def _check_sanity(self):
107
+ # check plausibility of the profile
108
+ assert isinstance(self._depths, (list, np.ndarray)), "Some depths are not valid"
109
+ assert isinstance(self._values, (list, np.ndarray)), "Some values are not valid"
110
+ assert len(self._values) == len(self._depths), "There exist uneven number of depths and values"
111
+ assert all(0 <= d <= 1 for d in self._depths), "Some depths is not between 0 and 1"
112
+ if self.boundaries_mapped:
113
+ assert all(0 <= d <= 1 for d in self.boundary_positions.values()), "Some boundary positions are not between 0 and 1"
114
+ assert all(
115
+ layerpair in self.BOUNDARIES
116
+ for layerpair in self.boundary_positions.keys()
117
+ ), "Some value in BOUNDARIES are not mapped in boundary_positions"
118
+
119
+ @property
120
+ def unit(self) -> str:
121
+ """Optionally overridden in derived classes."""
122
+ if self._unit is None:
123
+ raise NotImplementedError(f"'unit' not set for {self.__class__.__name__}.")
124
+ return self._unit
125
+
126
+ @property
127
+ def boundary_positions(self) -> Dict[Tuple[int, int], float]:
128
+ if self._boundary_positions is None:
129
+ return {}
130
+ else:
131
+ return self._boundary_positions
132
+
133
+ def assign_layer(self, depth: float):
134
+ """Compute the cortical layer for a given depth from the
135
+ layer boundary positions. If no positions are available
136
+ for this profile, return None."""
137
+ assert 0 <= depth <= 1
138
+ if len(self.boundary_positions) == 0:
139
+ return None
140
+ else:
141
+ return max(
142
+ [l2 for (l1, l2), d in self.boundary_positions.items() if d < depth]
143
+ )
144
+
145
+ @property
146
+ def boundaries_mapped(self) -> bool:
147
+ if self.boundary_positions is None:
148
+ return False
149
+ else:
150
+ return all((b in self.boundary_positions) for b in self.BOUNDARIES)
151
+
152
+ @property
153
+ def _layers(self):
154
+ """List of layers assigned to each measurments,
155
+ if layer boundaries are available for this features.
156
+ """
157
+ if self.boundaries_mapped:
158
+ return [self.assign_layer(d) for d in self._depths]
159
+ else:
160
+ return None
161
+
162
+ @property
163
+ def data(self):
164
+ """Return a pandas Series representing the profile."""
165
+ self._check_sanity()
166
+ iscompound = len(self._values.shape) > 1 and self._values.shape[1] == 2
167
+ if iscompound:
168
+ columns = [f"{self.modality} mean ({self.unit})", "std"]
169
+ else:
170
+ columns = [f"{self.modality} ({self.unit})"]
171
+ return pd.DataFrame(self._values, index=self._depths, columns=columns)
172
+
173
+ @classmethod
174
+ def _merge_elements(
175
+ cls,
176
+ elements: List["CorticalProfile"],
177
+ description: str,
178
+ modality: str,
179
+ anchor: _anchor.AnatomicalAnchor,
180
+ ):
181
+ assert all(np.array_equal(elements[0]._depths, f._depths) for f in elements)
182
+ assert len({f.unit for f in elements}) == 1
183
+ values_stacked = np.stack([f._values for f in elements])
184
+ return CorticalProfile(
185
+ description=description,
186
+ modality=modality,
187
+ anchor=anchor,
188
+ depths=np.stack([f._depths for f in elements]).mean(0),
189
+ values=np.stack([values_stacked.mean(0), values_stacked.std(0)]).T,
190
+ unit=elements[0].unit,
191
+ boundary_positions=None,
192
+ )
193
+
194
+ def plot(self, *args, backend="matplotlib", **kwargs):
195
+ """
196
+ Plot the profile.
197
+
198
+ Parameters
199
+ ----------
200
+ backend: str
201
+ "matplotlib", "plotly", or others supported by pandas DataFrame
202
+ plotting backend.
203
+ **kwargs
204
+ Keyword arguments are passed on to the plot command. 'layercolor'
205
+ can be used to specify a color for cortical layer shading.
206
+ """
207
+ wrapwidth = kwargs.pop("textwrap") if "textwrap" in kwargs else 40
208
+ kwargs["title"] = kwargs.get("title", "\n".join(wrap(self.name, wrapwidth)))
209
+ layercolor = kwargs.pop("layercolor", "gray")
210
+
211
+ iscompound = len(self._values.shape) > 1 and self._values.shape[1] == 2
212
+ ymax = max(
213
+ 0,
214
+ sum(self._values.max(axis=0)) if iscompound else self._values.max()
215
+ )
216
+ if backend == "matplotlib":
217
+ kwargs["xlabel"] = kwargs.get("xlabel", "Cortical depth")
218
+ kwargs["ylabel"] = kwargs.get("ylabel", self.unit)
219
+ kwargs["grid"] = kwargs.get("grid", True)
220
+ axs = self.data.iloc[:, 0].plot(*args, **kwargs, backend=backend)
221
+ axs.set_ylim(kwargs.get("ylim", (0, ymax)))
222
+
223
+ if self.boundaries_mapped:
224
+ bvals = list(self.boundary_positions.values())
225
+ for i, (d1, d2) in enumerate(list(zip(bvals[:-1], bvals[1:]))):
226
+ axs.text(
227
+ d1 + (d2 - d1) / 2.0,
228
+ 10,
229
+ self.LAYERS[i + 1],
230
+ weight="normal",
231
+ ha="center",
232
+ )
233
+ if i % 2 == 0:
234
+ axs.axvspan(d1, d2, color=layercolor, alpha=0.3)
235
+
236
+ axs.set_title(axs.get_title(), fontsize="medium")
237
+
238
+ if iscompound:
239
+ axs.set_ylabel(f"average {kwargs['ylabel']} \u00b1 std")
240
+ av = self.data.values[:, 0]
241
+ std = self.data.values[:, 1]
242
+ axs.fill_between(self.data.index.values, av - std, av + std, alpha=0.5)
243
+
244
+ return axs
245
+
246
+ elif backend == "plotly":
247
+ kwargs["title"] = kwargs["title"].replace("\n", "<br>")
248
+ kwargs["labels"] = {
249
+ "index": kwargs.pop("xlabel", None) or kwargs.pop("index", "Cortical depth"),
250
+ "value": kwargs.pop("ylabel", None) or kwargs.pop("value", self.unit)
251
+ }
252
+ fig = self.data.iloc[:, 0].plot(*args, **kwargs, backend=backend)
253
+ if self.boundaries_mapped:
254
+ bvals = list(self.boundary_positions.values())
255
+ for i, (d1, d2) in enumerate(list(zip(bvals[:-1], bvals[1:]))):
256
+ fig.add_vrect(
257
+ x0=d1, x1=d2, line_width=0, fillcolor=layercolor,
258
+ opacity=0.2 if i % 2 == 0 else 0.0,
259
+ label=dict(text=self.LAYERS[i + 1], textposition="bottom center")
260
+ )
261
+ fig.update_layout(
262
+ showlegend=False,
263
+ yaxis_range=(0, ymax),
264
+ title=dict(
265
+ automargin=True, yref="container", xref="container",
266
+ pad=dict(t=40), xanchor="left", yanchor="top"
267
+ )
268
+ )
269
+ if iscompound:
270
+ from plotly.graph_objects import Scatter
271
+ x = self.data.index.values
272
+ av = self.data.values[:, 0]
273
+ std = self.data.values[:, 1]
274
+ fig.update_layout(yaxis_title=f"average {kwargs['labels']['value']} &plusmn; std")
275
+ fig.add_traces(
276
+ Scatter(
277
+ x=np.concatenate((x, x[::-1])), # x, then x reversed
278
+ y=np.concatenate((av + std, (av - std)[::-1])), # upper, then lower reversed
279
+ fill='toself',
280
+ fillcolor='rgba(0,100,80,0.5)',
281
+ line=dict(color='rgba(255,255,255,0)'),
282
+ hoverinfo="skip",
283
+ showlegend=False
284
+ )
285
+ )
286
+ return fig
287
+ else:
288
+ return self.data.plot(*args, **kwargs, backend=backend)
289
+
290
+ @property
291
+ def _depths(self):
292
+ """
293
+ Returns a list of the relative cortical depths of the measured values in the range [0..1].
294
+
295
+ To be implemented in derived class.
296
+ """
297
+ if self._depths_cached is None:
298
+ raise NotImplementedError(
299
+ f"'_depths' not available for {self.__class__.__name__}."
300
+ )
301
+ return self._depths_cached
302
+
303
+ @property
304
+ def _values(self):
305
+ """
306
+ Returns a list of the measured values per depth.
307
+
308
+ To be implemented in derived class.
309
+ """
310
+ if self._values_cached is None:
311
+ raise NotImplementedError(
312
+ f"'_values' not available for {self.__class__.__name__}."
313
+ )
314
+ return self._values_cached
315
+
316
+ @property
317
+ def name(self):
318
+ if hasattr(self, "receptor"):
319
+ return super().name + f": {self.receptor}"
320
+ if hasattr(self, "location"):
321
+ return super().name + f": {self.location.coordinate}"
322
+ return super().name
@@ -0,0 +1,257 @@
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
+
16
+ from .. import anchor as _anchor
17
+ from . import tabular
18
+ from ...retrieval.datasets import GenericDataset
19
+
20
+ import pandas as pd
21
+ from textwrap import wrap
22
+ from typing import List
23
+ try:
24
+ from typing import TypedDict
25
+ except ImportError:
26
+ from typing_extensions import TypedDict
27
+
28
+
29
+ class GeneExpressions(
30
+ tabular.Tabular,
31
+ category='molecular'
32
+ ):
33
+ """
34
+ A set gene expressions for different candidate genes
35
+ measured inside a brain structure.
36
+ """
37
+
38
+ DESCRIPTION = """
39
+ Gene expressions extracted from microarray data in the Allen Atlas.
40
+ """
41
+
42
+ ALLEN_ATLAS_NOTIFICATION = """
43
+ For retrieving microarray data, siibra connects to the web API of
44
+ the Allen Brain Atlas (© 2015 Allen Institute for Brain Science),
45
+ available from https://brain-map.org/api/index.html. Any use of the
46
+ microarray data needs to be in accordance with their terms of use,
47
+ as specified at https://alleninstitute.org/legal/terms-use/.
48
+ """
49
+
50
+ DATASET = GenericDataset(
51
+ name="An anatomically comprehensive atlas of the adult human brain transcriptome",
52
+ contributors=[
53
+ 'Michael J. Hawrylycz',
54
+ 'Ed S. Lein',
55
+ 'Angela L. Guillozet-Bongaarts',
56
+ 'Elaine H. Shen',
57
+ 'Lydia Ng',
58
+ 'Jeremy A. Miller',
59
+ 'Louie N. van de Lagemaat',
60
+ 'Kimberly A. Smith',
61
+ 'Amanda Ebbert',
62
+ 'Zackery L. Riley',
63
+ 'Chris Abajian',
64
+ 'Christian F. Beckmann',
65
+ 'Amy Bernard',
66
+ 'Darren Bertagnolli',
67
+ 'Andrew F. Boe',
68
+ 'Preston M. Cartagena',
69
+ 'M. Mallar Chakravarty',
70
+ 'Mike Chapin',
71
+ 'Jimmy Chong',
72
+ 'Rachel A. Dalley',
73
+ 'Barry David Daly',
74
+ 'Chinh Dang',
75
+ 'Suvro Datta',
76
+ 'Nick Dee',
77
+ 'Tim A. Dolbeare',
78
+ 'Vance Faber',
79
+ 'David Feng',
80
+ 'David R. Fowler',
81
+ 'Jeff Goldy',
82
+ 'Benjamin W. Gregor',
83
+ 'Zeb Haradon',
84
+ 'David R. Haynor',
85
+ 'John G. Hohmann',
86
+ 'Steve Horvath',
87
+ 'Robert E. Howard',
88
+ 'Andreas Jeromin',
89
+ 'Jayson M. Jochim',
90
+ 'Marty Kinnunen',
91
+ 'Christopher Lau',
92
+ 'Evan T. Lazarz',
93
+ 'Changkyu Lee',
94
+ 'Tracy A. Lemon',
95
+ 'Ling Li',
96
+ 'Yang Li',
97
+ 'John A. Morris',
98
+ 'Caroline C. Overly',
99
+ 'Patrick D. Parker',
100
+ 'Sheana E. Parry',
101
+ 'Melissa Reding',
102
+ 'Joshua J. Royall',
103
+ 'Jay Schulkin',
104
+ 'Pedro Adolfo Sequeira',
105
+ 'Clifford R. Slaughterbeck',
106
+ 'Simon C. Smith',
107
+ 'Andy J. Sodt',
108
+ 'Susan M. Sunkin',
109
+ 'Beryl E. Swanson',
110
+ 'Marquis P. Vawter',
111
+ 'Derric Williams',
112
+ 'Paul Wohnoutka',
113
+ 'H. Ronald Zielke',
114
+ 'Daniel H. Geschwind',
115
+ 'Patrick R. Hof',
116
+ 'Stephen M. Smith',
117
+ 'Christof Koch',
118
+ 'Seth G. N. Grant',
119
+ 'Allan R. Jones'
120
+ ],
121
+ url="https://doi.org/10.1038%2Fnature11405",
122
+ description='Neuroanatomically precise, genome-wide maps of transcript '
123
+ 'distributions are critical resources to complement genomic '
124
+ 'sequence data and to correlate functional and genetic brain '
125
+ 'architecture. Here we describe the generation and analysis '
126
+ 'of a transcriptional atlas of the adult human brain, '
127
+ 'comprising extensive histological analysis and comprehensive '
128
+ 'microarray profiling of ~900 neuroanatomically precise '
129
+ 'subdivisions in two individuals. Transcriptional regulation '
130
+ 'varies enormously by anatomical location, with different '
131
+ 'regions and their constituent cell types displaying robust '
132
+ 'molecular signatures that are highly conserved between '
133
+ 'individuals. Analysis of differential gene expression and '
134
+ 'gene co-expression relationships demonstrates that brain-'
135
+ 'wide variation strongly reflects the distributions of major '
136
+ 'cell classes such as neurons, oligodendrocytes, astrocytes '
137
+ 'and microglia. Local neighbourhood relationships between '
138
+ 'fine anatomical subdivisions are associated with discrete '
139
+ 'neuronal subtypes and genes involved with synaptic '
140
+ 'transmission. The neocortex displays a relatively '
141
+ 'homogeneous transcriptional pattern, but with distinct '
142
+ 'features associated selectively with primary sensorimotor '
143
+ 'cortices and with enriched frontal lobe expression. Notably, '
144
+ 'the spatial topography of the neocortex is strongly '
145
+ 'reflected in its molecular topography— the closer two '
146
+ 'cortical regions, the more similar their transcriptomes. '
147
+ 'This freely accessible online data resource forms a high-'
148
+ 'resolution transcriptional baseline for neurogenetic studies '
149
+ 'of normal and abnormal human brain function.'
150
+ ""
151
+ "For retrieving microarray data, siibra connects to the web API of "
152
+ "the Allen Brain Atlas (© 2015 Allen Institute for Brain Science), "
153
+ "available from https://brain-map.org/api/index.html. Any use of the "
154
+ "microarray data needs to be in accordance with their terms of use, "
155
+ "as specified at https://alleninstitute.org/legal/terms-use/."
156
+ )
157
+
158
+ class _DonorDict(TypedDict):
159
+ id: int
160
+ name: str
161
+ race: str
162
+ age: int
163
+ gender: str
164
+
165
+ class _SampleStructure(TypedDict):
166
+ id: int
167
+ name: str
168
+ abbreviation: str
169
+ color: str
170
+
171
+ def __init__(
172
+ self,
173
+ levels: List[float],
174
+ z_scores: List[float],
175
+ genes: List[str],
176
+ additional_columns: dict,
177
+ anchor: _anchor.AnatomicalAnchor,
178
+ datasets: List = [DATASET]
179
+ ):
180
+ """
181
+ Construct gene expression table.
182
+
183
+ Parameters
184
+ ----------
185
+ levels : list of float
186
+ Expression levels measured
187
+ z_scores : list of float
188
+ corresponding z scores measured
189
+ genes : list of str
190
+ Name of the gene corresponding to each measurement
191
+ additional_columns : dict of list
192
+ columns with additional data to be added to the tabular feature.
193
+ Keys give column names, values are lists with the column data.
194
+ Each list given needs to have the same length as expression_levels
195
+ anchor: AnatomicalAnchor
196
+ datasets : list
197
+ list of datasets corresponding to this feature
198
+ """
199
+ assert len(z_scores) == len(levels)
200
+ assert len(genes) == len(levels)
201
+ if additional_columns is not None:
202
+ assert all(len(lst) == len(levels) for lst in additional_columns.values())
203
+ else:
204
+ additional_columns = {}
205
+
206
+ _data_cahced = pd.DataFrame(
207
+ dict(
208
+ **{'level': levels, 'zscore': z_scores, 'gene': genes},
209
+ **additional_columns
210
+ )
211
+ )
212
+ # data.index.name = 'probe_id'
213
+ tabular.Tabular.__init__(
214
+ self,
215
+ description=(
216
+ (self.DESCRIPTION + self.ALLEN_ATLAS_NOTIFICATION)
217
+ .replace('\n', ' ')
218
+ .replace('\t', '')
219
+ .strip()
220
+ ),
221
+ modality="Gene expression",
222
+ anchor=anchor,
223
+ data=_data_cahced,
224
+ datasets=datasets
225
+ )
226
+ self.unit = "expression level"
227
+
228
+ def plot(self, *args, backend="matplotlib", **kwargs):
229
+ """
230
+ Create a box plot per gene.
231
+
232
+ Parameters
233
+ ----------
234
+ backend: str
235
+ "matplotlib", "plotly", or others supported by pandas DataFrame
236
+ plotting backend.
237
+ **kwargs
238
+ Keyword arguments are passed on to the plot command.
239
+ """
240
+ wrapwidth = kwargs.pop("textwrap") if "textwrap" in kwargs else 40
241
+ kwargs["title"] = kwargs.pop("title", None) \
242
+ or "\n".join(wrap(f"{self.modality} measured in {self.anchor._regionspec or self.anchor.location}", wrapwidth))
243
+ kwargs["kind"] = "box"
244
+ if backend == "matplotlib":
245
+ for arg in ['yerr', 'y', 'ylabel', 'xlabel', 'width']:
246
+ assert arg not in kwargs
247
+ default_kwargs = {
248
+ "grid": True, "legend": False, 'by': "gene",
249
+ 'column': ['level'], 'showfliers': False, 'ax': None,
250
+ 'ylabel': 'expression level'
251
+ }
252
+ return self.data.plot(*args, **{**default_kwargs, **kwargs}, backend=backend)
253
+ elif backend == "plotly":
254
+ kwargs["title"] = kwargs["title"].replace('\n', "<br>")
255
+ return self.data.plot(y='level', x='gene', backend=backend, **kwargs)
256
+ else:
257
+ return self.data.plot(*args, backend=backend, **kwargs)
@@ -0,0 +1,62 @@
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
+
16
+ from . import cortical_profile
17
+ from . import tabular
18
+
19
+ import pandas as pd
20
+ import numpy as np
21
+
22
+ from typing import TYPE_CHECKING
23
+ if TYPE_CHECKING:
24
+ from ...features.anchor import AnatomicalAnchor
25
+
26
+
27
+ class LayerwiseBigBrainIntensities(
28
+ tabular.Tabular,
29
+ category='cellular'
30
+ ):
31
+
32
+ DESCRIPTION = (
33
+ "Layerwise averages and standard deviations of of BigBrain staining intensities "
34
+ "computed by Konrad Wagstyl, as described in the publication "
35
+ "'Wagstyl, K., et al (2020). BigBrain 3D atlas of "
36
+ "cortical layers: Cortical and laminar thickness gradients diverge in sensory and "
37
+ "motor cortices. PLoS Biology, 18(4), e3000678. "
38
+ "http://dx.doi.org/10.1371/journal.pbio.3000678."
39
+ "The data is taken from the tutorial at "
40
+ "https://github.com/kwagstyl/cortical_layers_tutorial. Each vertex is "
41
+ "assigned to the regional map when queried."
42
+ )
43
+
44
+ def __init__(
45
+ self,
46
+ anchor: "AnatomicalAnchor",
47
+ means: list,
48
+ stds: list,
49
+ ):
50
+ data = pd.DataFrame(
51
+ np.array([means, stds]).T,
52
+ columns=['mean', 'std'],
53
+ index=list(cortical_profile.CorticalProfile.LAYERS.values())[1: -1]
54
+ )
55
+ data.index.name = "layer"
56
+ tabular.Tabular.__init__(
57
+ self,
58
+ description=self.DESCRIPTION,
59
+ modality="Modified silver staining",
60
+ anchor=anchor,
61
+ data=data
62
+ )