Source code for neuron_morphology.morphology_builder

import warnings
import random

from neuron_morphology.morphology import Morphology
from neuron_morphology.constants import (
    SOMA, AXON, APICAL_DENDRITE, BASAL_DENDRITE)

[docs]class MorphologyBuilder: @property def next_id(self): result = self._id self._id += 1 return result @property def parent_id(self): return self._parent_queue[-1] if self._parent_queue else -1 @property def active_node_id(self): if self._parent_queue: return self._parent_queue[-1] def __init__(self): """ A utility for putting together a morphology object using succinct, declarative code. See tests/test_morphology_builder.py for example usage. """ self._id = 0 self._parent_queue = [] self.nodes = [] self.rng = random.Random()
[docs] def up(self, by=1): """ Terminate a branch. Set the active node to the previous active node's ancestor. Parameters ---------- by : how far (up the tree) to set the new active node. Default is the parent of the current node (1). 2 would correspond to the """ for _ in range(by): if self._parent_queue: self._parent_queue.pop() else: warnings.warn( f"this {self.__class__.__name__}'s active node has been " "unset. If you wish to add more nodes from this point " "you must use .root() to create a new root" ) return self
[docs] def root(self, x=0, y=0, z=0, node_type=SOMA, radius=1): """ Add a new root node (parent -1) to this reconstruction. This will be the new active node. """ self._parent_queue = [] return self._add_node(x, y, z, node_type, radius)
[docs] def child(self, x, y, z, node_type, radius=1): """ Add a child node to the current active node. This will become the new active node. """ if not self._parent_queue: raise ValueError( "attempted to create a child node, but the active node is " "unset. If you wish to add more nodes from this point " "you must use .root() to create a new root" ) return self._add_node(x, y, z, node_type, radius)
def _add_node(self, x, y, z, node_type, radius): """ Add a new node to this morphology. Parameters ---------- x : x coordinate of this node's position y : y coordinate of this node's position z : z coordinate of this node's position node_type : one of AXON, SOMA, APICAL_DENDRITE, BASAL_DENDRITE radius : describe the size of this node """ node_id = self.next_id self.nodes.append({ "x": x if x is not None else self.rng.uniform(-1, 1), "y": y if y is not None else self.rng.uniform(-1, 1), "z": z if z is not None else self.rng.uniform(-1, 1), "radius": radius, "type": node_type, "id": node_id, "parent": self.parent_id }) self._parent_queue.append(node_id) return self
[docs] def axon(self, x=None, y=None, z=None, radius=1): """ Convenvience for creating an axon node. Will not create a root. """ return self.child(x, y, z, AXON, radius)
[docs] def apical_dendrite(self, x=None, y=None, z=None, radius=1): """ Convenvience for creating an apical dendrite node. Will not create a root. """ return self.child(x, y, z, APICAL_DENDRITE, radius)
[docs] def basal_dendrite(self, x=None, y=None, z=None, radius=1): """ Convenvience for creating a basal dendrite node. Will not create a root. """ return self.child(x, y, z, BASAL_DENDRITE, radius)
[docs] def build(self): """ Construct a Morphology object using this builder. This is a non- destructive operation. The Morphology will be validated at this stage. """ return Morphology( self.nodes, node_id_cb=lambda node: node["id"], parent_id_cb=lambda node: node["parent"] )