def last_openleaf(request, project_id=None, skeleton_id=None): """ Return the ID of the nearest node (or itself), and its location string; or two nulls if none found. """ tnid = int(request.POST['tnid']) cursor = connection.cursor() # Select all nodes and their tags cursor.execute(''' SELECT t.id, t.parent_id, t.location, ci.name FROM treenode t LEFT OUTER JOIN (treenode_class_instance tci INNER JOIN class_instance ci ON tci.class_instance_id = ci.id) ON t.id = tci.treenode_id WHERE t.skeleton_id = %s ''' % int(skeleton_id)) # Some entries repeated, when a node has more than one tag # Create a graph with edges from parent to child, and accumulate parents tree = nx.DiGraph() for row in cursor.fetchall(): nodeID = row[0] if row[1]: # It is ok to add edges that already exist: DiGraph doesn't keep duplicates tree.add_edge(row[1], nodeID) else: tree.add_node(nodeID) tree.node[nodeID]['loc'] = row[2] if row[3]: props = tree.node[nodeID] tags = props.get('tags') if tags: tags.append(row[3]) else: props['tags'] = [row[3]] if tnid not in tree: raise Exception("Could not find %s in skeleton %s" % (tnid, int(skeleton_id))) reroot(tree, tnid) distances = edge_count_to_root(tree, root_node=tnid) # Iterate end nodes, find closest nearest = None distance = tree.number_of_nodes() + 1 loc = None other_tags = set(('uncertain continuation', 'not a branch', 'soma')) for nodeID, out_degree in tree.out_degree_iter(): if 0 == out_degree: # Found an end node props = tree.node[nodeID] # Check if not tagged with a tag containing 'end' if not 'tags' in props and not [s for s in props if 'end' in s or s in other_tags]: # Found an open end d = distances[nodeID] if d < distance: nearest = nodeID distance = d loc = props['loc'] return HttpResponse(json.dumps((nearest, loc)))
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)