Source code for DLITE.ManualTracing

import numpy as np
from .cell_describe import node
from .AICS_data import data


[docs]class ManualTracing(data): def __init__(self, x, y, ground_truth_tensions=None): """ Class for a single frame of manual tracing that has been traced out using NeuronJ Manual tracing that outputs an array of X and Y co-ordinates length(X) == number of edges length(X[0]) == X co-ordinates on edge 0 length(Y[0]) == Y co-ordinates on edge 0 """ self.x = x self.y = y self.ground_truth_tensions = ground_truth_tensions self.length = len(self.x)
[docs] def co_ordinates(self, edge_num): """ Get X and Y co-ordinates for specified edge number """ return self.x[edge_num], self.y[edge_num]
[docs] def fit_X_Y(self, edge_num): """ Fit a circular arc to an edge. Call self.fit - .fit is a function in the data class """ r_2, xc_2, yc_2 = self.fit(self.x[edge_num], self.y[edge_num]) return r_2, xc_2, yc_2
[docs] def cleanup(self, cutoff): """ post process the data to merge nodes that are within a distance specified as 'cutoff'. Also calls functions (1) remove_dangling_edges (2) remove_two_edge_connections ---------- Parameters ------------ cutoff - distance within which we merge nodes num (optional) - Number of branches to consider (default - all of them) """ nodes, edges = [], [] for index in range(self.length): # Add 2 nodes at both ends of the branch node_a = node((self.x[index][0], self.y[index][0])) node_b = node((self.x[index][-1], self.y[index][-1])) dist_a, dist_b = [], [] for n in nodes: # Find distance of all nodes in the list (nodes) from current node_a dist_a.append(np.linalg.norm(np.subtract(n.loc, node_a.loc))) if not dist_a: # If dist = [], then nodes was empty -> add node_a to list nodes.append(node_a) else: # If all values in dist are larger than a cutoff, add the node if all(i >= cutoff for i in dist_a): nodes.append(node_a) else: # Find index of minimum distance value. Replace node_a with the node at that point ind = dist_a.index(min(dist_a)) node_a = nodes[ind] # Have to do this separately and not with node_a because # we want to check that distance between node_a and node_b is very small too # So if node_b is so close to node_a that we replace node_b with node_a, have to not add that edge for n in nodes: dist_b.append(np.linalg.norm(np.subtract(n.loc, node_b.loc))) if not dist_b: # If dist = [], then nodes was empty -> add node_a to list nodes.append(node_b) else: # If all values in dist are larger than a cutoff, add the node if all(i >= cutoff for i in dist_b): nodes.append(node_b) else: # Find index of minimum distance value. Replace node_a with the node at that point ind = dist_b.index(min(dist_b)) node_b = nodes[ind] if node_a.loc != node_b.loc: ed = self.add_edge(node_a, node_b, None, self.x[index], self.y[index]) if self.ground_truth_tensions is not None: mean_ground_truth = np.mean(self.ground_truth_tensions[index]) ed.ground_truth = mean_ground_truth edges.append(ed) else: print('node a = node b, possible topological change') # Remove dangling edges (single edges connected to an interface at nearly 90 deg angle) new_edges = [] # Possible to add cleanup in manual tracing, but not necessary # Below are the next 3 post processing steps # Step 1 - remove small stray edges (nodes connected to 1 edge) # nodes, edges = self.remove_dangling_edges(nodes, edges) # Step 2 - remove small cells # nodes, edges, new_edges = self.remove_small_cells(nodes, edges) # Step 3 - remove nodes connected to 2 edges # nodes, edges = self.remove_two_edge_connections(nodes, edges) return nodes, edges, new_edges