def mean_parent_daughter_ratio(data: MorphologyLike, node_types: Optional[List[int]] = None ) -> float: """ Calculate the average ratio of parent radii to child radii across a reconstruction. Parameters ---------- data : The reconstruction whose mean parent daugther ratio will be computed node_types : restrict the calculation to compartments involving these node types Notes ----- Note that this function differs from the L-measure parent daughter ratio, which calculates the ratio of the child node size to the parent. Note also that both the parent and child must be in node_types in order for a compartment to be included in the calculation """ morphology = get_morphology(data) roots = morphology.get_roots() counters: Dict[str, int] = defaultdict(lambda *a, **k: 0) visitor = partial(parent_daughter_ratio_visitor, morphology=morphology, counters=counters, node_types=node_types) for root in roots: morphology.breadth_first_traversal( visitor, start_id=morphology.node_id_cb(root)) return counters["ratio_sum"] / counters["ratio_count"]
def mean_bifurcation_angle_remote(data: MorphologyLike, node_types: Optional[List[int]] = None ) -> float: """ Compute the average angle between the next branch point or terminal tip of child segments at each bifurcation. Trifurcations are ignored. Note: this introduces possible segmentation artifacts if trifurcations are due to large segment sizes. Parameters ---------- Parameters ---------- data: The reconstruction whose max euclidean distance will be calculated node_types: restrict consideration to these types Returns ------- Scalar value, nan if no nodes """ morphology = get_morphology(data) total_angle = 0.0 n = 0 nodes = morphology.get_node_by_types(node_types) for node in nodes: if len(morphology.children_of(node)) == 2: node_vec = np.asarray([node['x'], node['y'], node['z']]) # find the point to measure to, whether it be the next # branch point or tip a = morphology.children_of(node)[0] while len(morphology.children_of(a)) == 1: a = morphology.children_of(a)[0] a_vec = np.asarray([a['x'], a['y'], a['z']]) b = morphology.children_of(node)[1] while len(morphology.children_of(b)) == 1: b = morphology.children_of(b)[0] b_vec = np.asarray([b['x'], b['y'], b['z']]) total_angle += angle_between(a_vec - node_vec, b_vec - node_vec) n += 1 if n == 0: return float('nan') return total_angle / n
def early_branch_path(data: MorphologyLike, node_types: Optional[List[int]] = None, soma: Optional[Dict] = None) -> float: """ Returns the ratio of the longest 'short' branch from a bifurcation to the maximum path length of the tree. In other words, for each bifurcation, the maximum path length below that branch is calculated, and the shorter of these values is used. The maximum of these short values is divided by the maximum path length. Parameters ---------- data : the input reconstruction node_types : if provided, restrict the calculation to nodes of these types soma : if provided, use this node as the root, otherwise infer the root from the argued morphology Returns ------- ratio of max short branch to max path length """ morphology = get_morphology(data) soma = soma or morphology.get_root() path_len = _calculate_max_path_distance(morphology, soma, node_types) if path_len == 0: return 0.0 nodes = morphology.get_node_by_types(node_types) longest_short = 0.0 for node in nodes: if len(morphology.get_children(node, node_types)) < 2: continue current_short = min( _calculate_max_path_distance(morphology, child, node_types) for child in morphology.children_of(node)) longest_short = max(longest_short, current_short) return longest_short / path_len
def mean_diameter(data: MorphologyLike, node_types: Optional[List[int]] = None) -> float: """ Calculates the mean diameter of all nodes Parameters ---------- morphology : The reconstruction whose mean diameter node_types : restrict the calculation to compartments involving these node types Returns ------- The average diameter across selected nodes """ morphology = get_morphology(data) return 2 * mean(node["radius"] for node in morphology.get_node_by_types(node_types))
def mean_bifurcation_angle_local(data: MorphologyLike, node_types: Optional[List[int]] = None ) -> float: """ Compute the average angle between child segments at bifurcations throughout the morphology. Trifurcations are ignored. Note: this introduces possible segmentation artifacts if trifurcations are due to large segment sizes. Parameters ---------- data: The reconstruction whose max euclidean distance will be calculated node_types: restrict consideration to these types Returns ------- Scalar value """ morphology = get_morphology(data) total_angle = 0.0 n = 0 nodes = morphology.get_node_by_types(node_types) for node in nodes: if len(morphology.children_of(node)) == 2: node_vec = np.asarray([node['x'], node['y'], node['z']]) a = morphology.children_of(node)[0] a_vec = np.asarray([a['x'], a['y'], a['z']]) b = morphology.children_of(node)[1] b_vec = np.asarray([b['x'], b['y'], b['z']]) total_angle += angle_between(a_vec - node_vec, b_vec - node_vec) n += 1 if n == 0: return float('nan') return total_angle / n
def max_path_distance(data: MorphologyLike, node_types: Optional[List[int]] = None) -> float: """ Calculate the distance, following the path of adjacent neurites, from the soma to the furthest compartment. This is equivalent to the distance to the furthest SWC node. Parameters ---------- data : the input reconstruction node_types : if provided, restrict the calculation to nodes of these types Returns ------- The along-path distance from the soma to the farthest (in the along-path sense) node. """ morphology = get_morphology(data) return calculate_max_path_distance(morphology, morphology.get_root(), node_types)
def mean_contraction(data: MorphologyLike, node_types: Optional[List[int]] = None) -> float: """ Calculate the average contraction of all sections. In other words, calculate the average ratio of euclidean distance to path distance between all bifurcations in the morphology. Trifurcations are treated as bifurcations. Parameters ---------- data : the input reconstruction node_types : if provided, restrict the calculation to nodes of these types Returns ------- The average contraction across all sections in this reconstruction """ morphology = get_morphology(data) return calculate_mean_contraction(morphology, morphology.get_root(), node_types)
def total_length(data: MorphologyLike, node_types: Optional[List[int]] = None) -> float: """ Calculate the total length across all compartments in a reconstruction Parameters ---------- data : the input reconstruction node_types : if provided, restrict the calculation to compartments involving these types Returns ------- The sum of segment lengths across all segments in the reconstruction Notes ----- Excludes compartments where the parent is: 1. the soma 2. a root of the reconstruction The logic here is that the soma root is likely to substantially overlap any of its compartments, while non-root soma nodes will be closer to the soma surface. """ morphology = get_morphology(data) nodes = morphology.get_node_by_types(node_types) compartment_list = morphology.get_compartments(nodes, node_types) total = 0.0 for compartment in compartment_list: first_node_in_compartment = compartment[0] if first_node_in_compartment['type'] is SOMA \ and not morphology.parent_of(first_node_in_compartment): continue total += morphology.get_compartment_length(compartment) return total
def total_volume(data: MorphologyLike, node_types: Optional[List[int]] = None) -> float: """ Calculates the sum of volumes across all comparments (linked pairs of nodes) in a reconstruction. This approximates the total volume of the reconstruction. See Morphology.get_compartment_volume for details. Parameters ---------- data : The reconstruction whose volume will be computed node_types : restrict the calculation to compartments involving these node types Returns ------- The sum of compartment volumes across this reconstruction """ morphology = get_morphology(data) nodes = morphology.get_node_by_types(node_types) compartments = morphology.get_compartments(nodes, node_types) return sum(map(morphology.get_compartment_volume, compartments))
def max_euclidean_distance(data: MorphologyLike, node_types: Optional[List[int]] = None) -> float: """Calculate the furthest distance, in 3-space, of a compartment's end from the soma. This is equivalent to the distance to the furthest SWC node. Parameters ---------- data: The reconstruction whose max euclidean distance will be calculated node_types: restrict consideration to these types Returns ------- The distance between the soma and the farthest-from-soma node in this morphology. """ morphology = get_morphology(data) soma = morphology.get_root() return max( morphology.euclidean_distance(soma, node) for node in morphology.get_node_by_types(node_types))
def test_get_morphology(self): aa = get_morphology(Data(self.morphology)) bb = get_morphology(self.morphology) self.assertEqual(aa.__class__.__name__, "Morphology") self.assertEqual(bb.__class__.__name__, "Morphology")