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 _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 format_node_data(node): ''' Formats node data for our json output. When we start using Django 1.4, we can use prefetch_related instead of using .values('treenode__xxx'), and will then be able to access a proper location object. ''' location = Double3D.from_str(node['treenode__location']) return { 'id': node['treenode'], 'x': int(location.x), 'y': int(location.y), 'z': int(location.z), 'skid': node['treenode__skeleton']}