How to label neurons¶
After placing cells inside the scaffold model, it is possible to define postprocessing functions that modify some features of the scaffold. For instance, it is possible to define a function that, given a specific cell type, assigns a label to each cell belonging to that cell type (e.g., subdivide a certain population into different subpopulations according to their position in the 3D space.)
Postprocessing functions can be configured in the after_placement dictionary of the root node of the configuration file, specifying each postprocessing function with its name, e.g. Labels:
"after_placement": {
"Labels": {
"strategy": "cell_labeling.label_cells.LabelCellA",
"cell_type": "cell_A"
}
}
after_placement:
Labels:
strategy: cell_labeling.label_cells.LabelCellA
cell_type: cell_A
config.after_placement.add(
"Labels",
strategy="cell_labeling.label_cells.LabelCellA",
cell_type="cell_A",
)
Here, we are linking the class LabelCellA stored in the file cell_labeling/label_cells.py.
For more information on linking your Python classes to the configuration file see
this section.
Example of a Python class for labeling neurons¶
import numpy as np
from bsb import AfterPlacementHook, config, refs, types
@config.node
class LabelCellA(AfterPlacementHook):
"""
Subdivide a cell population into 2 subpopulations based on their
position along a provided axis
"""
cell_type: str = config.ref(refs.cell_type_ref, required=True)
"""Reference to the cell type."""
axis: int = config.attr(type=types.int(min=0, max=2), default=0)
"""Axis along which to subdivide the population."""
def postprocess(self):
# Load the cell type positions
ps = self.scaffold.get_placement_set(self.cell_type)
cell_positions = ps.load_positions()
# create a filter that split the cells according to
# the mean of their positions along the chosen axis
mean_pos = np.mean(cell_positions[:, self.axis])
subpopulation_1 = np.where(cell_positions[:, self.axis] <= mean_pos)[0]
subpopulation_2 = np.where(cell_positions[:, self.axis] > mean_pos)[0]
# set the cell label according to the filter
ps.label(labels=["cell_A_type_1"], cells=subpopulation_1)
ps.label(labels=["cell_A_type_2"], cells=subpopulation_2)
In this example, we can see that the LabelCellA class must inherit from
AfterPlacementHook and it must specify a method postprocess in which the
neural population cell_A is subdivided into two populations.
Here, along the chosen axis, cells placed above the mean position of the population
will be assigned the label cell_A_type_1 and the rest cell_A_type_2.
You can then filter back these cells like so:
from bsb import from_storage
import numpy as np
scaffold = from_storage("network.hdf5")
ps = scaffold.get_placement_set("cell_A")
subpopulation_1 = ps.get_labelled(["cell_A_type_1"])
subpopulation_2 = ps.get_labelled(["cell_A_type_2"])
# or alternatively directly filter when loading the placement set
ps_1 = scaffold.get_placement_set("cell_A", labels=["cell_A_type_1"])
ps_2 = scaffold.get_placement_set("cell_A", labels=["cell_A_type_2"])
# check that the labeling was correctly positions along the axis chosen
axis = 0 # corresponds to the default value
positions_type1 = ps_1.load_positions()
positions_type2 = ps_2.load_positions()
print(
f"{len(positions_type1)} cells were labeled as type 1, "
f"up to {np.max(positions_type1[:, axis])} along axis {axis}"
)
print(
f"{len(positions_type2)} cells were labeled as type 2, "
f"starting from {np.min(positions_type2[:, axis])} along axis {axis}"
)
Full example configuration file¶
{
"name": "Example cell labeling",
"storage": {
"engine": "hdf5",
"root": "network.hdf5"
},
"network": {
"x": 200.0,
"y": 200.0,
"z": 200.0
},
"regions": {
"brain_region": {
"type": "stack",
"children": ["base_layer"]
}
},
"partitions": {
"base_layer": {
"type": "layer",
"thickness": 100
}
},
"cell_types": {
"cell_A": {
"spatial": {
"radius": 2.5,
"density": 3.9e-4
}
}
},
"placement": {
"example_placement": {
"strategy": "bsb.placement.RandomPlacement",
"cell_types": ["cell_A"],
"partitions": ["base_layer"]
}
},
"connectivity": {},
"after_placement": {
"Labels": {
"strategy": "cell_labeling.label_cells.LabelCellA",
"cell_type": "cell_A"
}
}
}
name: Example cell labeling
storage:
engine: hdf5
root: network.hdf5
network:
x: 200
y: 200
z: 200
regions:
brain_region:
type: stack
children:
- base_layer
partitions:
base_layer:
type: layer
thickness: 100
cell_types:
cell_A:
spatial:
radius: 2.5
density: 3.9e-4
placement:
example_placement:
strategy: bsb.placement.RandomPlacement
cell_types:
- cell_A
partitions:
- base_layer
connectivity: {}
after_placement:
Labels:
strategy: cell_labeling.label_cells.LabelCellA
cell_type: cell_A
import bsb.options
from bsb import Configuration, Scaffold
bsb.options.verbosity = 3
config = Configuration.default(storage={"engine": "hdf5", "root": "network.hdf5"})
config.network.x = 200.0
config.network.y = 200.0
config.network.z = 200.0
config.partitions.add("base_layer", thickness=100)
config.regions.add(
"brain_region",
type="stack",
children=[
"base_layer",
],
)
config.cell_types.add(
"cell_A",
spatial=dict(
radius=2.5,
density=3.9e-4,
),
)
config.placement.add(
"base_placement",
strategy="bsb.placement.RandomPlacement",
cell_types=["cell_A"],
partitions=["base_layer"],
)
config.after_placement.add(
"Labels",
strategy="cell_labeling.label_cells.LabelCellA",
cell_type="cell_A",
)
scaffold = Scaffold(config)
scaffold.compile(clear=True)