Morphologies

Morphologies are the 3D representation of a cell. In the BSB they consist of branches, pieces of cable described as vectors of the properties of points. Consider the following branch with 4 points p0, p1, p2, p3:

branch0 = [x, y, z, r]
x = [x0, x1, x2, x3]
y = [y0, y1, y2, y3]
z = [z0, z1, z2, z3]
r = [r0, r1, r2, r3]

The points on the branch can also be described as individual Compartments:

branch0 = [c0, c1, c2]
c0 = Comp(start=[x0, y0, z0], end=[x1, y1, z1], radius=r1)
c1 = Comp(start=[x1, y1, z1], end=[x2, y2, z2], radius=r2)
c2 = Comp(start=[x2, y2, z2], end=[x3, y3, z3], radius=r3)

Branches also specify which other branches they are connected to and in this way the entire network of neuronal processes can be described. Those branches that do not have a parent branch are called roots. A morphology can have as many roots as it likes; usually in the case of 1 root it represents the soma; in the case of many roots they each represent the start of a process such as an axon on dendrite around an imaginary soma.

In the end a morphology can be summed up in pseudo-code as:

m = Morphology(roots)
m.roots = <all roots>
m.branches = <all branches, depth first starting from the roots>

The branches attribute is the result of a depth-first iteration of the roots list. Any kind of iteration over roots or branches will always follow this same depth-first order.

The data of these morphologies are stored in MorphologyRepositories as groups of branches following the first vector-based branch description. If you want to use compartments you’ll have to call branch.to_compartments() or morphology.to_compartments(). For a root branch this will yield n - 1 compartments formed as line segments between pairs of points on the branch. For non-root branches an extra compartment is prepended between the last point of the parent branch and the first point of the child branch. Compartments are individuals so branches are no longer used to describe the network of points, instead each compartment lists their own parent compartment.

Using morphologies

For this introduction we’re going to assume that you have a MorphologyRepository with morphologies already present in them. To learn how to create your own morphologies stored in MorphologyRepositories see morphologies/repository.

Let’s start with loading a morphology and inspecting its root Branch:

from bsb.core import from_hdf5
from bsb.output import MorphologyRepository

mr = MorphologyRepository("path/to/mr.hdf5")
# Alternatively if you have your MR inside of a compiled network:
network = from_hdf5("network.hdf5")
mr = network.morphology_repository
morfo = mr.get_morphology("my_morphology")

# Use a local reference to the properties if you're not going to manipulate the
# morphology, as they require a full search of the morphology to be determined every
# time the property is accessed.
roots = morfo.roots
branches = morfo.branches
print("Loaded a morphology with", len(roots), "roots, and", len(branches), "branches")
# In most morphologies there will be a single root, representing the soma.
soma_branch = roots[0]

# Use the vectors of the branch (this is the most performant option)
print("A branch can be represented by the following vectors:")
print("x:", soma_branch.x)
print("y:", soma_branch.y)
print("z:", soma_branch.z)
print("r:", soma_branch.radii)
# Use the points property to retrieve a matrix notation of the branch
# (Stacks the vectors into a 2d matrix)
print("The soma can also be represented by the following matrix:", soma_branch.points)

# There's also an iterator to walk over the points in the vectors
print("The soma is defined as the following points:")
for point in soma_branch.walk():
  print("*", point)

As you can see an individual branch contains all the positional data of the individual points in the morphology. The morphology object itself then contains the collection of branches. Normally you’d use the .branches but if you want to work with the positional data of the whole morphology in a object you can do this by flattening the morphology:

from bsb.core import from_hdf5

network = from_hdf5("network.hdf5")
mr = network.morphology_repository
morfo = mr.get_morphology("my_morphology")

print("All the branches in depth-first order:", morfo.branches)
print("All the points on those branches in depth first order:")
print("- As vectors:", morfo.flatten())
print("- As matrix:", morfo.flatten(matrix=True).shape)