def test_register_neurite_feature_nrns(): def npts(neurite): return len(neurite.points) def vol(neurite): return neurite.volume fst.register_neurite_feature('foo', npts) n_points_ref = [len(n.points) for n in iter_neurites(NRNS)] n_points = fst.get('foo', NRNS) assert_items_equal(n_points, n_points_ref) # test neurite type filtering n_points_ref = [len(n.points) for n in iter_neurites(NRNS, filt=_is_type(NeuriteType.axon))] n_points = fst.get('foo', NRNS, neurite_type=NeuriteType.axon) assert_items_equal(n_points, n_points_ref) fst.register_neurite_feature('bar', vol) n_volume_ref = [n.volume for n in iter_neurites(NRNS)] n_volume = fst.get('bar', NRNS) assert_items_equal(n_volume, n_volume_ref) # test neurite type filtering n_volume_ref = [n.volume for n in iter_neurites(NRNS, filt=_is_type(NeuriteType.axon))] n_volume = fst.get('bar', NRNS, neurite_type=NeuriteType.axon) assert_items_equal(n_volume, n_volume_ref)
def test_register_neurite_feature_pop(): def npts(neurite): return len(neurite.points) def vol(neurite): return neurite.volume fst.register_neurite_feature('foo', npts) n_points_ref = [len(n.points) for n in iter_neurites(POP)] n_points = fst.get('foo', POP) assert_items_equal(n_points, n_points_ref) # test neurite type filtering n_points_ref = [len(n.points) for n in iter_neurites(POP, filt=_is_type(NeuriteType.basal_dendrite))] n_points = fst.get('foo', POP, neurite_type=NeuriteType.basal_dendrite) assert_items_equal(n_points, n_points_ref) fst.register_neurite_feature('bar', vol) n_volume_ref = [n.volume for n in iter_neurites(POP)] n_volume = fst.get('bar', POP) assert_items_equal(n_volume, n_volume_ref) # test neurite type filtering n_volume_ref = [n.volume for n in iter_neurites(POP, filt=_is_type(NeuriteType.basal_dendrite))] n_volume = fst.get('bar', POP, neurite_type=NeuriteType.basal_dendrite) assert_items_equal(n_volume, n_volume_ref)
def test_get_section_path_distances_endpoint(self): ref_sec_path_len_start = list(iter_neurites(self.neuron, sec.start_point_path_length)) ref_sec_path_len = list(iter_neurites(self.neuron, sec.end_point_path_length)) path_lengths = self.neuron.get_section_path_distances() nt.assert_true(ref_sec_path_len != ref_sec_path_len_start) nt.assert_equal(len(path_lengths), 84) nt.assert_true(np.all(path_lengths == ref_sec_path_len))
def test_section_path_distances_endpoint(): ref_sec_path_len_start = list(iter_neurites(NEURON, sec.start_point_path_length)) ref_sec_path_len = list(iter_neurites(NEURON, sec.end_point_path_length)) path_lengths = fst_get('section_path_distances', NEURON) nt.ok_(ref_sec_path_len != ref_sec_path_len_start) nt.eq_(len(path_lengths), 84) nt.ok_(np.all(path_lengths == ref_sec_path_len))
def test_section_path_distances_endpoint(): ref_sec_path_len_start = list( iter_neurites(NEURON, sec.start_point_path_length)) ref_sec_path_len = list(iter_neurites(NEURON, sec.end_point_path_length)) path_lengths = get_feature('section_path_distances', NEURON) assert ref_sec_path_len != ref_sec_path_len_start assert len(path_lengths) == 84 assert np.all(path_lengths == ref_sec_path_len)
def _check_volume(obj): sec_vol = [l for l in iter_neurites(obj, sec.volume)] seg_vol = [l for l in iter_neurites(obj, seg.volume)] sum_sec_vol = sum(sec_vol) sum_seg_vol = sum(seg_vol) # check that sum of section volumes is same as sum of segment lengths nt.assert_almost_equal(sum_sec_vol, sum_seg_vol) nt.assert_almost_equal(sum_sec_vol, 307.68010178856395)
def _check_area(obj): sec_area = [l for l in iter_neurites(obj, sec.area)] seg_area = [l for l in iter_neurites(obj, seg.area)] sum_sec_area = sum(sec_area) sum_seg_area = sum(seg_area) # check that sum of section areas is same as sum of segment lengths nt.assert_almost_equal(sum_sec_area, sum_seg_area) nt.assert_almost_equal(sum_sec_area, 349.75070138106133)
def _check_length(obj): sec_len = [l for l in iter_neurites(obj, sec.length)] seg_len = [l for l in iter_neurites(obj, seg.length)] sum_sec_len = sum(sec_len) sum_seg_len = sum(seg_len) # check that sum of section lengths is same as sum of segment lengths nt.eq_(sum_sec_len, sum_seg_len) nt.assert_almost_equal(sum_sec_len, 33.0330776588)
def TMD(neuron_handle): """ Compute the TMD of a neuron i.e. its dimension 0 persistence using path distance as a filtration :param neuron_handle: :return: """ nrn = nm.load_neuron(neuron_handle) diag = [] roots = [] f = {None: 0} nodes = [neurite.root_node for neurite in nm.iter_neurites(nrn)] while len(nodes) > 0: n = nodes.pop() f[n] = f[n.parent] + n.length nodes.extend(n.children) for neurite in nm.iter_neurites(nrn): R = neurite.root_node # the root of the neuron tree A = {} # A set of active nodes, initialized to the set of tree leaves for l in R.ileaf(): A[l] = f[l] while not R in A: for l in A: p = l.parent # break if a child of p is not active, might need to improve this to avoid quadratic complexity stop = False m = 0 c0 = None for c in p.children: if not c in A: stop = True break elif A[c] > m: m = A[c] c0 = c if not stop: A[p] = m for c in p.children: if not c == c0: diag.append((min(A[c], f[p]), max(A[c], f[p]))) A.pop(c) break roots.append((min(A[R], f[R]), max(A[R], f[R]))) # merge root of dendrites i = np.argmax(map(lambda a, b: b, roots)) a, b = roots.pop(i) diag.extend(roots) diag.append((b, )) return diag
def test_get_section_radial_distances_endpoint(self): ref_sec_rad_dist_start = [] for t in self.neuron.neurites: ref_sec_rad_dist_start.extend( ll for ll in iter_neurites(t, sec.radial_dist(t.value, use_start_point=True))) ref_sec_rad_dist = [] for t in self.neuron.neurites: ref_sec_rad_dist.extend(ll for ll in iter_neurites(t, sec.radial_dist(t.value))) rad_dists = self.neuron.get_section_radial_distances() nt.assert_true(ref_sec_rad_dist != ref_sec_rad_dist_start) nt.assert_equal(len(rad_dists), 84) nt.assert_true(np.all(rad_dists == ref_sec_rad_dist))
def _check_segment_radial_dists(obj): origin = [0.0, 0.0, 0.0] rd = [d for d in iter_neurites(SIMPLE_NEURON, seg.radial_dist(origin))] nt.eq_(rd, [1.0, 3.0, 5.0, 7.0, 1.0, 3.0, 5.0, 7.0])
def _check_section_radial_dists_start_point(obj): origin = [0.0, 0.0, 0.0] rd = [d for d in iter_neurites(obj, sec.radial_dist(origin, True))] nt.eq_(rd, [0.0, 0.0])
def _check_section_radial_dists_end_point(obj): origin = [0.0, 0.0, 0.0] rd = [d for d in iter_neurites(obj, sec.radial_dist(origin))] nt.eq_(rd, [8.0, 8.0])
def test_section_path_distances_start_point(): ref_sec_path_len_start = list( iter_neurites(NEURON, sec.start_point_path_length)) path_lengths = get_feature('section_path_distances', NEURON, use_start_point=True) assert len(path_lengths) == 84 assert np.all(path_lengths == ref_sec_path_len_start)
def _check_points(obj): @bif.bifurcation_point_function(as_tree=False) def point(bif): return bif[:4] bif_points = [p for p in iter_neurites(obj, point)] nt.eq_(bif_points, [[0.0, 4.0, 0.0, 2.0], [0.0, 5.0, 0.0, 2.0], [0.0, 5.0, 3.0, 0.75]])
def test_load_trees_good_neuron(): '''Check trees in good neuron are the same as trees from loaded neuron''' filepath = os.path.join(SWC_PATH, 'Neuron.swc') nrn = utils.load_neuron(filepath) trees = utils.load_trees(filepath) nt.eq_(len(nrn.neurites), 4) nt.eq_(len(nrn.neurites), len(trees)) nrn2 = MockNeuron(trees) @pts.point_function(as_tree=False) def elem(point): return point # Check data are the same in tree collection and neuron's neurites for a, b in izip(iter_neurites(nrn, elem), iter_neurites(nrn2, elem)): nt.ok_(np.all(a == b))
def test_get_remote_bifurcation_angles(self): ref_remote_bifangles = list(iter_neurites(self.neuron, bifs.remote_angle)) remote_bifangles = self.neuron.get_remote_bifurcation_angles() nt.assert_equal(len(remote_bifangles), 40) nt.assert_true(np.all(remote_bifangles == ref_remote_bifangles)) remote_bifangles = self.neuron.get_remote_bifurcation_angles(TreeType.all) nt.assert_equal(len(remote_bifangles), 40) nt.assert_true(np.all(remote_bifangles == ref_remote_bifangles))
def _pkg(self, magic_iter, neurite_type=TreeType.all): '''Return an iterable built from magic_iter''' stuff = list( iter_neurites(self, magic_iter, tree_type_checker(neurite_type)) ) return self._iterable_type(stuff)
def test_section_path_distances_start_point(): ref_sec_path_len_start = list( iter_neurites(NEURON, sec.start_point_path_length)) path_lengths = get_feature('section_path_distances', NEURON, use_start_point=True) nt.eq_(len(path_lengths), 84) nt.ok_(np.all(path_lengths == ref_sec_path_len_start))
def _check_segment_areas(obj): sa = (l/math.pi for l in iter_neurites(obj, seg.area)) ref = (2.0, 2.0, 6.7082039, 4.0, 6.7082039, 1.8038587, 1.5, 6.7082039, 1.8038587, 1.5) for a, b in izip(sa, ref): nt.assert_almost_equal(a, b)
def test_get_section_lengths(self): ref_seclen = list(iter_neurites(self.neuron, sec.length)) seclen = self.neuron.get_section_lengths() nt.assert_equal(len(seclen), 84) nt.assert_true(np.all(seclen == ref_seclen)) seclen = self.neuron.get_section_lengths(TreeType.all) nt.assert_equal(len(seclen), 84) nt.assert_true(np.all(seclen == ref_seclen))
def _check_segment_volumes(obj): sv = (l/math.pi for l in iter_neurites(obj, seg.volume)) ref = (1.0, 1.0, 4.6666667, 4.0, 4.6666667, 0.7708333, 0.5625, 4.6666667, 0.7708333, 0.5625) for a, b in izip(sv, ref): nt.assert_almost_equal(a, b)
def test_volume_density_per_neurite(): vol = np.array(_nf.total_volume_per_neurite(NRN)) hull_vol = np.array([convex_hull(n).volume for n in nm.iter_neurites(NRN)]) vol_density = _nf.volume_density_per_neurite(NRN) nt.eq_(len(vol_density), 4) nt.ok_(np.allclose(vol_density, vol / hull_vol)) ref_density = [0.43756606998299519, 0.52464681266899216, 0.24068543213643726, 0.26289304906104355] nt.ok_(np.allclose(vol_density, ref_density))
def _make_trace(neuron, plane, prefix='', opacity=1., visible=True, style=None, line_width=2): '''Create the trace to be plotted''' names = defaultdict(int) lines = list() for neurite in iter_neurites(neuron): names[neurite.type] += 1 coords = dict(x=list(), y=list(), z=list()) colors = list() try: default_color = style[neurite]['color'] except KeyError: default_color = TREE_COLOR.get(neurite.root_node.type, 'black') for section in iter_sections(neurite): segs = [(s[0][COLS.XYZ], s[1][COLS.XYZ]) for s in iter_segments(section)] section_style = style.get(section, { 'range': slice(0, len(segs)), 'color': default_color }) range_ = section_style['range'] colors += list(repeat(default_color, 3 * range_.start)) colors += list( repeat(section_style['color'], 3 * (range_.stop - range_.start))) colors += list(repeat(default_color, 3 * (len(segs) - range_.stop))) for i, coord in enumerate('xyz'): coords[coord] += list( chain.from_iterable( (p1[i], p2[i], None) for p1, p2 in segs) if coord in plane else chain.from_iterable((0, 0, None) for _ in segs)) lines.append( go.Scatter3d(name=_neurite_name(neurite, prefix, names), showlegend=False, visible=visible, opacity=opacity, line=dict(color=colors, width=line_width), mode='lines', **coords)) return lines
def test_neurite_volume_density(): vol = np.array(_nf.total_volume_per_neurite(NRN)) hull_vol = np.array([convex_hull(n).volume for n in nm.iter_neurites(NRN)]) vol_density = _nf.neurite_volume_density(NRN) nt.eq_(len(vol_density), 4) nt.ok_(np.allclose(vol_density, vol / hull_vol)) ref_density = [ 0.43756606998299519, 0.52464681266899216, 0.24068543213643726, 0.26289304906104355 ] assert_allclose(vol_density, ref_density)
def _find_intact_sub_trees(self): '''Returns intact neurites There is a fallback mechanism in case there are no intact basals: https://bbpcode.epfl.ch/source/xref/platform/BlueRepairSDK/BlueRepairSDK/src/repair.cpp#658 ''' basals = [ neurite.root_node for neurite in iter_neurites(self.neuron) if (neurite.type == NeuriteType.basal_dendrite and is_branch_intact(neurite.root_node, self.cut_leaves)) ] if not basals: L.warning( "No intact basals found. Falling back on less strict selection." ) basals = [ section for section in iter_sections(self.neuron) if (section.type == NeuriteType.basal_dendrite and not is_cut_section(section, self.cut_leaves)) ] axons = [ neurite.root_node for neurite in iter_neurites(self.neuron) if (neurite.type == NeuriteType.axon and is_branch_intact(neurite.root_node, self.cut_leaves)) ] obliques = self._find_intact_obliques() tufts = [ section for section in iter_sections(self.neuron) if (self.repair_type_map[section] == RepairType.tuft and not is_cut_section(section, self.cut_leaves)) ] return basals + obliques + axons + tufts
def _make_trace2d(neuron, plane, prefix='', opacity=1., visible=True, style=None, line_width=2): '''Create the trace to be plotted''' names = defaultdict(int) lines = list() for neurite in iter_neurites(neuron): names[neurite.type] += 1 try: neurite_color = style[neurite]['color'] except KeyError: neurite_color = TREE_COLOR.get(neurite.root_node.type, 'black') name = _neurite_name(neurite, prefix, names) for section in iter_sections(neurite): segs = [(s[0][COLS.XYZ], s[1][COLS.XYZ]) for s in iter_segments(section)] try: colors = style[section]['color'] except KeyError: colors = neurite_color coords = dict() for i, coord in enumerate('xyz'): coords[coord] = list( chain.from_iterable( (p1[i], p2[i], None) for p1, p2 in segs)) coords = dict(x=coords[plane[0]], y=coords[plane[1]]) lines.append( go.Scattergl(name=name, visible=visible, opacity=opacity, showlegend=False, line=dict(color=colors, width=line_width), mode='lines', **coords)) return lines
def _make_trace(neuron, plane): '''Create the trace to be plotted''' for neurite in iter_neurites(neuron): segments = list(iter_segments(neurite)) segs = [(s[0][COLS.XYZ], s[1][COLS.XYZ]) for s in segments] coords = dict(x=list(chain.from_iterable((p1[0], p2[0], None) for p1, p2 in segs)), y=list(chain.from_iterable((p1[1], p2[1], None) for p1, p2 in segs)), z=list(chain.from_iterable((p1[2], p2[2], None) for p1, p2 in segs))) color = TREE_COLOR.get(neurite.root_node.type, 'black') if plane.lower() == '3d': plot_fun = go.Scatter3d else: plot_fun = go.Scatter coords = dict(x=coords[plane[0]], y=coords[plane[1]]) yield plot_fun( line=dict(color=color, width=2), mode='lines', **coords )
def _make_trace(neuron, plane): """Create the trace to be plotted.""" for neurite in iter_neurites(neuron): segments = list(iter_segments(neurite)) segs = [(s[0][COLS.XYZ], s[1][COLS.XYZ]) for s in segments] coords = dict( x=list(chain.from_iterable( (p1[0], p2[0], None) for p1, p2 in segs)), y=list(chain.from_iterable( (p1[1], p2[1], None) for p1, p2 in segs)), z=list(chain.from_iterable( (p1[2], p2[2], None) for p1, p2 in segs))) color = TREE_COLOR.get(neurite.root_node.type, 'black') if plane.lower() == '3d': plot_fun = go.Scatter3d else: plot_fun = go.Scatter coords = dict(x=coords[plane[0]], y=coords[plane[1]]) yield plot_fun(line=dict(color=color, width=2), mode='lines', **coords)
def count(neuron): """ Return number of bifurcation points in neuron or population """ return sum(1 for _ in iter_neurites(neuron, identity))
def count(neuron, tree_filter=None): """ Return number of segments in neuron or population """ return sum(1 for _ in iter_neurites(neuron, identity, tree_filter))
def _check_segment_taper_rate(obj): tp = [t for t in iter_neurites(obj, seg.taper_rate)] nt.eq_(tp, [0.0, 0.0, 1.0, 0.0, 1.0, 0.5, 0.0, 1.0, 0.5, 0.0])
def _check_path_length_start_point(obj, ref): pl = [l for l in iter_neurites(obj, sec.start_point_path_length)] nt.eq_(pl, ref)
def _check_segment_radius(obj): rad = [r for r in iter_neurites(obj, seg.radius)] nt.eq_(rad, [1.0, 1.0, 1.5, 2.0, 1.5, 0.875, 0.75, 1.5, 0.875, 0.75])
def count(neuron): """ Return number of triplets in neuron or population """ return sum(1 for _ in iter_neurites(neuron, identity))
def _check_segment_lengths(obj): lg = [l for l in iter_neurites(obj, seg.length)] nt.eq_(lg, [1.0, 1.0, 2.0, 1.0, 2.0, 1.0, 1.0, 2.0, 1.0, 1.0])
def test_section_branch_order(): sec_bo = [bo for bo in iter_neurites(MOCK_TREE, sec.branch_order)] nt.eq_(sec_bo, [0, 1, 1, 0, 1, 2, 2, 1])
def complete_morph_feature_info(self, neuroM_extra_config_path=None): """Adding more features by means of other NeuroM's functionalities to the prediction generated by function 'set_morph_feature_info', which uses just NeuroM's API for morph_stats Example of features added: field diameter, bounding-box -X,Y,Z- extents and -largest,shortest- principal extents""" extra_file_exists = os.path.isfile(neuroM_extra_config_path) if not extra_file_exists: return with open(neuroM_extra_config_path, 'r') as fp: morph_extra_dict = json.load(fp) # Adding more neurite's features, if requested: # field diameter, bounding-box -X,Y,Z- extents and -largest,shortest- principal extents with open(self.output_pred_file, 'r') as fp: mod_prediction = json.load(fp) if os.path.isdir(self.morph_path): morph_files = nm.io.utils.get_morph_files(self.morph_path) mapping = lambda section: section.points for neurite_name, extra_feat_list in list( morph_extra_dict.items()): # Dict. with neurite names and # extra features to be computed for cell_ID, dict0 in list(mod_prediction.items( )): # Dict. with cell's morph_path-features dict. pairs # for each cell if os.path.isdir(self.morph_path): morph_file_name = [ morph_file for morph_file in morph_files if cell_ID in morph_file ] neuron_path = os.path.join( self.morph_path, os.path.basename(morph_file_name[0])) else: neuron_path = self.morph_path neuron_model = nm.load_neuron(neuron_path) for cell_part, dict1 in list(dict0.items()): if cell_part == neurite_name: neurite_filter = lambda neurite: neurite.type == getattr( nm.NeuriteType, cell_part) neurite_points = [ neurite_points for neurite_points in nm.iter_neurites( neuron_model, mapping, neurite_filter) ] neurite_points = np.concatenate(neurite_points) neurite_cloud = neurite_points[:, 0:3] for feat_name in extra_feat_list: # Compute the neurite's bounding-box -X,Y,Z- extents if feat_name == 'neurite_X_extent': neurite_X_extent = np.max(neurite_cloud[:, 0], axis=0) - \ np.min(neurite_cloud[:, 0], axis=0) dict1.update( {"neurite_X_extent": neurite_X_extent}) elif feat_name == 'neurite_Y_extent': neurite_Y_extent = np.max(neurite_cloud[:, 1], axis=0) - \ np.min(neurite_cloud[:, 1], axis=0) dict1.update( {"neurite_Y_extent": neurite_Y_extent}) elif feat_name == 'neurite_Z_extent': neurite_Z_extent = np.max(neurite_cloud[:, 2], axis=0) - \ np.min(neurite_cloud[:, 2], axis=0) dict1.update( {"neurite_Z_extent": neurite_Z_extent}) # Compute the neurite's principal extents elif feat_name == 'neurite_shortest_extent': # Compute the neurite's shortest principal extents principal_extents = sorted( nm.morphmath.principal_direction_extent( neurite_cloud)) dict1.update({ "neurite_shortest_extent": principal_extents[0] }) elif feat_name == 'neurite_largest_extent': # Compute the neurite's largest principal extents principal_extents = sorted( nm.morphmath.principal_direction_extent( neurite_cloud)) dict1.update({ "neurite_largest_extent": principal_extents[-1] }) # Compute the neurite-field diameter elif feat_name == 'neurite_field_diameter': neurite_field_diameter = nm.morphmath.polygon_diameter( neurite_cloud) dict1.update({ "neurite_field_diameter": neurite_field_diameter }) # Saving NeuroM's output in a formatted json-file # with open(self.output_pred_file, 'w') as fp: # json.dump(mod_prediction, fp, sort_keys=True, indent=3) return mod_prediction
def _check_local_bifurcation_angles(obj): angles = [a for a in iter_neurites(obj, bif.local_angle)] nt.eq_(angles, [math.pi / 4, math.pi / 2, math.pi / 4])
def _check_remote_bifurcation_angles(obj): angles = [a for a in iter_neurites(obj, bif.remote_angle)] nt.eq_(angles, [0.9380474917927135, math.pi / 2, math.pi / 4])
view.plot_neuron(ax, neuron) # draw circles center = neuron.soma.center[:2] _dist = np.linalg.norm(neuron.points[:,:2]-center, axis=1).max() radii = np.arange(step_size, _dist, step_size) patches = [] for rad in radii: circle = mpatches.Circle(center, rad, fill=False, edgecolor='dimgray') patches.append(circle) p = PatchCollection(patches, match_original=True) ax.add_collection(p) # add labels if label_dict is None: apical_points = np.concatenate([x.points for x in nm.iter_neurites(neuron, filt=lambda t: t.type==nm.APICAL_DENDRITE)]) apical_label_pos_xs = [apical_points[:,0].min()-center[0], apical_points[:,0].max()-center[0]] apical_label_pos_x = apical_label_pos_xs[0] if np.abs(apical_label_pos_xs[0])>np.abs(apical_label_pos_xs[1]) else apical_label_pos_xs[1] apical_label_pos_y = center[1]+(apical_points[:,1].max()-center[1])/2 basal_points = np.concatenate([x.points for x in nm.iter_neurites(neuron, filt=lambda t: t.type==nm.BASAL_DENDRITE)]) basal_label_pos_xs = [basal_points[:,0].min()-center[0],basal_points[:,0].max()-center[0]] basal_label_pos_x = basal_label_pos_xs[0] if np.abs(basal_label_pos_xs[0])>np.abs(basal_label_pos_xs[1]) else basal_label_pos_xs[1] basal_label_pos_y = center[1]+(basal_points[:,1].min()-center[1])/2 label_dict = {'Apical':(apical_label_pos_x, apical_label_pos_y), 'Basal': (basal_label_pos_x, basal_label_pos_y)} for name,pos in label_dict.items(): plt.annotate(name, pos) ax.autoscale() ax.set_axis_off() plt.title(None)