siibra 0.5a2__py3-none-any.whl → 1.0.0a1__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 (83) hide show
  1. siibra/VERSION +1 -1
  2. siibra/__init__.py +20 -12
  3. siibra/commons.py +145 -90
  4. siibra/configuration/__init__.py +1 -1
  5. siibra/configuration/configuration.py +22 -17
  6. siibra/configuration/factory.py +177 -128
  7. siibra/core/__init__.py +1 -8
  8. siibra/core/{relation_qualification.py → assignment.py} +17 -14
  9. siibra/core/atlas.py +66 -35
  10. siibra/core/concept.py +81 -39
  11. siibra/core/parcellation.py +83 -67
  12. siibra/core/region.py +569 -263
  13. siibra/core/space.py +7 -39
  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 +16 -0
  22. siibra/explorer/url.py +112 -52
  23. siibra/explorer/util.py +31 -9
  24. siibra/features/__init__.py +73 -8
  25. siibra/features/anchor.py +75 -196
  26. siibra/features/connectivity/__init__.py +1 -1
  27. siibra/features/connectivity/functional_connectivity.py +2 -2
  28. siibra/features/connectivity/regional_connectivity.py +99 -10
  29. siibra/features/connectivity/streamline_counts.py +1 -1
  30. siibra/features/connectivity/streamline_lengths.py +1 -1
  31. siibra/features/connectivity/tracing_connectivity.py +1 -1
  32. siibra/features/dataset/__init__.py +1 -1
  33. siibra/features/dataset/ebrains.py +3 -3
  34. siibra/features/feature.py +219 -110
  35. siibra/features/image/__init__.py +1 -1
  36. siibra/features/image/image.py +21 -13
  37. siibra/features/image/sections.py +1 -1
  38. siibra/features/image/volume_of_interest.py +1 -1
  39. siibra/features/tabular/__init__.py +1 -1
  40. siibra/features/tabular/bigbrain_intensity_profile.py +24 -13
  41. siibra/features/tabular/cell_density_profile.py +111 -69
  42. siibra/features/tabular/cortical_profile.py +82 -16
  43. siibra/features/tabular/gene_expression.py +117 -6
  44. siibra/features/tabular/layerwise_bigbrain_intensities.py +7 -9
  45. siibra/features/tabular/layerwise_cell_density.py +9 -24
  46. siibra/features/tabular/receptor_density_fingerprint.py +11 -6
  47. siibra/features/tabular/receptor_density_profile.py +12 -15
  48. siibra/features/tabular/regional_timeseries_activity.py +74 -18
  49. siibra/features/tabular/tabular.py +17 -8
  50. siibra/livequeries/__init__.py +1 -7
  51. siibra/livequeries/allen.py +139 -77
  52. siibra/livequeries/bigbrain.py +104 -128
  53. siibra/livequeries/ebrains.py +7 -4
  54. siibra/livequeries/query.py +1 -2
  55. siibra/locations/__init__.py +32 -25
  56. siibra/locations/boundingbox.py +153 -127
  57. siibra/locations/location.py +45 -80
  58. siibra/locations/point.py +97 -83
  59. siibra/locations/pointcloud.py +349 -0
  60. siibra/retrieval/__init__.py +1 -1
  61. siibra/retrieval/cache.py +107 -13
  62. siibra/retrieval/datasets.py +9 -14
  63. siibra/retrieval/exceptions/__init__.py +2 -1
  64. siibra/retrieval/repositories.py +147 -53
  65. siibra/retrieval/requests.py +64 -29
  66. siibra/vocabularies/__init__.py +2 -2
  67. siibra/volumes/__init__.py +7 -9
  68. siibra/volumes/parcellationmap.py +396 -253
  69. siibra/volumes/providers/__init__.py +20 -0
  70. siibra/volumes/providers/freesurfer.py +113 -0
  71. siibra/volumes/{gifti.py → providers/gifti.py} +29 -18
  72. siibra/volumes/{neuroglancer.py → providers/neuroglancer.py} +204 -92
  73. siibra/volumes/{nifti.py → providers/nifti.py} +64 -44
  74. siibra/volumes/providers/provider.py +107 -0
  75. siibra/volumes/sparsemap.py +159 -260
  76. siibra/volumes/volume.py +720 -152
  77. {siibra-0.5a2.dist-info → siibra-1.0.0a1.dist-info}/METADATA +25 -28
  78. siibra-1.0.0a1.dist-info/RECORD +84 -0
  79. {siibra-0.5a2.dist-info → siibra-1.0.0a1.dist-info}/WHEEL +1 -1
  80. siibra/locations/pointset.py +0 -198
  81. siibra-0.5a2.dist-info/RECORD +0 -74
  82. {siibra-0.5a2.dist-info → siibra-1.0.0a1.dist-info}/LICENSE +0 -0
  83. {siibra-0.5a2.dist-info → siibra-1.0.0a1.dist-info}/top_level.txt +0 -0
