示例#1
0
    def test_insert_treenoded_not_on_edge_with_permission(self):
        self.fake_authentication()
        class_map = get_class_to_id_map(self.test_project_id)
        count_treenodes = lambda: Treenode.objects.all().count()
        count_skeletons = lambda: ClassInstance.objects.filter(
            project=self.test_project_id, class_column=class_map['skeleton'
                                                                 ]).count()
        count_neurons = lambda: ClassInstance.objects.filter(
            project=self.test_project_id, class_column=class_map['neuron'
                                                                 ]).count()

        treenode_count = count_treenodes()
        skeleton_count = count_skeletons()
        neuron_count = count_neurons()

        # Get two nodes and calculate point between them
        child_id = 2374
        parent_id = 2372
        child = Treenode.objects.get(pk=child_id)
        parent = Treenode.objects.get(pk=parent_id)

        new_node_x = 0.5 * (child.location_x + parent.location_x)
        new_node_y = 0.5 * (child.location_y + parent.location_y) + 10
        new_node_z = 0.5 * (child.location_z + parent.location_z)

        # Try to insert with a slight distorition in Y. This is allowed if the
        # user has permission to edit the neuron.
        response = self.client.post(
            '/%d/treenode/insert' % self.test_project_id, {
                'x': new_node_x,
                'y': new_node_y,
                'z': new_node_z,
                'child_id': child_id,
                'parent_id': parent_id,
                'state': make_nocheck_state()
            })

        self.assertEqual(response.status_code, 200)
        parsed_response = json.loads(response.content)

        self.assertTrue('treenode_id' in parsed_response)
        self.assertTrue('skeleton_id' in parsed_response)

        self.assertEqual(treenode_count + 1, count_treenodes())
        self.assertEqual(skeleton_count, count_skeletons())
        self.assertEqual(neuron_count, count_neurons())

        new_node_id = parsed_response['treenode_id']
        new_node = Treenode.objects.get(pk=new_node_id)
        child = Treenode.objects.get(pk=child_id)
        self.assertEqual(new_node.parent_id, parent_id)
        self.assertEqual(child.parent_id, new_node_id)
        self.assertEqual(new_node.user, child.user)
        self.assertEqual(new_node.creation_time, child.creation_time)
        self.assertEqual(new_node.skeleton_id, child.skeleton_id)
        self.assertEqual(new_node.location_x, new_node_x)
        self.assertEqual(new_node.location_y, new_node_y)
        self.assertEqual(new_node.location_z, new_node_z)
示例#2
0
    def test_insert_treenoded_not_on_edge_with_permission(self):
        self.fake_authentication()
        class_map = get_class_to_id_map(self.test_project_id)
        count_treenodes = lambda: Treenode.objects.all().count()
        count_skeletons = lambda: ClassInstance.objects.filter(
                project=self.test_project_id,
                class_column=class_map['skeleton']).count()
        count_neurons = lambda: ClassInstance.objects.filter(
                project=self.test_project_id,
                class_column=class_map['neuron']).count()

        treenode_count = count_treenodes()
        skeleton_count = count_skeletons()
        neuron_count = count_neurons()

        # Get two nodes and calculate point between them
        child_id = 2374
        parent_id = 2372
        child = Treenode.objects.get(pk=child_id)
        parent = Treenode.objects.get(pk=parent_id)

        new_node_x = 0.5 * (child.location_x + parent.location_x)
        new_node_y = 0.5 * (child.location_y + parent.location_y) + 10
        new_node_z = 0.5 * (child.location_z + parent.location_z)

        # Try to insert with a slight distorition in Y. This is allowed if the
        # user has permission to edit the neuron.
        response = self.client.post('/%d/treenode/insert' % self.test_project_id, {
            'x': new_node_x,
            'y': new_node_y,
            'z': new_node_z,
            'child_id': child_id,
            'parent_id': parent_id,
            'state': make_nocheck_state()})

        self.assertEqual(response.status_code, 200)
        parsed_response = json.loads(response.content)

        self.assertTrue('treenode_id' in parsed_response)
        self.assertTrue('skeleton_id' in parsed_response)

        self.assertEqual(treenode_count + 1, count_treenodes())
        self.assertEqual(skeleton_count, count_skeletons())
        self.assertEqual(neuron_count, count_neurons())

        new_node_id = parsed_response['treenode_id']
        new_node = Treenode.objects.get(pk=new_node_id)
        child = Treenode.objects.get(pk=child_id)
        self.assertEqual(new_node.parent_id, parent_id)
        self.assertEqual(child.parent_id, new_node_id)
        self.assertEqual(new_node.user, child.user)
        self.assertEqual(new_node.creation_time, child.creation_time)
        self.assertEqual(new_node.skeleton_id, child.skeleton_id)
        self.assertEqual(new_node.location_x, new_node_x)
        self.assertEqual(new_node.location_y, new_node_y)
        self.assertEqual(new_node.location_z, new_node_z)
示例#3
0
    def add_test_treenodes(self):
        # Skeletons with a single chain of nodes each
        # User ID, Creation time, X, Y, Z
        skeletons = [
            [[1, "2017-06-01T07:54:16.301Z", 0, 0, 0],
             [1, "2017-06-30T22:23:24.117Z", 10, 0, 0],
             [1, "2017-07-02T08:54:16.301Z", 10, 10, 0],
             [1, "2017-08-02T08:55:16.301Z", 10, 10, 10]],
            [[3, "2017-07-01T07:54:16.301Z", 1, 2, 3],
             [3, "2017-07-01T07:55:13.844Z", -1, 2, 3],
             [3, "2017-07-01T22:55:16.301Z", -1, 0, 3],
             [3, "2017-07-01T02:50:10.204Z", -1, 0, 0]],
        ]

        cursor = connection.cursor()
        classes = get_class_to_id_map(self.test_project_id, cursor=cursor)
        skeleton_class_id = classes['skeleton']
        for i, skeleton in enumerate(skeletons):
            cursor.execute(
                """
                INSERT INTO class_instance (project_id, class_id, name,
                    user_id, creation_time)
                SELECT %(project_id)s, %(skeleton_class_id)s, %(name)s,
                    %(user_id)s, %(creation_time)s
                RETURNING id
            """, {
                    "project_id": self.test_project_id,
                    "skeleton_class_id": skeleton_class_id,
                    "name": f"Test skeleton {i} ",
                    "user_id": self.test_user_id,
                    "creation_time": datetime.datetime(2017, 7, 5, 16, 20, 10),
                })
            skeleton_id = cursor.fetchone()[0]
            last_node = None
            for node in skeleton:
                cursor.execute(
                    """
                    INSERT INTO treenode (project_id, skeleton_id, parent_id,
                        location_x, location_y, location_z, user_id, editor_id,
                        creation_time)
                    SELECT %(project_id)s, %(skeleton_id)s, %(parent_id)s,
                        %(x)s, %(y)s, %(z)s, %(user_id)s, %(editor_id)s,
                        %(creation_time)s::timestamptz
                    RETURNING id
                """, {
                        'project_id': self.test_project_id,
                        'skeleton_id': skeleton_id,
                        'parent_id': last_node,
                        'x': node[2],
                        'y': node[3],
                        'z': node[4],
                        'user_id': node[0],
                        'editor_id': node[0],
                        'creation_time': node[1]
                    })
                last_node = cursor.fetchone()[0]
示例#4
0
    def test_insert_treenoded_on_edge(self):
        self.fake_authentication()
        class_map = get_class_to_id_map(self.test_project_id)
        count_treenodes = lambda: Treenode.objects.all().count()
        count_skeletons = lambda: ClassInstance.objects.filter(
            project=self.test_project_id, class_column=class_map['skeleton'
                                                                 ]).count()
        count_neurons = lambda: ClassInstance.objects.filter(
            project=self.test_project_id, class_column=class_map['neuron'
                                                                 ]).count()

        treenode_count = count_treenodes()
        skeleton_count = count_skeletons()
        neuron_count = count_neurons()

        # Get two nodes and calculate point between them
        child_id = 2374
        parent_id = 2372
        child = Treenode.objects.get(pk=child_id)
        parent = Treenode.objects.get(pk=parent_id)

        new_node_x = 0.5 * (child.location_x + parent.location_x)
        new_node_y = 0.5 * (child.location_y + parent.location_y)
        new_node_z = 0.5 * (child.location_z + parent.location_z)

        response = self.client.post(
            '/%d/treenode/insert' % self.test_project_id, {
                'x': new_node_x,
                'y': new_node_y,
                'z': new_node_z,
                'child_id': child_id,
                'parent_id': parent_id,
                'state': make_nocheck_state()
            })

        self.assertEqual(response.status_code, 200)
        parsed_response = json.loads(response.content.decode('utf-8'))

        self.assertTrue('treenode_id' in parsed_response)
        self.assertTrue('skeleton_id' in parsed_response)

        self.assertEqual(treenode_count + 1, count_treenodes())
        self.assertEqual(skeleton_count, count_skeletons())
        self.assertEqual(neuron_count, count_neurons())

        new_node_id = parsed_response['treenode_id']
        new_node = Treenode.objects.get(pk=new_node_id)
        child = Treenode.objects.get(pk=child_id)
        self.assertEqual(new_node.parent_id, parent_id)
        self.assertEqual(child.parent_id, new_node_id)
        self.assertEqual(new_node.user_id, self.test_user_id)
        self.assertEqual(new_node.skeleton_id, child.skeleton_id)
        self.assertEqual(new_node.location_x, new_node_x)
        self.assertEqual(new_node.location_y, new_node_y)
        self.assertEqual(new_node.location_z, new_node_z)
示例#5
0
    def test_create_treenode2(self):
        self.fake_authentication()
        relation_map = get_relation_to_id_map(self.test_project_id)
        class_map = get_class_to_id_map(self.test_project_id)
        count_treenodes = lambda: Treenode.objects.all().count()
        count_skeletons = lambda: ClassInstance.objects.filter(
            project=self.test_project_id, class_column=class_map['skeleton'
                                                                 ]).count()
        count_neurons = lambda: ClassInstance.objects.filter(
            project=self.test_project_id, class_column=class_map['neuron'
                                                                 ]).count()
        treenode_count = count_treenodes()
        skeleton_count = count_skeletons()
        neuron_count = count_neurons()

        response = self.client.post(
            '/%d/treenode/create' % self.test_project_id, {
                'x': 5,
                'y': 10,
                'z': 15,
                'confidence': 5,
                'parent_id': -1,
                'radius': 2
            })
        self.assertEqual(response.status_code, 200)
        parsed_response = json.loads(response.content.decode('utf-8'))

        self.assertTrue('treenode_id' in parsed_response)
        self.assertTrue('skeleton_id' in parsed_response)

        self.assertEqual(treenode_count + 1, count_treenodes())
        self.assertEqual(skeleton_count + 1, count_skeletons())
        self.assertEqual(neuron_count + 1, count_neurons())

        treenode_skeleton_relation = TreenodeClassInstance.objects.filter(
            project=self.test_project_id,
            relation=relation_map['element_of'],
            treenode=parsed_response['treenode_id'],
            class_instance=parsed_response['skeleton_id'])
        neuron_skeleton_relation = ClassInstanceClassInstance.objects.filter(
            project=self.test_project_id,
            relation=relation_map['model_of'],
            class_instance_a=parsed_response['skeleton_id'])
        # FIXME: Log test doesn't work like this, because we don't have the
        # neuron ID available
        #neuron_log = Log.objects.filter(
        #        project=self.test_project_id,
        #        operation_type='create_neuron',
        #        freetext='Create neuron %s and skeleton %s' % (parsed_response['neuron_id'], parsed_response['skeleton_id']))

        root = ClassInstance.objects.filter(project=self.test_project_id,
                                            class_column=class_map['root'])[0]

        self.assertEqual(1, neuron_skeleton_relation.count())
示例#6
0
    def add_test_treenodes(self):
        # Skeletons with a single chain of nodes each
        # User ID, Creation time, X, Y, Z
        skeletons = [
            [[1, "2017-06-01T07:54:16.301Z", 0, 0, 0],
             [1, "2017-06-30T22:23:24.117Z", 10, 0, 0],
             [1, "2017-07-02T08:54:16.301Z", 10, 10, 0],
             [1, "2017-08-02T08:55:16.301Z", 10, 10, 10]],
            [[3, "2017-07-01T07:54:16.301Z", 1, 2, 3],
             [3, "2017-07-01T07:55:13.844Z", -1, 2, 3],
             [3, "2017-07-01T22:55:16.301Z", -1, 0, 3],
             [3, "2017-07-01T02:50:10.204Z", -1, 0, 0]],
        ]

        cursor = connection.cursor()
        classes = get_class_to_id_map(self.test_project_id, cursor=cursor)
        skeleton_class_id = classes['skeleton']
        for i, skeleton in enumerate(skeletons):
            cursor.execute("""
                INSERT INTO class_instance (project_id, class_id, name,
                    user_id, creation_time)
                SELECT %(project_id)s, %(skeleton_class_id)s, %(name)s,
                    %(user_id)s, %(creation_time)s
                RETURNING id
            """, {
                "project_id": self.test_project_id,
                "skeleton_class_id": skeleton_class_id,
                "name": "Test skeleton %s ".format(i),
                "user_id": self.test_user_id,
                "creation_time": datetime.datetime(2017, 7, 5, 16, 20, 10),
            })
            skeleton_id = cursor.fetchone()[0]
            last_node = None
            for node in skeleton:
                cursor.execute("""
                    INSERT INTO treenode (project_id, skeleton_id, parent_id,
                        location_x, location_y, location_z, user_id, editor_id,
                        creation_time)
                    SELECT %(project_id)s, %(skeleton_id)s, %(parent_id)s,
                        %(x)s, %(y)s, %(z)s, %(user_id)s, %(editor_id)s,
                        %(creation_time)s::timestamptz
                    RETURNING id
                """, {
                    'project_id': self.test_project_id,
                    'skeleton_id': skeleton_id,
                    'parent_id': last_node,
                    'x': node[2],
                    'y': node[3],
                    'z': node[4],
                    'user_id': node[0],
                    'editor_id': node[0],
                    'creation_time': node[1]
                })
                last_node = cursor.fetchone()[0]
