If there is not currently a selected NV within self.settings[patch_size] of pt, adds it to the selected list. If
        there is, removes that point from the selected list.
        Args:
            pt: the point to add or remove from the selected list
        Poststate: updates selected list

def toggle_NV(self, pt):
        '''
        If there is not currently a selected NV within self.settings[patch_size] of pt, adds it to the selected list. If
        there is, removes that point from the selected list.
        Args:
            pt: the point to add or remove from the selected list
        Poststate: updates selected list
        '''
        if not self.data['nv_locations']: #if self.data is empty so this is the first point
            self.data['nv_locations'].append(pt)
            self.data['image_data'] = None # clear image data
        else:
            # use KDTree to find NV closest to mouse click
            tree = scipy.spatial.KDTree(self.data['nv_locations'])
            #does a search with k=1, that is a search for the nearest neighbor, within distance_upper_bound
            d, i = tree.query(pt,k = 1, distance_upper_bound = self.settings['patch_size'])

            # removes NV if previously selected
            if d is not np.inf:
                self.data['nv_locations'].pop(i)
            # adds NV if not previously selected
            else:
                self.data['nv_locations'].append(pt)

            # randomize
            if self.settings['randomize']:
                self.log('warning! randomize not avalable when manually selecting points')

        # if type is not free we calculate the total points of locations from the first selected points
        if self.settings['type'] == 'square' and len(self.data['nv_locations'])>1:
            # here we create a rectangular grid, where pts a and be define the top left and bottom right corner of the rectangle
            Nx, Ny = self.settings['Nx'], self.settings['Ny']
            pta = self.data['nv_locations'][0]
            ptb = self.data['nv_locations'][1]
            tmp  = np.array([[[pta[0] + 1.0*i*(ptb[0]-pta[0])/(Nx-1), pta[1] + 1.0*j*(ptb[1]-pta[1])/(Ny-1)] for i in range(Nx)] for j in range(Ny)])
            nv_pts = np.reshape(tmp, (Nx * Ny, 2))

            # randomize
            if self.settings['randomize']:
                random.shuffle(nv_pts)  # shuffles in place

            self.data['nv_locations'] = nv_pts

            self.stop()
        elif self.settings['type'] == 'line' and len(self.data['nv_locations'])>1:
            # here we create a straight line between points a and b
            N = self.settings['Nx']
            pta = self.data['nv_locations'][0]
            ptb = self.data['nv_locations'][1]
            nv_pts = [np.array([pta[0] + 1.0*i*(ptb[0]-pta[0])/(N-1), pta[1] + 1.0*i*(ptb[1]-pta[1])/(N-1)]) for i in range(N)]


            # randomize
            if self.settings['randomize']:
                random.shuffle(nv_pts)  # shuffles in place

            self.data['nv_locations'] = nv_pts

            self.stop()
        elif self.settings['type'] == 'ring' and len(self.data['nv_locations'])>1:
            # here we create a circular grid, where pts a and be define the center and the outermost ring
            Nx, Ny = self.settings['Nx'], self.settings['Ny']
            pt_center = self.data['nv_locations'][0] # center
            pt_outer = self.data['nv_locations'][1] # outermost ring
            # radius of outermost ring:
            rmax = np.sqrt((pt_center[0] - pt_outer[0]) ** 2 + (pt_center[1] - pt_outer[1]) ** 2)

            # angles
            angles = np.linspace(0, 2 * np.pi, Nx+1)[0:-1]
            # create points on rings
            nv_pts = []
            for r in np.linspace(rmax, 0, Ny + 1)[0:-1]:
                for theta in angles:
                    nv_pts += [[r * np.sin(theta)+pt_center[0], r * np.cos(theta)+pt_center[1]]]



            # randomize
            if self.settings['randomize']:
                coarray = list(zip(nv_pts, angles))
                random.shuffle(coarray)  # shuffles in place
                nv_pts, angles = zip(*coarray)

            self.data['nv_locations'] = np.array(nv_pts)
            self.data['angles'] = np.array(angles)* 180 / np.pi
            self.data['ring_data'] = [pt_center, pt_outer]
            self.stop()

        elif self.settings['type'] == 'arc' and len(self.data['nv_locations']) > 3:
            # here we create a circular grid, where pts a and be define the center and the outermost ring
            Nx, Ny = self.settings['Nx'], self.settings['Ny']
            pt_center = self.data['nv_locations'][0]  # center
            pt_start = self.data['nv_locations'][1]  # arc point one (radius)
            pt_dir = self.data['nv_locations'][2]  # arc point two (direction)
            pt_end = self.data['nv_locations'][3]  # arc point three (angle)

            # radius of outermost ring:
            rmax = np.sqrt((pt_center[0] - pt_start[0]) ** 2 + (pt_center[1] - pt_start[1]) ** 2)
            angle_start = np.arctan((pt_start[1] - pt_center[1]) / (pt_start[0] - pt_center[0]))
            # arctan always returns between -pi/2 and pi/2, so adjust to allow full range of angles
            if ((pt_start[0] - pt_center[0]) < 0):
                angle_start += np.pi

            angle_end = np.arctan((pt_end[1] - pt_center[1]) / (pt_end[0] - pt_center[0]))
            # arctan always returns between -pi/2 and pi/2, so adjust to allow full range of angles
            if ((pt_end[0] - pt_center[0]) < 0):
                angle_end += np.pi

            if pt_dir[0] < pt_start[0]:
                # counter-clockwise: invert the order of the angles
                angle_start, angle_end = angle_end, angle_start

            if angle_start > angle_end:
                # make sure that start is the smaller
                # (e.g. angle_start= 180 deg and angle_end =10, we want to got from 180 to 370 deg)
                angle_end += 2 * np.pi

            # create points on arcs
            nv_pts = []
            for r in np.linspace(rmax, 0, Ny + 1)[0:-1]:
                for theta in np.linspace(angle_start, angle_end, Nx, endpoint=True):
                    nv_pts += [[r * np.cos(theta) + pt_center[0], r * np.sin(theta) + pt_center[1]]]

            # randomize
            if self.settings['randomize']:
                coarray = list(zip(nv_pts, np.linspace(angle_start, angle_end, Nx, endpoint=True)))
                random.shuffle(coarray)  # shuffles in place
                nv_pts, angles = zip(*coarray)
            else:
                angles = np.linspace(angle_start, angle_end, Nx, endpoint=True)
            self.data['nv_locations'] = np.array(nv_pts)
            self.data['arc_data'] = [pt_center, pt_start, pt_end]
            self.data['angles'] = np.array(angles) * 180 / np.pi
            self.stop()