@@ -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");
@@ -15,6 +15,7 @@
15
15
 
16
16
  from .. import anchor as _anchor
17
17
  from . import tabular
18
+ from ...retrieval.datasets import GenericDataset
18
19
 
19
20
  import pandas as pd
20
21
  from textwrap import wrap
@@ -46,6 +47,114 @@ class GeneExpressions(
46
47
  as specified at https://alleninstitute.org/legal/terms-use/.
47
48
  """
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
+
49
158
  class _DonorDict(TypedDict):
50
159
  id: int
51
160
  name: str
@@ -66,7 +175,7 @@ class GeneExpressions(
66
175
  genes: List[str],
67
176
  additional_columns: dict,
68
177
  anchor: _anchor.AnatomicalAnchor,
69
- datasets: List = []
178
+ datasets: List = [DATASET]
70
179
  ):
71
180
  """
72
181
  Construct gene expression table.
@@ -130,15 +239,17 @@ class GeneExpressions(
130
239
  """
131
240
  wrapwidth = kwargs.pop("textwrap") if "textwrap" in kwargs else 40
132
241
  kwargs["title"] = kwargs.pop("title", None) \
133
- or "\n".join(wrap(f"{self.modality} measured in {self.anchor._regionspec}", wrapwidth))
242
+ or "\n".join(wrap(f"{self.modality} measured in {self.anchor._regionspec or self.anchor.location}", wrapwidth))
134
243
  kwargs["kind"] = "box"
135
244
  if backend == "matplotlib":
136
245
  for arg in ['yerr', 'y', 'ylabel', 'xlabel', 'width']:
137
246
  assert arg not in kwargs
138
- passed_kwarg = {
139
- "grid": True, "legend": False, 'by': "gene", 'column': ['level'], 'showfliers': False, 'ax': None, **kwargs
247
+ default_kwargs = {
248
+ "grid": True, "legend": False, 'by': "gene",
249
+ 'column': ['level'], 'showfliers': False, 'ax': None,
250
+ 'ylabel': 'expression level'
140
251
  }
141
- return self.data.plot(*args, **passed_kwarg, backend=backend)
252
+ return self.data.plot(*args, **{**default_kwargs, **kwargs}, backend=backend)
142
253
  elif backend == "plotly":
143
254
  kwargs["title"] = kwargs["title"].replace('\n', "<br>")
144
255
  return self.data.plot(y='level', x='gene', backend=backend, **kwargs)
@@ -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");
@@ -19,6 +19,10 @@ from . import tabular
19
19
  import pandas as pd
20
20
  import numpy as np
21
21
 
22
+ from typing import TYPE_CHECKING
23
+ if TYPE_CHECKING:
24
+ from ...features.anchor import AnatomicalAnchor
25
+
22
26
 
23
27
  class LayerwiseBigBrainIntensities(
24
28
  tabular.Tabular,
@@ -31,7 +35,7 @@ class LayerwiseBigBrainIntensities(
31
35
  "'Wagstyl, K., et al (2020). BigBrain 3D atlas of "
32
36
  "cortical layers: Cortical and laminar thickness gradients diverge in sensory and "
33
37
  "motor cortices. PLoS Biology, 18(4), e3000678. "
34
- "http://dx.doi.org/10.1371/journal.pbio.3000678'."
38
+ "http://dx.doi.org/10.1371/journal.pbio.3000678."
35
39
  "The data is taken from the tutorial at "
36
40
  "https://github.com/kwagstyl/cortical_layers_tutorial. Each vertex is "
37
41
  "assigned to the regional map when queried."
@@ -39,16 +43,10 @@ class LayerwiseBigBrainIntensities(
39
43
 
40
44
  def __init__(
41
45
  self,
42
- regionname: str,
46
+ anchor: "AnatomicalAnchor",
43
47
  means: list,
44
48
  stds: list,
45
49
  ):
46
-
47
- from ..anchor import AnatomicalAnchor
48
- anchor = AnatomicalAnchor(
49
- region=regionname,
50
- species='Homo sapiens'
51
- )
52
50
  data = pd.DataFrame(
53
51
  np.array([means, stds]).T,
54
52
  columns=['mean', 'std'],
@@ -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");
@@ -16,13 +16,13 @@
16
16
  from . import cortical_profile
17
17
  from .. import anchor as _anchor
18
18
  from . import tabular
19
+ from ..tabular.cell_density_profile import cell_reader, layer_reader
19
20
 
20
21
  from ... import commons
21
22
  from ...retrieval import requests
22
23
 
23
24
  import pandas as pd
24
25
  import numpy as np
25
- from io import BytesIO
26
26
 
27
27
 
28
28
  class LayerwiseCellDensity(
@@ -40,22 +40,14 @@ class LayerwiseCellDensity(
40
40
  "The cortical depth is estimated from the measured layer thicknesses."
41
41
  )
42
42
 
43
- @classmethod
44
- def CELL_READER(cls, b):
45
- return pd.read_csv(BytesIO(b[2:]), delimiter=" ", header=0).astype(
46
- {"layer": int, "label": int}
47
- )
48
-
49
- @classmethod
50
- def LAYER_READER(cls, b):
51
- return pd.read_csv(BytesIO(b[2:]), delimiter=" ", header=0, index_col=0)
52
-
53
43
  def __init__(
54
44
  self,
55
45
  segmentfiles: list,
56
46
  layerfiles: list,
57
47
  anchor: _anchor.AnatomicalAnchor,
58
48
  datasets: list = [],
49
+ id: str = None,
50
+ prerelease: bool = False,
59
51
  ):
60
52
  tabular.Tabular.__init__(
61
53
  self,
@@ -63,7 +55,9 @@ class LayerwiseCellDensity(
63
55
  modality="Cell body density",
64
56
  anchor=anchor,
65
57
  datasets=datasets,
66
- data=None # lazy loading below
58
+ data=None, # lazy loading below
59
+ id=id,
60
+ prerelease=prerelease,
67
61
  )
68
62
  self.unit = "# detected cells/0.1mm3"
69
63
  self._filepairs = list(zip(segmentfiles, layerfiles))
@@ -73,8 +67,8 @@ class LayerwiseCellDensity(
73
67
  density_dict = {}
74
68
  for i, (cellfile, layerfile) in enumerate(self._filepairs):
75
69
  try:
76
- cells = requests.HttpRequest(cellfile, func=self.CELL_READER).data
77
- layers = requests.HttpRequest(layerfile, func=self.LAYER_READER).data
70
+ cells = requests.HttpRequest(cellfile, func=cell_reader).data
71
+ layers = requests.HttpRequest(layerfile, func=layer_reader).data
78
72
  except requests.SiibraHttpRequestError as e:
79
73
  print(str(e))
80
74
  commons.logger.error(f"Skipping to bootstrap a {self.__class__.__name__} feature, cannot access file resource.")
@@ -99,12 +93,3 @@ class LayerwiseCellDensity(
99
93
  )
100
94
  self._data_cached.index.name = 'layer'
101
95
  return self._data_cached
102
-
103
- @property
104
- def key(self):
105
- assert len(self.species) == 1
106
- return commons.create_key("{}_{}_{}".format(
107
- self.dataset_id,
108
- self.species[0]['name'],
109
- self.regionspec
110
- ))
@@ -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");
@@ -42,7 +42,9 @@ class ReceptorDensityFingerprint(
42
42
  self,
43
43
  tsvfile: str,
44
44
  anchor: _anchor.AnatomicalAnchor,
45
- datasets: list = []
45
+ datasets: list = [],
46
+ id: str = None,
47
+ prerelease: bool = False,
46
48
  ):
47
49
  """ Generate a receptor fingerprint from a URL to a .tsv file
48
50
  formatted according to the structure used by Palomero-Gallagher et al.
@@ -54,6 +56,8 @@ class ReceptorDensityFingerprint(
54
56
  anchor=anchor,
55
57
  data=None, # lazy loading below
56
58
  datasets=datasets,
59
+ id=id,
60
+ prerelease=prerelease,
57
61
  )
58
62
  self._loader = requests.HttpRequest(tsvfile)
59
63
 
@@ -170,10 +174,11 @@ class ReceptorDensityFingerprint(
170
174
  self.data["mean"] + self.data["std"]
171
175
  ]
172
176
  ),
173
- "cat":
174
- len(self.data) * ["mean"] +\
175
- len(self.data) * ["mean - std"] +\
176
- len(self.data) * ["mean + std"]
177
+ "cat": (
178
+ len(self.data) * ["mean"]
179
+ + len(self.data) * ["mean - std"]
180
+ + len(self.data) * ["mean + std"]
181
+ )
177
182
  }