示例#7
0
    def test_create_treenode2(self):
        self.fake_authentication()
        relation_map = get_relation_to_id_map(self.test_project_id)
        class_map = get_class_to_id_map(self.test_project_id)
        count_treenodes = lambda: Treenode.objects.all().count()
        count_skeletons = lambda: ClassInstance.objects.filter(
                project=self.test_project_id,
                class_column=class_map['skeleton']).count()
        count_neurons = lambda: ClassInstance.objects.filter(
                project=self.test_project_id,
                class_column=class_map['neuron']).count()
        treenode_count = count_treenodes()
        skeleton_count = count_skeletons()
        neuron_count = count_neurons()

        response = self.client.post('/%d/treenode/create' % self.test_project_id, {
            'x': 5,
            'y': 10,
            'z': 15,
            'confidence': 5,
            'parent_id': -1,
            'radius': 2})
        self.assertEqual(response.status_code, 200)
        parsed_response = json.loads(response.content.decode('utf-8'))

        self.assertTrue('treenode_id' in parsed_response)
        self.assertTrue('skeleton_id' in parsed_response)

        self.assertEqual(treenode_count + 1, count_treenodes())
        self.assertEqual(skeleton_count + 1, count_skeletons())
        self.assertEqual(neuron_count + 1, count_neurons())

        treenode_skeleton_relation = TreenodeClassInstance.objects.filter(
                project=self.test_project_id,
                relation=relation_map['element_of'],
                treenode=parsed_response['treenode_id'],
                class_instance=parsed_response['skeleton_id'])
        neuron_skeleton_relation = ClassInstanceClassInstance.objects.filter(
                project=self.test_project_id,
                relation=relation_map['model_of'],
                class_instance_a=parsed_response['skeleton_id'])
        # FIXME: Log test doesn't work like this, because we don't have the
        # neuron ID available
        #neuron_log = Log.objects.filter(
        #        project=self.test_project_id,
        #        operation_type='create_neuron',
        #        freetext='Create neuron %s and skeleton %s' % (parsed_response['neuron_id'], parsed_response['skeleton_id']))

        root = ClassInstance.objects.filter(
                project=self.test_project_id,
                class_column=class_map['root'])[0]

        self.assertEqual(1, neuron_skeleton_relation.count())
示例#8
0
    def test_insert_treenoded_on_edge(self):
        self.fake_authentication()
        class_map = get_class_to_id_map(self.test_project_id)
        count_treenodes = lambda: Treenode.objects.all().count()
        count_skeletons = lambda: ClassInstance.objects.filter(
                project=self.test_project_id,
                class_column=class_map['skeleton']).count()
        count_neurons = lambda: ClassInstance.objects.filter(
                project=self.test_project_id,
                class_column=class_map['neuron']).count()

        treenode_count = count_treenodes()
        skeleton_count = count_skeletons()
        neuron_count = count_neurons()

        # Get two nodes and calculate point between them
        child_id = 2374
        parent_id = 2372
        child = Treenode.objects.get(pk=child_id)
        parent = Treenode.objects.get(pk=parent_id)

        new_node_x = 0.5 * (child.location_x + parent.location_x)
        new_node_y = 0.5 * (child.location_y + parent.location_y)
        new_node_z = 0.5 * (child.location_z + parent.location_z)

        response = self.client.post('/%d/treenode/insert' % self.test_project_id, {
            'x': new_node_x,
            'y': new_node_y,
            'z': new_node_z,
            'child_id': child_id,
            'parent_id': parent_id,
            'state': make_nocheck_state()})

        self.assertEqual(response.status_code, 200)
        parsed_response = json.loads(response.content.decode('utf-8'))

        self.assertTrue('treenode_id' in parsed_response)
        self.assertTrue('skeleton_id' in parsed_response)

        self.assertEqual(treenode_count + 1, count_treenodes())
        self.assertEqual(skeleton_count, count_skeletons())
        self.assertEqual(neuron_count, count_neurons())

        new_node_id = parsed_response['treenode_id']
        new_node = Treenode.objects.get(pk=new_node_id)
        child = Treenode.objects.get(pk=child_id)
        self.assertEqual(new_node.parent_id, parent_id)
        self.assertEqual(child.parent_id, new_node_id)
        self.assertEqual(new_node.user_id, self.test_user_id)
        self.assertEqual(new_node.skeleton_id, child.skeleton_id)
        self.assertEqual(new_node.location_x, new_node_x)
        self.assertEqual(new_node.location_y, new_node_y)
        self.assertEqual(new_node.location_z, new_node_z)
示例#9
0
    def test_create_treenode(self):
        self.fake_authentication()
        relation_map = get_relation_to_id_map(self.test_project_id)
        class_map = get_class_to_id_map(self.test_project_id)
        count_treenodes = lambda: Treenode.objects.all().count()
        count_skeletons = lambda: ClassInstance.objects.filter(
            project=self.test_project_id, class_column=class_map['skeleton'
                                                                 ]).count()
        count_neurons = lambda: ClassInstance.objects.filter(
            project=self.test_project_id, class_column=class_map['neuron'
                                                                 ]).count()

        treenode_count = count_treenodes()
        skeleton_count = count_skeletons()
        neuron_count = count_neurons()

        response = self.client.post(
            '/%d/treenode/create' % self.test_project_id, {
                'x': 5,
                'y': 10,
                'z': 15,
                'confidence': 5,
                'parent_id': -1,
                'radius': 2
            })
        self.assertEqual(response.status_code, 200)
        parsed_response = json.loads(response.content.decode('utf-8'))

        self.assertTrue('treenode_id' in parsed_response)
        self.assertTrue('skeleton_id' in parsed_response)

        self.assertEqual(treenode_count + 1, count_treenodes())
        self.assertEqual(skeleton_count + 1, count_skeletons())
        self.assertEqual(neuron_count + 1, count_neurons())

        treenode_skeleton_relation = TreenodeClassInstance.objects.filter(
            project=self.test_project_id,
            relation=relation_map['element_of'],
            treenode=parsed_response['treenode_id'],
            class_instance=parsed_response['skeleton_id'])
        neuron_skeleton_relation = ClassInstanceClassInstance.objects.filter(
            project=self.test_project_id,
            relation=relation_map['model_of'],
            class_instance_a=parsed_response['skeleton_id'])
        neuron_log = Log.objects.filter(project=self.test_project_id,
                                        operation_type='create_neuron')

        # FIXME: discussed in
        # https://github.com/catmaid/CATMAID/issues/754
        #self.assertEqual(1, treenode_skeleton_relation.count())
        self.assertEqual(1, neuron_skeleton_relation.count())
示例#10
0
    def test_create_treenode(self):
        self.fake_authentication()
        relation_map = get_relation_to_id_map(self.test_project_id)
        class_map = get_class_to_id_map(self.test_project_id)
        count_treenodes = lambda: Treenode.objects.all().count()
        count_skeletons = lambda: ClassInstance.objects.filter(
                project=self.test_project_id,
                class_column=class_map['skeleton']).count()
        count_neurons = lambda: ClassInstance.objects.filter(
                project=self.test_project_id,
                class_column=class_map['neuron']).count()

        treenode_count = count_treenodes()
        skeleton_count = count_skeletons()
        neuron_count = count_neurons()

        response = self.client.post('/%d/treenode/create' % self.test_project_id, {
            'x': 5,
            'y': 10,
            'z': 15,
            'confidence': 5,
            'parent_id': -1,
            'radius': 2})
        self.assertEqual(response.status_code, 200)
        parsed_response = json.loads(response.content.decode('utf-8'))

        self.assertTrue('treenode_id' in parsed_response)
        self.assertTrue('skeleton_id' in parsed_response)

        self.assertEqual(treenode_count + 1, count_treenodes())
        self.assertEqual(skeleton_count + 1, count_skeletons())
        self.assertEqual(neuron_count + 1, count_neurons())

        treenode_skeleton_relation = TreenodeClassInstance.objects.filter(
                project=self.test_project_id,
                relation=relation_map['element_of'],
                treenode=parsed_response['treenode_id'],
                class_instance=parsed_response['skeleton_id'])
        neuron_skeleton_relation = ClassInstanceClassInstance.objects.filter(
                project=self.test_project_id,
                relation=relation_map['model_of'],
                class_instance_a=parsed_response['skeleton_id'])
        neuron_log = Log.objects.filter(
                project=self.test_project_id,
                operation_type='create_neuron')

        # FIXME: discussed in
        # https://github.com/catmaid/CATMAID/issues/754
        #self.assertEqual(1, treenode_skeleton_relation.count())
        self.assertEqual(1, neuron_skeleton_relation.count())
示例#11
0
def _list_neurons(project_id, created_by, reviewed_by, from_date, to_date,
                  nodecount_gt) -> List:
    """ Returns a list of neuron IDs of which nodes exist that fulfill the
    given constraints (if any). It can be constrained who created nodes in this
    neuron during a given period of time. Having nodes that are reviewed by
    a certain user is another constraint. And so is the node count that one can
    specify which each result node must exceed.
    """
    cursor = connection.cursor()
    class_map = get_class_to_id_map(project_id, ["neuron"])

    # Without any constraints, it is fastest to list all neurons in the project.
    with_constraints = created_by or reviewed_by or from_date or to_date or nodecount_gt > 0
    if with_constraints:
        # Need to import internally to prevent cyclic import
        from catmaid.control.skeleton import _list_skeletons

        skeleton_ids = _list_skeletons(project_id, created_by, reviewed_by,
                                       from_date, to_date, nodecount_gt)
        skeleton_id_template = ",".join("(%s)" for _ in skeleton_ids)

        # Get neurons modeled by skeletons
        if skeleton_ids:
            cursor.execute(
                """
                SELECT DISTINCT c.id
                FROM class_instance_class_instance cc
                JOIN class_instance c
                    ON cc.class_instance_b = c.id
                JOIN (VALUES {}) skeleton(id)
                    ON cc.class_instance_a = skeleton.id
                WHERE cc.project_id = %s
                AND c.class_id = %s
            """.format(skeleton_id_template),
                skeleton_ids + [project_id, class_map["neuron"]])

            return list(map(lambda x: x[0], cursor.fetchall()))
        else:
            return []
    else:
        cursor.execute(
            """
            SELECT id
            FROM class_instance
            WHERE project_id = %s
            AND class_id = %s
        """, (project_id, class_map["neuron"]))

        return list(map(lambda x: x[0], cursor.fetchall()))
示例#12
0
    def test_insert_treenoded_not_on_edge_without_permission(self):
        self.fake_authentication(username='******')
        class_map = get_class_to_id_map(self.test_project_id)
        count_treenodes = lambda: Treenode.objects.all().count()
        count_skeletons = lambda: ClassInstance.objects.filter(
            project=self.test_project_id, class_column=class_map['skeleton'
                                                                 ]).count()
        count_neurons = lambda: ClassInstance.objects.filter(
            project=self.test_project_id, class_column=class_map['neuron'
                                                                 ]).count()

        treenode_count = count_treenodes()
        skeleton_count = count_skeletons()
        neuron_count = count_neurons()

        # Get two nodes and calculate point between them
        child_id = 2374
        parent_id = 2372
        child = Treenode.objects.get(pk=child_id)
        parent = Treenode.objects.get(pk=parent_id)

        # Set chld and parent to different creators and lock it
        owner = User.objects.get(username='******')
        for n in (child, parent):
            n.creator = owner
            n.save()

        new_node_x = 0.5 * (child.location_x + parent.location_x)
        new_node_y = 0.5 * (child.location_y + parent.location_y) + 10
        new_node_z = 0.5 * (child.location_z + parent.location_z)

        # Try to insert with a slight distorition in Y. This should fail since
        # the new node would introduce a structural change to the skeleton.
        response = self.client.post(
            '/%d/treenode/insert' % self.test_project_id, {
                'x': new_node_x,
                'y': new_node_y,
                'z': new_node_z,
                'child_id': child_id,
                'parent_id': parent_id
            })

        self.assertEqual(response.status_code, 200)
        parsed_response = json.loads(response.content.decode('utf-8'))
        self.assertTrue('error' in parsed_response)

        self.assertEqual(treenode_count, count_treenodes())
        self.assertEqual(skeleton_count, count_skeletons())
        self.assertEqual(neuron_count, count_neurons())
示例#13
0
def create_new_classification( workspace_pid, project_id ):
    """ creates a new classification graph instance. This basically
    means a new class instance is created that is based on a class
    whilh has a 'is_a' relation to the class 'classification_root'.
    Such a new class instance will live in the dummy project -1.
    """
    # Get the classification project class
    class_map = get_class_to_id_map(workspace_pid)
    if 'classification_project' not in class_map:
        raise Exception("Couldn't find 'classification_project' class")

    # Create new classification
    cls_graph = None
    # Link new classification to project
    link_to_classification( project_id, cls_graph )
示例#14
0
def setup_classification(workspace_pid, user):
    """ Tests which of the needed classes and relations is missing
    from the dummy project''s semantic space and adds those.
    """
    # Get classification and relation data
    class_map = get_class_to_id_map(workspace_pid)
    relation_map = get_relation_to_id_map(workspace_pid)

    # Add what is missing
    for c in needed_classes:
        if c not in class_map:
            add_class(workspace_pid, user, c, needed_classes[c])
    for r in needed_relations:
        if r not in relation_map:
            add_relation(workspace_pid, user, r, needed_relations[r])
示例#15
0
    def test_create_treenode_with_existing_neuron(self):
        self.fake_authentication()
        relation_map = get_relation_to_id_map(self.test_project_id)
        class_map = get_class_to_id_map(self.test_project_id)
        neuron_id = 2389
        count_skeletons = lambda: ClassInstance.objects.filter(
            project=self.test_project_id, class_column=class_map['skeleton'
                                                                 ]).count()
        count_treenodes = lambda: Treenode.objects.all().count()

        treenode_count = count_treenodes()
        skeleton_count = count_skeletons()

        response = self.client.post(
            '/%d/treenode/create' % self.test_project_id, {
                'x': 5,
                'y': 10,
                'z': 15,
                'confidence': 5,
                'parent_id': -1,
                'useneuron': neuron_id,
                'radius': 2
            })
        self.assertEqual(response.status_code, 200)
        parsed_response = json.loads(response.content.decode('utf-8'))

        self.assertTrue('treenode_id' in parsed_response)
        self.assertTrue('skeleton_id' in parsed_response)

        self.assertEqual(treenode_count + 1, count_treenodes())
        self.assertEqual(skeleton_count + 1, count_skeletons())

        treenode_skeleton_relation = TreenodeClassInstance.objects.filter(
            project=self.test_project_id,
            relation=relation_map['element_of'],
            treenode=parsed_response['treenode_id'],
            class_instance=parsed_response['skeleton_id'])
        neuron_skeleton_relation = ClassInstanceClassInstance.objects.filter(
            project=self.test_project_id,
            relation=relation_map['model_of'],
            class_instance_a=parsed_response['skeleton_id'],
            class_instance_b=neuron_id)

        # FIXME: treenode_skeleton_relation.count() should be 1, but we
        # currently don't store these relations.
        # See: https://github.com/catmaid/CATMAID/issues/754
        self.assertEqual(0, treenode_skeleton_relation.count())
        self.assertEqual(1, neuron_skeleton_relation.count())
