def _check_cloned_neuron(nrn1, nrn2): # check if two neurons are identical # soma assert isinstance(nrn2.soma, type(nrn1.soma)) assert nrn1.soma.radius == nrn2.soma.radius for v1, v2 in zip(nrn1.soma.iter(), nrn2.soma.iter()): assert np.allclose(v1, v2) # neurites for v1, v2 in zip(iter_segments(nrn1), iter_segments(nrn2)): (v1_start, v1_end), (v2_start, v2_end) = v1, v2 assert np.allclose(v1_start, v2_start) assert np.allclose(v1_end, v2_end) # check if the ids are different # somata assert nrn1.soma is not nrn2.soma # neurites for neu1, neu2 in zip(nrn1.neurites, nrn2.neurites): assert neu1 is not neu2 # check if changes are propagated between neurons nrn2.soma.radius = 10. assert nrn1.soma.radius != nrn2.soma.radius
def test_iter_segments_nrn(): ref = list(iter_segments(SIMPLE)) assert len(ref) == 6 ref = list( iter_segments(SIMPLE, neurite_filter=lambda n: n.type == nm.AXON)) assert len(ref) == 3 ref = list( iter_segments(SIMPLE, neurite_filter=lambda n: n.type == nm.BASAL_DENDRITE)) assert len(ref) == 3 ref = list( iter_segments(SIMPLE, neurite_filter=lambda n: n.type == nm.APICAL_DENDRITE)) assert len(ref) == 0 ref = list(iter_segments(NRN1)) assert len(ref) == 840 ref = list(iter_segments(NRN1, neurite_filter=lambda n: n.type == nm.AXON)) assert len(ref) == 210 ref = list( iter_segments(NRN1, neurite_filter=lambda n: n.type == nm.BASAL_DENDRITE)) assert len(ref) == 420 ref = list( iter_segments(NRN1, neurite_filter=lambda n: n.type == nm.APICAL_DENDRITE)) assert len(ref) == 210
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_segments_pop(): ref = list(iter_segments(POP)) assert len(ref) == 3387 ref = list(iter_segments(POP, neurite_filter=lambda n: n.type == nm.AXON)) assert len(ref) == 919 ref = list( iter_segments(POP, neurite_filter=lambda n: n.type == nm.BASAL_DENDRITE)) assert len(ref) == 1549 ref = list( iter_segments(POP, neurite_filter=lambda n: n.type == nm.APICAL_DENDRITE)) assert len(ref) == 919
def _count_crossings(neurite, radius): """Used to count_crossings of segments in neurite with radius.""" r2 = radius**2 count = 0 for start, end in iter_segments(neurite): start_dist2, end_dist2 = (morphmath.point_dist2(center, start), morphmath.point_dist2(center, end)) count += int(start_dist2 <= r2 <= end_dist2 or end_dist2 <= r2 <= start_dist2) return count
def _get_linewidth(tree, linewidth, diameter_scale): """Calculate the desired linewidth based on tree contents. If diameter_scale exists, it is used to scale the diameter of each of the segments in the tree If diameter_scale is None, the linewidth is used. """ if diameter_scale is not None and tree: linewidth = [ 2 * segment_radius(s) * diameter_scale for s in iter_segments(tree) ] return linewidth
def test_iter_segments_section(): sec = load_neuron(StringIO(u""" ((CellBody) (0 0 0 2)) ((Dendrite) (1 2 3 8) (5 6 7 16) (8 7 6 10) (4 3 2 2)) """), reader='asc').sections[0] ref = [[p1[COLS.XYZR].tolist(), p2[COLS.XYZR].tolist()] for p1, p2 in iter_segments(sec)] assert_array_equal( ref, [[[1, 2, 3, 4], [5, 6, 7, 8]], [[5, 6, 7, 8], [8, 7, 6, 5]], [[8, 7, 6, 5], [4, 3, 2, 1]]])
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 segment_areas(neurites, neurite_type=NeuriteType.all): """Areas of the segments in a collection of neurites.""" return [morphmath.segment_area(seg) for seg in iter_segments(neurites, is_type(neurite_type))]
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)