def _evaluate(tr1, tr2, comp_func): for v1, v2 in izip(val_iter(ipreorder(tr1)), val_iter(ipreorder(tr2))): #print "v1 : ", v1[:COLS.R] #print "v2 : ", v2[:COLS.R] #print "-" * 10 nt.assert_true(comp_func(v1[:COLS.R], v2[:COLS.R]))
def test_postorder_iteration(): nt.ok_( list(val_iter(ipostorder(REF_TREE))) == [111, 112, 11, 12111, 12112, 1211, 121, 122, 12, 0]) nt.ok_(list(val_iter(ipostorder(REF_TREE.children[0]))) == [111, 112, 11]) nt.ok_( list(val_iter(ipostorder(REF_TREE.children[1]))) == [12111, 12112, 1211, 121, 122, 12])
def point_iter(iterator): '''Transform tree iterator into a point iterator Args: iterator: tree iterator for a tree holding raw data rows. ''' return imap(as_point, tree.val_iter(iterator))
def test_iter_points(self): ref_point_radii = [] for t in self.neuron.neurites: ref_point_radii.extend(p[COLS.R] for p in val_iter(ipreorder(t))) rads = [r for r in self.neuron.iter_points(lambda p: p[COLS.R])] nt.assert_true(np.all(ref_point_radii == rads))
def test_copy(): soma = neuron.make_soma([[0, 0, 0, 1, 1, 1, -1]]) nrn1 = neuron.Neuron(soma, [TREE], name="Rabbit of Caerbannog") nrn2 = nrn1.copy() # check if two neurons are identical # somata nt.assert_true(isinstance(nrn2.soma, type(nrn1.soma))) nt.assert_true(nrn1.soma.radius == nrn2.soma.radius) for v1, v2 in izip(nrn1.soma.iter(), nrn2.soma.iter()): nt.assert_true(np.allclose(v1, v2)) # neurites for neu1, neu2 in izip(nrn1.neurites, nrn2.neurites): nt.assert_true(isinstance(neu2, type(neu1))) for v1, v2 in izip(val_iter(ipreorder(neu1)), val_iter(ipreorder(neu2))): nt.assert_true(np.allclose(v1, v2)) # check if the ids are different # somata nt.assert_true( nrn1.soma is not nrn2.soma) # neurites for neu1, neu2 in izip(nrn1.neurites, nrn2.neurites): nt.assert_true(neu1 is not neu2) # check if changes are propagated between neurons nrn2.soma.radius = 10. nt.assert_false(nrn1.soma.radius == nrn2.soma.radius) # neurites for neu1, neu2 in izip(nrn1.neurites, nrn2.neurites): for v1, v2 in izip(val_iter(ipreorder(neu1)), val_iter(ipreorder(neu2))): v2 = np.array([-1000., -1000., -1000., 1000., -100., -100., -100.]) nt.assert_false(any(v1 == v2))
def test_ibifurcation_point_upstream(): leaves = [l for l in ileaf(REF_TREE2)] ref_paths = [[11, 0], [11, 0], [11, 0], [11, 0], [1211, 12, 0], [1211, 12, 0], [12, 0]] for l, ref in zip(leaves, ref_paths): nt.assert_equal( [s for s in val_iter(ibifurcation_point(l, iupstream))], ref)
def find_tree_type(tree): """ Calculates the 'mean' type of the tree. Accepted tree types are: 'undefined', 'axon', 'basal', 'apical' The 'mean' tree type is defined as the type that is shared between at least 51% of the tree's points. Returns: The type of the tree """ tree_types = tuple(TreeType) types = [node[COLS.TYPE] for node in tr.val_iter(tr.ipreorder(tree))] types = [node[COLS.TYPE] for node in tr.val_iter(tr.ipreorder(tree))] return tree_types[int(np.median(types))]
def test_segment_iteration(): nt.assert_equal(list(val_iter(isegment(REF_TREE))), [(0, 11), (11, 111), (11, 112), (0, 12), (12, 121), (121, 1211), (1211, 12111), (1211, 12112), (12, 122)]) nt.assert_equal(list(val_iter(isegment(REF_TREE.children[0]))), [(0, 11), (11, 111), (11, 112)]) nt.assert_equal(list(val_iter(isegment(REF_TREE.children[0].children[0]))), [(11, 111)]) nt.assert_equal(list(val_iter(isegment(REF_TREE.children[0].children[1]))), [(11, 112)]) nt.assert_equal(list(val_iter(isegment(REF_TREE.children[1]))), [(0, 12), (12, 121), (121, 1211), (1211, 12111), (1211, 12112), (12, 122)]) nt.assert_equal(list(val_iter(isegment(REF_TREE.children[1].children[0]))), [(12, 121), (121, 1211), (1211, 12111), (1211, 12112)]) nt.assert_equal(list(val_iter(isegment(REF_TREE.children[1].children[1]))), [(12, 122)])
def test_segment_iteration(): nt.assert_equal(list(val_iter(isegment(REF_TREE))), [(0, 11),(11, 111),(11, 112), (0, 12),(12, 121),(121,1211), (1211,12111),(1211,12112),(12, 122)]) nt.assert_equal(list(val_iter(isegment(REF_TREE.children[0]))), [(0, 11), (11, 111),(11, 112)]) nt.assert_equal(list(val_iter(isegment(REF_TREE.children[0].children[0]))), [(11, 111)]) nt.assert_equal(list(val_iter(isegment(REF_TREE.children[0].children[1]))), [(11, 112)]) nt.assert_equal(list(val_iter(isegment(REF_TREE.children[1]))), [(0, 12), (12, 121), (121, 1211), (1211, 12111), (1211, 12112), (12, 122)]) nt.assert_equal(list(val_iter(isegment(REF_TREE.children[1].children[0]))), [(12, 121), (121, 1211), (1211, 12111), (1211, 12112)]) nt.assert_equal(list(val_iter(isegment(REF_TREE.children[1].children[1]))), [(12, 122)])
def calculate_and_plot_end_to_end_distance(path): '''Calculate and plot the end-to-end distance vs the number of segments for an increasingly larger part of a given path. Note that the plots are not very meaningful for bifurcating trees.''' end_to_end_distance = [morphmath.point_dist(segment[1], path.value) for segment in tree.val_iter(tree.isegment(path))] make_end_to_end_distance_plot(np.arange(len(end_to_end_distance)) + 1, end_to_end_distance, path.type)
def radius_of_gyration(neurite): '''Calculate and return radius of gyration of a given neurite.''' centre_mass = neurite_centre_of_mass(neurite) sum_sqr_distance = 0 N = 0 for segment in tree.val_iter(tree.isegment(neurite)): sum_sqr_distance = sum_sqr_distance + distance_sqr(centre_mass, segment) N += 1 return np.sqrt(sum_sqr_distance / N)
def neurite_centre_of_mass(neurite): '''Calculate and return centre of mass of a neurite.''' centre_of_mass = np.zeros(3) total_volume = 0 for segment in tree.val_iter(tree.isegment(neurite)): seg_volume = morphmath.segment_volume(segment) centre_of_mass = centre_of_mass + seg_volume * segment_centre_of_mass(segment) total_volume += seg_volume return centre_of_mass / total_volume
def test_ibifurcation_point_upstream(): leaves = [l for l in ileaf(REF_TREE2)] ref_paths = [ [11, 0], [11, 0], [11, 0], [11, 0], [1211, 12, 0], [1211, 12, 0], [12, 0] ] for l, ref in zip(leaves, ref_paths): nt.assert_equal([s for s in val_iter(ibifurcation_point(l, iupstream))], ref)
def test_leaf_iteration(): nt.ok_(list(val_iter(ileaf(REF_TREE))) == [111, 112, 12111, 12112, 122]) nt.ok_(list(val_iter(ileaf(REF_TREE.children[0]))) == [111, 112]) nt.ok_(list(val_iter(ileaf(REF_TREE.children[1]))) == [12111, 12112, 122]) nt.ok_(list(val_iter(ileaf(REF_TREE.children[0].children[0]))) == [111]) nt.ok_(list(val_iter(ileaf(REF_TREE.children[0].children[1]))) == [112]) nt.ok_(list(val_iter(ileaf(REF_TREE.children[1].children[0]))) == [12111, 12112]) nt.ok_(list(val_iter(ileaf(REF_TREE.children[1].children[1]))) == [122])
def neurite_centre_of_mass(neurite): '''Calculate and return centre of mass of a neurite.''' centre_of_mass = np.zeros(3) total_volume = 0 for segment in tree.val_iter(tree.isegment(neurite)): seg_volume = morphmath.segment_volume(segment) centre_of_mass = centre_of_mass + seg_volume * segment_centre_of_mass( segment) total_volume += seg_volume return centre_of_mass / total_volume
def radius_of_gyration(neurite): '''Calculate and return radius of gyration of a given neurite.''' centre_mass = neurite_centre_of_mass(neurite) sum_sqr_distance = 0 N = 0 for segment in tree.val_iter(tree.isegment(neurite)): sum_sqr_distance = sum_sqr_distance + distance_sqr( centre_mass, segment) N += 1 return np.sqrt(sum_sqr_distance / N)
def _generate_dendro(current_node, lines, colors, n, max_dims, spacing, offsets, show_diameters=True): '''Recursive function for dendrogram line computations ''' start_x = _spacingx(current_node, max_dims, offsets, spacing) radii = [0., 0.] # store the parent radius in order to construct polygonal segments # isntead of simple line segments radii[0] = current_node.value[3] if show_diameters else 0. for child in current_node.children: # segment length length = segment_length(list(val_iter((current_node, child)))) # extract the radius of the child node. Need both radius for # realistic segment representation radii[1] = child.value[3] if show_diameters else 0. # number of leaves in child terminations = n_terminations(child) # horizontal spacing with respect to the number of # terminations new_offsets = (start_x + spacing[0] * terminations / 2., offsets[1] + spacing[1] * 2. + length) # vertical segment lines[n[0]] = _vertical_segment(offsets, new_offsets, spacing, radii) # assign segment id to color array colors[n[0]] = child.value[4] n[0] += 1 if offsets[1] + spacing[1] * 2 + length > max_dims[1]: max_dims[1] = offsets[1] + spacing[1] * 2. + length # recursive call to self. _generate_dendro(child, lines, colors, n, max_dims, spacing, new_offsets, show_diameters=show_diameters) # update the starting position for the next child start_x += terminations * spacing[0] # write the horizontal lines only for bifurcations, where the are actual horizontal lines # and not zero ones if offsets[0] != new_offsets[0]: # horizontal segment lines[n[0]] = _horizontal_segment(offsets, new_offsets, spacing, 0.) colors[n[0]] = current_node.value[4] n[0] += 1
def nonzero_segment_lengths(neuron, threshold=0.0): '''Check presence of neuron segments with length not above threshold Arguments: neuron: Neuron object whose segments will be tested threshold: value above which a segment length is considered to be non-zero Return: list of (first_id, second_id) of zero length segments ''' l = [[s for s in val_iter(isegment(t)) if segment_length(s) <= threshold] for t in neuron.neurites] return [(i[0][COLS.ID], i[1][COLS.ID]) for i in chain(*l)]
def nonzero_section_lengths(neuron, threshold=0.0): '''Check presence of neuron sections with length not above threshold Arguments: neuron: Neuron object whose segments will be tested threshold: value above which a section length is considered to be non-zero Return: list of ids of first point in bad sections ''' l = [[s for s in val_iter(isection(t)) if section_length(s) <= threshold] for t in neuron.neurites] return [i[0][COLS.ID] for i in chain(*l)]
def test_leaf_iteration(): nt.ok_(list(val_iter(ileaf(REF_TREE))) == [111, 112, 12111, 12112, 122]) nt.ok_(list(val_iter(ileaf(REF_TREE.children[0]))) == [111, 112]) nt.ok_(list(val_iter(ileaf(REF_TREE.children[1]))) == [12111, 12112, 122]) nt.ok_(list(val_iter(ileaf(REF_TREE.children[0].children[0]))) == [111]) nt.ok_(list(val_iter(ileaf(REF_TREE.children[0].children[1]))) == [112]) nt.ok_( list(val_iter(ileaf(REF_TREE.children[1].children[0]))) == [12111, 12112]) nt.ok_(list(val_iter(ileaf(REF_TREE.children[1].children[1]))) == [122])
def test_upstream_iteration(): nt.ok_(list(val_iter(iupstream(REF_TREE))) == [0]) nt.ok_(list(val_iter(iupstream(REF_TREE.children[0]))) == [11, 0]) nt.ok_(list(val_iter(iupstream(REF_TREE.children[0].children[0]))) == [111, 11, 0]) nt.ok_(list(val_iter(iupstream(REF_TREE.children[0].children[1]))) == [112, 11, 0]) nt.ok_(list(val_iter(iupstream(REF_TREE.children[1]))) == [12, 0]) nt.ok_(list(val_iter(iupstream(REF_TREE.children[1].children[0]))) == [121, 12, 0]) nt.ok_(list(val_iter(iupstream(REF_TREE.children[1].children[1]))) == [122, 12, 0])
def nonzero_neurite_radii(neuron, threshold=0.0): '''Check presence of neurite points with radius not above threshold Arguments: neuron: Neuron object whose segments will be tested threshold: value above which a radius is considered to be non-zero Return: list of IDs of zero-radius points ''' ids = [[i[COLS.ID] for i in val_iter(ipreorder(t)) if i[COLS.R] <= threshold] for t in neuron.neurites] return [i for i in chain(*ids)]
def test_section_upstream_iteration(): leaves = [l for l in ileaf(REF_TREE2)] ref_paths = [[(1111, 11111), (11, 111, 1111), (0, 11)], [(1111, 11112), (11, 111, 1111), (0, 11)], [(1111, 11113), (11, 111, 1111), (0, 11)], [(11, 112), (0, 11)], [(1211, 12111), (12, 121, 1211), (0, 12)], [(1211, 12112), (12, 121, 1211), (0, 12)], [(12, 122), (0, 12)]] for l, ref in zip(leaves, ref_paths): nt.assert_equal([s for s in val_iter(isection(l, iupstream))], ref)
def test_make_copy(): tree_copy = make_copy(REF_TREE3) # assert that the two trees have the same values # first by total nodes nt.assert_true(len(list(ipreorder(tree_copy))) == len(list(ipreorder(REF_TREE3)))) # then node by node for val1, val2 in izip(val_iter(ipreorder(tree_copy)), val_iter(ipreorder(REF_TREE3))): nt.assert_true(all(val1 == val2)) # assert that the tree values do not have the same identity for val1, val2 in izip(val_iter(ipreorder(tree_copy)), val_iter(ipreorder(REF_TREE3))): nt.assert_false(val1 is val2) # create a deepcopy of the original tree for validation validation_tree = deepcopy(REF_TREE3) # modify copied tree tree_copy.value[0:3] = np.array([1000.0, 1000.0, -1000.0]) tree_copy.children[0].add_child(Tree(np.array([0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0]))) # check if anything changed in REF_TREE3 with respect to the validation deepcopy nt.assert_true(len(list(ipreorder(validation_tree))) == len(list(ipreorder(REF_TREE3)))) for val1, val2 in izip(val_iter(ipreorder(REF_TREE3)), val_iter(ipreorder(validation_tree))): nt.assert_true(all(val1 == val2))
def nonzero_neurite_radii(neuron, threshold=0.0): '''Check presence of neurite points with radius not above threshold Arguments: neuron: Neuron object whose segments will be tested threshold: value above which a radius is considered to be non-zero Return: list of IDs of zero-radius points ''' ids = [[ i[COLS.ID] for i in val_iter(ipreorder(t)) if i[COLS.R] <= threshold ] for t in neuron.neurites] return [i for i in chain(*ids)]
def test_section_upstream_iteration(): leaves = [l for l in ileaf(REF_TREE2)] ref_paths = [ [(1111, 11111), (11, 111, 1111), (0, 11)], [(1111, 11112), (11, 111, 1111), (0, 11)], [(1111, 11113), (11, 111, 1111), (0, 11)], [(11, 112), (0, 11)], [(1211, 12111), (12, 121, 1211), (0, 12)], [(1211, 12112), (12, 121, 1211), (0, 12)], [(12, 122), (0, 12)]] for l, ref in zip(leaves, ref_paths): nt.assert_equal([s for s in val_iter(isection(l, iupstream))], ref)
def compare_trees(tree1, tree2): ''' Comparison between all the nodes and their respective radii between two trees. Ids are do not have to be identical between the trees, and swapping is allowed Returns: False if the trees are not identical. True otherwise. ''' leaves1 = list(tr.ileaf(tree1)) leaves2 = list(tr.ileaf(tree2)) if len(leaves1) != len(leaves2): return False else: nleaves = len(leaves1) for leaf1, leaf2 in product(leaves1, leaves2): is_equal = True for node1, node2 in izip(tr.val_iter(tr.iupstream(leaf1)), tr.val_iter(tr.iupstream(leaf2))): if any(node1[0:5] != node2[0:5]): is_equal = False continue if is_equal: nleaves -= 1 return nleaves == 0
def get_bounding_box(tree): """ Returns: The boundaries of the tree in three dimensions: [[xmin, ymin, zmin], [xmax, ymax, zmax]] """ min_xyz, max_xyz = (np.array([np.inf, np.inf, np.inf]), np.array([np.NINF, np.NINF, np.NINF])) for p in val_iter(tr.ipreorder(tree)): min_xyz = np.minimum(p[: COLS.R], min_xyz) max_xyz = np.maximum(p[: COLS.R], max_xyz) return np.array([min_xyz, max_xyz])
def get_bounding_box(tree): """ Returns: The boundaries of the tree in three dimensions: [[xmin, ymin, zmin], [xmax, ymax, zmax]] """ min_xyz, max_xyz = (np.array([np.inf, np.inf, np.inf]), np.array([np.NINF, np.NINF, np.NINF])) for p in val_iter(tr.ipreorder(tree)): min_xyz = np.minimum(p[:COLS.R], min_xyz) max_xyz = np.maximum(p[:COLS.R], max_xyz) return np.array([min_xyz, max_xyz])
def test_branch_order(): branch_order_map = { (0, 11): 0, (11, 111, 1111): 1, (1111, 11111): 2, (1111, 11112): 2, (1111, 11113): 2, (11, 112): 1, (0, 12): 0, (12, 121, 1211): 1, (1211, 12111): 2, (1211, 12112): 2, (12, 122): 1 } for sec in tr.isection(MOCK_TREE): nt.assert_equal(branch_order(sec), branch_order_map[tuple(p for p in tr.val_iter(sec))])
def test_upstream_iteration(): nt.ok_(list(val_iter(iupstream(REF_TREE))) == [0]) nt.ok_(list(val_iter(iupstream(REF_TREE.children[0]))) == [11, 0]) nt.ok_( list(val_iter(iupstream(REF_TREE.children[0].children[0]))) == [111, 11, 0]) nt.ok_( list(val_iter(iupstream(REF_TREE.children[0].children[1]))) == [112, 11, 0]) nt.ok_(list(val_iter(iupstream(REF_TREE.children[1]))) == [12, 0]) nt.ok_( list(val_iter(iupstream(REF_TREE.children[1].children[0]))) == [121, 12, 0]) nt.ok_( list(val_iter(iupstream(REF_TREE.children[1].children[1]))) == [122, 12, 0])
def _affineTransformTree(tree, A, t, origin=None): ''' Apply an affine transform on your tree by applying a linear transform A (e.g. rotation) and a non-linear transform t (translation) Input: A : 3x3 transformation matrix t : 3x1 translation array tree : tree object origin : the point with respect of which the rotation is applied. If None then the x,y,z of the root node is assumed to be the origin. ''' # if no origin is specified, the position from the root node # becomes the origin if origin is None: origin = tree.value[:COLS.R] for value in val_iter(ipreorder(tree)): _affineTransformPoint(value, A, t, origin)
def principal_direction_extent(tree): '''Calculate the extent of a tree, that is the maximum distance between the projections on the principal directions of the covariance matrix of the x,y,z points of the nodes of the tree. Input tree : a tree object Returns extents : the extents for each of the eigenvectors of the cov matrix eigs : eigenvalues of the covariance matrix eigv : respective eigenvectors of the covariance matrix ''' # extract the x,y,z coordinates of all the points in the tree points = np.array([value[COLS.X: COLS.R]for value in val_iter(ipreorder(tree))]) # center the points around 0.0 points -= np.mean(points, axis=0) # principal components _, eigv = pca(points) extent = np.zeros(3) for i in range(eigv.shape[1]): # orthogonal projection onto the direction of the v component scalar_projs = np.sort(np.array([np.dot(p, eigv[:, i]) for p in points])) extent[i] = scalar_projs[-1] if scalar_projs[0] < 0.: extent -= scalar_projs[0] return extent
def tree3d(tr, new_fig=True, new_axes=True, subplot=False, **kwargs): ''' 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. Parameters: tr: Tree \ neurom.Tree object linewidth: float \ Defines the linewidth of the tree, \ if diameter is set to False. \ Default value is 1.2. alpha: float \ Defines throughe transparency of the tree. \ 0.0 transparent through 1.0 opaque. \ Default value is 0.8. treecolor: str or None \ Defines the color of the tree. \ If None the default values will be used, \ depending on the type of tree: \ Basal dendrite: "red" \ Axon : "blue" \ Apical dendrite: "purple" \ Undefined tree: "black" \ Default value is None. new_fig: boolean \ Defines if the tree will be plotted \ in the current figure (False) \ or in a new figure (True) \ Default value is True. subplot: matplotlib subplot value or False \ If False the default subplot 111 will be used. \ For any other value a matplotlib subplot \ will be generated. \ Default value is False. diameter: boolean \ If True the diameter, scaled with diameter_scale factor, \ will define the width of the tree lines. \ If False use linewidth to select the width of the tree lines. \ Default value is True. diameter_scale: float \ Defines the scale factor that will be multiplied \ with the diameter to define the width of the tree line. \ Default value is 1. white_space: float \ Defines the white space around \ the boundary box of the morphology. \ Default value is 1. Returns: A 3D matplotlib figure with a tree view. ''' from mpl_toolkits.mplot3d.art3d import Line3DCollection # Initialization of matplotlib figure and axes. fig, ax = common.get_figure(new_fig=new_fig, new_axes=new_axes, subplot=subplot, params={'projection': '3d'}) # Data needed for the viewer: x,y,z,r bounding_box = get_bounding_box(tr) def _seg_3d(seg): '''2d coordinates needed for the plotting of a segment''' horz = getattr(COLS, 'X') vert = getattr(COLS, 'Y') depth = getattr(COLS, 'Z') parent_point = seg[0] child_point = seg[1] horz1 = parent_point[horz] horz2 = child_point[horz] vert1 = parent_point[vert] vert2 = child_point[vert] depth1 = parent_point[depth] depth2 = child_point[depth] return ((horz1, vert1, depth1), (horz2, vert2, depth2)) segs = [_seg_3d(seg) for seg in val_iter(isegment(tr))] linewidth = get_default('linewidth', **kwargs) # Definition of the linewidth according to diameter, if diameter is True. if get_default('diameter', **kwargs): # TODO: This was originally a numpy array. Did it have to be one? linewidth = [2 * d * get_default('diameter_scale', **kwargs) for d in iter_neurites(tr, segment_radius)] if len(linewidth) == 0: linewidth = get_default('linewidth', **kwargs) # Plot the collection of lines. collection = Line3DCollection(segs, color=common.get_color(get_default('treecolor', **kwargs), get_tree_type(tr)), linewidth=linewidth, alpha=get_default('alpha', **kwargs)) ax.add_collection3d(collection) kwargs['title'] = kwargs.get('title', 'Tree 3d-view') kwargs['xlabel'] = kwargs.get('xlabel', 'X') kwargs['ylabel'] = kwargs.get('ylabel', 'Y') kwargs['zlabel'] = kwargs.get('zlabel', 'Z') kwargs['xlim'] = kwargs.get('xlim', [bounding_box[0][0] - get_default('white_space', **kwargs), bounding_box[1][0] + get_default('white_space', **kwargs)]) kwargs['ylim'] = kwargs.get('ylim', [bounding_box[0][1] - get_default('white_space', **kwargs), bounding_box[1][1] + get_default('white_space', **kwargs)]) kwargs['zlim'] = kwargs.get('zlim', [bounding_box[0][2] - get_default('white_space', **kwargs), bounding_box[1][2] + get_default('white_space', **kwargs)]) return common.plot_style(fig=fig, ax=ax, **kwargs)
def tree3d(tr, new_fig=True, new_axes=True, subplot=False, **kwargs): """Generates a figure of the tree in 3d. Parameters: tr: Tree neurom.Tree object Options: linewidth: float \ Defines the linewidth of the tree, \ if diameter is set to False. \ Default value is 1.2. alpha: float \ Defines throughe transparency of the tree. \ 0.0 transparent through 1.0 opaque. \ Default value is 0.8. treecolor: str or None \ Defines the color of the tree. \ If None the default values will be used, \ depending on the type of tree: \ Basal dendrite: "red" \ Axon : "blue" \ Apical dendrite: "purple" \ Undefined tree: "black" \ Default value is None. new_fig: boolean \ Defines if the tree will be plotted \ in the current figure (False) \ or in a new figure (True) \ Default value is True. subplot: matplotlib subplot value or False \ If False the default subplot 111 will be used. \ For any other value a matplotlib subplot \ will be generated. \ Default value is False. diameter: boolean If True the diameter, scaled with diameter_scale factor, \ will define the width of the tree lines. \ If False use linewidth to select the width of the tree lines. \ Default value is True. diameter_scale: float \ Defines the scale factor that will be multiplied \ with the diameter to define the width of the tree line. \ Default value is 1. white_space: float \ Defines the white space around \ the boundary box of the morphology. \ Default value is 1. Returns: A 3D matplotlib figure with a tree view. """ from mpl_toolkits.mplot3d.art3d import Line3DCollection # Initialization of matplotlib figure and axes. fig, ax = common.get_figure(new_fig=new_fig, new_axes=new_axes, subplot=subplot, params={"projection": "3d"}) # Data needed for the viewer: x,y,z,r bounding_box = get_bounding_box(tr) def _seg_3d(seg): """2d coordinates needed for the plotting of a segment""" horz = getattr(COLS, "X") vert = getattr(COLS, "Y") depth = getattr(COLS, "Z") parent_point = seg[0] child_point = seg[1] horz1 = parent_point[horz] horz2 = child_point[horz] vert1 = parent_point[vert] vert2 = child_point[vert] depth1 = parent_point[depth] depth2 = child_point[depth] return ((horz1, vert1, depth1), (horz2, vert2, depth2)) segs = [_seg_3d(seg) for seg in val_iter(isegment(tr))] linewidth = get_default("linewidth", **kwargs) # Definition of the linewidth according to diameter, if diameter is True. if get_default("diameter", **kwargs): # TODO: This was originally a numpy array. Did it have to be one? linewidth = [2 * d * get_default("diameter_scale", **kwargs) for d in i_segment_radius(tr)] # Plot the collection of lines. collection = Line3DCollection( segs, color=common.get_color(get_default("treecolor", **kwargs), get_tree_type(tr)), linewidth=linewidth, alpha=get_default("alpha", **kwargs), ) ax.add_collection3d(collection) kwargs["title"] = kwargs.get("title", "Tree 3d-view") kwargs["xlabel"] = kwargs.get("xlabel", "X") kwargs["ylabel"] = kwargs.get("ylabel", "Y") kwargs["zlabel"] = kwargs.get("zlabel", "Z") kwargs["xlim"] = kwargs.get( "xlim", [ bounding_box[0][0] - get_default("white_space", **kwargs), bounding_box[1][0] + get_default("white_space", **kwargs), ], ) kwargs["ylim"] = kwargs.get( "ylim", [ bounding_box[0][1] - get_default("white_space", **kwargs), bounding_box[1][1] + get_default("white_space", **kwargs), ], ) kwargs["zlim"] = kwargs.get( "zlim", [ bounding_box[0][2] - get_default("white_space", **kwargs), bounding_box[1][2] + get_default("white_space", **kwargs), ], ) return common.plot_style(fig=fig, ax=ax, **kwargs)
def _build_tuple(tree): return tuple(p for p in val_iter(i_branch_end_points(tree)))
def tree3d(tr, new_fig=True, new_axes=True, subplot=False, **kwargs): '''Generates a figure of the tree in 3d. Parameters: tr: Tree neurom.Tree object Options: linewidth: float \ Defines the linewidth of the tree, \ if diameter is set to False. \ Default value is 1.2. alpha: float \ Defines throughe transparency of the tree. \ 0.0 transparent through 1.0 opaque. \ Default value is 0.8. treecolor: str or None \ Defines the color of the tree. \ If None the default values will be used, \ depending on the type of tree: \ Basal dendrite: "red" \ Axon : "blue" \ Apical dendrite: "purple" \ Undefined tree: "black" \ Default value is None. new_fig: boolean \ Defines if the tree will be plotted \ in the current figure (False) \ or in a new figure (True) \ Default value is True. subplot: matplotlib subplot value or False \ If False the default subplot 111 will be used. \ For any other value a matplotlib subplot \ will be generated. \ Default value is False. diameter: boolean If True the diameter, scaled with diameter_scale factor, \ will define the width of the tree lines. \ If False use linewidth to select the width of the tree lines. \ Default value is True. diameter_scale: float \ Defines the scale factor that will be multiplied \ with the diameter to define the width of the tree line. \ Default value is 1. white_space: float \ Defines the white space around \ the boundary box of the morphology. \ Default value is 1. Returns: A 3D matplotlib figure with a tree view. ''' from mpl_toolkits.mplot3d.art3d import Line3DCollection # Initialization of matplotlib figure and axes. fig, ax = common.get_figure(new_fig=new_fig, new_axes=new_axes, subplot=subplot, params={'projection': '3d'}) # Data needed for the viewer: x,y,z,r bounding_box = get_bounding_box(tr) def _seg_3d(seg): '''2d coordinates needed for the plotting of a segment''' horz = getattr(COLS, 'X') vert = getattr(COLS, 'Y') depth = getattr(COLS, 'Z') parent_point = seg[0] child_point = seg[1] horz1 = parent_point[horz] horz2 = child_point[horz] vert1 = parent_point[vert] vert2 = child_point[vert] depth1 = parent_point[depth] depth2 = child_point[depth] return ((horz1, vert1, depth1), (horz2, vert2, depth2)) segs = [_seg_3d(seg) for seg in val_iter(isegment(tr))] linewidth = get_default('linewidth', **kwargs) # Definition of the linewidth according to diameter, if diameter is True. if get_default('diameter', **kwargs): # TODO: This was originally a numpy array. Did it have to be one? linewidth = [2 * d * get_default('diameter_scale', **kwargs) for d in i_segment_radius(tr)] # Plot the collection of lines. collection = Line3DCollection(segs, color=common.get_color(get_default('treecolor', **kwargs), get_tree_type(tr)), linewidth=linewidth, alpha=get_default('alpha', **kwargs)) ax.add_collection3d(collection) kwargs['title'] = kwargs.get('title', 'Tree 3d-view') kwargs['xlabel'] = kwargs.get('xlabel', 'X') kwargs['ylabel'] = kwargs.get('ylabel', 'Y') kwargs['zlabel'] = kwargs.get('zlabel', 'Z') kwargs['xlim'] = kwargs.get('xlim', [bounding_box[0][0] - get_default('white_space', **kwargs), bounding_box[1][0] + get_default('white_space', **kwargs)]) kwargs['ylim'] = kwargs.get('ylim', [bounding_box[0][1] - get_default('white_space', **kwargs), bounding_box[1][1] + get_default('white_space', **kwargs)]) kwargs['zlim'] = kwargs.get('zlim', [bounding_box[0][2] - get_default('white_space', **kwargs), bounding_box[1][2] + get_default('white_space', **kwargs)]) return common.plot_style(fig=fig, ax=ax, **kwargs)
def test_valiter_bifurcation_point(): nt.ok_(list(val_iter(ibifurcation_point(REF_TREE2))) == [0, 11, 12, 1211])
def test_valiter_forking_point(): nt.ok_(list(val_iter(iforking_point(REF_TREE2))) == [0, 11, 1111, 12, 1211])
def test_valiter_forking_point(): nt.ok_( list(val_iter(iforking_point(REF_TREE2))) == [0, 11, 1111, 12, 1211])
def test_postorder_iteration(): nt.ok_(list(val_iter(ipostorder(REF_TREE))) == [111, 112, 11, 12111, 12112, 1211, 121, 122, 12, 0]) nt.ok_(list(val_iter(ipostorder(REF_TREE.children[0]))) == [111, 112, 11]) nt.ok_(list(val_iter(ipostorder(REF_TREE.children[1]))) == [12111, 12112, 1211, 121, 122, 12])
def tree(tr, plane='xy', new_fig=True, subplot=False, **kwargs): ''' Generates a 2d figure of the tree's segments. \ If the tree contains one single point the plot will be empty \ since no segments can be constructed. Parameters: tr: Tree \ neurom.Tree object plane: str \ Accepted values: Any pair of of xyz \ Default value is 'xy'.treecolor linewidth: float \ Defines the linewidth of the tree, \ if diameter is set to False. \ Default value is 1.2. alpha: float \ Defines throughe transparency of the tree. \ 0.0 transparent through 1.0 opaque. \ Default value is 0.8. treecolor: str or None \ Defines the color of the tree. \ If None the default values will be used, \ depending on the type of tree: \ Basal dendrite: "red" \ Axon : "blue" \ Apical dendrite: "purple" \ Undefined tree: "black" \ Default value is None. new_fig: boolean \ Defines if the tree will be plotted \ in the current figure (False) \ or in a new figure (True) \ Default value is True. subplot: matplotlib subplot value or False \ If False the default subplot 111 will be used. \ For any other value a matplotlib subplot \ will be generated. \ Default value is False. diameter: boolean If True the diameter, scaled with diameter_scale factor, \ will define the width of the tree lines. \ If False use linewidth to select the width of the tree lines. \ Default value is True. diameter_scale: float \ Defines the scale factor that will be multiplied \ with the diameter to define the width of the tree line. \ Default value is 1. limits: list or boolean \ List of type: [[xmin, ymin, zmin], [xmax, ymax, zmax]] \ If False the figure will not be scaled. \ If True the figure will be scaled according to tree limits. \ Default value is False. white_space: float \ Defines the white space around \ the boundary box of the morphology. \ Default value is 1. Returns: A 2D matplotlib figure with a tree view, at the selected plane. ''' if plane not in ('xy', 'yx', 'xz', 'zx', 'yz', 'zy'): return None, 'No such plane found! Please select one of: xy, xz, yx, yz, zx, zy.' # Initialization of matplotlib figure and axes. fig, ax = common.get_figure(new_fig=new_fig, subplot=subplot) # Data needed for the viewer: x,y,z,r bounding_box = get_bounding_box(tr) def _seg_2d(seg): '''2d coordinates needed for the plotting of a segment''' horz = getattr(COLS, plane[0].capitalize()) vert = getattr(COLS, plane[1].capitalize()) parent_point = seg[0] child_point = seg[1] horz1 = parent_point[horz] horz2 = child_point[horz] vert1 = parent_point[vert] vert2 = child_point[vert] return ((horz1, vert1), (horz2, vert2)) segs = [_seg_2d(seg) for seg in val_iter(isegment(tr))] linewidth = get_default('linewidth', **kwargs) # Definition of the linewidth according to diameter, if diameter is True. if get_default('diameter', **kwargs): scale = get_default('diameter_scale', **kwargs) # TODO: This was originally a numpy array. Did it have to be one? linewidth = [2 * d * scale for d in iter_neurites(tr, segment_radius)] if len(linewidth) == 0: linewidth = get_default('linewidth', **kwargs) # Plot the collection of lines. collection = LineCollection(segs, color=common.get_color(get_default('treecolor', **kwargs), get_tree_type(tr)), linewidth=linewidth, alpha=get_default('alpha', **kwargs)) ax.add_collection(collection) kwargs['title'] = kwargs.get('title', 'Tree view') kwargs['xlabel'] = kwargs.get('xlabel', plane[0]) kwargs['ylabel'] = kwargs.get('ylabel', plane[1]) kwargs['xlim'] = kwargs.get('xlim', [bounding_box[0][getattr(COLS, plane[0].capitalize())] - get_default('white_space', **kwargs), bounding_box[1][getattr(COLS, plane[0].capitalize())] + get_default('white_space', **kwargs)]) kwargs['ylim'] = kwargs.get('ylim', [bounding_box[0][getattr(COLS, plane[1].capitalize())] - get_default('white_space', **kwargs), bounding_box[1][getattr(COLS, plane[1].capitalize())] + get_default('white_space', **kwargs)]) return common.plot_style(fig=fig, ax=ax, **kwargs)
def tree(tr, plane='xy', new_fig=True, subplot=False, **kwargs): '''Generates a 2d figure of the tree. Parameters: tr: Tree \ neurom.Tree object Options: plane: str \ Accepted values: Any pair of of xyz \ Default value is 'xy'.treecolor linewidth: float \ Defines the linewidth of the tree, \ if diameter is set to False. \ Default value is 1.2. alpha: float \ Defines throughe transparency of the tree. \ 0.0 transparent through 1.0 opaque. \ Default value is 0.8. treecolor: str or None \ Defines the color of the tree. \ If None the default values will be used, \ depending on the type of tree: \ Basal dendrite: "red" \ Axon : "blue" \ Apical dendrite: "purple" \ Undefined tree: "black" \ Default value is None. new_fig: boolean \ Defines if the tree will be plotted \ in the current figure (False) \ or in a new figure (True) \ Default value is True. subplot: matplotlib subplot value or False \ If False the default subplot 111 will be used. \ For any other value a matplotlib subplot \ will be generated. \ Default value is False. diameter: boolean If True the diameter, scaled with diameter_scale factor, \ will define the width of the tree lines. \ If False use linewidth to select the width of the tree lines. \ Default value is True. diameter_scale: float \ Defines the scale factor that will be multiplied \ with the diameter to define the width of the tree line. \ Default value is 1. limits: list or boolean \ List of type: [[xmin, ymin, zmin], [xmax, ymax, zmax]] \ If False the figure will not be scaled. \ If True the figure will be scaled according to tree limits. \ Default value is False. white_space: float \ Defines the white space around \ the boundary box of the morphology. \ Default value is 1. Returns: A 2D matplotlib figure with a tree view, at the selected plane. ''' if plane not in ('xy', 'yx', 'xz', 'zx', 'yz', 'zy'): return None, 'No such plane found! Please select one of: xy, xz, yx, yz, zx, zy.' # Initialization of matplotlib figure and axes. fig, ax = common.get_figure(new_fig=new_fig, subplot=subplot) # Data needed for the viewer: x,y,z,r bounding_box = get_bounding_box(tr) def _seg_2d(seg): '''2d coordinates needed for the plotting of a segment''' horz = getattr(COLS, plane[0].capitalize()) vert = getattr(COLS, plane[1].capitalize()) parent_point = seg[0] child_point = seg[1] horz1 = parent_point[horz] horz2 = child_point[horz] vert1 = parent_point[vert] vert2 = child_point[vert] return ((horz1, vert1), (horz2, vert2)) segs = [_seg_2d(seg) for seg in val_iter(isegment(tr))] linewidth = get_default('linewidth', **kwargs) # Definition of the linewidth according to diameter, if diameter is True. if get_default('diameter', **kwargs): scale = get_default('diameter_scale', **kwargs) # TODO: This was originally a numpy array. Did it have to be one? linewidth = [2 * d * scale for d in i_segment_radius(tr)] # Plot the collection of lines. collection = LineCollection(segs, color=common.get_color(get_default('treecolor', **kwargs), get_tree_type(tr)), linewidth=linewidth, alpha=get_default('alpha', **kwargs)) ax.add_collection(collection) kwargs['title'] = kwargs.get('title', 'Tree view') kwargs['xlabel'] = kwargs.get('xlabel', plane[0]) kwargs['ylabel'] = kwargs.get('ylabel', plane[1]) kwargs['xlim'] = kwargs.get('xlim', [bounding_box[0][getattr(COLS, plane[0].capitalize())] - get_default('white_space', **kwargs), bounding_box[1][getattr(COLS, plane[0].capitalize())] + get_default('white_space', **kwargs)]) kwargs['ylim'] = kwargs.get('ylim', [bounding_box[0][getattr(COLS, plane[1].capitalize())] - get_default('white_space', **kwargs), bounding_box[1][getattr(COLS, plane[1].capitalize())] + get_default('white_space', **kwargs)]) return common.plot_style(fig=fig, ax=ax, **kwargs)
def path_end_to_end_distance(path): '''Calculate and return end-to-end-distance of a given path.''' trunk = path.value return max(morphmath.point_dist(l, trunk) for l in tree.val_iter(tree.ileaf(path)))