示例#16
0
    def test_insert_treenoded_not_on_edge_without_permission(self):
        self.fake_authentication(username='******')
        class_map = get_class_to_id_map(self.test_project_id)
        count_treenodes = lambda: Treenode.objects.all().count()
        count_skeletons = lambda: ClassInstance.objects.filter(
                project=self.test_project_id,
                class_column=class_map['skeleton']).count()
        count_neurons = lambda: ClassInstance.objects.filter(
                project=self.test_project_id,
                class_column=class_map['neuron']).count()

        treenode_count = count_treenodes()
        skeleton_count = count_skeletons()
        neuron_count = count_neurons()

        # Get two nodes and calculate point between them
        child_id = 2374
        parent_id = 2372
        child = Treenode.objects.get(pk=child_id)
        parent = Treenode.objects.get(pk=parent_id)

        # Set chld and parent to different creators and lock it
        owner = User.objects.get(username='******')
        for n in (child, parent):
            n.creator = owner
            n.save()

        new_node_x = 0.5 * (child.location_x + parent.location_x)
        new_node_y = 0.5 * (child.location_y + parent.location_y) + 10
        new_node_z = 0.5 * (child.location_z + parent.location_z)

        # Try to insert with a slight distorition in Y. This should fail since
        # the new node would introduce a structural change to the skeleton.
        response = self.client.post('/%d/treenode/insert' % self.test_project_id, {
            'x': new_node_x,
            'y': new_node_y,
            'z': new_node_z,
            'child_id': child_id,
            'parent_id': parent_id})

        self.assertEqual(response.status_code, 200)
        parsed_response = json.loads(response.content.decode('utf-8'))
        self.assertTrue('error' in parsed_response)

        self.assertEqual(treenode_count, count_treenodes())
        self.assertEqual(skeleton_count, count_skeletons())
        self.assertEqual(neuron_count, count_neurons())
示例#17
0
    def test_create_treenode_with_existing_neuron(self):
        self.fake_authentication()
        relation_map = get_relation_to_id_map(self.test_project_id)
        class_map = get_class_to_id_map(self.test_project_id)
        neuron_id = 2389
        count_skeletons = lambda: ClassInstance.objects.filter(
                project=self.test_project_id,
                class_column=class_map['skeleton']).count()
        count_treenodes = lambda: Treenode.objects.all().count()

        treenode_count = count_treenodes()
        skeleton_count = count_skeletons()

        response = self.client.post('/%d/treenode/create' % self.test_project_id, {
            'x': 5,
            'y': 10,
            'z': 15,
            'confidence': 5,
            'parent_id': -1,
            'useneuron': neuron_id,
            'radius': 2})
        self.assertEqual(response.status_code, 200)
        parsed_response = json.loads(response.content.decode('utf-8'))

        self.assertTrue('treenode_id' in parsed_response)
        self.assertTrue('skeleton_id' in parsed_response)

        self.assertEqual(treenode_count + 1, count_treenodes())
        self.assertEqual(skeleton_count + 1, count_skeletons())

        treenode_skeleton_relation = TreenodeClassInstance.objects.filter(
                project=self.test_project_id,
                relation=relation_map['element_of'],
                treenode=parsed_response['treenode_id'],
                class_instance=parsed_response['skeleton_id'])
        neuron_skeleton_relation = ClassInstanceClassInstance.objects.filter(
                project=self.test_project_id,
                relation=relation_map['model_of'],
                class_instance_a=parsed_response['skeleton_id'],
                class_instance_b=neuron_id)

        # FIXME: treenode_skeleton_relation.count() should be 1, but we
        # currently don't store these relations.
        # See: https://github.com/catmaid/CATMAID/issues/754
        self.assertEqual(0, treenode_skeleton_relation.count())
        self.assertEqual(1, neuron_skeleton_relation.count())
示例#18
0
def check_classification_setup(workspace_pid):
    """ Checks if all classes and relations needed by the
    classification system are available. Needed classes are
    'classification_root' and 'classification_project' and the
    nedded relations are 'is_a' and 'classified_by'.
    """
    # Get classification and relation data
    class_map = get_class_to_id_map(workspace_pid)
    relation_map = get_relation_to_id_map(workspace_pid)

    # Check if all is good
    all_good = True
    for c in needed_classes:
        all_good = (all_good and (c in class_map))
    for r in needed_relations:
        all_good = (all_good and (r in relation_map))

    return all_good
示例#19
0
def list_annotations(request, project_id=None):
    """ Creates a list of objects containing an annotation name and the user
    name and ID of the users having linked that particular annotation.
    """

    if not request.POST:
        cursor = connection.cursor()
        classes = get_class_to_id_map(project_id, ("annotation",), cursor)
        relations = get_relation_to_id_map(project_id, ("annotated_with",), cursor)

        cursor.execute(
            """
            SELECT DISTINCT ci.name, ci.id, u.id, u.username
            FROM class_instance ci
            LEFT OUTER JOIN class_instance_class_instance cici
                         ON (ci.id = cici.class_instance_b)
            LEFT OUTER JOIN auth_user u
                         ON (cici.user_id = u.id)
            WHERE (ci.class_id = %s AND cici.relation_id = %s
              AND ci.project_id = %s AND cici.project_id = %s);
                       """,
            (classes["annotation"], relations["annotated_with"], project_id, project_id),
        )
        annotation_tuples = cursor.fetchall()
    else:
        annotation_query = create_annotation_query(project_id, request.POST)
        annotation_tuples = annotation_query.distinct().values_list(
            "name", "id", "cici_via_b__user__id", "cici_via_b__user__username"
        )

    # Create a set mapping annotation names to its users
    ids = {}
    annotation_dict = {}
    for annotation, aid, uid, username in annotation_tuples:
        ids[aid] = annotation
        ls = annotation_dict.get(aid)
        if ls is None:
            ls = []
            annotation_dict[aid] = ls
        ls.append({"id": uid, "name": username})
    # Flatten dictionary to list
    annotations = tuple({"name": ids[aid], "id": aid, "users": users} for aid, users in annotation_dict.iteritems())
    return HttpResponse(json.dumps({"annotations": annotations}), content_type="text/json")
示例#20
0
    def test_insert_treenoded_no_child_parent(self):
        self.fake_authentication()
        class_map = get_class_to_id_map(self.test_project_id)
        count_treenodes = lambda: Treenode.objects.all().count()
        count_skeletons = lambda: ClassInstance.objects.filter(
            project=self.test_project_id, class_column=class_map['skeleton'
                                                                 ]).count()
        count_neurons = lambda: ClassInstance.objects.filter(
            project=self.test_project_id, class_column=class_map['neuron'
                                                                 ]).count()

        treenode_count = count_treenodes()
        skeleton_count = count_skeletons()
        neuron_count = count_neurons()

        # Get two nodes and calculate point between them
        child_id = 2376
        parent_id = 2372
        child = Treenode.objects.get(pk=child_id)
        parent = Treenode.objects.get(pk=parent_id)

        new_node_x = 0.5 * (child.location_x + parent.location_x)
        new_node_y = 0.5 * (child.location_y + parent.location_y)
        new_node_z = 0.5 * (child.location_z + parent.location_z)

        # Try to insert with a slight distorition in Y
        response = self.client.post(
            '/%d/treenode/insert' % self.test_project_id, {
                'x': new_node_x,
                'y': new_node_y,
                'z': new_node_z,
                'child_id': child_id,
                'parent_id': parent_id
            })

        self.assertEqual(response.status_code, 200)
        parsed_response = json.loads(response.content.decode('utf-8'))
        self.assertTrue('error' in parsed_response)

        self.assertEqual(treenode_count, count_treenodes())
        self.assertEqual(skeleton_count, count_skeletons())
        self.assertEqual(neuron_count, count_neurons())
示例#21
0
def check_tracing_setup_detailed(
        project_id,
        opt_class_map=None,
        opt_relation_map=None,
        check_root_ci=True) -> Tuple[bool, List, List, List]:
    """ Checks if all classes and relations needed by the tracing system are
    available. It returns a four-tuple with a boolean indicating if all is
    setup, the missing class names, the missing relation names and the missing
    class instance names. Allows avoidng tests for root class instances and
    passing already available class and relation maps.
    """
    # Get class and relation data. If available, use the provided one.
    class_map = opt_class_map or get_class_to_id_map(project_id)
    relation_map = opt_relation_map or get_relation_to_id_map(project_id)

    # Check if all classes and relations are available
    all_good = True
    missing_classes = []
    missing_relations = []
    missing_classinstances = []

    for c in needed_classes:
        if c not in class_map:
            all_good = False
            missing_classes.append(c)
    for r in needed_relations:
        if r not in relation_map:
            all_good = False
            missing_relations.append(r)
    # Check if the root node is there if requested
    if check_root_ci:
        if 'root' in class_map:
            exists = ClassInstance.objects.filter(
                class_column=class_map['root'],
                project_id=project_id).exists()
            if not exists:
                all_good = False
                missing_classinstances.append('root')
        else:
            missing_classinstances.append('root')

    return all_good, missing_classes, missing_relations, missing_classinstances
示例#22
0
    def test_insert_treenoded_no_child_parent(self):
        self.fake_authentication()
        class_map = get_class_to_id_map(self.test_project_id)
        count_treenodes = lambda: Treenode.objects.all().count()
        count_skeletons = lambda: ClassInstance.objects.filter(
                project=self.test_project_id,
                class_column=class_map['skeleton']).count()
        count_neurons = lambda: ClassInstance.objects.filter(
                project=self.test_project_id,
                class_column=class_map['neuron']).count()

        treenode_count = count_treenodes()
        skeleton_count = count_skeletons()
        neuron_count = count_neurons()

        # Get two nodes and calculate point between them
        child_id = 2376
        parent_id = 2372
        child = Treenode.objects.get(pk=child_id)
        parent = Treenode.objects.get(pk=parent_id)

        new_node_x = 0.5 * (child.location_x + parent.location_x)
        new_node_y = 0.5 * (child.location_y + parent.location_y)
        new_node_z = 0.5 * (child.location_z + parent.location_z)

        # Try to insert with a slight distorition in Y
        response = self.client.post('/%d/treenode/insert' % self.test_project_id, {
            'x': new_node_x,
            'y': new_node_y,
            'z': new_node_z,
            'child_id': child_id,
            'parent_id': parent_id})

        self.assertEqual(response.status_code, 200)
        parsed_response = json.loads(response.content.decode('utf-8'))
        self.assertTrue('error' in parsed_response)

        self.assertEqual(treenode_count, count_treenodes())
        self.assertEqual(skeleton_count, count_skeletons())
        self.assertEqual(neuron_count, count_neurons())
示例#23
0
文件: tracing.py 项目: catsop/CATMAID
def check_tracing_setup_detailed(project_id, opt_class_map=None,
        opt_relation_map=None, check_root_ci=True):
    """ Checks if all classes and relations needed by the tracing system are
    available. It returns a four-tuple with a boolean indicating if all is
    setup, the missing class names, the missing relation names and the missing
    class instance names. Allows to avoid test for root class instances and to
    pass already available class and relation maps.
    """
    # Get class and relation data. If available, use the provided one.
    class_map = opt_class_map or get_class_to_id_map(project_id)
    relation_map = opt_relation_map or get_relation_to_id_map(project_id)

    # Check if all classes and relations are available
    all_good = True
    missing_classes = []
    missing_relations = []
    missing_classinstances = []

    for c in needed_classes:
        if not c in class_map:
            all_good = False
            missing_classes.append(c)
    for r in needed_relations:
        if not r in relation_map:
            all_good = False
            missing_relations.append(r)
    # Check if the root node is there if requested
    if check_root_ci:
        if 'root' in class_map:
            exists = ClassInstance.objects.filter(
                class_column=class_map['root'],
                project_id=project_id).exists()
            if not exists:
                all_good = False
                missing_classinstances.append('root')
        else:
                missing_classinstances.append('root')

    return all_good, missing_classes, missing_relations, missing_classinstances
示例#24
0
def _create_treenode(project_id, creator, editor, x, y, z, radius, confidence,
                     neuron_id, parent_id, creation_time=None, neuron_name=None):

    relation_map = get_relation_to_id_map(project_id)
    class_map = get_class_to_id_map(project_id)

    def insert_new_treenode(parent_id=None, skeleton_id=None):
        """ If the parent_id is not None and the skeleton_id of the parent does
        not match with the skeleton.id, then the database will throw an error
        given that the skeleton_id, being defined as foreign key in the
        treenode table, will not meet the being-foreign requirement.
        """
        new_treenode = Treenode()
        new_treenode.user = creator
        new_treenode.editor = editor
        new_treenode.project_id = project_id
        if creation_time:
            new_treenode.creation_time = creation_time
        new_treenode.location_x = float(x)
        new_treenode.location_y = float(y)
        new_treenode.location_z = float(z)
        new_radius = int(radius if (radius and not math.isnan(radius)) else 0)
        new_treenode.radius = new_radius
        new_treenode.skeleton_id = skeleton_id
        new_confidence = int(confidence if not math.isnan(confidence) and (confidence or confidence is 0) else 5)
        new_treenode.confidence = new_confidence
        if parent_id:
            new_treenode.parent_id = parent_id
        new_treenode.save()
        return new_treenode

    def relate_neuron_to_skeleton(neuron, skeleton):
        return _create_relation(creator, project_id,
                                relation_map['model_of'], skeleton, neuron)

    response_on_error = ''
    try:
        if -1 != int(parent_id):  # A root node and parent node exist
            # Select the parent treenode for update to prevent race condition
            # updates to its skeleton ID while this node is being created.
            cursor = connection.cursor()
            cursor.execute('''
                SELECT t.skeleton_id, t.edition_time FROM treenode t
                WHERE t.id = %s FOR NO KEY UPDATE OF t
                ''', (parent_id,))

            if cursor.rowcount != 1:
                raise ValueError('Parent treenode %s does not exist' % parent_id)

            parent_node = cursor.fetchone()
            parent_skeleton_id = parent_node[0]
            parent_edition_time = parent_node[1]

            # Raise an Exception if the user doesn't have permission to edit
            # the neuron the skeleton of the treenode is modeling.
            can_edit_skeleton_or_fail(editor, project_id, parent_skeleton_id,
                                      relation_map['model_of'])

            response_on_error = 'Could not insert new treenode!'
            new_treenode = insert_new_treenode(parent_id, parent_skeleton_id)

            return NewTreenode(new_treenode.id, new_treenode.edition_time,
                               parent_skeleton_id, parent_edition_time)
        else:
            # No parent node: We must create a new root node, which needs a
            # skeleton and a neuron to belong to.
            response_on_error = 'Could not insert new treenode instance!'

            new_skeleton = ClassInstance()
            new_skeleton.user = creator
            new_skeleton.project_id = project_id
            new_skeleton.class_column_id = class_map['skeleton']
            new_skeleton.name = 'skeleton'
            new_skeleton.save()
            new_skeleton.name = 'skeleton %d' % new_skeleton.id
            new_skeleton.save()

            if -1 != neuron_id:
                # Check that the neuron to use exists
                if 0 == ClassInstance.objects.filter(pk=neuron_id).count():
                    neuron_id = -1

            if -1 != neuron_id:
                # Raise an Exception if the user doesn't have permission to
                # edit the existing neuron.
                can_edit_class_instance_or_fail(editor, neuron_id, 'neuron')

                # A neuron already exists, so we use it
                response_on_error = 'Could not relate the neuron model to ' \
                                    'the new skeleton!'
                relate_neuron_to_skeleton(neuron_id, new_skeleton.id)

                response_on_error = 'Could not insert new treenode!'
                new_treenode = insert_new_treenode(None, new_skeleton.id)

                return NewTreenode(new_treenode.id, new_treenode.edition_time,
                                   new_skeleton.id, None)
            else:
                # A neuron does not exist, therefore we put the new skeleton
                # into a new neuron.
                response_on_error = 'Failed to insert new instance of a neuron.'
                new_neuron = ClassInstance()
                new_neuron.user = creator
                new_neuron.project_id = project_id
                new_neuron.class_column_id = class_map['neuron']
                if neuron_name:
                    # Create a regular expression to find allowed patterns. The
                    # first group is the whole {nX} part, while the second group
                    # is X only.
                    counting_pattern = re.compile(r"(\{n(\d+)\})")
                    # Look for patterns, replace all {n} with {n1} to normalize.
                    neuron_name = neuron_name.replace("{n}", "{n1}")

                    if counting_pattern.search(neuron_name):
                        # Find starting values for each substitution.
                        counts = [int(m.groups()[1]) for m in counting_pattern.finditer(neuron_name)]
                        # Find existing matching neurons in database.
                        name_match = counting_pattern.sub(r"(\d+)", neuron_name)
                        name_pattern = re.compile(name_match)
                        matching_neurons = ClassInstance.objects.filter(
                                project_id=project_id,
                                class_column_id=class_map['neuron'],
                                name__regex=name_match).order_by('name')

                        # Increment substitution values based on existing neurons.
                        for n in matching_neurons:
                            for i, (count, g) in enumerate(zip(counts, name_pattern.search(n.name).groups())):
                                if count == int(g):
                                    counts[i] = count + 1

                        # Substitute values.
                        count_ind = 0
                        m = counting_pattern.search(neuron_name)
                        while m:
                            neuron_name = m.string[:m.start()] + str(counts[count_ind]) + m.string[m.end():]
                            count_ind = count_ind + 1
                            m = counting_pattern.search(neuron_name)

                    new_neuron.name = neuron_name
                else:
                    new_neuron.name = 'neuron'
                    new_neuron.save()
                    new_neuron.name = 'neuron %d' % new_neuron.id

                new_neuron.save()

                response_on_error = 'Could not relate the neuron model to ' \
                                    'the new skeleton!'
                relate_neuron_to_skeleton(new_neuron.id, new_skeleton.id)

                response_on_error = 'Failed to insert instance of treenode.'
                new_treenode = insert_new_treenode(None, new_skeleton.id)

                response_on_error = 'Failed to write to logs.'
                new_location = (new_treenode.location_x, new_treenode.location_y,
                                new_treenode.location_z)
                insert_into_log(project_id, creator.id, 'create_neuron',
                                new_location, 'Create neuron %d and skeleton '
                                '%d' % (new_neuron.id, new_skeleton.id))

                return NewTreenode(new_treenode.id, new_treenode.edition_time,
                                   new_skeleton.id, None)

    except Exception as e:
        import traceback
        raise Exception("%s: %s %s" % (response_on_error, str(e),
                                       str(traceback.format_exc())))
