(self, request:Request, project_id)
Create a new similarity/NBLAST configuration either by providing
        parameters to have the back-end queue a job or by providing the complete
        matrix data.
        ---
        parameters:
          - name: project_id
            description: Project of the NBLAST configuration
            type: integer
            paramType: path
            required: true
          - name: name
            description: Name of the new NBLAST configuration
            type: string
            paramType: form
            required: true
          - name: source
            description: Where random skeletons come from. Either
            "data", "request" or "backend-random".
            required: false
            defaultValue: "backend-random"
            paramType: form
          - name: distance_breaks
            description: Bin boundaries for the distance in nm. Defaults to [0, 500] in an increasing logarithmic bin sizw
            required: false
            defaultValue: 21
            paramType: form
          - name: dot_breaks
            description: Bin boundaries for the absolute dot product. Defaults to [0, 1] in 0.1 steps.
            required: false
            defaultValue: 10
            paramType: form
          - name: tangent_neighbors
            description: The number of neighbor nodes that should be considered when computing a tangent vector.
            required: false
            defaultValue: 20
            paramType: form
          - name: matching_skeleton_ids
            description: A list of matching skeleton IDs if <source> is not "data".
            required: false
            defaultValue: []
            paramType: form
          - name: matching_pointset_ids
            description: A list of matching pointset IDs if <source> is not "data".
            required: false
            defaultValue: []
            paramType: form
          - name: matching_pointcloud_ids
            description: A list of matching pointcloud IDs if <source> is not "data".
            required: false
            defaultValue: []
            paramType: form
          - name: random_skeleton_ids
            description: A list of random skeleton IDs if <source> is not "request".
            required: false
            defaultValue: []
            paramType: form
          - name: matching_sample_id
            description: An NblastSample foreign key of the matching sample.
            required: false
            defaultValue: None
            paramType: form
          - name: random_sample_id
            description: An NblastSample foreign key tp a random sample.
            required: false
            defaultValue: None
            paramType: form
          - name: scoring
            description: |
                If passed in a new similarity matrix will be created based on
                this explict scoring. It is assumed to be a simple list which is
                organized in rows following each other sequentially. Requires
                distance binning and dot binning information.
            required: false
Create a new similarity/NBLAST configuration either by providing
        parameters to have the back-end queue a job or by providing the complete
        matrix data.
        ---
        parameters:
          - name: project_id
            description: Project of the NBLAST configuration
            type: integer
            paramType: path
            required: true
          - name: name
            description: Name of the new NBLAST configuration
            type: string
            paramType: form
            required: true
          - name: source
            description: Where random skeletons come from. Either
            "data", "request" or "backend-random".
            required: false
            defaultValue: "backend-random"
            paramType: form
          - name: distance_breaks
            description: Bin boundaries for the distance in nm. Defaults to [0, 500] in an increasing logarithmic bin sizw
            required: false
            defaultValue: 21
            paramType: form
          - name: dot_breaks
            description: Bin boundaries for the absolute dot product. Defaults to [0, 1] in 0.1 steps.
            required: false
            defaultValue: 10
            paramType: form
          - name: tangent_neighbors
            description: The number of neighbor nodes that should be considered when computing a tangent vector.
            required: false
            defaultValue: 20
            paramType: form
          - name: matching_skeleton_ids
            description: A list of matching skeleton IDs if <source> is not "data".
            required: false
            defaultValue: []
            paramType: form
          - name: matching_pointset_ids
            description: A list of matching pointset IDs if <source> is not "data".
            required: false
            defaultValue: []
            paramType: form
          - name: matching_pointcloud_ids
            description: A list of matching pointcloud IDs if <source> is not "data".
            required: false
            defaultValue: []
            paramType: form
          - name: random_skeleton_ids
            description: A list of random skeleton IDs if <source> is not "request".
            required: false
            defaultValue: []
            paramType: form
          - name: matching_sample_id
            description: An NblastSample foreign key of the matching sample.
            required: false
            defaultValue: None
            paramType: form
          - name: random_sample_id
            description: An NblastSample foreign key tp a random sample.
            required: false
            defaultValue: None
            paramType: form
          - name: scoring
            description: |
                If passed in a new similarity matrix will be created based on
                this explict scoring. It is assumed to be a simple list which is
                organized in rows following each other sequentially. Requires
                distance binning and dot binning information.
            required: false
