def branchwise_node_infos(tree): branches = [] for branch in partition(tree): branch = filter(lambda node_id: node_id != -1, branch) branch_nodes = map(lambda node_id: tree.node[node_id]['info'], branch) branches.append(branch_nodes) return branches
def _node_centrality_by_synapse(tree, nodes, totalOutputs, totalInputs): """ tree: a DiGraph nodes: a dictionary of treenode ID vs Counts instance totalOutputs: the total number of output synapses of the tree totalInputs: the total number of input synapses of the tree Returns nothing, the results are an update to the Counts instance of each treenode entry in nodes, namely the nPossibleIOPaths. """ # 1. Ensure the root is an end by checking that it has only one child; otherwise reroot at the first end node found if 0 == totalOutputs: # Not computable for counts in nodes.itervalues(): counts.synapse_centrality = -1 return if len(tree.successors(find_root(tree))) > 1: # Reroot at the first end node found tree = tree.copy() endNode = (nodeID for nodeID in nodes.iterkeys() if not tree.successors(nodeID)).next() reroot(tree, endNode) # 2. Partition into sequences, sorted from small to large sequences = sorted(partition(tree), key=len) # 3. Traverse all partitions counting synapses seen for seq in sequences: # Each seq runs from an end node towards the root or a branch node seenI = 0 seenO = 0 for nodeID in seq: counts = nodes[nodeID] seenI += counts.inputs + counts.seenInputs seenO += counts.outputs + counts.seenOutputs counts.seenInputs = seenI counts.seenOutputs = seenO counts.nPossibleIOPaths = counts.seenInputs * (totalOutputs - counts.seenOutputs) + counts.seenOutputs * (totalInputs - counts.seenInputs) counts.synapse_centrality = counts.nPossibleIOPaths / float(totalOutputs)
def _measure_skeletons(skeleton_ids): if not skeleton_ids: raise Exception("Must provide the ID of at least one skeleton.") skids_string = ",".join(map(str, skeleton_ids)) cursor = connection.cursor() cursor.execute(''' SELECT id, parent_id, skeleton_id, location_x, location_y, location_z FROM treenode WHERE skeleton_id IN (%s) ''' % skids_string) # TODO should be all done with numpy, # TODO by partitioning the skeleton into sequences of x,y,z representing the slabs # TODO and then convolving them. class Skeleton(): def __init__(self): self.nodes = {} self.raw_cable = 0 self.smooth_cable = 0 self.principal_branch_cable = 0 self.n_ends = 0 self.n_branch = 0 self.n_pre = 0 self.n_post = 0 class Node(): def __init__(self, parent_id, x, y, z): self.parent_id = parent_id self.x = x self.y = y self.z = z self.wx = x # weighted average of itself and neighbors self.wy = y self.wz = z self.children = {} # node ID vs distance skeletons = defaultdict(dict) # skeleton ID vs (node ID vs Node) for row in cursor.fetchall(): skeleton = skeletons.get(row[2]) if not skeleton: skeleton = Skeleton() skeletons[row[2]] = skeleton skeleton.nodes[row[0]] = Node(row[1], row[3], row[4], row[5]) for skeleton in skeletons.itervalues(): nodes = skeleton.nodes tree = nx.DiGraph() root = None # Accumulate children for nodeID, node in nodes.iteritems(): if not node.parent_id: root = nodeID continue tree.add_edge(node.parent_id, nodeID) parent = nodes[node.parent_id] distance = sqrt( pow(node.x - parent.x, 2) + pow(node.y - parent.y, 2) + pow(node.z - parent.z, 2)) parent.children[nodeID] = distance # Measure raw cable, given that we have the parent already skeleton.raw_cable += distance # Utilize accumulated children and the distances to them for nodeID, node in nodes.iteritems(): # Count end nodes and branch nodes n_children = len(node.children) if not node.parent_id: if 1 == n_children: skeleton.n_ends += 1 continue if n_children > 2: skeleton.n_branch += 1 continue # Else, if 2 == n_children, the root node is in the middle of the skeleton, being a slab node elif 0 == n_children: skeleton.n_ends += 1 continue elif n_children > 1: skeleton.n_branch += 1 continue # Compute weighted position for slab nodes only # (root, branch and end nodes do not move) oids = node.children.copy() if node.parent_id: oids[node.parent_id] = skeleton.nodes[node.parent_id].children[nodeID] sum_distances = sum(oids.itervalues()) wx, wy, wz = 0, 0, 0 for oid, distance in oids.iteritems(): other = skeleton.nodes[oid] w = distance / sum_distances if sum_distances != 0 else 0 wx += other.x * w wy += other.y * w wz += other.z * w node.wx = node.x * 0.4 + wx * 0.6 node.wy = node.y * 0.4 + wy * 0.6 node.wz = node.z * 0.4 + wz * 0.6 # Find out nodes that belong to the principal branch principal_branch_nodes = set(sorted(partition(tree, root), key=len)[-1]) # Compute smoothed cable length, also for principal branch for nodeID, node in nodes.iteritems(): if not node.parent_id: # root node continue parent = nodes[node.parent_id] length = sqrt( pow(node.wx - parent.wx, 2) + pow(node.wy - parent.wy, 2) + pow(node.wz - parent.wz, 2)) skeleton.smooth_cable += length if nodeID in principal_branch_nodes: skeleton.principal_branch_cable += length # Count inputs cursor.execute(''' SELECT tc.skeleton_id, count(tc.skeleton_id) FROM treenode_connector tc, relation r WHERE tc.skeleton_id IN (%s) AND tc.relation_id = r.id AND r.relation_name = 'postsynaptic_to' GROUP BY tc.skeleton_id ''' % skids_string) for row in cursor.fetchall(): skeletons[row[0]].n_pre = row[1] # Count outputs cursor.execute(''' SELECT tc1.skeleton_id, count(tc1.skeleton_id) FROM treenode_connector tc1, treenode_connector tc2, relation r1, relation r2 WHERE tc1.skeleton_id IN (%s) AND tc1.connector_id = tc2.connector_id AND tc1.relation_id = r1.id AND r1.relation_name = 'presynaptic_to' AND tc2.relation_id = r2.id AND r2.relation_name = 'postsynaptic_to' GROUP BY tc1.skeleton_id ''' % skids_string) for row in cursor.fetchall(): skeletons[row[0]].n_post = row[1] return skeletons