示例#25
0
文件: tree.py 项目: AdaEne/CATMAID
def instance_operation(request, project_id=None):
    params = {}
    int_keys = ('id', 'src', 'ref', 'parentid', 'relationnr')
    str_keys = ('title', 'operation', 'title', 'rel', 'classname', 'relationname', 'objname', 'targetname')
    for k in int_keys:
        params[k] = int(request.POST.get(k, 0))
    for k in str_keys:
        # TODO sanitize
        params[k] = request.POST.get(k, 0)

    relation_map = get_relation_to_id_map(project_id)
    class_map = get_class_to_id_map(project_id)

    # We avoid many try/except clauses by setting this string to be the
    # response we return if an exception is thrown.
    instance_operation.res_on_err = ''

    def remove_skeletons(skeleton_id_list):
        if request.user.is_superuser:
            instance_operation.res_on_err = 'Failed to delete in treenode for skeletons #%s' % skeleton_id_list
            # TODO this failed at least once, whereas direct deletion of a single skeleton by skeleton_id on the treenode table succeeded. Inspect!
            Treenode.objects.filter(
                    project=project_id,
                    skeleton__in=skeleton_id_list).delete()

            instance_operation.res_on_err = 'Failed to delete in treenode_connector for skeletons #%s' % skeleton_id_list
            TreenodeConnector.objects.filter(
                    project=project_id,
                    skeleton__in=skeleton_id_list).delete()

            instance_operation.res_on_err = 'Failed to delete in class_instance for skeletons #%s' % skeleton_id_list
            ClassInstance.objects.filter(
                    id__in=skeleton_id_list).delete()
        else:
            # Cannot delete the skeleton if at least one node does not belong to the user
            cursor = connection.cursor()
            for skid in skeleton_id_list:
                cursor.execute('''
                SELECT user_id, count(user_id) FROM treenode WHERE skeleton_id=%s GROUP BY user_id
                ''', [skid])
                rows = tuple(row for row in cursor.fetchall())
                if 1 == len(rows) and rows[0][0] == request.user.id:
                    instance_operation.res_on_err = 'Failed to delete in treenode for skeletons #%s' % skeleton_id_list
                    Treenode.objects.filter(
                            project=project_id,
                            skeleton=skid).delete()

                    instance_operation.res_on_err = 'Failed to delete in treenode_connector for skeletons #%s' % skeleton_id_list
                    TreenodeConnector.objects.filter(
                            project=project_id,
                            skeleton=skid).delete()

                    instance_operation.res_on_err = 'Failed to delete in class_instance for skeletons #%s' % skeleton_id_list
                    ClassInstance.objects.filter(pk=skid).delete()
                else:
                    cursor.execute('SELECT first_name, last_name FROM "auth_user" WHERE id IN (%s)', [row[0] for row in rows if row[0] != request.user.id])
                    users = [a[0] + ' ' + a[1] for a in cursor.fetchall()]
                    raise Exception('Cannot delete skeleton #%s: %s of %s nodes belong to user(s) %s' % (sum(row[1] for row in rows if row[0] != request.user.id),
              sum(row[1] for row in rows),
              ", ".join(a[0] + ' ' + a[1] for a in cursor.fetchall())))


    def rename_node():
        can_edit_class_instance_or_fail(request.user, params['id'])
        # Do not allow '|' in name because it is used as string separator in NeuroHDF export
        if '|' in params['title']:
            raise Exception('Name should not contain pipe character!')

        instance_operation.res_on_err = 'Failed to update class instance.'
        nodes_to_rename = ClassInstance.objects.filter(id=params['id'])
        node_ids = [node.id for node in nodes_to_rename]
        if len(node_ids) > 0:
            old_name = ",".join([n.name for n in nodes_to_rename])
            nodes_to_rename.update(name=params['title'])
            insert_into_log(project_id, request.user.id, "rename_%s" % params['classname'], None, "Renamed %s with ID %s from %s to %s" % (params['classname'], params['id'], old_name, params['title']))
            return HttpResponse(json.dumps({'class_instance_ids': node_ids}))
        else:
            instance_operation.res_on_err = ''
            raise Exception('Could not find any node with ID %s' % params['id'])

    def remove_node():
        # Can only remove the node if the user owns it or the user is a superuser
        can_edit_class_instance_or_fail(request.user, params['id'])
        # Check if node is a skeleton. If so, we have to remove its treenodes as well!
        if 0 == params['rel']:
            raise Exception('No relation given!')

        elif 'skeleton' == params['rel']:
            remove_skeletons([params['id']])
            insert_into_log(project_id, request.user.id, 'remove_skeleton', None, 'Removed skeleton with ID %s and name %s' % (params['id'], params['title']))
            return HttpResponse(json.dumps({'status': 1, 'message': 'Removed skeleton successfully.'}))

        elif 'neuron' == params['rel']:
            instance_operation.res_on_err = 'Failed to retrieve node skeleton relations.'
            skeleton_relations = ClassInstanceClassInstance.objects.filter(
                    project=project_id,
                    relation=relation_map['model_of'],
                    class_instance_b=params['id'])
            remove_skeletons([s.class_instance_a_id for s in skeleton_relations])
            instance_operation.res_on_err = 'Failed to delete node from instance table.'
            node_to_delete = ClassInstance.objects.filter(id=params['id'])
            if node_to_delete.count() > 0:
                node_to_delete.delete()
                insert_into_log(project_id, request.user.id, 'remove_neuron', None, 'Removed neuron with ID %s and name %s' % (params['id'], params['title']))
                return HttpResponse(json.dumps({'status': 1, 'message': 'Removed neuron successfully.'}))
            else:
                instance_operation.res_on_err = ''
                raise Exception('Could not find any node with ID %s' % params['id'])

        else:
            instance_operation.res_on_err = 'Failed to delete node from instance table.'
            node_to_delete = ClassInstance.objects.filter(id=params['id'])
            if node_to_delete.count() > 0:
                node_to_delete.delete()
                return HttpResponse(json.dumps({'status': 1, 'message': 'Removed node successfully.'}))
            else:
                instance_operation.res_on_err = ''
                raise Exception('Could not find any node with ID %s' % params['id'])

    def create_node():
        # Can only create a node if the parent node is owned by the user
        # or the user is a superuser
        # Given that the parentid is 0 to signal root (but root has a non-zero id),
        # this implies that regular non-superusers cannot create nodes under root,
        # but only in their staging area.
        can_edit_class_instance_or_fail(request.user, params['parentid'])

        if params['classname'] not in class_map:
            raise Exception('Failed to select class.')
        instance_operation.res_on_err = 'Failed to insert instance of class.'
        node = ClassInstance(
                user=request.user,
                name=params['objname'])
        node.project_id = project_id
        node.class_column_id = class_map[params['classname']]
        node.save()
        insert_into_log(project_id, request.user.id, "create_%s" % params['classname'], None, "Created %s with ID %s" % (params['classname'], params['id']))

        # We need to connect the node to its parent, or to root if no valid parent is given.
        node_parent_id = params['parentid']
        if 0 == params['parentid']:
            # Find root element
            instance_operation.res_on_err = 'Failed to select root.'
            node_parent_id = ClassInstance.objects.filter(
                    project=project_id,
                    class_column=class_map['root'])[0].id

        if params['relationname'] not in relation_map:
            instance_operation.res_on_err = ''
            raise Exception('Failed to select relation %s' % params['relationname'])

        instance_operation.res_on_err = 'Failed to insert relation.'
        cici = ClassInstanceClassInstance()
        cici.user = request.user
        cici.project_id = project_id
        cici.relation_id = relation_map[params['relationname']]
        cici.class_instance_a_id = node.id
        cici.class_instance_b_id = node_parent_id
        cici.save()

        return HttpResponse(json.dumps({'class_instance_id': node.id}))

    def move_node():
        # Can only move the node if the user owns the node and the target node,
        # or the user is a superuser
        can_edit_class_instance_or_fail(request.user, params['src'], 'node') # node to move
        can_edit_class_instance_or_fail(request.user, params['ref'], 'node') # new parent node
        #
        if 0 == params['src'] or 0 == params['ref']:
            raise Exception('src (%s) or ref (%s) not set.' % (params['src'], params['ref']))

        relation_type = 'part_of'
        if 'skeleton' == params['classname']:  # Special case for model_of relationship
            relation_type = 'model_of'

        instance_operation.res_on_err = 'Failed to update %s relation.' % relation_type
        ClassInstanceClassInstance.objects.filter(
                project=project_id,
                relation=relation_map[relation_type],
                class_instance_a=params['src']).update(class_instance_b=params['ref'])

        insert_into_log(project_id, request.user.id, 'move_%s' % params['classname'], None, 'Moved %s with ID %s to %s with ID %s' % (params['classname'], params['id'], params['targetname'], params['ref']))
        return HttpResponse(json.dumps({'message': 'Success.'}))

    def has_relations():
        relations = [request.POST.get('relation%s' % i, 0) for i in range(int(params['relationnr']))]
        relation_ids = []
        for relation in relations:
            instance_operation.res_on_err = 'Failed to select relation %s' % relation
            relation_ids.append(relation_map[relation])
        instance_operation.res_on_err = 'Failed to select CICI.'
        relation_count = ClassInstanceClassInstance.objects.filter(
                project=project_id,
                class_instance_b=params['id'],
                relation__in=relation_ids).count()
        if relation_count > 0:
            return HttpResponse(json.dumps({'has_relation': 1}))
        else:
            return HttpResponse(json.dumps({'has_relation': 0}))

    try:
        # Dispatch to operation
        if params['operation'] not in ['rename_node', 'remove_node', 'create_node', 'move_node', 'has_relations']:
            raise Exception('No operation called %s.' % params['operation'])
        return locals()[params['operation']]()

    except Exception as e:
        if instance_operation.res_on_err == '':
            raise
        else:
            raise Exception(instance_operation.res_on_err + '\n' + str(e))
示例#26
0
def list_annotations(request, project_id=None):
    """List annotations matching filtering criteria that are currently in use.

    The result set is the intersection of annotations matching criteria (the
    criteria are conjunctive) unless stated otherwise.
    ---
    parameters:
      - name: annotations
        description: A list of (meta) annotations with which which resulting annotations should be annotated with.
        paramType: form
        type: array
        items:
            type: integer
            description: An annotation ID
      - name: annotates
        description: A list of entity IDs (like annotations and neurons) that should be annotated by the result set.
        paramType: form
        type: array
        items:
            type: integer
            description: An entity ID
      - name: parallel_annotations
        description: A list of annotation that have to be used alongside the result set.
        paramType: form
        type: array
        items:
            type: integer
            description: An annotation ID
      - name: user_id
        description: Result annotations have to be used by this user.
        paramType: form
        type: integer
      - name: neuron_id
        description: Result annotations will annotate this neuron.
        paramType: form
        type: integer
      - name: skeleton_id
        description: Result annotations will annotate the neuron modeled by this skeleton.
        paramType: form
        type: integer
      - name: ignored_annotations
        description: A list of annotation names that will be excluded from the result set.
        paramType: form
        type: array
        items:
            type: string
    models:
      annotation_user_list_element:
        id: annotation_user_list_element
        properties:
          id:
            type: integer
            name: id
            description: The user id
            required: true
          name:
            type: string
            name: name
            description: The user name
            required: true
      annotation_list_element:
        id: annotation_list_element
        description: Represents one annotation along with its users.
        properties:
          name:
            type: string
            description: The name of the annotation
            required: true
          id:
            type: integer
            description: The id of the annotation
            required: true
          users:
            type: array
            description: A list of users
            required: true
            items:
              $ref: annotation_user_list_element
    type:
      - type: array
        items:
          $ref: annotation_list_element
        required: true
    """

    if not request.POST:
        cursor = connection.cursor()
        classes = get_class_to_id_map(project_id, ('annotation',), cursor)
        relations = get_relation_to_id_map(project_id, ('annotated_with',), cursor)

        cursor.execute('''
            SELECT DISTINCT ci.name, ci.id, u.id, u.username
            FROM class_instance ci
            LEFT OUTER JOIN class_instance_class_instance cici
                         ON (ci.id = cici.class_instance_b)
            LEFT OUTER JOIN auth_user u
                         ON (cici.user_id = u.id)
            WHERE (ci.class_id = %s AND cici.relation_id = %s
              AND ci.project_id = %s AND cici.project_id = %s);
                       ''',
            (classes['annotation'], relations['annotated_with'], project_id,
                project_id))
        annotation_tuples = cursor.fetchall()
    else:
        annotation_query = create_annotation_query(project_id, request.POST)
        annotation_tuples = annotation_query.distinct().values_list('name', 'id',
            'cici_via_b__user__id', 'cici_via_b__user__username')

    # Create a set mapping annotation names to its users
    ids = {}
    annotation_dict = {}
    for annotation, aid, uid, username in annotation_tuples:
        ids[aid] = annotation
        ls = annotation_dict.get(aid)
        if ls is None:
            ls = []
            annotation_dict[aid] = ls
        ls.append({'id': uid, 'name': username})
    # Flatten dictionary to list
    annotations = tuple({'name': ids[aid], 'id': aid, 'users': users} for aid, users in annotation_dict.iteritems())
    return HttpResponse(json.dumps({'annotations': annotations}), content_type="application/json")