Create a new similarity / NBLAST configuration either by providing parameters to have the back - end queue a job or by providing the complete matrix data . --- parameters : - name : project_id description : Project of the NBLAST configuration type : integer paramType : path required : true - name : name description : Name of the new NBLAST configuration type : string paramType : form required : true - name : source description : Where random skeletons come from . Either data request or backend - random . required : false defaultValue : backend - random paramType : form - name : distance_breaks description : Bin boundaries for the distance in nm . Defaults to [ 0 500 ] in an increasing logarithmic bin sizw required : false defaultValue : 21 paramType : form - name : dot_breaks description : Bin boundaries for the absolute dot product . Defaults to [ 0 1 ] in 0 . 1 steps . required : false defaultValue : 10 paramType : form - name : tangent_neighbors description : The number of neighbor nodes that should be considered when computing a tangent vector . required : false defaultValue : 20 paramType : form - name : matching_skeleton_ids description : A list of matching skeleton IDs if <source > is not data . required : false defaultValue : [] paramType : form - name : matching_pointset_ids description : A list of matching pointset IDs if <source > is not data . required : false defaultValue : [] paramType : form - name : matching_pointcloud_ids description : A list of matching pointcloud IDs if <source > is not data . required : false defaultValue : [] paramType : form - name : random_skeleton_ids description : A list of random skeleton IDs if <source > is not request . required : false defaultValue : [] paramType : form - name : matching_sample_id description : An NblastSample foreign key of the matching sample . required : false defaultValue : None paramType : form - name : random_sample_id description : An NblastSample foreign key tp a random sample . required : false defaultValue : None paramType : form - name : scoring description : | If passed in a new similarity matrix will be created based on this explict scoring . It is assumed to be a simple list which is organized in rows following each other sequentially . Requires distance binning and dot binning information . required : false
def put(self, request:Request, project_id) -> Response:
        """Create a new similarity/NBLAST configuration either by providing
        parameters to have the back-end queue a job or by providing the complete
        matrix data.
        ---
        parameters:
          - name: project_id
            description: Project of the NBLAST configuration
            type: integer
            paramType: path
            required: true
          - name: name
            description: Name of the new NBLAST configuration
            type: string
            paramType: form
            required: true
          - name: source
            description: Where random skeletons come from. Either
            "data", "request" or "backend-random".
            required: false
            defaultValue: "backend-random"
            paramType: form
          - name: distance_breaks
            description: Bin boundaries for the distance in nm. Defaults to [0, 500] in an increasing logarithmic bin sizw
            required: false
            defaultValue: 21
            paramType: form
          - name: dot_breaks
            description: Bin boundaries for the absolute dot product. Defaults to [0, 1] in 0.1 steps.
            required: false
            defaultValue: 10
            paramType: form
          - name: tangent_neighbors
            description: The number of neighbor nodes that should be considered when computing a tangent vector.
            required: false
            defaultValue: 20
            paramType: form
          - name: matching_skeleton_ids
            description: A list of matching skeleton IDs if <source> is not "data".
            required: false
            defaultValue: []
            paramType: form
          - name: matching_pointset_ids
            description: A list of matching pointset IDs if <source> is not "data".
            required: false
            defaultValue: []
            paramType: form
          - name: matching_pointcloud_ids
            description: A list of matching pointcloud IDs if <source> is not "data".
            required: false
            defaultValue: []
            paramType: form
          - name: random_skeleton_ids
            description: A list of random skeleton IDs if <source> is not "request".
            required: false
            defaultValue: []
            paramType: form
          - name: matching_sample_id
            description: An NblastSample foreign key of the matching sample.
            required: false
            defaultValue: None
            paramType: form
          - name: random_sample_id
            description: An NblastSample foreign key tp a random sample.
            required: false
            defaultValue: None
            paramType: form
          - name: scoring
            description: |
                If passed in a new similarity matrix will be created based on
                this explict scoring. It is assumed to be a simple list which is
                organized in rows following each other sequentially. Requires
                distance binning and dot binning information.
            required: false
        """
        name = request.data.get('name')
        if not name:
            raise ValueError("Need name")

        # Cancel if user isn't allowed to queue computation tasks
        p = Project.objects.get(pk=project_id)

        distance_breaks = get_request_list(request.data, 'distance_breaks', map_fn=float)
        dot_breaks = get_request_list(request.data, 'dot_breaks', map_fn=float)

        scoring = get_request_list(request.data, 'scoring', map_fn=float)
        if not scoring:
            has_role = check_user_role(request.user, p, UserRole.QueueComputeTask)
            if not has_role:
                raise PermissionError("User " + str(request.user.id) +
                        " does not have permission to queue computation tasks.")

        source = request.data.get('source', 'backend-random')
        tangent_neighbors = int(request.data.get('tangent_neighbors', '20'))
        matching_sample_id = int(request.data.get('matching_sample_id')) \
                if 'matching_sample_id' in request.data else None
        random_sample_id = int(request.data.get('random_sample_id')) \
                if 'random_sample_id' in request.data else None
        min_length = float(request.data.get('min_length', 0))
        min_nodes = int(request.data.get('min_nodes', 50))
        user_id = request.user.id

        matching_skeleton_ids = get_request_list(request.data,
                'matching_skeleton_ids', map_fn=int)
        matching_pointset_ids = get_request_list(request.data,
                'matching_pointset_ids', map_fn=int)
        matching_pointcloud_ids = get_request_list(request.data,
                'matching_pointcloud_ids', map_fn=int)
        random_skeleton_ids = get_request_list(request.data,
                'random_skeleton_ids', map_fn=int)
        matching_meta = request.POST.get('matching_meta')
        if matching_meta:
            matching_meta = json.loads(matching_meta)
        matching_subset = request.POST.get('matching_subset')
        if matching_subset:
            matching_subset = json.loads(matching_subset)

            if type(matching_subset) != list:
                raise ValueError("Expected matching_subset to be a list")

            for subset in matching_subset:
                if type(subset) != list:
                    raise ValueError("Expected all matching_subset elements to be list")
                for element in subset:
                    if type(element) != list or len(element) != 2:
                        raise ValueError("Expeceted subset elements to be lists with two elements")
                    if type(element[0]) not in (int, list) or type(element[1]) != int:
                        raise ValueError("Expected subset selements to consist of ints or lists of ints")

        # Load and store point sets, if there are any.
        if matching_pointset_ids and matching_meta:
            created_ids = []
            for pointset_id in matching_pointset_ids:
                pointset_data = matching_meta.get(str(pointset_id))
                if not pointset_data:
                    raise ValueError(f"Could not find data for pointset {pointset_id}")
                flat_points = list(chain.from_iterable(pointset_data['points']))
                pointset = PointSet.objects.create(project_id=project_id,
                        user=request.user, name=pointset_data['name'],
                        description=pointset_data.get('description'),
                        points=flat_points)
                pointset.save()
                created_ids.append(pointset.id)

                # Update matching_subset with actual ID of point set. The subset
                # is a list of lists that represent the subsets. Each subset
                # element is a list of two elements [type, id]. For skeletons
                # the ID is 0, for point sets the ID is 1 and for point clouds
                # the ID is 2.
                if matching_subset:
                    for subset in matching_subset:
                        for element in subset:
                            if element[0] == 1 and element[1] == pointset_id:
                                element[1] = pointset.id

            # Update matching point set IDs with actual
            matching_pointset_ids = created_ids

        if not dot_breaks:
            dot_breaks = NblastConfigDefaultDotBreaks

        if not distance_breaks:
            distance_breaks = NblastConfigDefaultDistanceBreaks

        # Make sure bins and breaks match

        if scoring:
            config = self.add_from_raw_data(project_id, request.user.id, name,
                    scoring, distance_breaks, dot_breaks, tangent_neighbors)
            return Response(serialize_config(config))
        elif source == 'request':
            if not matching_skeleton_ids and not matching_pointset_ids:
                raise ValueError("Need matching_skeleton_ids or matching_pointset_ids")
            if not random_skeleton_ids:
                raise ValueError("Need random_skeleton_ids")
            config = self.add_delayed(project_id, user_id, name, matching_skeleton_ids,
                    matching_pointset_ids, random_skeleton_ids, distance_breaks,
                    dot_breaks, tangent_neighbors=tangent_neighbors,
                    matching_subset=matching_subset)
            return Response(serialize_config(config))
        elif source == 'backend-random':
            if not matching_skeleton_ids and not matching_pointset_ids:
                raise ValueError("Need matching_skeleton_ids or matching_pointset_ids")
            n_random_skeletons = int(request.data.get('n_random_skeletons', 5000))

            # Cancel if user isn't allowed to queue computation tasks
            p = Project.objects.get(pk=project_id)
            has_role = check_user_role(request.user, p, UserRole.QueueComputeTask)
            if not has_role:
                raise PermissionError("User " + str(request.user.id) +
                        " does not have permission to queue computation tasks.")

            config = self.compute_random_and_add_delayed(project_id, user_id, name,
                    matching_skeleton_ids, matching_pointset_ids,
                    matching_pointcloud_ids, distance_breaks, dot_breaks, None,
                    None, n_random_skeletons, min_length, min_nodes,
                    tangent_neighbors, matching_subset)
            return Response(serialize_config(config))
        else:
            raise ValueError("Unknown source: " + source)
