def partition_asymmetries(neurites, neurite_type=NeuriteType.all, variant='branch-order'): """Partition asymmetry at bifurcation points of a collection of neurites. Variant: length is a different definition, as the absolute difference in downstream path lenghts, relative to the total neurite path length """ if variant not in {'branch-order', 'length'}: raise ValueError('Please provide a valid variant for partition asymmetry,\ found %s' % variant) if variant == 'branch-order': return map(bifurcationfunc.partition_asymmetry, iter_sections(neurites, iterator_type=Section.ibifurcation_point, neurite_filter=is_type(neurite_type))) asymmetries = list() for neurite in iter_neurites(neurites, filt=is_type(neurite_type)): neurite_length = total_length_per_neurite(neurite)[0] for section in iter_sections(neurite, iterator_type=Section.ibifurcation_point, neurite_filter=is_type(neurite_type)): pathlength_diff = abs(sectionfunc.downstream_pathlength(section.children[0]) - sectionfunc.downstream_pathlength(section.children[1])) asymmetries.append(pathlength_diff / neurite_length) return asymmetries
def has_no_single_children(neuron): """Check if the neuron has sections with only one child section.""" bad_ids = [ section.id for section in iter_sections(neuron) if len(section.children) == 1 ] return CheckResult(len(bad_ids) == 0, bad_ids)
def has_no_narrow_neurite_section(neuron, neurite_filter, radius_threshold=0.05, considered_section_min_length=50): """Check if the neuron has dendrites with narrow sections. Arguments: neuron(Neuron): The neuron object to test neurite_filter(callable): filter the neurites by this callable radius_threshold(float): radii below this are considered narro considered_section_min_length(float): sections with length below this are not taken into account Returns: CheckResult with result. result.info contains the narrow section ids and their first point """ considered_sections = ( sec for sec in iter_sections(neuron, neurite_filter=neurite_filter) if sec.length > considered_section_min_length) def narrow_section(section): """Select narrow sections.""" return section.points[:, COLS.R].mean() < radius_threshold bad_ids = [(section.id, section.points[np.newaxis, 1]) for section in considered_sections if narrow_section(section)] return CheckResult(len(bad_ids) == 0, bad_ids)
def has_no_jumps(neuron, max_distance=30.0, axis='z'): """Check if there are jumps (large movements in the `axis`). Arguments: neuron(Neuron): The neuron object to test max_distance(float): value above which consecutive z-values are considered a jump axis(str): one of x/y/z, which axis to check for jumps Returns: CheckResult with result list of ids of bad sections """ bad_ids = [] axis = { 'x': COLS.X, 'y': COLS.Y, 'z': COLS.Z, }[axis.lower()] for neurite in iter_neurites(neuron): section_segment = ((sec, seg) for sec in iter_sections(neurite) for seg in iter_segments(sec)) for sec, (p0, p1) in islice(section_segment, 1, None): # Skip neurite root segment if max_distance < abs(p0[axis] - p1[axis]): bad_ids.append((sec.id, [p0, p1])) return CheckResult(len(bad_ids) == 0, bad_ids)
def test_iter_section_nrn(): ref = list(iter_sections(SIMPLE)) assert len(ref) == 6 ref = list( iter_sections(SIMPLE, neurite_filter=lambda n: n.type == nm.AXON)) assert len(ref) == 3 ref = list( iter_sections(SIMPLE, neurite_filter=lambda n: n.type == nm.BASAL_DENDRITE)) assert len(ref) == 3 ref = list( iter_sections(SIMPLE, neurite_filter=lambda n: n.type == nm.APICAL_DENDRITE)) assert len(ref) == 0
def map_segments(func, neurites, neurite_type): """Map `func` to all the segments in a collection of neurites. `func` accepts a section and returns list of values corresponding to each segment. """ neurite_filter = is_type(neurite_type) return [ s for ss in iter_sections(neurites, neurite_filter=neurite_filter) for s in func(ss) ]
def partition_pairs(neurites, neurite_type=NeuriteType.all): """Partition pairs at bifurcation points of a collection of neurites. Partition pair is defined as the number of bifurcations at the two daughters of the bifurcating section """ return map(bifurcationfunc.partition_pair, iter_sections(neurites, iterator_type=Section.ibifurcation_point, neurite_filter=is_type(neurite_type)))
def test_iter_sections_filter(): for ntyp in nm.NEURITE_TYPES: a = [ s.id for n in filter(lambda nn: nn.type == ntyp, POP.neurites) for s in n.iter_sections() ] b = [ n.id for n in iter_sections(POP, neurite_filter=lambda n: n.type == ntyp) ] assert a == b
def sibling_ratios(neurites, neurite_type=NeuriteType.all, method='first'): """Sibling ratios at bifurcation points of a collection of neurites. The sibling ratio is the ratio between the diameters of the smallest and the largest child. It is a real number between 0 and 1. Method argument allows one to consider mean diameters along the child section instead of diameter of the first point. """ return map(lambda bif_point: bifurcationfunc.sibling_ratio(bif_point, method), iter_sections(neurites, iterator_type=Section.ibifurcation_point, neurite_filter=is_type(neurite_type)))
def diameter_power_relations(neurites, neurite_type=NeuriteType.all, method='first'): """Calculate the diameter power relation at a bifurcation point. Diameter power relation is defined in https://www.ncbi.nlm.nih.gov/pubmed/18568015 This quantity gives an indication of how far the branching is from the Rall ratio (when =1). """ return (bifurcationfunc.diameter_power_relation(bif_point, method) for bif_point in iter_sections(neurites, iterator_type=Section.ibifurcation_point, neurite_filter=is_type(neurite_type)))
def section_radial_distances(neurites, neurite_type=NeuriteType.all, origin=None, iterator_type=Section.ipreorder): """Section radial distances in a collection of neurites. The iterator_type can be used to select only terminal sections (ileaf) or only bifurcations (ibifurcation_point). """ dist = [] for n in iter_neurites(neurites, filt=is_type(neurite_type)): pos = n.root_node.points[0] if origin is None else origin dist.extend(sectionfunc.section_radial_distance(s, pos) for s in iter_sections(n, iterator_type=iterator_type)) return dist
def segment_path_lengths(neurites, neurite_type=NeuriteType.all): """Returns pathlengths between all non-root points and their root point.""" pathlength = {} neurite_filter = is_type(neurite_type) def _get_pathlength(section): if section.id not in pathlength: if section.parent: pathlength[section.id] = section.parent.length + _get_pathlength(section.parent) else: pathlength[section.id] = 0 return pathlength[section.id] result = [_get_pathlength(section) + np.cumsum(sectionfunc.segment_lengths(section)) for section in iter_sections(neurites, neurite_filter=neurite_filter)] return np.hstack(result) if result else np.array([])
def section_path_lengths(neurites, neurite_type=NeuriteType.all): """Path lengths of a collection of neurites.""" # Calculates and stores the section lengths in one pass, # then queries the lengths in the path length iterations. # This avoids repeatedly calculating the lengths of the # same sections. dist = {} neurite_filter = is_type(neurite_type) for s in iter_sections(neurites, neurite_filter=neurite_filter): dist[s] = s.length def pl2(node): """Calculate the path length using cached section lengths.""" return sum(dist[n] for n in node.iupstream()) return _map_sections(pl2, neurites, neurite_type=neurite_type)
def plot_tree3d(ax, tree, diameter_scale=_DIAMETER_SCALE, linewidth=_LINEWIDTH, color=None, alpha=_ALPHA): """Generates a figure of the tree in 3d. If the tree contains one single point the plot will be empty \ since no segments can be constructed. Args: ax(matplotlib axes): on what to plot tree(neurom.core.Section or neurom.core.Neurite): plotted tree diameter_scale(float): Scale factor multiplied with segment diameters before plotting linewidth(float): all segments are plotted with this width, but only if diameter_scale=None color(str or None): Color of plotted values, None corresponds to default choice alpha(float): Transparency of plotted values """ section_segment_list = [(section, segment) for section in iter_sections(tree) for segment in iter_segments(section)] segs = [(seg[0][COLS.XYZ], seg[1][COLS.XYZ]) for _, seg in section_segment_list] colors = [ _get_color(color, section.type) for section, _ in section_segment_list ] linewidth = _get_linewidth(tree, diameter_scale=diameter_scale, linewidth=linewidth) collection = Line3DCollection(segs, colors=colors, linewidth=linewidth, alpha=alpha) ax.add_collection3d(collection) _update_3d_datalim(ax, tree)
def terminal_path_lengths_per_neurite(neurites, neurite_type=NeuriteType.all): """Get the path lengths to each terminal point per neurite in a collection.""" return list(sectionfunc.section_path_length(s) for n in iter_neurites(neurites, filt=is_type(neurite_type)) for s in iter_sections(n, iterator_type=Section.ileaf))
def _map_sections(fun, neurites, neurite_type=NeuriteType.all, iterator_type=Section.ipreorder): """Map `fun` to all the sections in a collection of neurites.""" return map(fun, iter_sections(neurites, iterator_type=iterator_type, neurite_filter=is_type(neurite_type)))
def test_iter_sections_default(): ref = [s for n in POP.neurites for s in n.iter_sections()] assert (ref == [n for n in iter_sections(POP)])
def plot_tree(ax, tree, plane='xy', diameter_scale=_DIAMETER_SCALE, linewidth=_LINEWIDTH, color=None, alpha=_ALPHA, realistic_diameters=False): """Plots a 2d figure of the tree's segments. Args: ax(matplotlib axes): on what to plot tree(neurom.core.Section or neurom.core.Neurite): plotted tree plane(str): Any pair of 'xyz' diameter_scale(float): Scale factor multiplied with segment diameters before plotting linewidth(float): all segments are plotted with this width, but only if diameter_scale=None color(str or None): Color of plotted values, None corresponds to default choice alpha(float): Transparency of plotted values realistic_diameters(bool): scale linewidths with axis data coordinates Note: If the tree contains one single point the plot will be empty since no segments can be constructed. """ plane0, plane1 = _plane2col(plane) section_segment_list = [(section, segment) for section in iter_sections(tree) for segment in iter_segments(section)] colors = [ _get_color(color, section.type) for section, _ in section_segment_list ] if realistic_diameters: def _get_rectangle(x, y, linewidth): """Draw a rectangle to represent a secgment.""" x, y = np.array(x), np.array(y) diff = y - x angle = np.arctan2(diff[1], diff[0]) % (2 * np.pi) return Rectangle( x - linewidth / 2. * np.array([-np.sin(angle), np.cos(angle)]), np.linalg.norm(diff), linewidth, np.rad2deg(angle)) segs = [ _get_rectangle((seg[0][plane0], seg[0][plane1]), (seg[1][plane0], seg[1][plane1]), 2 * segment_radius(seg) * diameter_scale) for _, seg in section_segment_list ] collection = PatchCollection(segs, alpha=alpha, facecolors=colors) else: segs = [((seg[0][plane0], seg[0][plane1]), (seg[1][plane0], seg[1][plane1])) for _, seg in section_segment_list] linewidth = _get_linewidth( tree, diameter_scale=diameter_scale, linewidth=linewidth, ) collection = LineCollection(segs, colors=colors, linewidth=linewidth, alpha=alpha) ax.add_collection(collection)
def has_multifurcation(neuron): """Check if a section has more than 3 children.""" bad_ids = [(section.id, section.points[np.newaxis, -1]) for section in iter_sections(neuron) if len(section.children) > 3] return CheckResult(len(bad_ids) == 0, bad_ids)
def n_segments(neurites, neurite_type=NeuriteType.all): """Number of segments in a collection of neurites.""" return sum(len(s.points) - 1 for s in iter_sections(neurites, neurite_filter=is_type(neurite_type)))
def bifurcation_partitions(neurites, neurite_type=NeuriteType.all): """Partition at bifurcation points of a collection of neurites.""" return map(bifurcationfunc.bifurcation_partition, iter_sections(neurites, iterator_type=Section.ibifurcation_point, neurite_filter=is_type(neurite_type)))
def n_sections(neurites, neurite_type=NeuriteType.all, iterator_type=Section.ipreorder): """Number of sections in a collection of neurites.""" return sum(1 for _ in iter_sections(neurites, iterator_type=iterator_type, neurite_filter=is_type(neurite_type)))
def test_iter_sections_default_pop(): ref = [s.id for n in POP.neurites for s in n.iter_sections()] assert ref == [n.id for n in iter_sections(POP)]