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": "my_model.postprocessing.LabelCellA",
      "cell_type": "cell_A"
    }
  }
}

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


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.asarray(cell_positions >= mean_pos, dtype=int)
        subpopulation_2 = np.asarray(cell_positions < mean_pos, dtype=int)

        # 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

scaffold = from_storage("my_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"])