示例#27
0
def create_treenode(request, project_id=None):
    """
    Add a new treenode to the database
    ----------------------------------

    1. Add new treenode for a given skeleton id. Parent should not be empty.
       return: new treenode id
       If the parent's skeleton has a single node and belongs to the
       'Isolated synaptic terminals' group, then reassign ownership
       of the skeleton and the neuron to the user. The treenode remains
       property of the original user who created it.

    2. Add new treenode (root) and create a new skeleton (maybe for a given
       neuron) return: new treenode id and skeleton id.

    If a neuron id is given, use that one to create the skeleton as a model of
    it.
    """

    params = {}
    float_values = {'x': 0, 'y': 0, 'z': 0, 'radius': 0}
    int_values = {'confidence': 0, 'useneuron': -1, 'parent_id': -1}
    string_values = {}
    for p in float_values.keys():
        params[p] = float(request.POST.get(p, float_values[p]))
    for p in int_values.keys():
        params[p] = int(request.POST.get(p, int_values[p]))
    for p in string_values.keys():
        params[p] = request.POST.get(p, string_values[p])

    relation_map = get_relation_to_id_map(project_id)
    class_map = get_class_to_id_map(project_id)

    def insert_new_treenode(parent_id=None, skeleton=None):
        """ If the parent_id is not None and the skeleton_id of the parent does
        not match with the skeleton.id, then the database will throw an error
        given that the skeleton_id, being defined as foreign key in the
        treenode table, will not meet the being-foreign requirement.
        """
        new_treenode = Treenode()
        new_treenode.user = request.user
        new_treenode.editor = request.user
        new_treenode.project_id = project_id
        new_treenode.location_x = float(params['x'])
        new_treenode.location_y = float(params['y'])
        new_treenode.location_z = float(params['z'])
        new_treenode.radius = int(params['radius'])
        new_treenode.skeleton = skeleton
        new_treenode.confidence = int(params['confidence'])
        if parent_id:
            new_treenode.parent_id = parent_id
        new_treenode.save()
        return new_treenode

    def relate_neuron_to_skeleton(neuron, skeleton):
        return _create_relation(request.user, project_id,
                                relation_map['model_of'], skeleton, neuron)

    response_on_error = ''
    try:
        if -1 != int(params['parent_id']):  # A root node and parent node exist
            # Raise an Exception if the user doesn't have permission to edit
            # the neuron the skeleton of the treenode is modeling.
            can_edit_treenode_or_fail(request.user, project_id,
                                      params['parent_id'])

            parent_treenode = Treenode.objects.get(pk=params['parent_id'])

            response_on_error = 'Could not insert new treenode!'
            skeleton = ClassInstance.objects.get(
                pk=parent_treenode.skeleton_id)
            new_treenode = insert_new_treenode(params['parent_id'], skeleton)

            return HttpResponse(
                json.dumps({
                    'treenode_id': new_treenode.id,
                    'skeleton_id': skeleton.id
                }))
        else:
            # No parent node: We must create a new root node, which needs a
            # skeleton and a neuron to belong to.
            response_on_error = 'Could not insert new treenode instance!'

            new_skeleton = ClassInstance()
            new_skeleton.user = request.user
            new_skeleton.project_id = project_id
            new_skeleton.class_column_id = class_map['skeleton']
            new_skeleton.name = 'skeleton'
            new_skeleton.save()
            new_skeleton.name = 'skeleton %d' % new_skeleton.id
            new_skeleton.save()

            if -1 == params['useneuron']:
                # Check that the neuron to use exists
                if 0 == ClassInstance.objects.filter(
                        pk=params['useneuron']).count():
                    params['useneuron'] = -1

            if -1 != params['useneuron']:
                # Raise an Exception if the user doesn't have permission to
                # edit the existing neuron.
                can_edit_class_instance_or_fail(request.user,
                                                params['useneuron'], 'neuron')

                # A neuron already exists, so we use it
                response_on_error = 'Could not relate the neuron model to ' \
                                    'the new skeleton!'
                relate_neuron_to_skeleton(params['useneuron'], new_skeleton.id)

                response_on_error = 'Could not insert new treenode!'
                new_treenode = insert_new_treenode(None, new_skeleton)

                return HttpResponse(
                    json.dumps({
                        'treenode_id': new_treenode.id,
                        'skeleton_id': new_skeleton.id,
                        'neuron_id': params['useneuron']
                    }))
            else:
                # A neuron does not exist, therefore we put the new skeleton
                # into a new neuron.
                response_on_error = 'Failed to insert new instance of a neuron.'
                new_neuron = ClassInstance()
                new_neuron.user = request.user
                new_neuron.project_id = project_id
                new_neuron.class_column_id = class_map['neuron']
                new_neuron.name = 'neuron'
                new_neuron.save()
                new_neuron.name = 'neuron %d' % new_neuron.id
                new_neuron.save()

                response_on_error = 'Could not relate the neuron model to ' \
                                    'the new skeleton!'
                relate_neuron_to_skeleton(new_neuron.id, new_skeleton.id)

                response_on_error = 'Failed to insert instance of treenode.'
                new_treenode = insert_new_treenode(None, new_skeleton)

                response_on_error = 'Failed to write to logs.'
                new_location = (new_treenode.location_x,
                                new_treenode.location_y,
                                new_treenode.location_z)
                insert_into_log(
                    project_id, request.user.id, 'create_neuron', new_location,
                    'Create neuron %d and skeleton '
                    '%d' % (new_neuron.id, new_skeleton.id))

                return HttpResponse(
                    json.dumps({
                        'treenode_id': new_treenode.id,
                        'skeleton_id': new_skeleton.id,
                    }))

    except Exception as e:
        import traceback
        raise Exception(
            "%s: %s %s" %
            (response_on_error, str(e), str(traceback.format_exc())))
示例#28
0
文件: treenode.py 项目: pgunn/CATMAID
def _create_treenode(project_id,
                     creator,
                     editor,
                     x,
                     y,
                     z,
                     radius,
                     confidence,
                     neuron_id,
                     parent_id,
                     creation_time=None,
                     neuron_name=None):

    relation_map = get_relation_to_id_map(project_id)
    class_map = get_class_to_id_map(project_id)

    def insert_new_treenode(parent_id=None, skeleton_id=None):
        """ If the parent_id is not None and the skeleton_id of the parent does
        not match with the skeleton.id, then the database will throw an error
        given that the skeleton_id, being defined as foreign key in the
        treenode table, will not meet the being-foreign requirement.
        """
        new_treenode = Treenode()
        new_treenode.user = creator
        new_treenode.editor = editor
        new_treenode.project_id = project_id
        if creation_time:
            new_treenode.creation_time = creation_time
        new_treenode.location_x = float(x)
        new_treenode.location_y = float(y)
        new_treenode.location_z = float(z)
        new_treenode.radius = int(radius)
        new_treenode.skeleton_id = skeleton_id
        new_treenode.confidence = int(confidence)
        if parent_id:
            new_treenode.parent_id = parent_id
        new_treenode.save()
        return new_treenode

    def relate_neuron_to_skeleton(neuron, skeleton):
        return _create_relation(creator, project_id, relation_map['model_of'],
                                skeleton, neuron)

    response_on_error = ''
    try:
        if -1 != int(parent_id):  # A root node and parent node exist
            # Select the parent treenode for update to prevent race condition
            # updates to its skeleton ID while this node is being created.
            cursor = connection.cursor()
            cursor.execute(
                '''
                SELECT t.skeleton_id, t.edition_time FROM treenode t
                WHERE t.id = %s FOR NO KEY UPDATE OF t
                ''', (parent_id, ))

            if cursor.rowcount != 1:
                raise ValueError('Parent treenode %s does not exist' %
                                 parent_id)

            parent_node = cursor.fetchone()
            parent_skeleton_id = parent_node[0]
            parent_edition_time = parent_node[1]

            # Raise an Exception if the user doesn't have permission to edit
            # the neuron the skeleton of the treenode is modeling.
            can_edit_skeleton_or_fail(editor, project_id, parent_skeleton_id,
                                      relation_map['model_of'])

            response_on_error = 'Could not insert new treenode!'
            new_treenode = insert_new_treenode(parent_id, parent_skeleton_id)

            return NewTreenode(new_treenode.id, new_treenode.edition_time,
                               parent_skeleton_id, parent_edition_time)
        else:
            # No parent node: We must create a new root node, which needs a
            # skeleton and a neuron to belong to.
            response_on_error = 'Could not insert new treenode instance!'

            new_skeleton = ClassInstance()
            new_skeleton.user = creator
            new_skeleton.project_id = project_id
            new_skeleton.class_column_id = class_map['skeleton']
            new_skeleton.name = 'skeleton'
            new_skeleton.save()
            new_skeleton.name = 'skeleton %d' % new_skeleton.id
            new_skeleton.save()

            if -1 != neuron_id:
                # Check that the neuron to use exists
                if 0 == ClassInstance.objects.filter(pk=neuron_id).count():
                    neuron_id = -1

            if -1 != neuron_id:
                # Raise an Exception if the user doesn't have permission to
                # edit the existing neuron.
                can_edit_class_instance_or_fail(editor, neuron_id, 'neuron')

                # A neuron already exists, so we use it
                response_on_error = 'Could not relate the neuron model to ' \
                                    'the new skeleton!'
                relate_neuron_to_skeleton(neuron_id, new_skeleton.id)

                response_on_error = 'Could not insert new treenode!'
                new_treenode = insert_new_treenode(None, new_skeleton.id)

                return NewTreenode(new_treenode.id, new_treenode.edition_time,
                                   new_skeleton.id, None)
            else:
                # A neuron does not exist, therefore we put the new skeleton
                # into a new neuron.
                response_on_error = 'Failed to insert new instance of a neuron.'
                new_neuron = ClassInstance()
                new_neuron.user = creator
                new_neuron.project_id = project_id
                new_neuron.class_column_id = class_map['neuron']
                if neuron_name:
                    # Create a regular expression to find allowed patterns. The
                    # first group is the whole {nX} part, while the second group
                    # is X only.
                    counting_pattern = re.compile(r"(\{n(\d+)\})")
                    # Look for patterns, replace all {n} with {n1} to normalize.
                    neuron_name = neuron_name.replace("{n}", "{n1}")

                    if counting_pattern.search(neuron_name):
                        # Find starting values for each substitution.
                        counts = [
                            int(m.groups()[1])
                            for m in counting_pattern.finditer(neuron_name)
                        ]
                        # Find existing matching neurons in database.
                        name_match = counting_pattern.sub(
                            r"(\d+)", neuron_name)
                        name_pattern = re.compile(name_match)
                        matching_neurons = ClassInstance.objects.filter(
                            project_id=project_id,
                            class_column_id=class_map['neuron'],
                            name__regex=name_match).order_by('name')

                        # Increment substitution values based on existing neurons.
                        for n in matching_neurons:
                            for i, (count, g) in enumerate(
                                    zip(counts,
                                        name_pattern.search(n.name).groups())):
                                if count == int(g):
                                    counts[i] = count + 1

                        # Substitute values.
                        count_ind = 0
                        m = counting_pattern.search(neuron_name)
                        while m:
                            neuron_name = m.string[:m.start()] + str(
                                counts[count_ind]) + m.string[m.end():]
                            count_ind = count_ind + 1
                            m = counting_pattern.search(neuron_name)

                    new_neuron.name = neuron_name
                else:
                    new_neuron.name = 'neuron'
                    new_neuron.save()
                    new_neuron.name = 'neuron %d' % new_neuron.id

                new_neuron.save()

                response_on_error = 'Could not relate the neuron model to ' \
                                    'the new skeleton!'
                relate_neuron_to_skeleton(new_neuron.id, new_skeleton.id)

                response_on_error = 'Failed to insert instance of treenode.'
                new_treenode = insert_new_treenode(None, new_skeleton.id)

                response_on_error = 'Failed to write to logs.'
                new_location = (new_treenode.location_x,
                                new_treenode.location_y,
                                new_treenode.location_z)
                insert_into_log(
                    project_id, creator.id, 'create_neuron', new_location,
                    'Create neuron %d and skeleton '
                    '%d' % (new_neuron.id, new_skeleton.id))

                return NewTreenode(new_treenode.id, new_treenode.edition_time,
                                   new_skeleton.id, None)

    except Exception as e:
        import traceback
        raise Exception(
            "%s: %s %s" %
            (response_on_error, str(e), str(traceback.format_exc())))
