Adding morphologies#
Note
This guide is a continuation of the 📚 Getting Started guide.
Hint
To follow along, download 2 morphologies from
NeuroMorpho and save them as neuron_A.swc
and
neuron2.swc
locally.
Previously we constructed a stacked double layer topology, with 2 cell types. We then connected them in an all-to-all fashion. The next step assigns morphologies to our cells, and connects the cells based on the intersection of their morphologies!
Morphologies can be loaded from local files or to fetch from remote sources, like NeuroMorpho.
Using local files#
You can declare source morphologies in the root morphologies list:
morphologies:
- neuron_A.swc
"morphologies": [
"neuron_A"
],
{"name": "neuron_B", "file": "neuron2.swc"},
]
config.cell_types.base_type.spatial.morphologies = ["neuron_A"]
In this case a morphology is created from neuron_A.swc
and given the name "neuron_A"
.
As a second step, we associate this morphology to the base_type
by referencing it by name
in cell_types.base_type.spatial.morphologies:
cell_types:
base_type:
spatial:
radius: 2
density: 0.001
morphologies:
- neuron_A
"cell_types": {
"base_type": {
"spatial": {
"radius": 2,
"density": 1e-3,
"morphologies": [
"neuron_A"
]
}
},
config.morphologies.append(
By default the name assigned to the morphology is the file name without its extension (here .swc
). To
change the name we can use a node with a name and file:
morphologies:
- neuron_A.swc
- name: neuron_B
file: neuron2.swc
"morphologies": [
"neuron_A.swc",
{
"name": "neuron_B",
"file": "neuron2.swc"
},
{"name": "neuron_B", "file": "neuron2.swc"},
]
config.cell_types.base_type.spatial.morphologies = ["neuron_A"]
It is also possible to add a pipeline to perform transformations on the loaded
morphology. Pipelines can be added by adding a :guilabel`pipeline` list to the morphology node.
Each item in the list may either be a string reference to an importable function or a method of
the Morphology
class. To pass parameters, use a node with the
function reference placed in the guilabel:func attribute, and a parameters list.
Here is an example what that would look like:
morphologies:
- file: my_neuron.swc
pipeline:
- center
- my_module.add_axon
- func: rotate
rotation: [20, 0, 20]
"morphologies": [
{
"file": "my_neuron.swc",
"pipeline": [
"center",
"my_module.add_axon",
{
"func": "rotate",
"rotation": [20, 0, 20]
},
],
}
]
Note
Any additional keys given in a pipeline step, such as rotation in the example, are passed to the function as keyword arguments.
Fetching with alternative URI schemes#
The framework uses URI schemes to define the path of the sources that are loaded. By
default it tries to load from the project local folder, using the``file`` URI scheme ("file://"
).
It is possible to fetch morphologies directly from neuromorpho.org using the NeuroMorpho scheme ("nm://"
). You can refer to
NeuroMorpho morphologies by their morphology name:
morphologies:
- neuron_A.swc
- name: neuron_B
file: neuron2.swc
"morphologies": [
"neuron_A.swc",
{
"name": "neuron_B",
"file": "neuron2.swc"
},
{
"name": "neuron_NM",
"file": "nm://cell005_GroundTruth"
}
],
"cell_types": {
"base_type": {
"spatial": {
"radius": 2,
"density": 1e-3,
"morphologies": [
"neuron_A"
]
}
},
"top_type": {
"spatial": {
"radius": 7,
"count": 10,
"morphologies": [
"neuron_B",
"neuron_NM"
]
}
}
},
)
config.cell_types.add(
"top_type",
spatial=dict(
radius=7,
count=10,
morphologies=["neuron_B", "neuron_NM"],
),
)
config.placement.add(
"all_placement",
Morphology intersection#
Now that we have assigned morphologies to our cell types, we can use morphology-based
connection strategies such as VoxelIntersection
:
connectivity:
A_to_B:
strategy: bsb.connectivity.VoxelIntersection
presynaptic:
cell_types:
- base_type
postsynaptic:
cell_types:
- top_type
"connectivity": {
"A_to_B": {
"strategy": "bsb.connectivity.VoxelIntersection",
"presynaptic": {
"cell_types": ["base_type"]
},
"postsynaptic": {
"cell_types": ["top_type"]
}
}
}
strategy="bsb.connectivity.VoxelIntersection",
presynaptic=dict(cell_types=["base_type"]),
postsynaptic=dict(cell_types=["top_type"]),
)
network = Scaffold(config)
Note
If there’s multiple morphologies per cell type, they’ll be assigned randomly, unless you
specify a MorphologyDistributor
.
Recap#
name: Starting example
storage:
engine: hdf5
root: network.hdf5
network:
x: 400
y: 600
z: 400
morphologies:
- neuron_A.swc
- name: neuron_B
file: neuron2.swc
- name: neron_NM
file: nm://cell005_GroundTruth
regions:
brain_region:
type: stack
children:
- base_layer
- top_layer
partitions:
base_layer:
type: layer
thickness: 100
stack_index: 0
top_layer:
type: layer
thickness: 100
stack_index: 1
cell_types:
base_type:
spatial:
radius: 2
density: 0.001
morphologies:
- neuron_A
top_type:
spatial:
radius: 7
count: 10
morphologies:
- neuron_NM
placement:
base_placement:
strategy: bsb.placement.RandomPlacement
cell_types:
- base_type
partitions:
- base_layer
top_placement:
strategy: bsb.placement.RandomPlacement
cell_types:
- top_type
partitions:
- top_layer
connectivity:
A_to_B:
strategy: bsb.connectivity.VoxelIntersection
presynaptic:
cell_types:
- base_type
postsynaptic:
cell_types:
- top_type
{
"name": "Starting example",
"storage": {
"engine": "hdf5",
"root": "network.hdf5"
},
"network": {
"x": 400.0,
"y": 600.0,
"z": 400.0
},
"morphologies": [
"neuron_A.swc",
{
"name": "neuron_B",
"file": "neuron2.swc"
},
{
"name": "neuron_NM",
"file": "nm://cell005_GroundTruth"
}
],
"regions": {
"brain_region": {
"type": "stack",
"children": ["base_layer", "top_layer"]
}
},
"partitions": {
"base_layer": {
"type": "layer",
"thickness": 100,
"stack_index": 0
},
"top_layer": {
"type": "layer",
"thickness": 100,
"stack_index": 1
}
},
"cell_types": {
"base_type": {
"spatial": {
"radius": 2,
"density": 1e-3,
"morphologies": [
"neuron_A"
]
}
},
"top_type": {
"spatial": {
"radius": 7,
"count": 10,
"morphologies": [
"neuron_B",
"neuron_NM"
]
}
}
},
"placement": {
"base_placement": {
"strategy": "bsb.placement.RandomPlacement",
"cell_types": ["base_type"],
"partitions": ["base_layer"]
},
"top_placement": {
"strategy": "bsb.placement.RandomPlacement",
"cell_types": ["top_type"],
"partitions": ["top_layer"]
}
},
"connectivity": {
"A_to_B": {
"strategy": "bsb.connectivity.VoxelIntersection",
"presynaptic": {
"cell_types": ["base_type"]
},
"postsynaptic": {
"cell_types": ["top_type"]
}
}
}
}
from bsb_plot import plot_network
import bsb.options
from bsb import Scaffold, Stack, from_json
bsb.options.verbosity = 3
config = from_json("network_configuration.json")
config.partitions.add("top_layer", thickness=100, stack_index=1)
config.regions["brain_region"] = Stack(
children=[
"base_layer",
"top_layer",
]
)
config.morphologies = [
"neuron_A.swc",
{"name": "neuron_B", "file": "neuron2.swc"},
]
config.cell_types.base_type.spatial.morphologies = ["neuron_A"]
config.morphologies.append(
{"name": "neuron_NM", "file": "nm://cell005_GroundTruth"},
)
config.cell_types.add(
"top_type",
spatial=dict(
radius=7,
count=10,
morphologies=["neuron_B", "neuron_NM"],
),
)
config.placement.add(
"all_placement",
strategy="bsb.placement.RandomPlacement",
cell_types=["base_type", "top_type"],
partitions=["base_layer"],
)
config.connectivity.add(
"A_to_B",
strategy="bsb.connectivity.VoxelIntersection",
presynaptic=dict(cell_types=["base_type"]),
postsynaptic=dict(cell_types=["top_type"]),
)
network = Scaffold(config)
network.compile()
plot_network(network)