siibra 1.0.1a2__py3-none-any.whl → 1.0.1a5__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 CHANGED
@@ -1 +1 @@
1
- 1.0.1-alpha.2
1
+ 1.0.1-alpha.5
siibra/commons.py CHANGED
@@ -534,13 +534,21 @@ def resample_img_to_img(
534
534
  -------
535
535
  Nifti1Image
536
536
  """
537
+ from nilearn._version import version as nilearn_version
538
+ from packaging.version import Version
539
+
537
540
  interpolation = "nearest" if np.array_equal(np.unique(source_img.dataobj), [0, 1]) else "linear"
538
- resampled_img = resample_to_img(
541
+ kwargs = dict(
539
542
  source_img=source_img,
540
543
  target_img=target_img,
541
544
  interpolation=interpolation,
542
545
  force_resample=True, # False is intended for testing. see nilearn docs
543
546
  )
547
+ if Version(nilearn_version) >= Version("0.11.0"):
548
+ # because nilearn>=0.11.0 don't support "copy_header" and python <= 3.8
549
+ kwargs["copy_header"] = True # use new default in nilearn >= 0.11.0
550
+
551
+ resampled_img = resample_to_img(**kwargs)
544
552
  return resampled_img
545
553
 
546
554
 
@@ -725,6 +733,7 @@ class Species(Enum):
725
733
  MACACA_MULATTA = 5
726
734
  MACACA_FUSCATA = 6
727
735
  CHLOROCEBUS_AETHIOPS_SABAEUS = 7
736
+ CALLITHRIX_JACCHUS = 8
728
737
 
729
738
  UNSPECIFIED_SPECIES = 999
730
739
 
@@ -185,5 +185,4 @@ class Configuration:
185
185
 
186
186
 
187
187
  if SIIBRA_USE_CONFIGURATION:
188
- logger.warning(f"config.SIIBRA_USE_CONFIGURATION defined, use configuration at {SIIBRA_USE_CONFIGURATION}")
189
188
  Configuration.use_configuration(SIIBRA_USE_CONFIGURATION)
@@ -487,6 +487,10 @@ class Factory:
487
487
  return volume_of_interest.LSFMVolumeOfInterest(
488
488
  modality="Light Sheet Fluorescence Microscopy", **kwargs
489
489
  )
490
+ elif modality == "morphometry":
491
+ return volume_of_interest.MorphometryVolumeOfInterest(
492
+ modality="Morphometry", **kwargs
493
+ )
490
494
  else:
491
495
  raise ValueError(
492
496
  f"No method for building image section feature type {modality}."
siibra/core/assignment.py CHANGED
@@ -26,12 +26,12 @@ T = TypeVar("T")
26
26
 
27
27
  class Qualification(Enum):
28
28
  EXACT = 1
29
- OVERLAPS = 2
30
- CONTAINED = 3
31
- CONTAINS = 4
32
- APPROXIMATE = 5
33
- HOMOLOGOUS = 6
34
- OTHER_VERSION = 7
29
+ APPROXIMATE = 2
30
+ OTHER_VERSION = 3
31
+ CONTAINED = 4
32
+ CONTAINS = 5
33
+ OVERLAPS = 6
34
+ HOMOLOGOUS = 7
35
35
 
36
36
  @property
37
37
  def verb(self):
@@ -67,6 +67,17 @@ class Qualification(Enum):
67
67
  assert self in inverses, f"{str(self)} inverses cannot be found."
68
68
  return inverses[self]
69
69
 
70
+ def __lt__(self, other: "Qualification"):
71
+ """
72
+ This is used to sort feature query results. Since it is very difficult
73
+ to determine a well-ordering principle and it is difficult to sort
74
+ without one, the enum values are used for sorting. This means
75
+ not all comparisons have logical basis but they are well-defined,
76
+ making it reproducible but also clearly distinguishes important
77
+ comparisons.
78
+ """
79
+ return self.value < other.value
80
+
70
81
  def __str__(self):
71
82
  return f"{self.__class__.__name__}={self.name.lower()}"
72
83
 
@@ -108,4 +119,4 @@ class AnatomicalAssignment(Generic[T]):
108
119
  def __lt__(self, other: 'AnatomicalAssignment'):
109
120
  if not isinstance(other, AnatomicalAssignment):
110
121
  raise ValueError(f"Cannot compare AnatomicalAssignment with instances of '{type(other)}'")
111
- return self.qualification.value < other.qualification.value
122
+ return self.qualification < other.qualification
siibra/explorer/url.py CHANGED
@@ -136,7 +136,7 @@ def encode_url(
136
136
 
137
137
  try:
138
138
  result_props = region.spatial_props(space, maptype="labelled")
139
- if len(result_props.components) == 0:
139
+ if len(result_props) == 0:
140
140
  return return_url + nav_string.format(encoded_nav=encoded_position or "0.0.0", **zoom_kwargs)
141
141
  except Exception as e:
142
142
  print(f"Cannot get_spatial_props {str(e)}")
@@ -144,7 +144,7 @@ def encode_url(
144
144
  raise e
145
145
  return return_url + nav_string.format(encoded_nav=encoded_position or "0.0.0", **zoom_kwargs)
146
146
 
147
- centroid = result_props.components[0].centroid
147
+ centroid = result_props[0].centroid
148
148
 
149
149
  encoded_centroid = separator.join(
150
150
  [encode_number(math.floor(val * 1e6)) for val in centroid]
siibra/features/anchor.py CHANGED
@@ -176,9 +176,7 @@ class AnatomicalAnchor:
176
176
  assignments.append(region.assign(concept))
177
177
  self._assignments[concept] = sorted(a for a in assignments if a is not None)
178
178
 
179
- self._last_matched_concept = concept \
180
- if len(self._assignments[concept]) > 0 \
181
- else None
179
+ self._last_matched_concept = concept if len(self._assignments[concept]) > 0 else None
182
180
  return self._assignments[concept]
183
181
 
184
182
  def matches(self, concept: Union[BrainStructure, Space]) -> bool:
@@ -104,6 +104,7 @@ class RegionalConnectivity(Feature, Compoundable):
104
104
  self._matrix = None
105
105
  self._subject = subject
106
106
  self._feature = feature
107
+ self._matrix_std = None # only used for compound feature
107
108
 
108
109
  @property
109
110
  def subject(self):
@@ -170,6 +171,9 @@ class RegionalConnectivity(Feature, Compoundable):
170
171
  merged._matrix = elements[0]._arraylike_to_dataframe(
171
172
  np.stack(all_arrays).mean(0)
172
173
  )
174
+ merged._matrix_std = elements[0]._arraylike_to_dataframe(
175
+ np.stack(all_arrays).std(0)
176
+ )
173
177
  return merged
174
178
 
175
179
  def _plot_matrix(
@@ -258,10 +262,14 @@ class RegionalConnectivity(Feature, Compoundable):
258
262
  non-symmetric matrices. ('column' or 'row')
259
263
  """
260
264
  matrix = self.data
265
+ assert isinstance(matrix, pd.DataFrame)
266
+ matrix_std = self._matrix_std
261
267
  if direction.lower() not in ['column', 'row']:
262
268
  raise ValueError("Direction can only be 'column' or 'row'")
263
269
  if direction.lower() == 'row':
264
270
  matrix = matrix.transpose()
271
+ if matrix_std is not None:
272
+ matrix_std = matrix_std.transpose()
265
273
 
266
274
  def matches(r1, r2):
267
275
  if isinstance(r1, tuple):
@@ -270,32 +278,38 @@ class RegionalConnectivity(Feature, Compoundable):
270
278
  assert isinstance(r1, _region.Region)
271
279
  return r1.matches(r2)
272
280
 
273
- regions = [r for r in matrix.index if matches(r, region)]
274
- if len(regions) == 0:
281
+ # decode region spec
282
+ region_candidates = [r for r in matrix.index if matches(r, region)]
283
+ if len(region_candidates) == 0:
275
284
  raise ValueError(f"Invalid region specification: {region}")
276
- elif len(regions) > 1:
277
- raise ValueError(f"Region specification {region} matched more than one profile: {regions}")
278
- else:
279
- name = self.modality
280
- series = matrix[regions[0]]
281
- last_index = len(series) - 1 if max_rows is None \
282
- else min(max_rows, len(series) - 1)
283
- return Tabular(
284
- description=self.description,
285
- modality=f"{self.modality} {self.cohort}",
286
- anchor=_anchor.AnatomicalAnchor(
287
- species=list(self.anchor.species)[0],
288
- region=regions[0]
289
- ),
290
- data=(
291
- series[:last_index]
292
- .to_frame(name=name)
293
- .query(f'`{name}` > {min_connectivity}')
294
- .sort_values(by=name, ascending=False)
295
- .rename_axis('Target regions')
296
- ),
297
- datasets=self.datasets
298
- )
285
+ if len(region_candidates) > 1:
286
+ raise ValueError(f"Region specification {region} matched more than one profile: {region_candidates}")
287
+ region = region_candidates[0]
288
+
289
+ # create DataFrame
290
+ data = matrix[region].to_frame('mean')
291
+ if matrix_std is not None:
292
+ data = pd.concat([data, matrix_std[region].rename('std')], axis=1)
293
+
294
+ last_index = len(data) if max_rows is None else min(max_rows, len(data))
295
+
296
+ data = (
297
+ data
298
+ .query(f'`mean` > {min_connectivity}')
299
+ .sort_values(by="mean", ascending=False)
300
+ .rename_axis('Target regions')
301
+ )[:last_index]
302
+
303
+ return Tabular(
304
+ description=self.description,
305
+ modality=f"{self.modality} {self.cohort}",
306
+ anchor=_anchor.AnatomicalAnchor(
307
+ species=list(self.anchor.species)[0],
308
+ region=region
309
+ ),
310
+ data=data,
311
+ datasets=self.datasets
312
+ )
299
313
 
300
314
  def plot(
301
315
  self,
@@ -336,8 +350,8 @@ class RegionalConnectivity(Feature, Compoundable):
336
350
  profile = self.get_profile(regions, min_connectivity, max_rows, direction)
337
351
  kwargs["kind"] = kwargs.get("kind", "barh")
338
352
  if backend == "matplotlib":
339
- kwargs["logx"] = kwargs.get("logx", logscale)
340
- return profile.data.plot(*args, backend=backend, **kwargs)
353
+ kwargs["logy"] = kwargs.get("logy", logscale)
354
+ return profile.plot(*args, backend=backend, **kwargs)
341
355
  elif backend == "plotly":
342
356
  kwargs.update({
343
357
  "color": kwargs.get("color", profile.data.columns[0]),
@@ -232,7 +232,10 @@ class Feature:
232
232
  from ..configuration.configuration import Configuration
233
233
  conf = Configuration()
234
234
  Configuration.register_cleanup(cls._clean_instances)
235
- assert cls._configuration_folder in conf.folders
235
+ if cls._configuration_folder not in conf.folders:
236
+ logger.debug(f"{cls._configuration_folder} is not in current configuration")
237
+ return []
238
+
236
239
  cls._preconfigured_instances = [
237
240
  o for o in conf.build_objects(cls._configuration_folder)
238
241
  if isinstance(o, cls)
@@ -580,7 +583,10 @@ class Feature:
580
583
  # with the query concept.
581
584
  live_instances = feature_type._livequery(concept, **kwargs)
582
585
 
583
- results = list(dict.fromkeys(preconfigured_instances + live_instances))
586
+ results = sorted(
587
+ dict.fromkeys(preconfigured_instances + live_instances), # to remove duplicates
588
+ key=lambda f: min(f.last_match_result) if f.last_match_result else False, # to order according to assignmnent ranking
589
+ )
584
590
  return CompoundFeature._compound(results, concept)
585
591
 
586
592
  @classmethod
@@ -21,7 +21,8 @@ from .volume_of_interest import (
21
21
  MRIVolumeOfInterest,
22
22
  XPCTVolumeOfInterest,
23
23
  LSFMVolumeOfInterest,
24
- DTIVolumeOfInterest
24
+ DTIVolumeOfInterest,
25
+ MorphometryVolumeOfInterest,
25
26
  )
26
27
  from .sections import (
27
28
  CellbodyStainedSection,
@@ -78,3 +78,12 @@ class LSFMVolumeOfInterest(
78
78
  ):
79
79
  def __init__(self, modality, **kwargs):
80
80
  image.Image.__init__(self, **kwargs, modality=modality)
81
+
82
+
83
+ class MorphometryVolumeOfInterest(
84
+ image.Image,
85
+ configuration_folder="features/images/vois/morphometry",
86
+ category="macrostructural"
87
+ ):
88
+ def __init__(self, modality, **kwargs):
89
+ image.Image.__init__(self, **kwargs, modality=modality)
@@ -225,6 +225,7 @@ class GeneExpressions(
225
225
  datasets=datasets
226
226
  )
227
227
  self.unit = "expression level"
228
+ self._genes = list(set(genes))
228
229
 
229
230
  def plot(self, *args, backend="matplotlib", **kwargs):
230
231
  """
@@ -239,18 +240,34 @@ class GeneExpressions(
239
240
  Keyword arguments are passed on to the plot command.
240
241
  """
241
242
  wrapwidth = kwargs.pop("textwrap") if "textwrap" in kwargs else 40
242
- kwargs["title"] = kwargs.pop("title", None) \
243
- or "\n".join(wrap(f"{self.modality} measured in {self.anchor._regionspec or self.anchor.location}", wrapwidth))
244
- kwargs["kind"] = "box"
243
+ kwargs["title"] = kwargs.pop(
244
+ "title",
245
+ "\n".join(wrap(
246
+ f"{self.modality}\n{self.anchor._regionspec or self.anchor.location}",
247
+ wrapwidth
248
+ ))
249
+ )
250
+ kwargs["kind"] = kwargs.get("kind", "box")
245
251
  if backend == "matplotlib":
246
- for arg in ['yerr', 'y', 'ylabel', 'xlabel', 'width']:
247
- assert arg not in kwargs
248
- default_kwargs = {
249
- "grid": True, "legend": False, 'by': "gene",
250
- 'column': ['level'], 'showfliers': False, 'ax': None,
251
- 'ylabel': 'expression level'
252
- }
253
- return self.data.plot(*args, **{**default_kwargs, **kwargs}, backend=backend)
252
+ if kwargs["kind"] == "box":
253
+ from matplotlib.pyplot import tight_layout
254
+
255
+ title = kwargs.pop("title")
256
+ default_kwargs = {
257
+ "grid": True,
258
+ 'by': "gene",
259
+ 'column': ['level'],
260
+ 'showfliers': False,
261
+ 'ylabel': 'expression level',
262
+ 'xlabel': 'gene',
263
+ 'color': 'dimgray',
264
+ 'rot': 90 if len(self._genes) > 1 else 0,
265
+ }
266
+ ax, *_ = self.data.plot(*args, backend=backend, **{**default_kwargs, **kwargs})
267
+ ax.set_title(title)
268
+ tight_layout()
269
+ return ax
270
+ return self.data.plot(*args, backend=backend, **kwargs)
254
271
  elif backend == "plotly":
255
272
  kwargs["title"] = kwargs["title"].replace('\n', "<br>")
256
273
  return self.data.plot(y='level', x='gene', backend=backend, **kwargs)
@@ -15,8 +15,8 @@
15
15
 
16
16
  import numpy as np
17
17
  import pandas as pd
18
+ from textwrap import wrap
18
19
 
19
- from . import cortical_profile
20
20
  from . import tabular, cell_reader, layer_reader
21
21
  from .. import anchor as _anchor
22
22
  from ... import commons
@@ -37,6 +37,7 @@ class LayerwiseCellDensity(
37
37
  "detected cells in that layer with the area covered by the layer. Therefore, each profile contains 6 measurement points. "
38
38
  "The cortical depth is estimated from the measured layer thicknesses."
39
39
  )
40
+ BIGBRAIN_VOLUMETRIC_SHRINKAGE_FACTOR = 1.931
40
41
 
41
42
  def __init__(
42
43
  self,
@@ -57,13 +58,13 @@ class LayerwiseCellDensity(
57
58
  id=id,
58
59
  prerelease=prerelease,
59
60
  )
60
- self.unit = "# detected cells/0.1mm3"
61
+ self.unit = "# detected cells / $0.1mm^3$"
61
62
  self._filepairs = list(zip(segmentfiles, layerfiles))
62
63
  self._densities = None
63
64
 
64
65
  def _load_densities(self):
65
- density_dict = {}
66
- for i, (cellfile, layerfile) in enumerate(self._filepairs):
66
+ data = []
67
+ for cellfile, layerfile in self._filepairs:
67
68
  try:
68
69
  cells = requests.HttpRequest(cellfile, func=cell_reader).data
69
70
  layers = requests.HttpRequest(layerfile, func=layer_reader).data
@@ -72,22 +73,82 @@ class LayerwiseCellDensity(
72
73
  commons.logger.error(f"Skipping to bootstrap a {self.__class__.__name__} feature, cannot access file resource.")
73
74
  continue
74
75
  counts = cells.layer.value_counts()
75
- areas = layers["Area(micron**2)"]
76
- indices = np.intersect1d(areas.index, counts.index)
77
- density_dict[i] = counts[indices] / areas * 100 ** 2 * 5
78
- return pd.DataFrame(density_dict)
76
+ # compute the volumetric shrinkage corrections in the same ways as it was used
77
+ # for the pdf reports in the underlying dataset
78
+ shrinkage_volumetric = self.BIGBRAIN_VOLUMETRIC_SHRINKAGE_FACTOR
79
+ layer_volumes = (
80
+ layers["Area(micron**2)"] # this is the number of pixels, shrinkage corrected from the dataset
81
+ * 20 # go to cube micrometer in one patch with 20 micron thickness
82
+ * np.cbrt(shrinkage_volumetric) # compensate linear shrinkage for 3rd dimension
83
+ / 100 ** 3 # go to 0.1 cube millimeter
84
+ )
85
+ fields = cellfile.split("/")
86
+ for layer in layer_volumes.index:
87
+ data.append({
88
+ 'layer': layer,
89
+ 'layername': layers["Name"].loc[layer],
90
+ 'counts': counts.loc[layer],
91
+ 'area_mu2': layers["Area(micron**2)"].loc[layer],
92
+ 'volume': layer_volumes.loc[layer],
93
+ 'density': counts.loc[layer] / layer_volumes.loc[layer],
94
+ 'regionspec': fields[-5],
95
+ 'section': int(fields[-3]),
96
+ 'patch': int(fields[-2]),
97
+ })
98
+ return pd.DataFrame(data)
79
99
 
80
100
  @property
81
101
  def data(self):
82
102
  if self._data_cached is None:
83
- densities = self._load_densities()
84
- self._data_cached = pd.DataFrame(
85
- np.array([
86
- list(densities.mean(axis=1)),
87
- list(densities.std(axis=1))
88
- ]).T,
89
- columns=['mean', 'std'],
90
- index=[cortical_profile.CorticalProfile.LAYERS[_] for _ in densities.index]
91
- )
92
- self._data_cached.index.name = 'layer'
103
+ self._data_cached = self._load_densities()
104
+ # self._data_cached.index.name = 'layer'
93
105
  return self._data_cached
106
+
107
+ def plot(self, *args, backend="matplotlib", **kwargs):
108
+ wrapwidth = kwargs.pop("textwrap") if "textwrap" in kwargs else 40
109
+ kwargs["title"] = kwargs.pop(
110
+ "title",
111
+ "\n".join(wrap(
112
+ f"{self.modality} in {self.anchor._regionspec or self.anchor.location}",
113
+ wrapwidth
114
+ ))
115
+ )
116
+ kwargs["kind"] = kwargs.get("kind", "box")
117
+ kwargs["ylabel"] = kwargs.get(
118
+ "ylabel",
119
+ f"\n{self.unit}" if hasattr(self, 'unit') else ""
120
+ )
121
+ if backend == "matplotlib":
122
+ if kwargs["kind"] == "box":
123
+ from matplotlib.pyplot import tight_layout
124
+
125
+ np.random.seed(int(self.data["density"].mean()))
126
+
127
+ title = kwargs.pop("title")
128
+ default_kwargs = {
129
+ "grid": True,
130
+ 'by': "layername",
131
+ 'column': ['density'],
132
+ 'showfliers': False,
133
+ 'xlabel': 'layer',
134
+ 'color': 'dimgray',
135
+ }
136
+ ax, *_ = self.data.plot(*args, backend=backend, **{**default_kwargs, **kwargs})
137
+ for i, (layer, d) in enumerate(self.data.groupby('layername')):
138
+ ax.scatter(
139
+ np.random.normal(i + 1, 0.05, len(d.density)),
140
+ d.density,
141
+ c='b', s=3
142
+ )
143
+ ax.set_title(title)
144
+ tight_layout()
145
+ return ax
146
+ return self.data.plot(*args, backend=backend, **kwargs)
147
+ elif backend == "plotly":
148
+ kwargs["title"] = kwargs["title"].replace('\n', "<br>")
149
+ yaxis_title = kwargs.pop("ylabel")
150
+ fig = self.data.plot(y='density', x='layer', points="all", backend=backend, **kwargs)
151
+ fig.update_layout(yaxis_title=yaxis_title)
152
+ return fig
153
+ else:
154
+ return self.data.plot(*args, backend=backend, **kwargs)
@@ -99,14 +99,20 @@ class Tabular(feature.Feature):
99
99
  if kwargs.get("error_y") is None:
100
100
  kwargs["yerr"] = kwargs.get("yerr", 'std' if 'std' in self.data.columns else None)
101
101
  yerr_label = f" \u00b1 {kwargs.get('yerr')}" if kwargs.get('yerr') else ''
102
- kwargs["width"] = kwargs.get("width", 0.95)
102
+ if kwargs.get('kind') == 'bar':
103
+ kwargs["width"] = kwargs.get("width", 0.8)
104
+ kwargs["edgecolor"] = kwargs.get('edgecolor', 'black')
105
+ kwargs["linewidth"] = kwargs.get('linewidth', 1.0)
106
+ kwargs["capsize"] = kwargs.get('capsize', 4)
103
107
  kwargs["ylabel"] = kwargs.get(
104
108
  "ylabel",
105
109
  f"{kwargs['y']}{yerr_label}" + f"\n{self.unit}" if hasattr(self, 'unit') else ""
106
110
  )
107
111
  kwargs["grid"] = kwargs.get("grid", True)
108
112
  kwargs["legend"] = kwargs.get("legend", False)
109
- xticklabel_rotation = kwargs.get("xticklabel_rotation", 60)
113
+ kwargs["color"] = kwargs.get('color', 'darkgrey')
114
+
115
+ xticklabel_rotation = kwargs.get("rot", 60)
110
116
  ax = self.data.plot(*args, backend=backend, **kwargs)
111
117
  ax.set_title(ax.get_title(), fontsize="medium")
112
118
  ax.set_xticklabels(
@@ -114,6 +120,8 @@ class Tabular(feature.Feature):
114
120
  rotation=xticklabel_rotation,
115
121
  ha='center' if xticklabel_rotation % 90 == 0 else 'right'
116
122
  )
123
+ ax.spines['top'].set_visible(False)
124
+ ax.spines['right'].set_visible(False)
117
125
  plt.tight_layout()
118
126
  return ax
119
127
  elif backend == "plotly":
@@ -22,6 +22,7 @@ import numpy as np
22
22
 
23
23
  from . import query as _query
24
24
  from ..core import structure
25
+ from ..core.region import Region
25
26
  from ..features import anchor as _anchor
26
27
  from ..features.tabular.gene_expression import GeneExpressions
27
28
  from ..commons import logger, Species
@@ -173,6 +174,8 @@ class AllenBrainAtlasQuery(_query.LiveQuery, args=['gene'], FeatureType=GeneExpr
173
174
  explanation=explanation
174
175
  )]
175
176
  anchor._last_matched_concept = concept
177
+ if isinstance(concept, Region):
178
+ anchor._regionspec = concept.name
176
179
 
177
180
  return [GeneExpressions(
178
181
  anchor=anchor,
@@ -16,7 +16,7 @@
16
16
 
17
17
  from itertools import product
18
18
  import hashlib
19
- from typing import TYPE_CHECKING, Union
19
+ from typing import TYPE_CHECKING, Union, Dict
20
20
 
21
21
  import numpy as np
22
22
 
@@ -282,14 +282,15 @@ class BoundingBox(location.Location):
282
282
  sigma_mm=np.mean([self.minpoint.sigma, self.maxpoint.sigma])
283
283
  )
284
284
 
285
- def warp(self, space):
285
+ def warp(self, space: Union[str, Dict, "Space"]):
286
286
  """Returns a new bounding box obtained by warping the
287
287
  min- and maxpoint of this one into the new target space.
288
288
 
289
289
  TODO process the sigma values o the points
290
290
  """
291
291
  from ..core.space import Space
292
- spaceobj = Space.get_instance(space)
292
+
293
+ spaceobj = space if isinstance(space, Space) else Space.get_instance(space)
293
294
  if spaceobj == self.space:
294
295
  return self
295
296
  else:
@@ -45,18 +45,24 @@ class Location(BrainStructure):
45
45
  _MASK_MEMO = {} # cache region masks for Location._assign_region()
46
46
  _ASSIGNMENT_CACHE = {} # caches assignment results, see Region.assign()
47
47
 
48
- def __init__(self, spacespec: Union[str, Dict[str, str], "_space.Space"]):
48
+ def __init__(self, spacespec: Union[str, Dict[str, str], _space.Space]):
49
49
  self._space_spec = spacespec
50
50
  self._space_cached = None
51
51
 
52
52
  @property
53
- def space(self) -> "_space.Space":
53
+ def space(self) -> _space.Space:
54
54
  if self._space_cached is None:
55
- if isinstance(self._space_spec, dict):
55
+ if self._space_spec is None:
56
+ return None
57
+ elif isinstance(self._space_spec, _space.Space):
58
+ self._space_cached = self._space_spec
59
+ elif isinstance(self._space_spec, dict):
56
60
  spec = self._space_spec.get("@id") or self._space_spec.get("name")
57
61
  self._space_cached = _space.Space.get_instance(spec)
58
- else:
62
+ elif isinstance(self._space_spec, str):
59
63
  self._space_cached = _space.Space.get_instance(self._space_spec)
64
+ else:
65
+ raise ValueError(f"Invalid space spec type: '{type(self._space_spec)}'")
60
66
  return self._space_cached
61
67
 
62
68
  @abstractmethod
siibra/locations/point.py CHANGED
@@ -19,7 +19,7 @@ import re
19
19
  import json
20
20
  import numbers
21
21
  import hashlib
22
- from typing import Tuple, Union
22
+ from typing import Tuple, Union, Dict, TYPE_CHECKING
23
23
 
24
24
  import numpy as np
25
25
 
@@ -28,6 +28,9 @@ from ..commons import logger
28
28
  from ..retrieval.requests import HttpRequest
29
29
  from ..exceptions import SpaceWarpingFailedError, NoneCoordinateSuppliedError
30
30
 
31
+ if TYPE_CHECKING:
32
+ from ..core.space import Space
33
+
31
34
 
32
35
  class Point(location.Location):
33
36
  """A single 3D point in reference space."""
@@ -118,13 +121,14 @@ class Point(location.Location):
118
121
  else:
119
122
  return self if other.intersection(self) else None
120
123
 
121
- def warp(self, space):
124
+ def warp(self, space: Union[str, Dict, "Space"]):
122
125
  """
123
126
  Creates a new point by warping this point to another space
124
127
  TODO this needs to maintain the sigma parameter!
125
128
  """
126
129
  from ..core.space import Space
127
- spaceobj = Space.get_instance(space)
130
+
131
+ spaceobj = space if isinstance(space, Space) else Space.get_instance(space)
128
132
  if spaceobj == self.space:
129
133
  return self
130
134
  if any(_ not in location.Location.SPACEWARP_IDS for _ in [self.space.id, spaceobj.id]):
@@ -14,7 +14,7 @@
14
14
  # limitations under the License.
15
15
  """A set of coordinates on a reference space."""
16
16
 
17
- from typing import List, Union, Tuple
17
+ from typing import List, Union, Tuple, Dict, TYPE_CHECKING
18
18
  import numbers
19
19
  import json
20
20
 
@@ -31,6 +31,9 @@ from ..retrieval.requests import HttpRequest
31
31
  from ..commons import logger
32
32
  from ..exceptions import SpaceWarpingFailedError, EmptyPointCloudError
33
33
 
34
+ if TYPE_CHECKING:
35
+ from ..core.space import Space
36
+
34
37
 
35
38
  def from_points(points: List["point.Point"], newlabels: List[Union[int, float, tuple]] = None) -> "PointCloud":
36
39
  """
@@ -140,9 +143,10 @@ class PointCloud(location.Location):
140
143
  def has_constant_sigma(self) -> bool:
141
144
  return len(set(self.sigma)) == 1
142
145
 
143
- def warp(self, space, chunksize=1000):
146
+ def warp(self, space: Union[str, Dict, "Space"], chunksize: int = 1000):
144
147
  """Creates a new point set by warping its points to another space"""
145
148
  from ..core.space import Space
149
+
146
150
  spaceobj = space if isinstance(space, Space) else Space.get_instance(space)
147
151
  if spaceobj == self.space:
148
152
  return self
@@ -354,7 +358,7 @@ class Contour(PointCloud):
354
358
  def __init__(self, coordinates, space=None, sigma_mm=0, labels: list = None):
355
359
  PointCloud.__init__(self, coordinates, space, sigma_mm, labels)
356
360
 
357
- def crop(self, voi: "_boundingbox.BoundingBox"):
361
+ def crop(self, voi: "_boundingbox.BoundingBox") -> List["Contour"]:
358
362
  """
359
363
  Crop the contour with a volume of interest.
360
364
  Since the contour might be split from the cropping,
@@ -761,10 +761,12 @@ class Map(concept.AtlasConcept, configuration_folder="maps"):
761
761
  f"{no_predefined_color}"
762
762
  )
763
763
 
764
+ max_label_index = max(index[0].label for index in self._indices.values())
765
+
764
766
  palette = np.array(
765
767
  [
766
768
  list(colors[i]) + [1] if i in colors else [0, 0, 0, 0]
767
- for i in range(max(colors.keys()) + 1)
769
+ for i in range(max_label_index + 1)
768
770
  ]
769
771
  ) / [255, 255, 255, 1]
770
772
  return ListedColormap(palette)
@@ -18,11 +18,10 @@ from os import path, makedirs
18
18
  from typing import Dict, List
19
19
 
20
20
  import numpy as np
21
- from nilearn import image
22
21
 
23
22
  from . import parcellationmap, volume as _volume
24
23
  from .providers import provider
25
- from ..commons import MapIndex, logger, connected_components, siibra_tqdm
24
+ from ..commons import MapIndex, logger, connected_components, siibra_tqdm, resample_img_to_img
26
25
  from ..locations import boundingbox
27
26
  from ..retrieval.cache import CACHE
28
27
  from ..retrieval.requests import HttpRequest, FileLoader
@@ -353,30 +352,23 @@ class SparseMap(parcellationmap.Map):
353
352
  split_components: bool, default: True
354
353
  Whether to split the query volume into disjoint components.
355
354
  """
355
+ from nibabel import Nifti1Image
356
+
356
357
  queryimg = queryvolume.fetch()
357
- imgdata = np.asanyarray(queryimg.dataobj)
358
- imgaffine = queryimg.affine
358
+ assert isinstance(queryimg, Nifti1Image)
359
359
  assignments = []
360
360
 
361
- # resample query image into this image's voxel space, if required
362
- if (imgaffine - self.affine).sum() == 0:
363
- querydata = imgdata.squeeze()
364
- else:
365
- if issubclass(imgdata.dtype.type, np.integer):
366
- interp = "nearest"
367
- else:
368
- interp = "linear"
369
- from nibabel import Nifti1Image
370
- queryimg = image.resample_img(
371
- Nifti1Image(imgdata, imgaffine),
372
- target_affine=self.affine,
373
- target_shape=self.shape,
374
- interpolation=interp,
361
+ # resample query image into this image's voxel space, if required (nilearn checks)
362
+ queryimg = resample_img_to_img(
363
+ source_img=queryimg,
364
+ target_img=Nifti1Image(
365
+ np.zeros(self.shape), affine=self.affine, dtype=queryimg.dataobj.dtype
375
366
  )
376
- querydata = np.asanyarray(queryimg.dataobj).squeeze()
367
+ )
368
+ self.space.get_template()
369
+ querydata = np.asanyarray(queryimg.dataobj).squeeze()
377
370
 
378
- iter_func = connected_components if split_components \
379
- else lambda img: [(1, img)]
371
+ iter_func = connected_components if split_components else lambda img: [(1, img)]
380
372
 
381
373
  for mode, modemask in iter_func(querydata):
382
374
 
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: siibra
3
- Version: 1.0.1a2
3
+ Version: 1.0.1a5
4
4
  Summary: siibra - Software interfaces for interacting with brain atlases
5
5
  Home-page: https://github.com/FZJ-INM1-BDA/siibra-python
6
6
  Author: Big Data Analytics Group, Forschungszentrum Juelich, Institute of Neuroscience and Medicine (INM-1)
@@ -33,6 +33,7 @@ Dynamic: classifier
33
33
  Dynamic: description
34
34
  Dynamic: description-content-type
35
35
  Dynamic: home-page
36
+ Dynamic: license-file
36
37
  Dynamic: requires-dist
37
38
  Dynamic: requires-python
38
39
  Dynamic: summary
@@ -43,18 +44,16 @@ Dynamic: summary
43
44
  siibra - Software interface for interacting with brain atlases
44
45
  ==============================================================
45
46
 
46
- Copyright 2018-2024, Forschungszentrum Jülich GmbH
47
+ Copyright 2018-2025, Forschungszentrum Jülich GmbH
47
48
 
48
49
  *Authors: Big Data Analytics Group, Institute of Neuroscience and
49
50
  Medicine (INM-1), Forschungszentrum Jülich GmbH*
50
51
 
51
52
  .. intro-start
52
53
 
53
- ``siibra`` is a Python client to a brain atlas framework that integrates brain parcellations and reference spaces at different spatial scales, and connects them with a broad range of multimodal regional data features.
54
+ ``siibra-python`` is a Python client to a brain atlas framework that integrates brain parcellations and reference spaces at different spatial scales, and connects them with a broad range of multimodal regional data features.
54
55
  It aims to facilitate programmatic and reproducible incorporation of brain parcellations and brain region features from different sources into neuroscience workflows.
55
56
 
56
- **Note:** ``siibra-python`` *is still in development. While care is taken that it works reliably, its API is not yet stable and you may still encounter bugs when using it.*
57
-
58
57
  ``siibra`` provides structured access to parcellation schemes in different brain reference spaces, including volumetric reference templates at macroscopic and microscopic resolutions as well as surface representations.
59
58
  It supports both discretely labelled and statistical (probabilistic) parcellation maps, which can be used to assign brain regions to spatial locations and image signals, to retrieve region-specific neuroscience datasets from multiple online repositories, and to sample information from high-resolution image data.
60
59
  The datasets anchored to brain regions address features of molecular, cellular and architecture as well as connectivity, and are complemented with live queries to external repositories as well as dynamic extraction from "big" image volumes such as the 20 micrometer BigBrain model.
@@ -84,10 +83,26 @@ Installation
84
83
 
85
84
  ``siibra`` is available on pypi.
86
85
  To install the latest released version, simply run ``pip install siibra``.
86
+ The installation typically takes about 2 minutes on a standard computer where Python is already installed.
87
87
  In order to work with the latest version from github, use ``pip install git+https://github.com/FZJ-INM1-BDA/siibra-python.git@main``.
88
88
 
89
- There is also an image based on jupyter:scipy-notebook, which already includes ``siibra``.
90
-
89
+ ``siibra-python`` should be installable on recent versions of Windows, Linux and Mac OS in a recent Python 3 environment.
90
+ We run continuous integration tests for versions 3.7 - 3.12 on recent Ubuntu images.
91
+
92
+ The library requires a couple of open source packages, namely:
93
+ ```
94
+ anytree >= 2.12.1
95
+ nibabel >= 5.3.2
96
+ appdirs >= 1.4.4
97
+ scikit-image >= 0.25.0
98
+ requests >= 2.32.3
99
+ neuroglancer-scripts >= 1.2.0
100
+ nilearn >= 0.11.0
101
+ filelock >= 3.16.1
102
+ ebrains-drive >= 0.6.0
103
+ ```
104
+
105
+ You can also install a docker image with all dependencies included:
91
106
  .. code-block:: sh
92
107
 
93
108
  docker run -dit \
@@ -97,19 +112,20 @@ There is also an image based on jupyter:scipy-notebook, which already includes `
97
112
  docker-registry.ebrains.eu/siibra/siibra-python:latest
98
113
 
99
114
 
115
+
100
116
  Documentation & Help
101
117
  ====================
102
118
 
103
119
  ``siibra-python``\ ’s documentation is hosted on https://siibra-python.readthedocs.io.
104
120
  The documentation includes a catalogue of documented code examples that walk you through the different concepts and functionalities.
121
+ These examples use real data and include both the code and the produced expected outputs.
122
+ They can be accessed at https://siibra-python.readthedocs.io/en/latest/examples.html, and are
123
+ automatically tested and updated whenever a new version of ``siibra-python`` is published.
105
124
  As a new user, it is recommended to go through these examples - they are easy and will quickly provide you with the right code snippets that get you started.
106
- Furthermore, a set of jupyter notebooks demonstrating more extensive example use cases are maintained in the `siibra-tutorials <https://github.com/FZJ-INM1-BDA/siibra-tutorials>`__ repository.
107
- We are working on a full API documentation of the library. You find the current status on readthedocs, but be aware that it is not yet complete and as up-to-date as the code examples.
125
+ The documentation on readthedocs further includes introductory explanations and an API reference.
108
126
 
109
127
  If you run into issues, please open a ticket on `EBRAINS support <https://ebrains.eu/support/>`__ or file bugs and
110
128
  feature requests on `github <https://github.com/FZJ-INM1-BDA/siibra-python/issues>`__.
111
- Please keep in mind that ``siibra-python`` is still in development.
112
- While care is taken to make everything work reliably, the API of the library is not yet stable, and the software is not yet fully tested.
113
129
 
114
130
  .. getting-started-end
115
131
 
@@ -1,12 +1,12 @@
1
- siibra/VERSION,sha256=tnNU724QbIsJd2y5y9A2yYp48XeoqEJ_sfDYRgMGdrg,14
1
+ siibra/VERSION,sha256=ipm-gM9pHLEb5l5Cx8ZcZ8wKJBYKiaWH87grIEoJ_OM,14
2
2
  siibra/__init__.py,sha256=1uWhsE93KG4N9wiWoMdEokUXxfoRcyznXDktjAGhpEI,4496
3
- siibra/commons.py,sha256=i4qS4CPteESu2NlchZuLjJrc23PYc0_WMiPr7WMi9ro,27646
3
+ siibra/commons.py,sha256=KmbRdX6pfKTgIgbYufxhkE9YiLQ35GObbw6VyFdRm_w,28016
4
4
  siibra/exceptions.py,sha256=6MlXOadwXcCsceOE4lmy4fLJyAaBCCVvJF6BZlMYjU8,1371
5
5
  siibra/configuration/__init__.py,sha256=ArqQ_B8C_O61KA4Fk3ho8ksckbjLu-COOlPGiXyf8LE,752
6
- siibra/configuration/configuration.py,sha256=FhJ2MF925BeI3KHk8r68-1PnMzIqTfsZEM8ZpvbtqzQ,7263
7
- siibra/configuration/factory.py,sha256=WPOP0hugX47cTWMGsXo99B4RER14pGllJDUvcC3kMko,22628
6
+ siibra/configuration/configuration.py,sha256=A651Tg632_a_c_yjxs-FJW_douQyzSJBoCDad4expVk,7151
7
+ siibra/configuration/factory.py,sha256=srhxxOAW_qyfe7oIFfuiX6gviou5CRfle5DVKe8FtB0,22798
8
8
  siibra/core/__init__.py,sha256=zW887SH2txImUfvU80k83NbxxnlHlbdzBjdryY-3-48,766
9
- siibra/core/assignment.py,sha256=7TL3cV2uU8XHatpOkrt5uMju04HfDtcgRR7HM3B1chU,3820
9
+ siibra/core/assignment.py,sha256=aSzunUMKVVE0wl_2qEK_NryQIoV8_qMV5t3MBmkdEo8,4310
10
10
  siibra/core/atlas.py,sha256=Iwqgcf8sG8_iL4mlw_4Nzi7HWVR-wxYLESqnIS0CFTw,8549
11
11
  siibra/core/concept.py,sha256=rLqgJ72Mt1Mc8mlh-bGYOyq65rV7Vc8vCZGs-amJp1w,10891
12
12
  siibra/core/parcellation.py,sha256=JzrnoB8G0XupffP8mnwE3oHYmHjo2Mzn4-pXnZ2R6Ow,14480
@@ -14,45 +14,45 @@ siibra/core/region.py,sha256=036Fjck1H6wGSubJomjEHUN1I-XMPSPqx3_78MEYbG8,44108
14
14
  siibra/core/space.py,sha256=X7FyKgdhao3ezSWQZ0MAjDxlQh305S-4a4D630RaM-c,4588
15
15
  siibra/core/structure.py,sha256=M2li4PPiJf27dOc3b2ycCfHf7Ad1AWxBYc9OpSFazJM,4498
16
16
  siibra/explorer/__init__.py,sha256=XBAeYm4W3HlbWsKtt8gOwqE_FinIEY7RdA6Rg4Y275A,781
17
- siibra/explorer/url.py,sha256=ja5i-VkEMYwqhlQ-K5tEfnlYTcgMpPFYJCK7IV0d3Us,7069
17
+ siibra/explorer/url.py,sha256=S6Tpg1p2gmu5byHVqsXfkugUStLd1Fu94EqsDzgEU9E,7047
18
18
  siibra/explorer/util.py,sha256=ul82TQZAULdupr4tJBACdkjlHm2mt8LJ9UpwNWGHYhE,2083
19
19
  siibra/features/__init__.py,sha256=FER6DMnkPhXSV1XMZWibZdyBwVhIgWYSUGYMEYEKb9c,3970
20
- siibra/features/anchor.py,sha256=Umu_Ljkr656h7jvgp43Wi6thMFEycxz_Lf8Bj_QOTZA,9129
21
- siibra/features/feature.py,sha256=mpQ0M7sMYJEqOkx91rvaDlV_W5iRi_-z4S3eJLAZR8M,35283
20
+ siibra/features/anchor.py,sha256=cMuaGB8ZCGMpdeb3plzHzNC4ImsxsriQ66janWcjhjk,9101
21
+ siibra/features/feature.py,sha256=uVTp1vvZRnl9DIks49-StrZ88UEfEe-ixshuK5_bvwg,35576
22
22
  siibra/features/connectivity/__init__.py,sha256=FkPf0vyrLo3ERxrDbsRHUd7FUgJyajD87NiiXIiXhmY,1161
23
23
  siibra/features/connectivity/functional_connectivity.py,sha256=9lQoOXv8lZUnyMduAbWABwDIkQC0QTI8V23yx0NjOBg,2122
24
- siibra/features/connectivity/regional_connectivity.py,sha256=V401G_EOTIDVz3IJJR4d2xOxLiWmIb9qQAMFD46qPlM,18283
24
+ siibra/features/connectivity/regional_connectivity.py,sha256=6oDx-tsvQIh-MG823-6yLpVHvr-rOoS--CKR22GSwxA,18706
25
25
  siibra/features/connectivity/streamline_counts.py,sha256=JaAYf6-1S8NYhkE4lhshCSY__EQ5BFcL2i_XXdFfgrM,1064
26
26
  siibra/features/connectivity/streamline_lengths.py,sha256=QeuoW_ZDVa9dxCguaemj4Cq9CCPB8ur8_alhATto2-w,1067
27
27
  siibra/features/connectivity/tracing_connectivity.py,sha256=rkYgD8mOZzDp0STo5djhDqOaEdz-9j5EuLffXE0F01A,1083
28
28
  siibra/features/dataset/__init__.py,sha256=qRV_P0335b4LnSMiONRpSC4elGckp0FXmtJz_QQuVLA,748
29
29
  siibra/features/dataset/ebrains.py,sha256=zA_GSIJzeJgClY5KrsfAJgrdjcM5N2Z_mz442UR_1vc,2544
30
- siibra/features/image/__init__.py,sha256=_Vf6AgIEiYTmtYiKdM7v6YRQco3XWnrEL8vLDhU1sqo,1015
30
+ siibra/features/image/__init__.py,sha256=i_NccD2WJmVAtpLVWeccn8UEnViDMC6Y2CSGARL0Qt8,1049
31
31
  siibra/features/image/image.py,sha256=heXBen5Sq3dVEcHSb4W4rs7n9nOXy3Nqp-eO0Vzjz4A,3583
32
32
  siibra/features/image/sections.py,sha256=rZPoeZbu_cK8td5J4LVxZxsojjwTodrHe42P2de28_Y,3708
33
- siibra/features/image/volume_of_interest.py,sha256=6rMMWekSAji7p0KFJMSVX7QuhbODfDBEIR-KNHGvnuM,2392
33
+ siibra/features/image/volume_of_interest.py,sha256=fBkTUujUHdcfzF1kPvMTV4x41VJXPUJ5Lbpr_g4GxYM,2649
34
34
  siibra/features/tabular/__init__.py,sha256=DdE1GXPEsHSNJ3pyNYZNWu5JxDfuI08DbrDF1iBrXIA,1203
35
35
  siibra/features/tabular/bigbrain_intensity_profile.py,sha256=C7rP2QTJPyTz_EnRlgdFWPVaDcwJszTlm1ylHBydJOE,2709
36
36
  siibra/features/tabular/cell_density_profile.py,sha256=ScpjD9W-w-lLxdG6q42Zfyqe8LW4JvaorIdnixuPzo4,10818
37
37
  siibra/features/tabular/cortical_profile.py,sha256=x0TqZh8FzcVx13EwPtbt8kBYfF1dREWWuf9BhpWzj7o,12542
38
- siibra/features/tabular/gene_expression.py,sha256=8n3aJgJfU_hyIZFnOmKg76GNCath5TMkH0tElWvZhTg,9828
38
+ siibra/features/tabular/gene_expression.py,sha256=8gJuUrL13oIySOPgiy5j46a5Udae_cJ1_QfrUHA72CI,10309
39
39
  siibra/features/tabular/layerwise_bigbrain_intensities.py,sha256=iFCNG641yCSuIXFTY30xgRQqLERDHMqJrAy3SdKkAJ4,2118
40
- siibra/features/tabular/layerwise_cell_density.py,sha256=j5EznhcWjGb_hwbsQtIiQNWkbeUtEOS13vPeP-Zw2Xw,3740
40
+ siibra/features/tabular/layerwise_cell_density.py,sha256=MYFiUfDfx6XQj8dezV5-3eKWBg0VOn0T3a1utELE2PM,6513
41
41
  siibra/features/tabular/receptor_density_fingerprint.py,sha256=CvFJv940whxzavhEQWnTjueDEq0ZoiuYVpqUpR8t-Ec,8065
42
42
  siibra/features/tabular/receptor_density_profile.py,sha256=VW2Ry8ifQLfmiBDKqIdvaN7K1YzMENGU92Lnm4wA8P0,3724
43
43
  siibra/features/tabular/regional_timeseries_activity.py,sha256=wuno4oI1I-dyxRr8-tLFj42iaD6dYZiPigCqVMhrG50,10027
44
- siibra/features/tabular/tabular.py,sha256=wFfCeRwh45Bu7eUT9hBygqy4K010tf7n96t2ddA0tIk,5392
44
+ siibra/features/tabular/tabular.py,sha256=37lSZ10cEAzGorA8jxdJvMcAIZvklIR3Vo75YPz7ONA,5783
45
45
  siibra/livequeries/__init__.py,sha256=hToUNmyFq1UW5CxScHyBB-mSZ7kUK_w1Cvrk1OkZQf0,875
46
- siibra/livequeries/allen.py,sha256=QtKf5sYsSuF8NeqPvyw_DakEJrVYh47mfJVF1rMkJWg,14827
46
+ siibra/livequeries/allen.py,sha256=l5OqVqq3SZ3x7-pol1PwX6AnvdyufjVUYXtGr3wWBj0,14946
47
47
  siibra/livequeries/bigbrain.py,sha256=hT-T6gKRoZQFPWvitm1hv-DoMkkGjz-NfqSx7khfLR0,15762
48
48
  siibra/livequeries/ebrains.py,sha256=GBwpm9f_rVjZgF-SyGZ5PGMmL9e9OZzXhHs78uCNhYs,5952
49
49
  siibra/livequeries/query.py,sha256=P_uUVFxv4KyOPQXh2WnDQxuaSSBK_dXPKEr8I0-4xSQ,1849
50
50
  siibra/locations/__init__.py,sha256=yTJVMdv-pICm_gUYLQ09lDKSkZBfgUihM6LNv07e_yk,3546
51
- siibra/locations/boundingbox.py,sha256=uCFQBiwsq39UUTz0xwTNIIl4RMXQRH3MDXO0t9pbY9Q,16369
51
+ siibra/locations/boundingbox.py,sha256=ACRittMABMZwLPzGnv5Z5E6cIHJfCFWv851s5Bg87WQ,16442
52
52
  siibra/locations/experimental.py,sha256=kd9yroLKpnY-N6hoMVgtHK4pVdgeGqhpad4GyxYy6LU,14484
53
- siibra/locations/location.py,sha256=sdIZiUHGURpOo9JVMUH2w1dEmZAtMBbBXYED-ho_K5s,4383
54
- siibra/locations/point.py,sha256=g8rjHCuHENTgkiJB7UGH0nWu4anbhf2GSlUfjhek67o,12533
55
- siibra/locations/pointcloud.py,sha256=_9-4k9yLMiCu8phoxFO6bUsIuJFbRqw7BmBMQ0_FHmk,13979
53
+ siibra/locations/location.py,sha256=tb__0td1c7_3BKJFqqEqwspO5m8BZ8ZlyYwvtVBq8SY,4706
54
+ siibra/locations/point.py,sha256=cL2hqbejec24ZoXpbBQQXtHZ-H7KcyxnbITzSBjkXTs,12675
55
+ siibra/locations/pointcloud.py,sha256=AxtR43xG4i1hUXNmal4F_g5WKQo_A1ZtW4l4jsf3p6o,14108
56
56
  siibra/retrieval/__init__.py,sha256=E-UA8rDQZFGkHmAcmit6siONo7G2mH_Y0xgLlR1RfvY,1062
57
57
  siibra/retrieval/cache.py,sha256=uMWEi93VePSOSXaiU5PZAbUlWBYyO7gbpRxod4jO2Rc,7833
58
58
  siibra/retrieval/datasets.py,sha256=JgnSc41TM0oGNAVn8zQjL84HML-feOBVy5bLxxHrEt8,11110
@@ -64,8 +64,8 @@ siibra/vocabularies/gene_names.json,sha256=i-gnh753GyZtQfX_dWibNYr_d5ccDPHooOwsd
64
64
  siibra/vocabularies/receptor_symbols.json,sha256=F6DZIArPCBmJV_lWGV-zDpBBH_GOJOZm67LBE4qzMa4,5722
65
65
  siibra/vocabularies/region_aliases.json,sha256=T2w1wRlxPNTsPppXn0bzC70tNsb8mOjLsoHuxDSYm2w,8563
66
66
  siibra/volumes/__init__.py,sha256=9eiVjgGTqq9BiFJaLVLABtTrhIcE2k3Cn51yC4EKplg,936
67
- siibra/volumes/parcellationmap.py,sha256=-Yb9SINRyug-nT_pZkLGvZB3iNrpxFyjp1-PgdMTv2k,51329
68
- siibra/volumes/sparsemap.py,sha256=PI-3dxORjCFyg_B03ByQpwdAT69GHMRrcLBgweHc0vM,17438
67
+ siibra/volumes/parcellationmap.py,sha256=z5wWxK_kcFpS_ROpc9ny4aCbM7P9qc3DRDxrOKGp2Hk,51409
68
+ siibra/volumes/sparsemap.py,sha256=Yv07LIlt5yigw-ubWFq89hHnsivT7dymYCsCTe7Wu9I,17167
69
69
  siibra/volumes/volume.py,sha256=wLmtqoXBDoPvE3WBO_Hc8uny3cdE9mB0KgdCq0LOTa0,32408
70
70
  siibra/volumes/providers/__init__.py,sha256=AHZCjutCqO4mnHxyykVjqxlz85jDqFWcSjsa4ciwc1A,934
71
71
  siibra/volumes/providers/freesurfer.py,sha256=l3zkLlE28EAEmg75tv9yp1YYiaHVkf4Zi8rKn9TUWVs,4893
@@ -73,8 +73,8 @@ siibra/volumes/providers/gifti.py,sha256=JGuixlSJTVjbDU_M5oMDCV8BAwIzuczhnI-qZ7L
73
73
  siibra/volumes/providers/neuroglancer.py,sha256=b3TiJ6yrx_akLFKgHRKZyHculzzRIqbZ7U3TMQHy6-k,28618
74
74
  siibra/volumes/providers/nifti.py,sha256=aAzkmeDZaXRZ-dkAeEb2cSywNn9WzIz0z7yFtN6iNpU,10135
75
75
  siibra/volumes/providers/provider.py,sha256=Vn02au_LKynO5SIfqLyjqzxCf7JD9Wm4i7yEFcTX0WU,3585
76
- siibra-1.0.1a2.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
77
- siibra-1.0.1a2.dist-info/METADATA,sha256=lndYng0x27sYef1UlLiD6evMTEYXFsCamHTuTWgfzcs,9111
78
- siibra-1.0.1a2.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
79
- siibra-1.0.1a2.dist-info/top_level.txt,sha256=NF0OSGLL0li2qyC7MaU0iBB5Y9S09_euPpvisD0-8Hg,7
80
- siibra-1.0.1a2.dist-info/RECORD,,
76
+ siibra-1.0.1a5.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
77
+ siibra-1.0.1a5.dist-info/METADATA,sha256=CO_Qej2SZ4h9saebuTGGPQLhPZOI4PQE4xSEHKVqKl4,9301
78
+ siibra-1.0.1a5.dist-info/WHEEL,sha256=0CuiUZ_p9E4cD6NyLD6UG80LBXYyiSYZOKDm5lp32xk,91
79
+ siibra-1.0.1a5.dist-info/top_level.txt,sha256=NF0OSGLL0li2qyC7MaU0iBB5Y9S09_euPpvisD0-8Hg,7
80
+ siibra-1.0.1a5.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (76.0.0)
2
+ Generator: setuptools (80.3.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5