示例#29
0
def classification_instance_operation(request, workspace_pid=None, project_id=None):
    workspace_pid = int(workspace_pid)
    params = {}
    int_keys = ('id', 'parentid', 'relationid', 'classid', 'linkid')
    str_keys = ('operation', 'title', 'rel', 'objname')
    for k in int_keys:
        params[k] = int(request.POST.get(k, 0))
    for k in str_keys:
        # TODO sanitize
        params[k] = request.POST.get(k, 0)

    relation_map = get_relation_to_id_map(workspace_pid)
    class_map = get_class_to_id_map(workspace_pid)

    # We avoid many try/except clauses by setting this string to be the
    # response we return if an exception is thrown.
    classification_instance_operation.res_on_err = ''

    def create_node():
        """ Creates a new node.
        """
        # TODO: Test if class and parent class instance exist
        # if params['classid'] not in class_map:
        #    raise CatmaidException('Failed to select class.')

        classification_instance_operation.res_on_err = 'Failed to insert instance of class.'
        node = ClassInstance(
                user=request.user,
                name=params['objname'])
        node.project_id = workspace_pid
        node.class_column_id = params['classid']
        node.save()
        class_name = node.class_column.class_name
        insert_into_log(project_id, request.user.id, "create_%s" % class_name,
            None, "Created %s with ID %s" % (class_name, params['id']))

        # We need to connect the node to its parent, or to root if no valid parent is given.
        node_parent_id = params['parentid']
        # TODO: Test if tis parent exists

        #if 0 == params['parentid']:
        #    # Find root element
        #    classification_instance_operation.res_on_err = 'Failed to select classification root.'
        #    node_parent_id = ClassInstance.objects.filter(
        #            project=workspace_pid,
        #            class_column=class_map['classification_root'])[0].id

        #Relation.objects.filter(id=params['relationid'])
        #if params['relationname'] not in relation_map:
        #    raise CatmaidException('Failed to select relation %s' % params['relationname'])

        classification_instance_operation.res_on_err = 'Failed to insert CICI-link.'
        cici = ClassInstanceClassInstance()
        cici.user = request.user
        cici.project_id = workspace_pid
        cici.relation_id = params['relationid']
        cici.class_instance_a_id = node.id
        cici.class_instance_b_id = node_parent_id
        cici.save()

        return HttpResponse(json.dumps({'class_instance_id': node.id}))

    def remove_node():
        """ Will remove a node.
        """
        # A class instance can be linked to different other class instances. This
        # operation will remove a complete class instance and thus *all* links to
        # other class instances.
        if 0 == params['rel']:
            raise Exception('No node type given!')
        elif 'element' == params['rel']:
            # Delete a standard non-root element and its sub-tree.

            def delete_node( node ):
                # Find and delete children
                classification_instance_operation.res_on_err \
                    = 'Failed to delete relation from instance table.'
                cici = ClassInstanceClassInstance.objects.filter(class_instance_b=node.id)
                for rel in cici:
                    # Delete children
                    delete_node( rel.class_instance_a )

                # Delete class instance
                node.delete()

                # Log
                insert_into_log(project_id, request.user.id, 'remove_element', None,
                    'Removed classification with ID %s and name %s' % (params['id'],
                        params['title']))

            classification_instance_operation.res_on_err \
                = 'Failed to select node from instance table.'
            node_to_delete = ClassInstance.objects.filter(id=params['id'])
            if node_to_delete.count() == 0:
                raise Exception('Could not find any node with ID %s' % params['id'])
            else:
                delete_node( node_to_delete[0] )
                response = {'status': 1, 'message': 'Removed node %s successfully.' % params['id']}
                return HttpResponse(json.dumps(response))
        else:
            classification_instance_operation.res_on_err \
                = 'Failed to delete node from instance table.'
            node_to_delete = ClassInstance.objects.filter(id=params['id'])
            if node_to_delete.count() == 0:
                raise Exception('Could not find any node with ID %s' % params['id'])
            else:
                node_to_delete.delete()
                response = {'status': 1, 'message': 'Removed node %s successfully.' % params['id']}
                return HttpResponse(json.dumps(response))

    try:
        # Dispatch to operation
        if params['operation'] not in ['create_node', 'remove_node']:
            raise Exception('No operation called %s.' % params['operation'])
        return locals()[params['operation']]()
    except Exception as e:
        if classification_instance_operation.res_on_err == '':
            raise
        else:
            raise Exception(classification_instance_operation.res_on_err + '\n' + str(e))
示例#30
0
文件: ontology.py 项目: pgunn/CATMAID
def get_available_classes(request, project_id=None):
    """ Returns a simple list of all classes available available
    for the given project."""
    class_map = get_class_to_id_map(project_id)
    return JsonResponse(class_map)
示例#31
0
def create_treenode(request, project_id=None):
    """
    Add a new treenode to the database
    ----------------------------------

    1. Add new treenode for a given skeleton id. Parent should not be empty.
       return: new treenode id
       If the parent's skeleton has a single node and belongs to the
       'Isolated synaptic terminals' group, then reassign ownership
       of the skeleton and the neuron to the user. The treenode remains
       property of the original user who created it.

    2. Add new treenode (root) and create a new skeleton (maybe for a given
       neuron) return: new treenode id and skeleton id.

    If a neuron id is given, use that one to create the skeleton as a model of
    it.
    """

    params = {}
    float_values = {
            'x': 0,
            'y': 0,
            'z': 0,
            'radius': 0}
    int_values = {
            'confidence': 0,
            'useneuron': -1,
            'parent_id': -1}
    string_values = {}
    for p in float_values.keys():
        params[p] = float(request.POST.get(p, float_values[p]))
    for p in int_values.keys():
        params[p] = int(request.POST.get(p, int_values[p]))
    for p in string_values.keys():
        params[p] = request.POST.get(p, string_values[p])

    relation_map = get_relation_to_id_map(project_id)
    class_map = get_class_to_id_map(project_id)

    def insert_new_treenode(parent_id=None, skeleton=None):
        """ If the parent_id is not None and the skeleton_id of the parent does
        not match with the skeleton.id, then the database will throw an error
        given that the skeleton_id, being defined as foreign key in the
        treenode table, will not meet the being-foreign requirement.
        """
        new_treenode = Treenode()
        new_treenode.user = request.user
        new_treenode.editor = request.user
        new_treenode.project_id = project_id
        new_treenode.location_x = float(params['x'])
        new_treenode.location_y = float(params['y'])
        new_treenode.location_z = float(params['z'])
        new_treenode.radius = int(params['radius'])
        new_treenode.skeleton = skeleton
        new_treenode.confidence = int(params['confidence'])
        if parent_id:
            new_treenode.parent_id = parent_id
        new_treenode.save()
        return new_treenode

    def relate_neuron_to_skeleton(neuron, skeleton):
        return _create_relation(request.user, project_id,
                                relation_map['model_of'], skeleton, neuron)

    response_on_error = ''
    try:
        if -1 != int(params['parent_id']):  # A root node and parent node exist
            # Raise an Exception if the user doesn't have permission to edit
            # the neuron the skeleton of the treenode is modeling.
            can_edit_treenode_or_fail(request.user, project_id, params['parent_id'])

            parent_treenode = Treenode.objects.get(pk=params['parent_id'])

            response_on_error = 'Could not insert new treenode!'
            skeleton = ClassInstance.objects.get(pk=parent_treenode.skeleton_id)
            new_treenode = insert_new_treenode(params['parent_id'], skeleton)

            return HttpResponse(json.dumps({
                'treenode_id': new_treenode.id,
                'skeleton_id': skeleton.id
            }))
        else:
            # No parent node: We must create a new root node, which needs a
            # skeleton and a neuron to belong to.
            response_on_error = 'Could not insert new treenode instance!'

            new_skeleton = ClassInstance()
            new_skeleton.user = request.user
            new_skeleton.project_id = project_id
            new_skeleton.class_column_id = class_map['skeleton']
            new_skeleton.name = 'skeleton'
            new_skeleton.save()
            new_skeleton.name = 'skeleton %d' % new_skeleton.id
            new_skeleton.save()

            if -1 == params['useneuron']:
                # Check that the neuron to use exists
                if 0 == ClassInstance.objects.filter(pk=params['useneuron']).count():
                    params['useneuron'] = -1

            if -1 != params['useneuron']:
                # Raise an Exception if the user doesn't have permission to
                # edit the existing neuron.
                can_edit_class_instance_or_fail(request.user,
                                                params['useneuron'], 'neuron')

                # A neuron already exists, so we use it
                response_on_error = 'Could not relate the neuron model to ' \
                                    'the new skeleton!'
                relate_neuron_to_skeleton(params['useneuron'], new_skeleton.id)

                response_on_error = 'Could not insert new treenode!'
                new_treenode = insert_new_treenode(None, new_skeleton)

                return HttpResponse(json.dumps({
                    'treenode_id': new_treenode.id,
                    'skeleton_id': new_skeleton.id,
                    'neuron_id': params['useneuron']}))
            else:
                # A neuron does not exist, therefore we put the new skeleton
                # into a new neuron.
                response_on_error = 'Failed to insert new instance of a neuron.'
                new_neuron = ClassInstance()
                new_neuron.user = request.user
                new_neuron.project_id = project_id
                new_neuron.class_column_id = class_map['neuron']
                new_neuron.name = 'neuron'
                new_neuron.save()
                new_neuron.name = 'neuron %d' % new_neuron.id
                new_neuron.save()

                response_on_error = 'Could not relate the neuron model to ' \
                                    'the new skeleton!'
                relate_neuron_to_skeleton(new_neuron.id, new_skeleton.id)

                response_on_error = 'Failed to insert instance of treenode.'
                new_treenode = insert_new_treenode(None, new_skeleton)

                response_on_error = 'Failed to write to logs.'
                new_location = (new_treenode.location_x, new_treenode.location_y,
                                new_treenode.location_z)
                insert_into_log(project_id, request.user.id, 'create_neuron',
                                new_location, 'Create neuron %d and skeleton '
                                '%d' % (new_neuron.id, new_skeleton.id))

                return HttpResponse(json.dumps({
                    'treenode_id': new_treenode.id,
                    'skeleton_id': new_skeleton.id,
                    }))

    except Exception as e:
        import traceback
        raise Exception("%s: %s %s" % (response_on_error, str(e),
                                       str(traceback.format_exc())))
示例#32
0
def list_connectors(request, project_id=None):
    """Get a collection of connectors.

    The `connectors` field of the returned object contains a list of all result
    nodes, each represented as a list of the form:

    `[id, x, y, z, confidence, creator_id, editor_id, creation_time, edition_time]`

    Both edition time and creation time are returned as UTC epoch values. If
    tags are requested, the `tags` field of the response object will contain a
    mapping of connector IDs versus tag lists. If partners are requested, the
    `partners` field of the response object will contain a mapping of connector
    IDs versus lists of partner links. Each partner link is an array of the
    following format:

    `[link_id, treenode_id, skeleton_id, relation_id, confidence]`

    If both `skeleton_ids` and `relation_type` are used, the linked skeletons
    need to be linked by the specified relation. Without `relation_type`,
    linked skeletons can have any relation and without `skeleton_ids` a
    connector needs to have a least one link with the specified relation.
    ---
    parameters:
      - name: project_id
        description: Project of connectors
        type: integer
        paramType: path
        required: true
      - name: skeleton_ids
        description: Skeletons linked to connectors
        type: array
        items:
          type: integer
        paramType: form
        required: false
      - name: tags
        description: Require a set of tags
        type: array
        items:
          type: string
        paramType: form
        required: false
      - name: relation_type
        description: Relation of linked skeletons to connector.
        type: string
        paramType: form
        required: false
      - name: with_tags
        description: If connector tags should be fetched
        type: boolean
        paramType: form
        defaultValue: true
        required: false
      - name: with_partners
        description: If partner node and link information should be fetched
        type: boolean
        paramType: form
        defaultValue: false
        required: false
    type:
      connectors:
        type: array
        items:
          type: array
          items:
            type: string
        description: Matching connector links
        required: true
      tags:
         type array
      partners:
         type array
    """
    project_id = int(project_id)
    skeleton_ids = get_request_list(request.POST, 'skeleton_ids', map_fn=int)
    tags = get_request_list(request.POST, 'tags')
    relation_type = request.POST.get('relation_type')
    with_tags = get_request_bool(request.POST, 'with_tags', True)
    with_partners = get_request_bool(request.POST, 'with_partners', False)

    cursor = connection.cursor()
    class_map = get_class_to_id_map(project_id, cursor=cursor)
    relation_map = get_relation_to_id_map(project_id, cursor=cursor)

    if relation_type:
        relation_id = relation_map.get(relation_type)
        if not relation_id:
            raise ValueError("Unknown relation: " + relation_type)

    # Query connectors
    constraints = []
    params = []

    if skeleton_ids:
        sk_template = ",".join("(%s)" for _ in skeleton_ids)
        constraints.append('''
            JOIN treenode_connector tc
                ON tc.connector_id = c.id
            JOIN (VALUES {}) q_skeleton(id)
                ON tc.skeleton_id = q_skeleton.id
        '''.format(sk_template))
        params.extend(skeleton_ids)
        if relation_type:
            constraints.append('''
                AND tc.relation_id = %s
            ''')
            params.append(relation_id)
    elif relation_type:
        constraints.append('''
            JOIN treenode_connector tc
                ON tc.connector_id = c.id
                AND tc.relation_id = %s
        ''')
        params.append(relation_id)

    if tags:
        tag_template = ",".join("%s" for _ in tags)
        constraints.append('''
            JOIN connector_class_instance cci
                ON cci.connector_id = c.id
            JOIN class_instance label
                ON label.id = class_instance_id
                AND cci.relation_id = %s
            JOIN (
                SELECT id
                FROM class_instance
                WHERE name IN ({})
                    AND project_id = %s
                    AND class_id = %s
            ) q_label(id) ON label.id = q_label.id
        '''.format(tag_template))
        params.append(relation_map['labeled_as'])
        params.extend(tags)
        params.append(project_id)
        params.append(class_map['label'])

    query = '''
        SELECT DISTINCT c.id, c.location_x, c.location_y, c.location_z, c.confidence,
            c.user_id, c.editor_id, EXTRACT(EPOCH FROM c.creation_time),
            EXTRACT(EPOCH FROM c.edition_time)
        FROM connector c
        {}
        WHERE c.project_id = %s
        ORDER BY c.id
    '''.format('\n'.join(constraints))
    params.append(project_id)

    cursor.execute(query, params)

    connectors = cursor.fetchall()

    connector_ids = [c[0] for c in connectors]
    tags = defaultdict(list)
    if connector_ids and with_tags:
        c_template = ",".join("(%s)" for _ in connector_ids)
        cursor.execute('''
            SELECT cci.connector_id, ci.name
            FROM connector_class_instance cci
            JOIN (VALUES {}) q_connector(id)
                ON cci.connector_id = q_connector.id
            JOIN (VALUES (%s)) q_relation(id)
                ON cci.relation_id = q_relation.id
            JOIN class_instance ci
                ON cci.class_instance_id = ci.id
        '''.format(c_template), connector_ids + [relation_map['labeled_as']])

        for row in cursor.fetchall():
            tags[row[0]].append(row[1])

        # Sort labels by name
        for connector_id, labels in tags.items():
            labels.sort(key=lambda k: k.upper())

    partners = defaultdict(list)
    if connector_ids and with_partners:
        c_template = ",".join("(%s)" for _ in connector_ids)
        cursor.execute('''
            SELECT tc.connector_id, tc.id, tc.treenode_id, tc.skeleton_id,
                tc.relation_id, tc.confidence, tc.user_id,
                EXTRACT(EPOCH FROM tc.creation_time),
                EXTRACT(EPOCH FROM tc.edition_time)
            FROM treenode_connector tc
            JOIN (VALUES {}) c(id)
                ON tc.connector_id = c.id
        '''.format(c_template), connector_ids)

        for row in cursor.fetchall():
            partners[row[0]].append(row[1:])

    return JsonResponse({
        "connectors": connectors,
        "tags": tags,
        "partners": partners
    }, safe=False)
