def __init__(self, data, transformer=None): try: self.data = data self.id = data['id'] # If space is not explicitly set, assume the coordinates are already in # the target space. self.space = data[ 'space'] if 'space' in data else transformer.target except Exception as e: logger.error("Missing ID and/or space fields. " "Please check database file, caught: %s" % str(e)) exit() # Loop through rows and set coordinates peaks = np.zeros((len(data['peaks']), 3), dtype=int) for i, f in enumerate(data['peaks']): peaks[i, ] = [float(j) for j in f[0:3]] # Convert between stereotactic spaces if transformer is not None and self.space != transformer.target: peaks = transformer.apply(self.space, peaks) # Convert from XYZ coordinates to matrix indices, saving both self.xyz = peaks self.peaks = transformations.xyz_to_mat(peaks)
def get_ids_by_peaks(self, peaks, r=10, threshold=0.0, get_image_data=False): """ A wrapper for get_ids_by_mask. Takes a set of xyz coordinates and generates a new Nifti1Image to use as a mask. Args: peaks: Either an n x 3 numpy array, or a list of lists (e.g., [[-10, 22, 14]]) specifying the world (x/y/z) coordinates of the target location(s). r: Radius in millimeters of the sphere to grow around each location. threshold: Optional float indicating the proportion of voxels that must be active in order for a Mappable to be considered active. get_image_data: If true, returns the image data for all activated Mappables in a voxel x Mappable numpy array. Otherwise, returns just the IDs of Mappables. Returns: Either a list of ids (if get_image_data = False) or a numpy array of image data. """ peaks = np.array(peaks) # Make sure we have a numpy array peaks = transformations.xyz_to_mat(peaks) img = imageutils.map_peaks_to_image(peaks, r, vox_dims=self.masker.vox_dims, dims=self.masker.dims, header=self.masker.get_header()) return self.get_ids_by_mask(img, threshold, get_image_data=get_image_data)
def get_ids_by_peaks(self, peaks, r=10, threshold=0.0, get_image_data=False): """ A wrapper for get_ids_by_mask. Takes a set of xyz coordinates and generates a new Nifti1Image to use as a mask. Args: peaks (ndarray, list): Either an n x 3 numpy array, or a list of lists (e.g., [[-10, 22, 14]]) specifying the world (x/y/z) coordinates of the target location(s). r (int): Radius in millimeters of the sphere to grow around each location. threshold (float): Optional float indicating the proportion of voxels that must be active in order for a Mappable to be considered active. get_image_data (bool): When True, returns a voxel x mappable matrix of image data rather than the Mappable instances themselves. Returns: Either a list of ids (if get_image_data = False) or a numpy array of image data. """ peaks = np.array(peaks) # Make sure we have a numpy array peaks = transformations.xyz_to_mat(peaks) img = imageutils.map_peaks_to_image( peaks, r, vox_dims=self.masker.vox_dims, dims=self.masker.dims, header=self.masker.get_header()) return self.get_ids_by_mask(img, threshold, get_image_data=get_image_data)
def _load_activations(self, filename): """ Load activation data from a text file. Args: filename (str): a string pointing to the location of the txt file to read from. """ logger.info("Loading activation data from %s..." % filename) activations = pd.read_csv(filename, sep='\t') activations.columns = [col.lower() for col in list(activations.columns)] # Make sure all mandatory columns exist mc = ['x', 'y', 'z', 'id', 'space'] if (set(mc) - set(list(activations.columns))): logger.error( "At least one of mandatory columns (x, y, z, id, and space) " "is missing from input file.") return # Transform to target space where needed spaces = activations['space'].unique() xyz = activations[['x', 'y', 'z']].values for s in spaces: if s != self.transformer.target: inds = activations['space'] == s xyz[inds] = self.transformer.apply(s, xyz[inds]) activations[['x', 'y', 'z']] = xyz # xyz --> ijk ijk = pd.DataFrame( transformations.xyz_to_mat(xyz), columns=['i', 'j', 'k']) activations = pd.concat([activations, ijk], axis=1) return activations
def peaks_to_vector(coordinates, mask= '/scratch/02863/mparikh/data/MNI152_T1_2mm_brain.nii.gz', radius=10): """ Takes in a list of valid peak coordinates and returns a vector of the corresponding image Parameters ---------- coordinates : list of lists list of x/y/z coordinates mask : mask object in nifti fomat used to vectorize the image radius : int, optional the radius of sphere to expand around the peaks in mm. defaults to 10mm. Returns ------- dense_img : nifti image 1D Numpy array of in-mask voxels """ # transform the coordinates to matrix space #print(coordinates) new_coordinates = nbt.xyz_to_mat(np.array(coordinates)) # now get the denser image, expanding via spheres dense_img = nbi.map_peaks_to_image(new_coordinates, r=radius) # Create a mask object for the image niftiMask = nbm.Mask(mask) # mask the image formed return niftiMask.mask(dense_img)
def __init__(self, data, transformer=None): try: self.data = data self.id = data['id'] # If space is not explicitly set, assume the coordinates are already in # the target space. self.space = data[ 'space'] if 'space' in data else transformer.target except Exception as e: logger.error("Missing ID and/or space fields. " "Please check database file, caught: %s" % str(e)) exit() # Loop through rows and set coordinates peaks = np.zeros((len(data['peaks']), 3), dtype=int) for i, f in enumerate(data['peaks']): peaks[i,] = [float(j) for j in f[0:3]] # Convert between stereotactic spaces if transformer is not None and self.space != transformer.target: peaks = transformer.apply(self.space, peaks) # Convert from XYZ coordinates to matrix indices, saving both self.xyz = peaks self.peaks = transformations.xyz_to_mat(peaks)
def __init__(self, data, transformer=None): try: self.data = data.copy().reset_index() self.id = data['id'].values[0] # If space is not explicitly set, assume the coordinates are already in # the target space. self.space = data['space'].values[0] if 'space' in data.columns else transformer.target except Exception as e: logger.error("Missing ID and/or space fields. " "Please check database file, caught: %s" % str(e)) exit() peaks = data[['x','y','z']].values # Convert between stereotactic spaces if transformer is not None and self.space != transformer.target: peaks = transformer.apply(self.space, peaks) # Convert from XYZ coordinates to matrix indices, saving both self.xyz = peaks self.peaks = transformations.xyz_to_mat(peaks)
def __init__(self, data, transformer=None): try: self.data = data.copy().reset_index() self.id = data['id'].values[0] # If space is not explicitly set, assume the coordinates are already in # the target space. self.space = data['space'].values[ 0] if 'space' in data.columns else transformer.target except Exception as e: logger.error("Missing ID and/or space fields. " "Please check database file, caught: %s" % str(e)) exit() peaks = data[['x', 'y', 'z']].values # Convert between stereotactic spaces if transformer is not None and self.space != transformer.target: peaks = transformer.apply(self.space, peaks) # Convert from XYZ coordinates to matrix indices, saving both self.xyz = peaks self.peaks = transformations.xyz_to_mat(peaks)
def is_valid(coordinates, mask='/scratch/02863/mparikh/data/2mm_brain_mask.npy'): """ Validates that the given x/y/z tuple is valid for the given mask Parameters ---------- coordinates : list/tuple x, y, z coordinates to be validated mask : mask object in nifti format Returns ------- bool : whether it is a valid coordinate or not """ try: mat = np.load(mask) idx = nbt.xyz_to_mat(np.asarray([coordinates])) idx_t = tuple(idx.reshape(1, -1)[0]) return mat[idx_t] == 1 except IndexError as e: return False
def get_ids_by_peaks(self, peaks, r=10, threshold=0.0, get_image_data=False): """ A wrapper for get_ids_by_mask. Takes a set of xyz coordinates and generates a new Nifti1Image to use as a mask. Args: peaks: Either an n x 3 numpy array, or a list of lists (e.g., [[-10, 22, 14]]) specifying the world (x/y/z) coordinates of the target location(s). r: Radius in millimeters of the sphere to grow around each location. threshold: Optional float indicating the proportion of voxels that must be active in order for a Mappable to be considered active. get_image_data: If true, returns the image data for all activated Mappables in a voxel x Mappable numpy array. Otherwise, returns just the IDs of Mappables. Returns: Either a list of ids (if get_image_data = False) or a numpy array of image data. """ peaks = np.array(peaks) # Make sure we have a numpy array peaks = transformations.xyz_to_mat(peaks) img = imageutils.map_peaks_to_image( peaks, r, vox_dims=self.volume.vox_dims, dims=self.volume.dims, header=self.volume.get_header()) return self.get_ids_by_mask(img, threshold, get_image_data=get_image_data)
def get_studies(self, features=None, expression=None, mask=None, peaks=None, frequency_threshold=0.001, activation_threshold=0.0, func=np.sum, return_type='ids', r=6 ): """ Get IDs or data for studies that meet specific criteria. If multiple criteria are passed, the set intersection is returned. For example, passing expression='emotion' and mask='my_mask.nii.gz' would return only those studies that are associated with emotion AND report activation within the voxels indicated in the passed image. Args: ids (list): A list of IDs of studies to retrieve. features (list or str): The name of a feature, or a list of features, to use for selecting studies. expression (str): A string expression to pass to the PEG for study retrieval. mask: the mask image (see Masker documentation for valid data types). peaks (ndarray or list): Either an n x 3 numpy array, or a list of lists (e.g., [[-10, 22, 14]]) specifying the world (x/y/z) coordinates of the target location(s). frequency_threshold (float): For feature-based or expression-based selection, the threshold for selecting studies--i.e., the cut-off for a study to be included. Must be a float in range [0, 1]. activation_threshold (int or float): For mask-based or peak-based selection, threshold for a study to be included based on amount of activation displayed. If an integer, represents the absolute number of voxels that must be active within the mask (or generated ROIs) in order for a study to be selected. If a float, it represents the proportion of voxels that must be active. func (Callable): The function to use when aggregating over the list of features. See documentation in FeatureTable.get_ids() for a full explanation. Only used for feature- or expression-based selection. return_type (str): A string specifying what data to return. Valid options are: 'ids': returns a list of IDs of selected studies. 'images': returns a voxel x mappable matrix of data for all selected studies. 'weights': returns a dict where the keys are study IDs and the values are the computed weights. Only valid when performing feature-based selection. r (int): For peak-based selection, the radius in millimeters of the sphere to grow around each peak. Returns: When return_type is 'ids' (default), returns a list of IDs of the selected studies. When return_type is 'data', returns a 2D numpy array, with voxels in rows and studies in columns. When return_type is 'weights' (valid only for expression-based selection), returns a dict, where the keys are study IDs, and the values are the computed weights. Examples -------- Select all studies tagged with the feature 'emotion': >>> ids = dataset.get_studies(features='emotion') Select all studies that activate at least 20% of voxels in an amygdala mask, and retrieve activation data rather than IDs: >>> data = dataset.get_studies(mask='amygdala_mask.nii.gz', threshold=0.2, return_type='images') Select studies that activate at least 5% of all voxels within 12 mm of three specific foci: >>> ids = dataset.get_studies(peaks=[[12, -20, 30], [-26, 22, 22], [0, 36, -20]], r=12) """ results = [] # Feature-based selection if features is not None: # Need to handle weights as a special case, because we can't # retrieve the weights later using just the IDs. if return_type == 'weights': if expression is not None or mask is not None or \ peaks is not None: raise ValueError( "return_type cannot be 'weights' when feature-based " "search is used in conjunction with other search " "modes.") return self.feature_table.get_ids( features, frequency_threshold, func, get_weights=True) else: results.append(self.feature_table.get_ids( features, frequency_threshold, func)) # Logical expression-based selection if expression is not None: _ids = self.feature_table.get_ids_by_expression( expression, frequency_threshold, func) results.append(list(_ids)) # Mask-based selection if mask is not None: mask = self.masker.mask(mask, in_global_mask=True).astype(bool) num_vox = np.sum(mask) prop_mask_active = self.image_table.data.T.dot(mask).astype(float) if isinstance(activation_threshold, float): prop_mask_active /= num_vox indices = np.where(prop_mask_active > activation_threshold)[0] results.append([self.image_table.ids[ind] for ind in indices]) # Peak-based selection if peaks is not None: peaks = np.array(peaks) # Make sure we have a numpy array peaks = transformations.xyz_to_mat(peaks) m = self.masker img = imageutils.map_peaks_to_image( peaks, r, vox_dims=m.vox_dims, dims=m.dims, header=m.get_header()) results.append(self.get_studies( mask=img, activation_threshold=activation_threshold)) # Get intersection of all sets ids = list(reduce(lambda x, y: set(x) & set(y), results)) if return_type == 'ids': return ids elif return_type == 'data': return self.get_image_data(ids)