def put ( self , request : Request , project_id ) -> Response : name = request . data . get ( 'name' ) if not name : raise ValueError ( "Need name" ) # Cancel if user isn't allowed to queue computation tasks p = Project . objects . get ( pk = project_id ) distance_breaks = get_request_list ( request . data , 'distance_breaks' , map_fn = float ) dot_breaks = get_request_list ( request . data , 'dot_breaks' , map_fn = float ) scoring = get_request_list ( request . data , 'scoring' , map_fn = float ) if not scoring : has_role = check_user_role ( request . user , p , UserRole . QueueComputeTask ) if not has_role : raise PermissionError ( "User " + str ( request . user . id ) + " does not have permission to queue computation tasks." ) source = request . data . get ( 'source' , 'backend-random' ) tangent_neighbors = int ( request . data . get ( 'tangent_neighbors' , '20' ) ) matching_sample_id = int ( request . data . get ( 'matching_sample_id' ) ) if 'matching_sample_id' in request . data else None random_sample_id = int ( request . data . get ( 'random_sample_id' ) ) if 'random_sample_id' in request . data else None min_length = float ( request . data . get ( 'min_length' , 0 ) ) min_nodes = int ( request . data . get ( 'min_nodes' , 50 ) ) user_id = request . user . id matching_skeleton_ids = get_request_list ( request . data , 'matching_skeleton_ids' , map_fn = int ) matching_pointset_ids = get_request_list ( request . data , 'matching_pointset_ids' , map_fn = int ) matching_pointcloud_ids = get_request_list ( request . data , 'matching_pointcloud_ids' , map_fn = int ) random_skeleton_ids = get_request_list ( request . data , 'random_skeleton_ids' , map_fn = int ) matching_meta = request . POST . get ( 'matching_meta' ) if matching_meta : matching_meta = json . loads ( matching_meta ) matching_subset = request . POST . get ( 'matching_subset' ) if matching_subset : matching_subset = json . loads ( matching_subset ) if type ( matching_subset ) != list : raise ValueError ( "Expected matching_subset to be a list" ) for subset in matching_subset : if type ( subset ) != list : raise ValueError ( "Expected all matching_subset elements to be list" ) for element in subset : if type ( element ) != list or len ( element ) != 2 : raise ValueError ( "Expeceted subset elements to be lists with two elements" ) if type ( element [ 0 ] ) not in ( int , list ) or type ( element [ 1 ] ) != int : raise ValueError ( "Expected subset selements to consist of ints or lists of ints" ) # Load and store point sets, if there are any. if matching_pointset_ids and matching_meta : created_ids = [ ] for pointset_id in matching_pointset_ids : pointset_data = matching_meta . get ( str ( pointset_id ) ) if not pointset_data : raise ValueError ( f"Could not find data for pointset {pointset_id}" ) flat_points = list ( chain . from_iterable ( pointset_data [ 'points' ] ) ) pointset = PointSet . objects . create ( project_id = project_id , user = request . user , name = pointset_data [ 'name' ] , description = pointset_data . get ( 'description' ) , points = flat_points ) pointset . save ( ) created_ids . append ( pointset . id ) # Update matching_subset with actual ID of point set. The subset # is a list of lists that represent the subsets. Each subset # element is a list of two elements [type, id]. For skeletons # the ID is 0, for point sets the ID is 1 and for point clouds # the ID is 2. if matching_subset : for subset in matching_subset : for element in subset : if element [ 0 ] == 1 and element [ 1 ] == pointset_id : element [ 1 ] = pointset . id # Update matching point set IDs with actual matching_pointset_ids = created_ids if not dot_breaks : dot_breaks = NblastConfigDefaultDotBreaks if not distance_breaks : distance_breaks = NblastConfigDefaultDistanceBreaks # Make sure bins and breaks match if scoring : config = self . add_from_raw_data ( project_id , request . user . id , name , scoring , distance_breaks , dot_breaks , tangent_neighbors ) return Response ( serialize_config ( config ) ) elif source == 'request' : if not matching_skeleton_ids and not matching_pointset_ids : raise ValueError ( "Need matching_skeleton_ids or matching_pointset_ids" ) if not random_skeleton_ids : raise ValueError ( "Need random_skeleton_ids" ) config = self . add_delayed ( project_id , user_id , name , matching_skeleton_ids , matching_pointset_ids , random_skeleton_ids , distance_breaks , dot_breaks , tangent_neighbors = tangent_neighbors , matching_subset = matching_subset ) return Response ( serialize_config ( config ) ) elif source == 'backend-random' : if not matching_skeleton_ids and not matching_pointset_ids : raise ValueError ( "Need matching_skeleton_ids or matching_pointset_ids" ) n_random_skeletons = int ( request . data . get ( 'n_random_skeletons' , 5000 ) ) # Cancel if user isn't allowed to queue computation tasks p = Project . objects . get ( pk = project_id ) has_role = check_user_role ( request . user , p , UserRole . QueueComputeTask ) if not has_role : raise PermissionError ( "User " + str ( request . user . id ) + " does not have permission to queue computation tasks." ) config = self . compute_random_and_add_delayed ( project_id , user_id , name , matching_skeleton_ids , matching_pointset_ids , matching_pointcloud_ids , distance_breaks , dot_breaks , None , None , n_random_skeletons , min_length , min_nodes , tangent_neighbors , matching_subset ) return Response ( serialize_config ( config ) ) else : raise ValueError ( "Unknown source: " + source )