def __init__(self, variable_dict=None): super(BrainData, self).__init__(variable_dict=variable_dict) self.subject_data_dict = {} self.nifti = NiftiTools() self.vector = VectorTools()
class BrainData(DataManager): ''' BrainData ------------ Recoded BrainData class in style of Jonathan Taylor's masking scheme. It preforms faster than my old one so I decided to go with this. However, his originally forced a matrix transposition (reversal) which may not be ideal. This has the option of either using his matrix format or preserving (as best as possible) the dimensionality when loading niftis using nipy or nibabel. ''' def __init__(self, variable_dict=None): super(BrainData, self).__init__(variable_dict=variable_dict) self.subject_data_dict = {} self.nifti = NiftiTools() self.vector = VectorTools() def create_niftis(self, subject_dirs=None, functional_name=None, anatomical_name=None, dxyz=None, talairach_template_path=None, nifti_name=None, within_subject_warp=True, to_template_warp=False): if not nifti_name.endswith('.nii'): nifti_name = nifti_name+'.nii' self.nifti.create_talairach_niftis(subject_dirs, functional_name, anatomical_name, dxyz, talairach_template_path, nifti_name, within_subject_warp, to_template_warp) def load_niftis_vectors(self, directory, verbose=True): ''' Loads niftis and response vectors from a directory. This function is fairly specific. The nifti files should be named in this manner: prefix_***.nii Such that prefix denotes a subject and an underscore splits this subject from the rest of the nifti filename. Likewise, the response vector file should be coded: prefix_***.1D Such that the prefix matches a prefix for a nifti file! NO DUPLICATE PREFIXES - WILL CHOOSE INDISCRIMINATELY ''' nifti_paths = sorted(glob.glob(os.path.join(directory, '*.nii'))) vector_paths = sorted(glob.glob(os.path.join(directory, '*.nii'))) npre = [os.path.split(n)[1].split('_')[0] for n in nifti_paths] vpre = [os.path.split(v)[1].split('_')[0] for v in vector_paths] pairs = [] for nifti, np in zip(nifti_paths, npre): for vector, vp in zip(vector_paths, vpre): if np == vp: pairs.append([nifti, self.vector.read(vector)]) break return pairs def load_niftis_fromdirs(self, subject_dirs, nifti_name, response_vector, verbose=True): ''' Iterates through subject directories, parses the response vector, and appends the path to the nifti file for loading later. Basic support for multiple niftis per subject (just added as different key in the subject_data_dict). ''' for subject in subject_dirs: nifti = os.path.join(subject, nifti_name) vec = os.path.join(subject, response_vector) if not os.path.exists(nifti): if verbose: print 'nifti not found: ', nifti elif not os.path.exists(vec): if verbose: print 'respnse vector not found: ', vec else: respvec = self.vector.read(vec, usefloat=True) subject_key = os.path.split(subject)[1] if verbose: pprint(nifti) print 'appending raw data for subject: ', subject_key if not subject_key in self.subject_data_dict: self.subject_data_dict[subject_key] = [nifti, respvec] else: tag = 2 while subject_key+'_'+str(tag) in self.subject_data_dict: tag += 2 self.subject_data_dict[subject_key+'_'+str(tag)] = [nifti, respvec] def parse_trialsvec(self, trialsvec): ''' Simple function to find the indices where Y is not 0. Returns the indices vector and the stripped Y vector. Used by masked_data(). ''' inds = [i for i,x in enumerate(trialsvec) if x != 0.] y = [x for x in trialsvec if x != 0] return inds, y def unmask_Xcoefs(self, Xcoefs, time_points, mask=None, reverse_transpose=True, verbose=True, slice_off_back=0, slice_off_front=0): ''' Reshape the coefficients from a statistical method back to the shape of the original brain matrix, so it can be output to nifti format. ''' if mask is None: mask = self.original_mask unmasked = [np.zeros(mask.shape) for i in range(time_points)] print 'xcoefs sum', np.sum(Xcoefs) if slice_off_back: print np.sum(Xcoefs[:-slice_off_back]), np.sum(Xcoefs[-slice_off_back:]) Xcoefs = Xcoefs[:-slice_off_back] if slice_off_front: Xcoefs = Xcoefs[slice_off_front:] print 'xcoefs sum', np.sum(Xcoefs) Xcoefs.shape = (time_points, -1) print 'Xcoefs shape', Xcoefs.shape for i in range(time_points): print 'raw coef time sum', np.sum(Xcoefs[i]) print 'mask, xind shapes', mask.shape, Xcoefs[i].shape unmasked[i][np.asarray(mask).astype(np.bool)] = np.squeeze(np.array(Xcoefs[i])) #unmasked[i][np.asarray(mask).astype(np.bool)] = np.squeeze(np.ones(np.sum(np.asarray(mask).astype(np.bool)))) print 'time ind coef sum', np.sum(unmasked[i]) if reverse_transpose: unmasked[i] = np.transpose(unmasked[i], [2, 1, 0]) unmasked = np.transpose(unmasked, [1, 2, 3, 0]) if verbose: print 'Shape of unmasked coefs: ', np.shape(unmasked) return np.array(unmasked) def save_unmasked_coefs(self, unmasked, nifti_filename, affine=None, talairach_template_path='./TT_N27+tlrc.'): ''' Simple function to save the unmasked coefficients to a specified nifti. Affine is usually self.mask_affine, but can be specified. ''' if affine is None: affine = self.mask_affine if self.verbose: print 'erasing old files with prefix:', nifti_filename#[:-4] glob_remove(nifti_filename)#[:-4]) self.nifti.save_nifti(unmasked, affine, nifti_filename) time.sleep(0.25) self.nifti.convert_to_afni(nifti_filename, nifti_filename)#[:-4]) time.sleep(0.25) subprocess.call(['3drefit','-view','tlrc',nifti_filename+'+orig.']) def make_masks(self, mask_path, ntrs, reverse_transpose=True, verbose=True): ''' A function that makes the various mask objects. ''' if verbose: if reverse_transpose: print 'using time-first reverse transposition of nifti matrix' else: print 'preserving dimensionality of nifti matrix (nt last)' mask = load_image(mask_path) tmp_mask, self.mask_affine, tmp_shape = self.nifti.load_nifti(mask_path) mask = np.asarray(mask) self.raw_affine = self.mask_affine if verbose: print 'mask shape:', mask.shape self.mask_shape = mask.shape if reverse_transpose: mask = np.transpose(mask.astype(np.bool), [2, 1, 0]) else: mask = mask.copy().astype(np.bool) self.original_mask = mask.copy() self.flat_mask = mask.copy() self.flat_mask.shape = np.product(mask.shape) if verbose: print 'flat mask shape:', self.flat_mask.shape nmask = np.not_equal(mask, 0).sum() if verbose: print 'mask shape', mask.shape self.trial_mask = np.zeros((ntrs, mask.shape[0], mask.shape[1], mask.shape[2])) if verbose: print 'trial mask shape', self.trial_mask.shape for t in range(ntrs): self.trial_mask[t,:,:,:] = mask self.trial_mask = self.trial_mask.astype(np.bool) def prepare_greymatter_mask(self, mask_path, greymatter_prefix='greymatter_resamp', afni_greymatter_dset='/Users/span/abin/TT_caez_gw_18+tlrc.', afni_index=0, reverse_transpose=True): # resample the gray matter mask to the user's mask: gm_resample_mask = os.path.join(os.path.split(mask_path)[0],greymatter_prefix) old_resamps = glob.glob(gm_resample_mask+'*') for oresamp in old_resamps: try: os.remove(oresamp) except: pass cmd = ['3dresample','-master', mask_path, '-prefix', gm_resample_mask, '-inset', afni_greymatter_dset+'['+str(afni_index)+']'] subprocess.call(cmd) niicmd = ['3dAFNItoNIFTI', '-prefix', greymatter_prefix, greymatter_prefix+'+tlrc.'] subprocess.call(niicmd) # for now need to have made the trial mask, etc... self.grey_matter = np.zeros(self.trial_mask.shape) gm_mask = load_image(gm_resample_mask+'.nii') gm_mask = np.asarray(gm_mask) self.grey_matter_flat = gm_mask.copy() self.grey_matter_flat.shape = np.product(self.grey_matter_flat.shape) if reverse_transpose: gm_mask = np.transpose(gm_mask, [2, 1, 0]) for tr in range(len(self.trial_mask)): self.grey_matter[tr,:,:,:] = gm_mask[:,:,:] def masked_data(self, nifti, trialsvec, selected_trs=[], mask_path=None, lag=2, reverse_transpose=True, verbose=True): ''' This function masks, transposes, and subselects the trials from the nifti data. -------- nifti : a filepath to the nifti. trialsvec : numpy array denoting the response variable at the TR of the trial onset. selected_trs : a list of the trs in the trial to be subselected mask_path : path to the mask (optional but recommended) lag : how many TRs to push out the trial (2 recommended) ''' if verbose: if reverse_transpose: print 'using time-first reverse transposition of nifti matrix' else: print 'preserving dimensionality of nifti matrix (nt last)' image = load_image(nifti) if verbose: print 'nifti shape:', image.shape nmask = np.not_equal(self.original_mask, 0).sum() ntrs = len(selected_trs) p = np.prod(image.shape[:-1]) trial_inds, response = self.parse_trialsvec(trialsvec) ntrials = len(trial_inds) if reverse_transpose: X = np.zeros((ntrials, ntrs, nmask)) else: X = np.zeros((ntrials, nmask, ntrs)) Y = np.zeros(ntrials) reselect_trs = [x-1 for x in selected_trs] if reverse_transpose: im = np.transpose(np.asarray(image), [3, 2, 1, 0]) for i in range(ntrials): if len(im) > trial_inds[i]+reselect_trs[-1]+lag: # OLD VERSION: could only do a continuous range #row = im[trial_inds[i]+reselect_trs[0]+lag:trial_inds[i]+reselect_trs[-1]+1+lag].reshape((ntrs,p)) # NEW VERSION: uses list comprehension for any index range row_inds = [trial_inds[i]+lag+x for x in reselect_trs] row = im[row_inds].reshape((ntrs,p)) X[i] = row[:,self.flat_mask] Y[i] = response[i] else: im = np.asarray(image) for i in range(ntrials): if im.shape[3] > trial_inds[i]+reselect_trs[-1]+lag: # OLD VERSION: could only do a continuous range #row = im[:,:,:,trial_inds[i]+reselect_trs[0]+lag:trial_inds[i]+reselect_trs[-1]+1+lag].reshape((p,ntrs)) # NEW VERSION: uses list comprehension for any index range row_inds = [trial_inds[i]+lag+x for x in reselect_trs] row = im[:,:,:,row_inds].reshape((p,ntrs)) X[i] = row[self.flat_mask,:] Y[i] = response[i] return X, Y def create_trial_mask(self, mask_path, ntrs, reverse_transpose=True): mask = load_image(mask_path) tmp_mask, self.mask_affine, tmp_shape = self.nifti.load_nifti(mask_path) mask = np.asarray(mask) if reverse_transpose: mask = np.transpose(mask.astype(np.bool), [2, 1, 0]) else: mask = mask.copy().astype(np.bool) self.original_mask = mask.copy() print mask.shape self.trial_mask = np.zeros((ntrs, mask.shape[0], mask.shape[1], mask.shape[2])) for t in range(ntrs): self.trial_mask[t,:,:,:] = mask self.trial_mask = self.trial_mask.astype(np.bool) print self.trial_mask.shape def create_design(self, subject_dirs, nifti_name, respvec_name, selected_trs, mask_path=None, lag=2, reverse_transpose=True): self.selected_trs = selected_trs self.load_niftis_fromdirs(subject_dirs, nifti_name, respvec_name) self.subject_design = {} for subject, [image, respvec] in self.subject_data_dict.items(): sX, sY = self.masked_data(image, respvec, selected_trs=selected_trs, mask_path=mask_path, lag=lag, reverse_transpose=reverse_transpose) sX.shape = (sX.shape[0], np.prod(sX.shape[1:])) print 'subject X shape:', sX.shape self.subject_design[subject] = [np.array(sX), np.array(sY)] del(self.subject_data_dict) def create_design_logan_npy(self, subject_npys): self.subject_design = {} for npy in subject_npys: subject = npy.split('.')[0] cur_data = np.load(npy) sX, sY = [], [] for ind in range(len(cur_data)): sY.append(cur_data[ind]['Y']) i_X = cur_data[ind]['X'].copy() i_X.shape = (i_X.shape[0]*i_X.shape[1]) #print i_X.shape sX.append(i_X) self.subject_design[subject] = [np.array(sX), np.array(sY)] del(self.subject_data_dict)