示例#33
0
def list_connectors(request:HttpRequest, project_id=None) -> JsonResponse:
    """Get a collection of connectors.

    The `connectors` field of the returned object contains a list of all result
    nodes, each represented as a list of the form:

    `[id, x, y, z, confidence, creator_id, editor_id, creation_time, edition_time]`

    Both edition time and creation time are returned as UTC epoch values. If
    tags are requested, the `tags` field of the response object will contain a
    mapping of connector IDs versus tag lists. If partners are requested, the
    `partners` field of the response object will contain a mapping of connector
    IDs versus lists of partner links. Each partner link is an array of the
    following format:

    `[link_id, treenode_id, skeleton_id, relation_id, confidence]`

    If both `skeleton_ids` and `relation_type` are used, the linked skeletons
    need to be linked by the specified relation. Without `relation_type`,
    linked skeletons can have any relation and without `skeleton_ids` a
    connector needs to have a least one link with the specified relation.
    ---
    parameters:
      - name: project_id
        description: Project of connectors
        type: integer
        paramType: path
        required: true
      - name: skeleton_ids
        description: Skeletons linked to connectors
        type: array
        items:
          type: integer
        paramType: form
        required: false
      - name: tags
        description: Require a set of tags
        type: array
        items:
          type: string
        paramType: form
        required: false
      - name: relation_type
        description: Relation of linked skeletons to connector.
        type: string
        paramType: form
        required: false
      - name: without_relation_types
        description: |
            Relations to linked skeletons that connectors must not have.
        type: array
        items:
          type: string
        paramType: form
        required: false
      - name: with_tags
        description: If connector tags should be fetched
        type: boolean
        paramType: form
        defaultValue: true
        required: false
      - name: with_partners
        description: If partner node and link information should be fetched
        type: boolean
        paramType: form
        defaultValue: false
        required: false
    type:
      connectors:
        type: array
        items:
          type: array
          items:
            type: string
        description: Matching connector links
        required: true
      tags:
         type array
      partners:
         type array
    """
    project_id = int(project_id)
    skeleton_ids = get_request_list(request.POST, 'skeleton_ids', map_fn=int)
    tags = get_request_list(request.POST, 'tags')
    relation_type = request.POST.get('relation_type')
    without_relation_types = get_request_list(request.POST, 'without_relation_types')
    with_tags = get_request_bool(request.POST, 'with_tags', True)
    with_partners = get_request_bool(request.POST, 'with_partners', False)

    cursor = connection.cursor()
    class_map = get_class_to_id_map(project_id, cursor=cursor)
    relation_map = get_relation_to_id_map(project_id, cursor=cursor)

    # Query connectors
    constraints = []
    extra_where = []
    params:Dict = {
        'project_id': project_id,
    }

    if relation_type:
        relation_id = relation_map.get(relation_type)
        params['relation_id'] = relation_id
        if not relation_id:
            raise ValueError("Unknown relation: " + relation_type)

    if skeleton_ids:
        constraints.append('''
            JOIN treenode_connector tc
                ON tc.connector_id = c.id
            JOIN UNNEST(%(skeleton_ids)s::bigint[]) q_skeleton(id)
                ON tc.skeleton_id = q_skeleton.id
        ''')
        params['skeleton_ids'] = skeleton_ids
        if relation_type:
            constraints.append('''
                AND tc.relation_id = %(relation_id)s
            ''')
    elif relation_type:
        constraints.append('''
            JOIN treenode_connector tc_rel
                ON tc_rel.connector_id = c.id
                AND tc_rel.relation_id = %(relation_id)s
        ''')

    if without_relation_types:
        # Only connectors without the passed in relations. This is done through
        # an anti-join.
        try:
            wo_rel_ids = list(map(lambda x: relation_map[x], without_relation_types))
        except KeyError:
            missing_relations = ", ".join(filter(lambda x: x not in relation_map, without_relation_types))
            raise ValueError(f'Unknown relation: {missing_relations}')
        constraints.append('''
            LEFT JOIN treenode_connector tc_wo
                ON tc_wo.connector_id = c.id
                AND tc_wo.relation_id  = ANY (%(wo_rel_ids)s::bigint[])
        ''')
        extra_where.append('''
            tc_wo.id IS NULL
        ''')

        params['wo_rel_ids'] = wo_rel_ids

    if tags:
        constraints.append('''
            JOIN connector_class_instance cci
                ON cci.connector_id = c.id
            JOIN class_instance label
                ON label.id = class_instance_id
                AND cci.relation_id = %(labeled_as)s
            JOIN (
                SELECT class_instance.id
                FROM class_instance
                JOIN UNNEST(%(tag_names)s::text[]) tag(name)
                    ON tag.name = class_instance.name
                WHERE project_id = %(project_id)s
                    AND class_id = %(label)s
            ) q_label(id) ON label.id = q_label.id
        ''')
        params['labeled_as'] = relation_map['labeled_as']
        params['tag_names'] = tags
        params['label'] = class_map['label']

    constlines = "\n".join(constraints)
    extra_where_lines = ("AND " + " AND ".join(extra_where)) if extra_where else ""
    cursor.execute(f'''
        SELECT DISTINCT ON (c.id) c.id, c.location_x, c.location_y, c.location_z, c.confidence,
            c.user_id, c.editor_id, EXTRACT(EPOCH FROM c.creation_time),
            EXTRACT(EPOCH FROM c.edition_time)
        FROM connector c
        {constlines}
        WHERE c.project_id = %(project_id)s
        {extra_where_lines}
        ORDER BY c.id
    ''', params)

    connectors = cursor.fetchall()

    connector_ids = [c[0] for c in connectors]
    tags = defaultdict(list)
    if connector_ids and with_tags:
        c_template = ",".join("(%s)" for _ in connector_ids)
        cursor.execute(f'''
            SELECT cci.connector_id, ci.name
            FROM connector_class_instance cci
            JOIN (VALUES {c_template}) q_connector(id)
                ON cci.connector_id = q_connector.id
            JOIN (VALUES (%s)) q_relation(id)
                ON cci.relation_id = q_relation.id
            JOIN class_instance ci
                ON cci.class_instance_id = ci.id
        ''', connector_ids + [relation_map['labeled_as']])

        for row in cursor.fetchall():
            tags[row[0]].append(row[1])

        # Sort labels by name
        for connector_id, labels in tags.items():
            labels.sort(key=lambda k: k.upper())

    partners:DefaultDict[Any, List] = defaultdict(list)
    if connector_ids and with_partners:
        c_template = ",".join("(%s)" for _ in connector_ids)
        cursor.execute(f'''
            SELECT tc.connector_id, tc.id, tc.treenode_id, tc.skeleton_id,
                tc.relation_id, tc.confidence, tc.user_id,
                EXTRACT(EPOCH FROM tc.creation_time),
                EXTRACT(EPOCH FROM tc.edition_time)
            FROM treenode_connector tc
            JOIN (VALUES {c_template}) c(id)
                ON tc.connector_id = c.id
        ''', connector_ids)

        for row in cursor.fetchall():
            partners[row[0]].append(row[1:])

    return JsonResponse({
        "connectors": connectors,
        "tags": tags,
        "partners": partners
    }, safe=False)
示例#34
0
def list_connectors(request, project_id=None):
    """Get a collection of connectors.

    The `connectors` field of the returned object contains a list of all result
    nodes, each represented as a list of the form:

    `[id, x, y, z, confidence, creator_id, editor_id, creation_time, edition_time]`

    Both edition time and creation time are returned as UTC epoch values. If
    tags are requested, the `tags` field of the response object will contain a
    mapping of connector IDs versus tag lists. If partners are requested, the
    `partners` field of the response object will contain a mapping of connector
    IDs versus lists of partner links. Each partner link is an array of the
    following format:

    `[link_id, treenode_id, skeleton_id, relation_id, confidence]`

    If both `skeleton_ids` and `relation_type` are used, the linked skeletons
    need to be linked by the specified relation. Without `relation_type`,
    linked skeletons can have any relation and without `skeleton_ids` a
    connector needs to have a least one link with the specified relation.
    ---
    parameters:
      - name: project_id
        description: Project of connectors
        type: integer
        paramType: path
        required: true
      - name: skeleton_ids
        description: Skeletons linked to connectors
        type: array
        items:
          type: integer
        paramType: form
        required: false
      - name: tags
        description: Require a set of tags
        type: array
        items:
          type: string
        paramType: form
        required: false
      - name: relation_type
        description: Relation of linked skeletons to connector.
        type: string
        paramType: form
        required: false
      - name: with_tags
        description: If connector tags should be fetched
        type: boolean
        paramType: form
        defaultValue: true
        required: false
      - name: with_partners
        description: If partner node information should be fetched
        type: boolean
        paramType: form
        defaultValue: false
        required: false
    type:
      connectors:
        type: array
        items:
          type: array
          items:
            type: string
        description: Matching connector links
        required: true
      tags:
         type array
      partners:
         type array
    """
    project_id = int(project_id)
    skeleton_ids = get_request_list(request.POST, 'skeleton_ids', map_fn=int)
    tags = get_request_list(request.POST, 'tags')
    relation_type = request.POST.get('relation_type')
    with_tags = get_request_bool(request.POST, 'with_tags', True)
    with_partners = get_request_bool(request.POST, 'with_partners', False)

    cursor = connection.cursor()
    class_map = get_class_to_id_map(project_id, cursor=cursor)
    relation_map = get_relation_to_id_map(project_id, cursor=cursor)

    if relation_type:
        relation_id = relation_map.get(relation_type)
        if not relation_id:
            raise ValueError("Unknown relation: " + relation_type)

    # Query connectors
    constraints = []
    params = []

    if skeleton_ids:
        sk_template = ",".join("(%s)" for _ in skeleton_ids)
        constraints.append('''
            JOIN treenode_connector tc
                ON tc.connector_id = c.id
            JOIN (VALUES {}) q_skeleton(id)
                ON tc.skeleton_id = q_skeleton.id
        '''.format(sk_template))
        params.extend(skeleton_ids)
        if relation_type:
            constraints.append('''
                AND tc.relation_id = %s
            ''')
            params.append(relation_id)
    elif relation_type:
        constraints.append('''
            JOIN treenode_connector tc
                ON tc.connector_id = c.id
                AND tc.relation_id = %s
        ''')
        params.append(relation_id)

    if tags:
        tag_template = ",".join("%s" for _ in tags)
        constraints.append('''
            JOIN connector_class_instance cci
                ON cci.connector_id = c.id
            JOIN class_instance label
                ON label.id = class_instance_id
                AND cci.relation_id = %s
            JOIN (
                SELECT id
                FROM class_instance
                WHERE name IN ({})
                    AND project_id = %s
                    AND class_id = %s
            ) q_label(id) ON label.id = q_label.id
        '''.format(tag_template))
        params.append(relation_map['labeled_as'])
        params.extend(tags)
        params.append(project_id)
        params.append(class_map['label'])

    query = '''
        SELECT DISTINCT c.id, c.location_x, c.location_y, c.location_z, c.confidence,
            c.user_id, c.editor_id, EXTRACT(EPOCH FROM c.creation_time),
            EXTRACT(EPOCH FROM c.edition_time)
        FROM connector c
        {}
        WHERE c.project_id = %s
        ORDER BY c.id
    '''.format('\n'.join(constraints))
    params.append(project_id)

    cursor.execute(query, params)

    connectors = cursor.fetchall()

    connector_ids = [c[0] for c in connectors]
    tags = defaultdict(list)
    if connector_ids and with_tags:
        c_template = ",".join("(%s)" for _ in connector_ids)
        cursor.execute(
            '''
            SELECT cci.connector_id, ci.name
            FROM connector_class_instance cci
            JOIN (VALUES {}) q_connector(id)
                ON cci.connector_id = q_connector.id
            JOIN (VALUES (%s)) q_relation(id)
                ON cci.relation_id = q_relation.id
            JOIN class_instance ci
                ON cci.class_instance_id = ci.id
        '''.format(c_template), connector_ids + [relation_map['labeled_as']])

        for row in cursor.fetchall():
            tags[row[0]].append(row[1])

        # Sort labels by name
        for connector_id, labels in six.iteritems(tags):
            labels.sort(key=lambda k: k.upper())

    partners = defaultdict(list)
    if connector_ids and with_partners:
        c_template = ",".join("(%s)" for _ in connector_ids)
        cursor.execute(
            '''
            SELECT tc.connector_id, tc.id, tc.treenode_id, tc.skeleton_id,
                tc.relation_id, tc.confidence
            FROM treenode_connector tc
            JOIN (VALUES {}) c(id)
                ON tc.connector_id = c.id
        '''.format(c_template), connector_ids)

        for row in cursor.fetchall():
            partners[row[0]].append(row[1:])

    return JsonResponse(
        {
            "connectors": connectors,
            "tags": tags,
            "partners": partners
        },
        safe=False)
示例#35
0
def list_annotations(request, project_id=None):
    """List annotations matching filtering criteria that are currently in use.

    The result set is the intersection of annotations matching criteria (the
    criteria are conjunctive) unless stated otherwise.
    ---
    parameters:
      - name: annotations
        description: A list of (meta) annotations with which which resulting annotations should be annotated with.
        paramType: form
        type: array
        items:
            type: integer
            description: An annotation ID
      - name: annotates
        description: A list of entity IDs (like annotations and neurons) that should be annotated by the result set.
        paramType: form
        type: array
        items:
            type: integer
            description: An entity ID
      - name: parallel_annotations
        description: A list of annotation that have to be used alongside the result set.
        paramType: form
        type: array
        items:
            type: integer
            description: An annotation ID
      - name: user_id
        description: Result annotations have to be used by this user.
        paramType: form
        type: integer
      - name: neuron_id
        description: Result annotations will annotate this neuron.
        paramType: form
        type: integer
      - name: skeleton_id
        description: Result annotations will annotate the neuron modeled by this skeleton.
        paramType: form
        type: integer
      - name: ignored_annotations
        description: A list of annotation names that will be excluded from the result set.
        paramType: form
        type: array
        items:
            type: string
    models:
      annotation_user_list_element:
        id: annotation_user_list_element
        properties:
          id:
            type: integer
            name: id
            description: The user id
            required: true
          name:
            type: string
            name: name
            description: The user name
            required: true
      annotation_list_element:
        id: annotation_list_element
        description: Represents one annotation along with its users.
        properties:
          name:
            type: string
            description: The name of the annotation
            required: true
          id:
            type: integer
            description: The id of the annotation
            required: true
          users:
            type: array
            description: A list of users
            required: true
            items:
              $ref: annotation_user_list_element
    type:
      - type: array
        items:
          $ref: annotation_list_element
        required: true
    """

    if not request.POST:
        cursor = connection.cursor()
        classes = get_class_to_id_map(project_id, ('annotation', ), cursor)
        relations = get_relation_to_id_map(project_id, ('annotated_with', ),
                                           cursor)

        cursor.execute(
            '''
            SELECT DISTINCT ci.name, ci.id, u.id, u.username
            FROM class_instance ci
            LEFT OUTER JOIN class_instance_class_instance cici
                         ON (ci.id = cici.class_instance_b)
            LEFT OUTER JOIN auth_user u
                         ON (cici.user_id = u.id)
            WHERE (ci.class_id = %s AND (cici.relation_id = %s OR cici.id IS NULL));
                       ''',
            (classes['annotation'], relations['annotated_with']))
        annotation_tuples = cursor.fetchall()
    else:
        annotation_query = create_annotation_query(project_id, request.POST)
        annotation_tuples = annotation_query.distinct().values_list(
            'name', 'id', 'cici_via_b__user__id', 'cici_via_b__user__username')

    # Create a set mapping annotation names to its users
    ids = {}
    annotation_dict = {}
    for annotation, aid, uid, username in annotation_tuples:
        ids[aid] = annotation
        ls = annotation_dict.get(aid)
        if ls is None:
            ls = []
            annotation_dict[aid] = ls
        if uid is not None:
            ls.append({'id': uid, 'name': username})
    # Flatten dictionary to list
    annotations = tuple({
        'name': ids[aid],
        'id': aid,
        'users': users
    } for aid, users in annotation_dict.iteritems())
    return JsonResponse({'annotations': annotations})
