Source code for bluecellulab.psection

# Copyright 2023-2024 Blue Brain Project / EPFL

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Represents a python version of NEURON Section (for drawing)."""
from __future__ import annotations
import re
import neuron

import bluecellulab
from bluecellulab.cell.serialized_sections import SerializedSections
from bluecellulab.psegment import PSegment
from bluecellulab.type_aliases import HocObjectType, NeuronSection


[docs] def init_psections( hoc_cell: HocObjectType, ) -> tuple[dict[int, PSection], dict[str, PSection]]: """Initialize the psections list. This list contains the Python representation of the psections of this morphology. """ psections: dict[int, PSection] = {} secname_to_psection: dict[str, PSection] = {} for sec in hoc_cell.all: secname = neuron.h.secname(sec=sec) secname_to_psection[secname] = PSection(sec) serial_sections = SerializedSections(hoc_cell) for isec, val in serial_sections.isec2sec.items(): hsection: NeuronSection = val.sec if hsection: secname = neuron.h.secname(sec=hsection) psections[isec] = secname_to_psection[secname] psections[isec].isec = isec # Set the parents and children of all the psections for psec in psections.values(): hparent = psec.hparent if hparent: parentname = hparent.name() psec.pparent = secname_to_psection[parentname] else: psec.pparent = None for hchild in psec.hchildren: childname = hchild.name() if "myelin" in childname: continue pchild = secname_to_psection[childname] psec.add_pchild(pchild) return psections, secname_to_psection
[docs] class PSection: """Class that represents a cell section.""" def __init__(self, hsection: NeuronSection, isec: int | None = None): self.L: float = hsection.L self.diam: float = hsection.diam self.hsection = hsection self.name: str = neuron.h.secname(sec=hsection) self.href: NeuronSection = neuron.h.SectionRef(sec=self.hsection) self.pparent: PSection | None = None self.pchildren: list[PSection] = [] self.isec = isec self.psegments: list[PSegment] = [] self.maxsegdiam = 0.0 for hsegment in hsection: # psegment = bluecellulab.PSegment(hsection(hsegment.x), self) psegment = bluecellulab.PSegment(hsegment, self) self.psegments.append(psegment) self.maxsegdiam = max(self.maxsegdiam, psegment.diam) self.xSpacing = 1.0 self.ySpacing = 5.0 @property def section_type(self) -> str: """Return the type of the section.""" # From Cell[0].soma[0] -> soma matches = re.findall(r'\.([^.\[\]]+)\[', self.name) if matches: return matches[-1] # Return the last match return 'unknown' # Return 'unknown' if no matches are found @property def is_leaf(self) -> bool: """Return true if section is a leaf in the morphological structure.""" return not self.hchildren @property def hparent(self) -> NeuronSection | None: """Return the hoc section of the parent.""" if self.href.has_parent(): return self.href.parent else: return None @property def hchildren(self) -> list[NeuronSection]: """Return a list with the hoc sections of the children.""" return [self.href.child[index] for index in range(0, int(self.href.nchild()))]
[docs] def add_pchild(self, pchild: PSection) -> None: """Add a python represent of a child section.""" self.pchildren.append(pchild) pchild.pparent = self
[docs] def getSectionVarBounds(self, variable): """Get bounds a variable in a section.""" varmin = None varmax = None for psegment in self.psegments: value = psegment.get_variable_value(variable) if value: varmin = min(value, varmin) if varmin else value varmax = max(value, varmax) if varmax else value return [varmin, varmax]
[docs] def getTreeVarBounds(self, variable): """Get the bounds of a variable in a dendritic subtree.""" varbounds = self.getSectionVarBounds(variable) for child in self.pchildren: child_varbounds = child.getTreeVarBounds(variable) if child_varbounds[0] and child_varbounds[1]: varbounds[0] = min( varbounds[0], child_varbounds[0]) if varbounds[0] else child_varbounds[0] varbounds[1] = max( varbounds[1], child_varbounds[1]) if varbounds[1] else child_varbounds[1] return varbounds
[docs] def all_descendants(self) -> list[PSection]: """Return all the psection that are descendants of this psection.""" pdescendants = list(self.pchildren) for child in self.pchildren: pdescendants += child.all_descendants() return pdescendants
[docs] def tree_width(self) -> float: """Width of a dendritic tree.""" if self.is_leaf: width = self.maxsegdiam + self.xSpacing else: width = sum(child.tree_width() for child in self.pchildren) return max(self.diam + self.xSpacing, width)
[docs] def tree_height(self) -> float: """Height of dendritic tree.""" return self.L + self.ySpacing + \ (max([child.tree_height() for child in self.pchildren]) if self.pchildren else 0)