def _export_review_skeleton(project_id=None, skeleton_id=None, format=None): treenodes = Treenode.objects.filter(skeleton_id=skeleton_id).values_list( 'id', 'location', 'parent_id', 'reviewer_id') g = nx.DiGraph() reviewed = set() for t in treenodes: loc = Double3D.from_str(t[1]) # While at it, send the reviewer ID, which is useful to iterate fwd # to the first unreviewed node in the segment. g.add_node(t[0], { 'id': t[0], 'x': loc.x, 'y': loc.y, 'z': loc.z, 'rid': t[3] }) if -1 != t[3]: reviewed.add(t[0]) if t[2]: # if parent g.add_edge(t[2], t[0]) # edge from parent to child else: root_id = t[0] # Create all sequences, as long as possible and always from end towards root distances = edge_count_to_root( g, root_node=root_id) # distance in number of edges from root seen = set() sequences = [] # Iterate end nodes sorted from highest to lowest distance to root endNodeIDs = (nID for nID in g.nodes() if 0 == len(g.successors(nID))) for nodeID in sorted(endNodeIDs, key=distances.get, reverse=True): sequence = [g.node[nodeID]] parents = g.predecessors(nodeID) while parents: parentID = parents[0] sequence.append(g.node[parentID]) if parentID in seen: break seen.add(parentID) parents = g.predecessors(parentID) if len(sequence) > 1: sequences.append(sequence) segments = [] for sequence in sorted(sequences, key=len, reverse=True): segments.append({ 'id': len(segments), 'sequence': sequence, 'status': '%.2f' % (100.0 * sum(1 for node in sequence if node['id'] in reviewed) / len(sequence)), 'nr_nodes': len(sequence) }) return segments
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 _export_review_skeleton(project_id=None, skeleton_id=None, format=None): """ Returns a list of segments for the requested skeleton. Each segment contains information about the review status of this part of the skeleton. """ # Get all treenodes of the requested skeleton treenodes = Treenode.objects.filter(skeleton_id=skeleton_id).values_list('id', 'location', 'parent_id') # Get all reviews for the requested skeleton reviews = get_treenodes_to_reviews(skeleton_ids=[skeleton_id]) # Add each treenode to a networkx graph and attach reviewer information to # it. g = nx.DiGraph() reviewed = set() for t in treenodes: loc = Double3D.from_str(t[1]) # While at it, send the reviewer IDs, which is useful to iterate fwd # to the first unreviewed node in the segment. g.add_node(t[0], {'id': t[0], 'x': loc.x, 'y': loc.y, 'z': loc.z, 'rids': reviews[t[0]]}) if reviews[t[0]]: reviewed.add(t[0]) if t[2]: # if parent g.add_edge(t[2], t[0]) # edge from parent to child else: root_id = t[0] # Create all sequences, as long as possible and always from end towards root distances = edge_count_to_root(g, root_node=root_id) # distance in number of edges from root seen = set() sequences = [] # Iterate end nodes sorted from highest to lowest distance to root endNodeIDs = (nID for nID in g.nodes() if 0 == len(g.successors(nID))) for nodeID in sorted(endNodeIDs, key=distances.get, reverse=True): sequence = [g.node[nodeID]] parents = g.predecessors(nodeID) while parents: parentID = parents[0] sequence.append(g.node[parentID]) if parentID in seen: break seen.add(parentID) parents = g.predecessors(parentID) if len(sequence) > 1: sequences.append(sequence) # Calculate status segments = [] for sequence in sorted(sequences, key=len, reverse=True): segments.append({ 'id': len(segments), 'sequence': sequence, 'status': '%.2f' % (100.0 * sum(1 for node in sequence if node['id'] in reviewed) / len(sequence)), 'nr_nodes': len(sequence) }) return segments
def export_review_skeleton(request, project_id=None, skeleton_id=None, format=None): """ Export the skeleton as a list of sequences of entries, each entry containing an id, a sequence of nodes, the percent of reviewed nodes, and the node count. """ treenodes = Treenode.objects.filter(skeleton_id=skeleton_id).values_list('id', 'location', 'parent_id', 'reviewer_id') g = nx.DiGraph() reviewed = set() for t in treenodes: loc = Double3D.from_str(t[1]) # While at it, send the reviewer ID, which is useful to iterate fwd # to the first unreviewed node in the segment. g.add_node(t[0], {'id': t[0], 'x': loc.x, 'y': loc.y, 'z': loc.z, 'rid': t[3]}) if -1 != t[3]: reviewed.add(t[0]) if t[2]: # if parent g.add_edge(t[2], t[0]) # edge from parent to child else: root_id = t[0] # Create all sequences, as long as possible and always from end towards root distances = edge_count_to_root(g, root_node=root_id) # distance in number of edges from root seen = set() sequences = [] # Iterate end nodes sorted from highest to lowest distance to root endNodeIDs = (nID for nID in g.nodes() if 0 == len(g.successors(nID))) for nodeID in sorted(endNodeIDs, key=distances.get, reverse=True): sequence = [g.node[nodeID]] parents = g.predecessors(nodeID) while parents: parentID = parents[0] sequence.append(g.node[parentID]) if parentID in seen: break seen.add(parentID) parents = g.predecessors(parentID) if len(sequence) > 1: sequences.append(sequence) segments = [] for sequence in sorted(sequences, key=len, reverse=True): segments.append({ 'id': len(segments), 'sequence': sequence, 'status': '%.2f' % (100.0 * sum(1 for node in sequence if node['id'] in reviewed) / len(sequence)), 'nr_nodes': len(sequence) }) return HttpResponse(json.dumps(segments))
def _export_review_skeleton(project_id=None, skeleton_id=None, format=None, subarbor_node_id=None): """ Returns a list of segments for the requested skeleton. Each segment contains information about the review status of this part of the skeleton. If a valid subarbor_node_id is given, only data for the sub-arbor is returned that starts at this node. """ # Get all treenodes of the requested skeleton treenodes = Treenode.objects.filter(skeleton_id=skeleton_id).values_list( 'id', 'parent_id', 'location_x', 'location_y', 'location_z') # Get all reviews for the requested skeleton reviews = get_treenodes_to_reviews_with_time(skeleton_ids=[skeleton_id]) # Add each treenode to a networkx graph and attach reviewer information to # it. g = nx.DiGraph() reviewed = set() for t in treenodes: # While at it, send the reviewer IDs, which is useful to iterate fwd # to the first unreviewed node in the segment. g.add_node(t[0], {'id': t[0], 'x': t[2], 'y': t[3], 'z': t[4], 'rids': reviews[t[0]]}) if reviews[t[0]]: reviewed.add(t[0]) if t[1]: # if parent g.add_edge(t[1], t[0]) # edge from parent to child else: root_id = t[0] if subarbor_node_id and subarbor_node_id != root_id: # Make sure the subarbor node ID (if any) is part of this skeleton if subarbor_node_id not in g: raise ValueError("Supplied subarbor node ID (%s) is not part of " "provided skeleton (%s)" % (subarbor_node_id, skeleton_id)) # Remove connection to parent parent = g.predecessors(subarbor_node_id)[0] g.remove_edge(parent, subarbor_node_id) # Remove all nodes that are upstream from the subarbor node to_delete = set() to_lookat = [root_id] while to_lookat: n = to_lookat.pop() to_lookat.extend(g.successors(n)) to_delete.add(n) g.remove_nodes_from(to_delete) # Replace root id with sub-arbor ID root_id=subarbor_node_id # Create all sequences, as long as possible and always from end towards root distances = edge_count_to_root(g, root_node=root_id) # distance in number of edges from root seen = set() sequences = [] # Iterate end nodes sorted from highest to lowest distance to root endNodeIDs = (nID for nID in g.nodes() if 0 == len(g.successors(nID))) for nodeID in sorted(endNodeIDs, key=distances.get, reverse=True): sequence = [g.node[nodeID]] parents = g.predecessors(nodeID) while parents: parentID = parents[0] sequence.append(g.node[parentID]) if parentID in seen: break seen.add(parentID) parents = g.predecessors(parentID) if len(sequence) > 1: sequences.append(sequence) # Calculate status segments = [] for sequence in sorted(sequences, key=len, reverse=True): segments.append({ 'id': len(segments), 'sequence': sequence, 'status': '%.2f' % (100.0 * sum(1 for node in sequence if node['id'] in reviewed) / len(sequence)), 'nr_nodes': len(sequence) }) return segments
def _export_review_skeleton(project_id=None, skeleton_id=None, subarbor_node_id=None): """ Returns a list of segments for the requested skeleton. Each segment contains information about the review status of this part of the skeleton. If a valid subarbor_node_id is given, only data for the sub-arbor is returned that starts at this node. """ # Get all treenodes of the requested skeleton cursor = connection.cursor() cursor.execute(""" SELECT t.id, t.parent_id, t.location_x, t.location_y, t.location_z, ARRAY_AGG(svt.orientation), ARRAY_AGG(svt.location_coordinate) FROM treenode t LEFT OUTER JOIN suppressed_virtual_treenode svt ON (t.id = svt.child_id) WHERE t.skeleton_id = %s GROUP BY t.id; """, (skeleton_id,)) treenodes = cursor.fetchall() # Get all reviews for the requested skeleton reviews = get_treenodes_to_reviews_with_time(skeleton_ids=[skeleton_id]) if 0 == len(treenodes): return [] # The root node will be assigned below, depending on retrieved nodes and # sub-arbor requests root_id = None # Add each treenode to a networkx graph and attach reviewer information to # it. g = nx.DiGraph() reviewed = set() for t in treenodes: # While at it, send the reviewer IDs, which is useful to iterate fwd # to the first unreviewed node in the segment. g.add_node(t[0], {'id': t[0], 'x': t[2], 'y': t[3], 'z': t[4], 'rids': reviews[t[0]], 'sup': [[o, l] for [o, l] in zip(t[5], t[6]) if o is not None]}) if reviews[t[0]]: reviewed.add(t[0]) if t[1]: # if parent g.add_edge(t[1], t[0]) # edge from parent to child else: root_id = t[0] if subarbor_node_id and subarbor_node_id != root_id: # Make sure the subarbor node ID (if any) is part of this skeleton if subarbor_node_id not in g: raise ValueError("Supplied subarbor node ID (%s) is not part of " "provided skeleton (%s)" % (subarbor_node_id, skeleton_id)) # Remove connection to parent parent = g.predecessors(subarbor_node_id)[0] g.remove_edge(parent, subarbor_node_id) # Remove all nodes that are upstream from the subarbor node to_delete = set() to_lookat = [root_id] while to_lookat: n = to_lookat.pop() to_lookat.extend(g.successors(n)) to_delete.add(n) g.remove_nodes_from(to_delete) # Replace root id with sub-arbor ID root_id=subarbor_node_id if not root_id: if subarbor_node_id: raise ValueError("Couldn't find a reference root node in provided " "skeleton (%s)" % (skeleton_id,)) else: raise ValueError("Couldn't find a reference root node for provided " "subarbor (%s) in provided skeleton (%s)" % (subarbor_node_id, skeleton_id)) # Create all sequences, as long as possible and always from end towards root distances = edge_count_to_root(g, root_node=root_id) # distance in number of edges from root seen = set() sequences = [] # Iterate end nodes sorted from highest to lowest distance to root endNodeIDs = (nID for nID in g.nodes() if 0 == len(g.successors(nID))) for nodeID in sorted(endNodeIDs, key=distances.get, reverse=True): sequence = [g.node[nodeID]] parents = g.predecessors(nodeID) while parents: parentID = parents[0] sequence.append(g.node[parentID]) if parentID in seen: break seen.add(parentID) parents = g.predecessors(parentID) if len(sequence) > 1: sequences.append(sequence) # Calculate status segments = [] for sequence in sorted(sequences, key=len, reverse=True): segments.append({ 'id': len(segments), 'sequence': sequence, 'status': '%.2f' % (100.0 * sum(1 for node in sequence if node['id'] in reviewed) / len(sequence)), 'nr_nodes': len(sequence) }) return segments