示例#36
0
文件: tree.py 项目: AdaEne/CATMAID
def tree_object_list(request, project_id=None):
    parent_id = int(request.POST.get('parentid', 0))
    parent_name = request.POST.get('parentname', '')
    expand_request = request.POST.get('expandtarget', None)
    if expand_request is None:
        expand_request = tuple()
    else:
        # Parse to int to sanitize
        expand_request = tuple(int(x) for x in expand_request.split(','))

    max_nodes = 5000  # Limit number of nodes retrievable.

    relation_map = get_relation_to_id_map(project_id)
    class_map = get_class_to_id_map(project_id)

    # First, check if the tracing system is correctly set-up
    setup_okay, mc, mr, mci = check_tracing_setup_detailed(project_id,
        class_map, relation_map, check_root_ci=False)
    if not setup_okay:
        # Check permissions
        can_administer = request.user.has_perm('can_administer', project_id)
        # Find missing links and classes
        return HttpResponse(json.dumps(
            {'needs_setup': True,
             'missing_classes': mc,
             'missing_relations': mr,
             'missing_classinstances': mci,
             'has_needed_permissions': can_administer}))

    response_on_error = ''
    try:
        if 0 == parent_id:
            response_on_error = 'Could not select the id of the root node.'
            root_node_q = ClassInstance.objects.filter(
                project=project_id,
                class_column=class_map['root'])

            if 0 == root_node_q.count():
                root_id = 0
                root_name = 'noname'
            else:
                root_node = root_node_q[0]
                root_id = root_node.id
                root_name = root_node.name

            return HttpResponse(json.dumps([{
                'data': {'title': root_name},
                'attr': {'id': 'node_%s' % root_id, 'rel': 'root'},
                'state': 'closed'}]))

        if 'Isolated synaptic terminals' in parent_name:
            response_on_error = 'Failed to find children of the Isolated synaptic terminals'
            c = connection.cursor()

            if not expand_request:
                return HttpResponse(json.dumps([]))

            neuron_id = expand_request[-2]

            c.execute('''
                    SELECT class_instance.name
                    FROM class_instance
                    WHERE class_instance.id = %s
                    ''', [neuron_id])

            row = c.fetchone()

            return HttpResponse(json.dumps([{
                'data': {'title': row[0]},
                'attr': {'id': 'node_%s' % neuron_id, 'rel': 'neuron'},
                'state': 'closed'}]))


        # parent_name is not 'Isolated synaptic terminals'
        response_on_error = 'Could not retrieve child nodes.'
        c = connection.cursor()
        # Must select the user as well because the user who created the skeleton may be differen
        # than the user who puts the request for the listing in the Object Tree.
        c.execute('''
                SELECT ci.id,
                       ci.name,
                       "auth_user".username AS username,
                       cl.class_name
                FROM class_instance AS ci
                    INNER JOIN class_instance_class_instance AS cici
                    ON ci.id = cici.class_instance_a
                    INNER JOIN class AS cl
                    ON ci.class_id = cl.id
                    INNER JOIN "auth_user"
                    ON ci.user_id = "auth_user".id
                WHERE cici.class_instance_b = %s
                  AND (cici.relation_id = %s
                       OR cici.relation_id = %s
                       OR cici.relation_id = %s)
                ORDER BY ci.class_id DESC, ci.name ASC
                LIMIT %s''', (
            parent_id,
            relation_map['model_of'],
            relation_map['annotated_with'],
            relation_map['part_of'],
            max_nodes))

        return HttpResponse(json.dumps(
                    tuple({'data': {'title': row[1] if not 'skeleton' == row[1] else '%s (%s)' % (row[1], row[2])},
                           'attr': {'id': 'node_%s' % row[0],
                                    'rel': string.replace(row[3], ' ', '')},
                           'state': 'closed'} for row in c.fetchall())))

    except Exception as e:
        raise Exception(response_on_error + ':' + str(e))
示例#37
0
文件: ontology.py 项目: pgunn/CATMAID
def list_ontology(request, project_id=None):
    root_class = request.GET.get('rootclass', None)
    parent_id = int(request.GET.get('parentid', 0))
    expand_request = request.GET.get('expandtarget', None)
    parent_type = request.GET.get('parenttype', "relation")
    class_b_id  = int(request.GET.get('classbid', 0))
    if expand_request is None:
        expand_request = tuple()
    else:
        # Parse to int to sanitize
        expand_request = tuple(int(x) for x in expand_request.split(','))

    relation_map = get_relation_to_id_map(project_id)
    class_map = get_class_to_id_map(project_id)

    response_on_error = ''
    try:
        if parent_type == "relation":
            # A class is wanted
            if 0 == parent_id:
                response_on_error = 'Could not select the id of any ontology root node'
                # If the no root class is explicitely requested, return all known
                # root classes.
                root_class_ids = []
                if root_class is None:
                    for rc in root_classes:
                        if rc in class_map:
                            root_class_ids.append( class_map[rc] )
                    if len(root_class_ids) == 0:
                        warning = {'warning': 'Could not find any of the known root classes. ' \
                            'Please add at least one of them to build an ontology.'}
                        return JsonResponse(warning)
                else:
                    if root_class not in class_map:
                        raise Exception('Root class "{0}" not found'.format( root_class ))
                    root_class_ids = [ class_map[root_class] ]

                root_node_q = Class.objects.filter(id__in=root_class_ids,
                    project=project_id)

                # Make sure we actually got at least one root node
                if 0 == len(root_node_q):
                    raise Exception("Couldn't select any root node")

                roots = []
                for root_node in root_node_q:
                    root_id = root_node.id
                    root_name = root_node.class_name
                    num_children = ClassClass.objects.filter(
                        class_b=root_id, project=project_id).count()

                    data = {
                        'id': root_id,
                        'text': '%s (%d)' % (root_name, root_id),
                        'type': 'root',
                        'cname': root_name
                    }
                    # Test if there are links present and mark the root
                    # as leaf if there are none.
                    if num_children > 0:
                        data['state'] = {
                            'opened': False
                        }
                    # Add this root node to the output list
                    roots.append(data)

                return JsonResponse(tuple(r for r in roots), safe=False)
            else:
                response_on_error = 'Could not retrieve child nodes.'
                # Select all classes that are linked with the passed relation
                cc_q = ClassClass.objects.filter(class_b=class_b_id,
                    relation=parent_id, project=project_id)

                links = []
                for cc in cc_q:
                    # Get known restrictions
                    restrictions = get_restrictions( cc )
                    restrictions_json = json.dumps( restrictions )
                    # Create name, mark restrictin availability with *
                    node_name = "%s (%d)" % (cc.class_a.class_name, cc.class_a.id)
                    if len(restrictions) > 0:
                        node_name = node_name + "*"
                    # Collect standard jSTree data
                    data = {
                        'id': cc.class_a.id,
                        'text': node_name,
                        'type': 'class',
                        'restrictions': restrictions_json,
                        'cname': cc.class_a.class_name,
                        'ccid': cc.id
                    }

                    # Only add a 'state' field if this node has children
                    # (i.e. relations where it is class_b).
                    num_children = ClassClass.objects.filter(
                        class_b=cc.class_a.id, project=project_id).count()
                    if num_children > 0:
                        data['state'] = {
                            'opened': False
                        }
                    # Add this class-class link to the list
                    links.append(data)

                return JsonResponse(tuple(l for l in links), safe=False)
        elif parent_type in ("class", "root"):
            # A relation is wanted
            cc_q = ClassClass.objects.filter(
                project=project_id, class_b_id=parent_id)
            # Combine same relations into one
            relations = {}
            for cc in cc_q:
                if cc.relation not in relations:
                    relations[ cc.relation ] = []
                relations[ cc.relation ].append( cc )

            return JsonResponse(tuple({
                'id': r.id,
                'text': '%s (%d)' % (r.relation_name, r.id),
                'type': 'relation',
                'name': r.relation_name,
                'classbname': relations[r][0].class_b.class_name,
                'classbid': parent_id
            } for r in relations), safe=False)
        else:
            response_on_error = 'Unknown parent type'
            raise Exception(parent_type)

    except Exception as e:
        raise Exception(response_on_error + ': ' + str(e))
示例#38
0
    def post(self, request, project_id):
        """Import and link landmarks, landmark groups and locations.

        The passed in <data> parameter is a list of two-element lists, each
        representing a group along with its linked landmark and locations. The
        group is represented by its name and the members are a list of
        four-element lists, containing the landmark name and the location. This
        results in the following format:

        [[group_1_name, [[landmark_1_name, x, y, z], [landmark_2_name, x, y, z]]], ...]

        Note that this parameter has to be transmitted as a JSON encoded string.

        ---
        parameters:
        - name: project_id
          description: The project the landmark group is part of.
          type: integer
          paramType: path
          required: true
        - name: data
          description: The data to import.
          required: true
          type: string
          paramType: form
        - name: reuse_existing_groups
          description: Whether existing groups should be reused.
          type: boolean
          paramType: form
          defaultValue: false
          required: false
        - name: reuse_existing_landmarks
          description: Whether existing landmarks should be reused.
          type: boolean
          paramType: form
          defaultValue: false
          required: false
        - name: create_non_existing_groups
          description: Whether non-existing groups should be created.
          type: boolean
          paramType: form
          defaultValue: true
          required: false
        - name: create_non_existing_landmarks
          description: Whether non-existing landmarks should be created.
          type: boolean
          paramType: form
          defaultValue: true
          required: false
        """
        project_id = int(project_id)
        if not project_id:
            raise ValueError("Need project ID")
        reuse_existing_groups = request.data.get('reuse_existing_groups',
                                                 'false') == 'true'
        reuse_existing_landmarks = request.data.get('reuse_existing_landmarks',
                                                    'false') == 'true'
        create_non_existing_groups = request.data.get(
            'create_non_existing_groups', 'true') == 'true'
        create_non_existing_landmarks = request.data.get(
            'create_non_existing_landmarks', 'true') == 'true'

        # Make sure the data to import matches our expectations
        data = request.data.get('data')
        if not data:
            raise ValueError("Need data to import")
        data = json.loads(data)
        for n, (group_name, landmarks) in enumerate(data):
            if not group_name:
                raise ValueError("The {}. group doesn't have a name".format(n))
            if not landmarks:
                raise ValueError(
                    "Group {} doesn't contain any landmarks".format(
                        group_name))
            for m, link in enumerate(landmarks):
                if not link or len(link) != 4:
                    raise ValueError("The {}. link of the {}. group ({}) " \
                        "doesn't conform to the [ID, X, Y, Z] format.".format(m,
                        n, group_name))
                for ci in (1, 2, 3):
                    coordinate = link[ci]
                    value = float(coordinate)
                    if math.isnan(value):
                        raise ValueError("The {}. link of the {}. group ({}) " \
                            "doesn't have a valid {}. coordinate: {}.".format(
                            m, n, group_name, ci, coordinate))
                    link[ci] = value

        classes = get_class_to_id_map(project_id)
        relations = get_relation_to_id_map(project_id)
        landmark_class = classes['landmark']
        landmarkgroup_class = classes['landmarkgroup']
        part_of_relation = relations['part_of']
        annotated_with_relation = relations['annotated_with']

        landmarks = dict(
            (k.lower(), v) for k, v in ClassInstance.objects.filter(
                project_id=project_id,
                class_column=landmark_class).values_list('name', 'id'))
        landmarkgroups = dict(
            (k.lower(), v) for k, v in ClassInstance.objects.filter(
                project_id=project_id,
                class_column=landmarkgroup_class).values_list('name', 'id'))

        imported_groups = []

        # Keep track of which landmarks have been seen and were accepted.
        seen_landmarks = set()

        for n, (group_name, linked_landmarks) in enumerate(data):
            # Test if group exists already and raise error if they do and are
            # prevented from being reused (option).
            existing_group_id = landmarkgroups.get(group_name.lower())
            if existing_group_id:
                if n == 0:
                    if not reuse_existing_groups:
                        raise ValueError("Group \"{}\" exists already ({}).  Please" \
                                "remove it or enable group re-use.".format(
                                group_name, existing_group_id))
                    can_edit_or_fail(request.user, existing_group_id,
                                     'class_instance')
            elif create_non_existing_groups:
                group = ClassInstance.objects.create(
                    project_id=project_id,
                    class_column_id=landmarkgroup_class,
                    user=request.user,
                    name=group_name)
                existing_group_id = group.id
                landmarkgroups[group_name.lower()] = group.id
            else:
                raise ValueError("Group \"{}\" does not exist. Please create " \
                        "it or enable automatic creation/".format(group_name))

            imported_landmarks = []
            imported_group = {
                'id': existing_group_id,
                'name': group_name,
                'members': imported_landmarks
            }
            imported_groups.append(imported_group)

            for m, link in enumerate(linked_landmarks):
                landmark_name = link[0]
                x, y, z = link[1], link[2], link[3]
                existing_landmark_id = landmarks.get(landmark_name.lower())
                if existing_landmark_id:
                    # Test only on first look at landmark
                    if existing_landmark_id not in seen_landmarks:
                        if not reuse_existing_landmarks:
                            raise ValueError("Landmark \"{}\" exists already. " \
                                        "Please remove it or enable re-use of " \
                                        "existing landmarks.".format(landmark_name))
                        can_edit_or_fail(request.user, existing_landmark_id,
                                         'class_instance')
                elif create_non_existing_landmarks:
                    landmark = ClassInstance.objects.create(
                        project_id=project_id,
                        class_column_id=landmark_class,
                        user=request.user,
                        name=landmark_name)
                    existing_landmark_id = landmark.id
                    landmarks[landmark_name.lower()] = landmark.id
                else:
                    raise ValueError("Landmark \"{}\" does not exist. Please " \
                            "create it or enable automatic creation.".format(
                            landmark_name))
                seen_landmarks.add(existing_landmark_id)

                # Make sure the landmark is linked to the group
                landmark_link = ClassInstanceClassInstance.objects.get_or_create(
                    project_id=project_id,
                    relation_id=part_of_relation,
                    class_instance_a_id=existing_landmark_id,
                    class_instance_b_id=existing_group_id,
                    defaults={'user': request.user})

                # With an existing group and landmark in place, the location can
                # be linked (to both).
                point = Point.objects.create(project_id=project_id,
                                             user=request.user,
                                             editor=request.user,
                                             location_x=x,
                                             location_y=y,
                                             location_z=z)
                point_landmark = PointClassInstance.objects.create(
                    point=point,
                    user=request.user,
                    class_instance_id=existing_landmark_id,
                    project_id=project_id,
                    relation_id=annotated_with_relation)
                point_landmark_group = PointClassInstance.objects.create(
                    point=point,
                    user=request.user,
                    class_instance_id=existing_group_id,
                    project_id=project_id,
                    relation_id=annotated_with_relation)

                imported_landmarks.append({
                    'id': existing_landmark_id,
                    'name': landmark_name,
                    'x': x,
                    'y': y,
                    'z': z
                })

        return Response(imported_groups)