178
183
  )
179
184
  return line_polar(
@@ -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");
@@ -41,7 +41,9 @@ class ReceptorDensityProfile(
41
41
  receptor: str,
42
42
  tsvfile: str,
43
43
  anchor: _anchor.AnatomicalAnchor,
44
- datasets: list = []
44
+ datasets: list = [],
45
+ id: str = None,
46
+ prerelease: bool = False,
45
47
  ):
46
48
  """Generate a receptor density profile from a URL to a .tsv file
47
49
  formatted according to the structure used by Palomero-Gallagher et al.
@@ -52,8 +54,10 @@ class ReceptorDensityProfile(
52
54
  modality="Receptor density",
53
55
  anchor=anchor,
54
56
  datasets=datasets,
57
+ id=id,
58
+ prerelease=prerelease
55
59
  )
56
- self.type = receptor
60
+ self.receptor = receptor
57
61
  self._data_cached = None
58
62
  self._loader = requests.HttpRequest(tsvfile)
59
63
  self._unit_cached = None
@@ -65,25 +69,18 @@ class ReceptorDensityProfile(
65
69
  self.id,
66
70
  create_key(self.species_name),
67
71
  create_key(self.regionspec),
68
- create_key(self.type)
72
+ create_key(self.receptor)
69
73
  )
70
74
 
71
75
  @property
72
- def receptor(self):
73
- return "{} ({})".format(
74
- self.type,
75
- vocabularies.RECEPTOR_SYMBOLS[self.type]['receptor']['name'],
76
- )
77
-
78
- @property
79
- def name(self):
80
- return super().name + f" for {self.type}"
76
+ def receptor_fullname(self):
77
+ return vocabularies.RECEPTOR_SYMBOLS[self.receptor]['receptor']['name']
81
78
 
82
79
  @property
83
80
  def neurotransmitter(self):
84
81
  return "{} ({})".format(
85
- vocabularies.RECEPTOR_SYMBOLS[self.type]['neurotransmitter']['label'],
86
- vocabularies.RECEPTOR_SYMBOLS[self.type]['neurotransmitter']['name'],
82
+ vocabularies.RECEPTOR_SYMBOLS[self.receptor]['neurotransmitter']['label'],
83
+ vocabularies.RECEPTOR_SYMBOLS[self.receptor]['neurotransmitter']['name'],
87
84
  )
88
85
 
89
86
  @property
@@ -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");
@@ -16,13 +16,14 @@
16
16
  from . import tabular
17
17
  from ..feature import Compoundable
18
18
 
19
+ from ...core import region as _region
19
20
  from .. import anchor as _anchor
20
- from ...commons import QUIET
21
- from ...locations import pointset
21
+ from ...commons import QUIET, siibra_tqdm
22
+ from ...locations import pointcloud
22
23
  from ...retrieval.repositories import RepositoryConnector
23
24
  from ...retrieval.requests import HttpRequest
24
25
 
25
- from typing import Callable, List
26
+ from typing import Callable, List, Union
26
27
  import pandas as pd
27
28
  import numpy as np
28
29
 
@@ -47,7 +48,9 @@ class RegionalTimeseriesActivity(tabular.Tabular, Compoundable):
47
48
  timestep: str,
48
49
  description: str = "",
49
50
  datasets: list = [],
50
- subject: str = "average"
51
+ subject: str = "average",
52
+ id: str = None,
53
+ prerelease: bool = False,
51
54
  ):
52
55
  """
53
56
  """
@@ -57,7 +60,9 @@ class RegionalTimeseriesActivity(tabular.Tabular, Compoundable):
57
60
  description=description,
58
61
  anchor=anchor,
59
62
  datasets=datasets,
60
- data=None # lazy loading below
63
+ data=None, # lazy loading below
64
+ id=id,
65
+ prerelease=prerelease,
61
66
  )
62
67
  self.cohort = cohort.upper()
63
68
  if isinstance(connector, str) and connector:
@@ -74,12 +79,12 @@ class RegionalTimeseriesActivity(tabular.Tabular, Compoundable):
74
79
 
75
80
  @property
76
81
  def subject(self):
77
- """Returns the subject identifiers for which the matrix represents."""
82
+ """Returns the subject identifiers for which the table represents."""
78
83
  return self._subject
79
84
 
80
85
  @property
81
86
  def name(self):
82
- return f"{super().name} with cohort {self.cohort} - subject {self.subject}"
87
+ return f"{self.subject} - " + super().name + f" cohort: {self.cohort}"
83
88
 
84
89
  @property
85
90
  def data(self) -> pd.DataFrame:
@@ -90,16 +95,61 @@ class RegionalTimeseriesActivity(tabular.Tabular, Compoundable):
90
95
  self._load_table()
91
96
  return self._table.copy()
92
97
 
98
+ @classmethod
99
+ def _merge_elements(
100
+ cls,
101
+ elements: List["RegionalTimeseriesActivity"],
102
+ description: str,
103
+ modality: str,
104
+ anchor: _anchor.AnatomicalAnchor,
105
+ ):
106
+ assert len({f.cohort for f in elements}) == 1
107
+ assert len({f.timestep for f in elements}) == 1
108
+ merged = cls(
109
+ cohort=elements[0].cohort,
110
+ regions=elements[0].regions,
111
+ connector=elements[0]._connector,
112
+ decode_func=elements[0]._decode_func,
113
+ filename="",
114
+ timestep=" ".join(str(val) for val in elements[0].timestep),
115
+ subject="average",
116
+ description=description,
117
+ modality=modality,
118
+ anchor=anchor,
119
+ **{"paradigm": "average"} if getattr(elements[0], "paradigm") else {}
120
+ )
121
+ if isinstance(elements[0]._connector, HttpRequest):
122
+ getter = lambda elm: elm._connector.get()
123
+ else:
124
+ getter = lambda elm: elm._connector.get(elm._filename, decode_func=elm._decode_func)
125
+ all_arrays = [
126
+ getter(elm)
127
+ for elm in siibra_tqdm(
128
+ elements,
129
+ total=len(elements),
130
+ desc=f"Averaging {len(elements)} activity tables"
131
+ )
132
+ ]
133
+ merged._table = elements[0]._arraylike_to_dataframe(
134
+ np.stack(all_arrays).mean(0)
135
+ )
136
+ return merged
137
+
93
138
  def _load_table(self):
94
139
  """
95
140
  Extract the timeseries table.
96
141
  """
97
- array = self._connector.get(self._filename, decode_func=self._decode_func)
142
+ if isinstance(self._connector, HttpRequest):
143
+ array = self._connector.data
144
+ else:
145
+ array = self._connector.get(self._filename, decode_func=self._decode_func)
146
+ self._table = self._arraylike_to_dataframe(array)
147
+
148
+ def _arraylike_to_dataframe(self, array: Union[np.ndarray, pd.DataFrame]) -> pd.DataFrame:
98
149
  if not isinstance(array, np.ndarray):
99
- assert isinstance(array, pd.DataFrame)
100
150
  array = array.to_numpy()
101
151
  ncols = array.shape[1]
102
- self._table = pd.DataFrame(
152
+ table = pd.DataFrame(
103
153
  array,
104
154
  index=pd.TimedeltaIndex(
105
155
  np.arange(0, array.shape[0]) * self.timestep[0],
@@ -120,7 +170,9 @@ class RegionalTimeseriesActivity(tabular.Tabular, Compoundable):
120
170
  label - min(columnmap.keys()): region
121
171
  for label, region in columnmap.items()
122
172
  }
123
- self._table = self._table.rename(columns=remapper)
173
+ table = table.rename(columns=remapper)
174
+
175
+ return table
124
176
 
125
177
  def __str__(self):
126
178
  return self.name
@@ -151,14 +203,14 @@ class RegionalTimeseriesActivity(tabular.Tabular, Compoundable):
151
203
  found = [r for r in region if r.name in all_centroids]
152
204
  assert len(found) > 0
153
205
  result.append(
154
- tuple(pointset.PointSet(
206
+ tuple(pointcloud.PointCloud(
155
207
  [all_centroids[r.name] for r in found], space=space
156
208
  ).centroid)
157
209
  )
158
210
  return result
159
211
 
160
212
  def plot(
161
- self, regions: List[str] = None, *args,
213
+ self, regions: List[Union[str, "_region.Region"]] = None, *args,
162
214
  backend="matplotlib", **kwargs
163
215
  ):
164
216
  """
@@ -166,13 +218,15 @@ class RegionalTimeseriesActivity(tabular.Tabular, Compoundable):
166
218
 
167
219
  Parameters
168
220
  ----------
169
- regions: str, Region
221
+ regions: List[str or Region]
170
222
  subject: str, default: None
171
223
  If None, returns the subject averaged table.
172
224
  args and kwargs:
173
225
  takes arguments and keyword arguments for the desired plotting
174
226
  backend.
175
227
  """
228
+ if isinstance(regions, (str, _region.Region)):
229
+ regions = [regions]
176
230
  if regions is None:
177
231
  regions = self.regions
178
232
  indices = [self.regions.index(r) for r in regions]
@@ -181,7 +235,7 @@ class RegionalTimeseriesActivity(tabular.Tabular, Compoundable):
181
235
  return table.mean().plot(kind="bar", *args, backend=backend, **kwargs)
182
236
 
183
237
  def plot_carpet(
184
- self, regions: List[str] = None, *args,
238
+ self, regions: List[Union[str, "_region.Region"]] = None, *args,
185
239
  backend="plotly", **kwargs
186
240
  ):
187
241
  """
@@ -189,7 +243,7 @@ class RegionalTimeseriesActivity(tabular.Tabular, Compoundable):
189
243
 
190
244
  Parameters
191
245
  ----------
192
- regions: str, Region
246
+ regions: List[str or Region]
193
247
  subject: str, default: None
194
248
  If None, returns the subject averaged table.
195
249
  args and kwargs:
@@ -197,6 +251,8 @@ class RegionalTimeseriesActivity(tabular.Tabular, Compoundable):
197
251
  """
198
252
  if backend != "plotly":
199
253
  raise NotImplementedError("Currently, carpet plot is only implemented with `plotly`.")
254
+ if isinstance(regions, (str, _region.Region)):
255
+ regions = [regions]
200
256
  if regions is None:
201
257
  regions = self.regions
202
258
  indices = [self.regions.index(r) for r in regions]
@@ -235,4 +291,4 @@ class RegionalBOLD(
235
291
 
236
292
  @property
237
293
  def name(self):
238
- return f"{super().name}, paradigm {self.paradigm}"
294
+ return super().name + f", paradigm: {self.paradigm}"
@@ -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");
@@ -44,14 +44,18 @@ class Tabular(feature.Feature):
44
44
  modality: str,
45
45
  anchor: _anchor.AnatomicalAnchor,
46
46
  data: pd.DataFrame, # sample x feature dimension
47
- datasets: list = []
47
+ datasets: list = [],
48
+ id: str = None,
49
+ prerelease: bool = False,
48
50
  ):
49
51
  feature.Feature.__init__(
50
52
  self,
51
53
  modality=modality,
52
54
  description=description,
53
55
  anchor=anchor,
54
- datasets=datasets
56
+ datasets=datasets,
57
+ id=id,
58
+ prerelease=prerelease
55
59
  )
56
60
  self._data_cached = data
57
61
 
@@ -59,8 +63,8 @@ class Tabular(feature.Feature):
59
63
  def data(self):
60
64
  return self._data_cached.copy()
61
65
 
62
- def _export(self, fh: ZipFile):
63
- super()._export(fh)
66
+ def _to_zip(self, fh: ZipFile):
67
+ super()._to_zip(fh)
64
68
  fh.writestr("tabular.csv", self.data.to_csv())
65
69
 
66
70
  def plot(self, *args, backend="matplotlib", **kwargs):
@@ -97,19 +101,24 @@ class Tabular(feature.Feature):
97
101
  kwargs["width"] = kwargs.get("width", 0.95)
98
102
  kwargs["ylabel"] = kwargs.get(
99
103
  "ylabel",
100
- f"{kwargs['y']}{yerr_label} {self.unit if hasattr(self, 'unit') else ''}"
104
+ f"{kwargs['y']}{yerr_label}" + f"\n{self.unit}" if hasattr(self, 'unit') else ""
101
105
  )
102
106
  kwargs["grid"] = kwargs.get("grid", True)
103
107
  kwargs["legend"] = kwargs.get("legend", False)
108
+ xticklabel_rotation = kwargs.get("xticklabel_rotation", 60)
104
109
  ax = self.data.plot(*args, backend=backend, **kwargs)
105
110
  ax.set_title(ax.get_title(), fontsize="medium")
106
- ax.set_xticklabels(ax.get_xticklabels(), rotation=60, ha="right")
111
+ ax.set_xticklabels(
112
+ ax.get_xticklabels(),
113
+ rotation=xticklabel_rotation,
114
+ ha='center' if xticklabel_rotation % 90 == 0 else 'right'
115
+ )
107
116
  plt.tight_layout()
108
117
  return ax
109
118
  elif backend == "plotly":
110
119
  kwargs["title"] = kwargs["title"].replace("\n", "<br>")
111
120
  kwargs["error_y"] = kwargs.get("error_y", 'std' if 'std' in self.data.columns else None)
112
- error_y_label = f" &plusmn; {kwargs.get('error_y')}" if kwargs.get('error_y') else ''
121
+ error_y_label = f" &plusmn; {kwargs.get('error_y')}<br>" if kwargs.get('error_y') else ''
113
122
  kwargs["labels"] = {
114
123
  "index": kwargs.pop("xlabel", None) or kwargs.pop("index", ""),
115
124
  "value": kwargs.pop("ylabel", None) or kwargs.pop(
@@ -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");
@@ -17,9 +17,3 @@
17
17
  from .allen import AllenBrainAtlasQuery
18
18
  from .bigbrain import LayerwiseBigBrainIntensityQuery, BigBrainProfileQuery
19
19
  from .ebrains import EbrainsFeatureQuery
20
-
21
-
22
- def warm_cache():
23
- """Preload downloadable livequeries."""
24
- from .bigbrain import WagstylProfileLoader
25
- WagstylProfileLoader()