def from_vol_files(self, mask_file=DEFAULT_MASK_VOL_FILE, paradigm_csv_file=DEFAULT_PARADIGM_CSV, bold_files=[DEFAULT_BOLD_VOL_FILE], tr=DEFAULT_BOLD_VOL_TR, background_label=None, paradigm_csv_delim=None): paradigm = Paradigm.from_csv(paradigm_csv_file, delim=paradigm_csv_delim) durations = paradigm.stimDurations onsets = paradigm.stimOnsets m, mmo, mlf, b, ss = load_vol_bold_and_mask(bold_files, mask_file) mask = m mask_meta_obj = mmo mask_loaded_from_file = mlf bold = b sessionScans = ss fd = FmriData(onsets, bold, tr, sessionScans, mask, stimDurations=durations, meta_obj=mask_meta_obj, data_files=bold_files + [mask_file, paradigm_csv_file], data_type='volume', mask_loaded_from_file=mask_loaded_from_file, backgroundLabel=background_label) fd.set_init(FmriData.from_vol_files, mask_file=mask_file, paradigm_csv_file=paradigm_csv_file, bold_files=bold_files, tr=tr, background_label=background_label, paradigm_csv_delim=paradigm_csv_delim) return fd
def from_vol_files_rel(self, mask_file, paradigm_csv_file, bold_files, tr, rel_conditions): paradigm = Paradigm.from_csv(paradigm_csv_file) durations = OrderedDict() onsets = OrderedDict() for i in xrange(len(rel_conditions)): durations[rel_conditions[i]] = paradigm.stimDurations[ rel_conditions[i]] onsets[rel_conditions[i]] = paradigm.stimOnsets[rel_conditions[i]] m, mmo, mlf, b, ss = load_vol_bold_and_mask(bold_files, mask_file) mask = m mask_meta_obj = mmo mask_loaded_from_file = mlf bold = b sessionScans = ss fd = FmriData(onsets, bold, tr, sessionScans, mask, stimDurations=durations, meta_obj=mask_meta_obj, data_files=bold_files + [mask_file, paradigm_csv_file], data_type='volume', mask_loaded_from_file=mask_loaded_from_file) fd.set_init(FmriData.from_vol_files, mask_file=mask_file, paradigm_csv_file=paradigm_csv_file, bold_files=bold_files, tr=tr) return fd
def create_physio_brf(physiological_params, response_dt=.5, response_duration=25., return_brf_q_v=False): """ Generate a BOLD response function by integrating a physiological model and setting its driving input signal to a single impulse. Args: - physiological_params (dict (<pname (str)> : <pvalue (float)>)): parameters of the physiological model. In jde.sandbox.physio see PHY_PARAMS_FRISTON00, PHY_PARAMS_FMRII ... - response_dt (float): temporal resolution of the response, in second - response_duration (float): duration of the response, in second Return: - np.array(nb_time_coeffs, float) -> the BRF (normalized) - also return brf_not_normalized, q, v when return_prf_q_v=True (for error checking of v and q generation in calc_hrfs) """ p = Paradigm({'c': [np.array([0.])]}, [response_duration], {'c': [np.array([1.])]}) n = np.array([[1.]]) s, f, v, q = create_evoked_physio_signals(physiological_params, p, n, response_dt) brf = create_bold_from_hbr_and_cbv(physiological_params, q[:, 0], v[:, 0]) if return_brf_q_v: return brf / ( brf**2).sum()**.5, q, v, s, f #WARNING!! Added to compute figures #return brf, q, v, s, f #WARNING!! Added to compute figures else: return brf / (brf**2).sum()**.5
def create_physio_prf(physiological_params, response_dt=.5, response_duration=25., return_prf_q_v=False): """ Generate a perfusion response function by setting the input driving signal of the given physiological model with a single impulse. Args: - physiological_params (dict (<pname (str)> : <pvalue (float)>)): parameters of the physiological model. In jde.sandbox.physio see PHY_PARAMS_FRISTON00, PHY_PARAMS_FMRII ... - response_dt (float): temporal resolution of the response, in second - response_duration (float): duration of the response, in second Return: - np.array(nb_time_coeffs, float) -> the PRF - also return brf_not_normalized, q, v when return_prf_q_v=True (for error checking of v and q generation in calc_hrfs) """ p = Paradigm({'c': [np.array([0.])]}, [response_duration], {'c': [np.array([1.])]}) # response_dt to match convention # in JDE analysis n = np.array([[1.]]) s, f, v, q = create_evoked_physio_signals(physiological_params, p, n, response_dt) prf = f[:, 0] - f[0, 0] #remove y-intercept if return_prf_q_v: return prf / (prf**2).sum()**.5, q, v #return prf, q, v else: return prf / (prf**2).sum()**.5
def from_surf_files(self, paradigm_csv_file=DEFAULT_PARADIGM_CSV, bold_files=None, tr=DEFAULT_BOLD_SURF_TR, mesh_file=DEFAULT_MESH_FILE, mask_file=None): """Return FmriData representation from surf files""" if bold_files is None: bold_files = [DEFAULT_BOLD_SURF_FILE] paradigm = Paradigm.from_csv(paradigm_csv_file) durations = paradigm.stimDurations onsets = paradigm.stimOnsets mask, mask_meta_obj, _, bold, session_scans, graphs, edge_lengths = \ load_surf_bold_mask(bold_files, mesh_file, mask_file) fmri_data = FmriData(onsets, bold, tr, session_scans, mask, graphs, stimDurations=durations, meta_obj=mask_meta_obj, data_files=bold_files + [mask_file, mesh_file], data_type='surface', edge_lengths=edge_lengths) fmri_data.set_init(FmriData.from_surf_files, paradigm_csv_file=paradigm_csv_file, bold_files=bold_files, tr=tr, mesh_file=mesh_file, mask_file=mask_file) return fmri_data
def __init__(self, onsets, bold, tr, sessionsScans, roiMask, graphs=None, stimDurations=None, meta_obj=None, simulation=None, backgroundLabel=0, data_files=None, data_type=None, edge_lengths=None, mask_loaded_from_file=False, extra_data=None): logger.info('Creation of FmriData object ...') if isinstance(bold, xndarray): logger.info('bold shape: %s', str(bold.data.shape)) else: logger.info('bold shape: %s', str(bold.shape)) logger.info('roi mask shape: %s', str(roiMask.shape)) logger.info('unique(mask): %s', str(np.unique(roiMask))) sessionsDurations = [len(ss) * tr for ss in sessionsScans] self.paradigm = Paradigm(onsets, sessionsDurations, stimDurations) self.tr = tr self.sessionsScans = sessionsScans self.extra_data = extra_data or {} if backgroundLabel is None: backgroundLabel = 0 self.backgroundLabel = backgroundLabel logger.info('backgroundLabel: %d', self.backgroundLabel) self.store_mask_sparse(roiMask) m = self.np_roi_mask if isinstance(bold, xndarray): if bold.data.ndim > 2: # volumic data print '----------------' if data_type is None: data_type = 'volume' assert roiMask.ndim == 3 if TIME_AXIS == 0: bold = bold.data[:, m[0], m[1], m[2]] else: # TIME_AXIS = 3 bold = bold.data[m[0], m[1], m[2], :].transpose() else: # surfacic or already flatten data assert bold.data.ndim == 2 if len(m[0]) != bold.data.shape[1]: bold = bold.data[:, m[0]] else: bold = bold.data else: if bold.ndim > 2: # volumic data if data_type is None: data_type = 'volume' assert roiMask.ndim == 3 if TIME_AXIS == 0: bold = bold[:, m[0], m[1], m[2]] else: # TIME_AXIS = 3 bold = bold[m[0], m[1], m[2], :].transpose() else: # surfacic or already flatten data assert bold.ndim == 2 if len(m[0]) != bold.shape[1]: bold = bold[:, m[0]] self.data_type = data_type logger.info('extracted bold shape (without background): %s', str(bold.shape)) self.bold = bold self.bold_full = bold self.bold_avg = None self.graphs = graphs self.edge_lengths = edge_lengths self.graphs_full = graphs self.graphs_avg = None self.meta_obj = meta_obj self.simulation = simulation self.nbConditions = len(self.paradigm.stimOnsets) self.nbSessions = len(sessionsScans) self.mask_loaded_from_file = mask_loaded_from_file if data_files is None: data_files = [] self.data_files = data_files
class FmriData(XmlInitable): """ Attributes: onsets -- a dictionary mapping a stimulus name to a list of session onsets. Each item of this list is a 1D numpy float array of onsets for a given session. stimDurations -- same as 'onsets' but stores durations of stimuli roiMask -- numpy int array of roi labels (0 stands for the background). shape depends on the data form (3D volumic or 1D surfacic) bold -- either a 4D numpy float array with axes [sag,cor,ax,scan] and then spatial axes must have the same shape as roiMask, Or a 2D numpy float array with axes [scan, position] and position axis must have the same length as the number of positions within roiMask (without background). Sessions are stacked in the scan axis sessionsScans -- a list of session indexes along scan axis. tr -- Time of repetition of the BOLD signal simulation -- if not None then it should be a list of simulation instance. meta_obj -- extra information associated to data """ parametersComments = { 'tr': 'repetition time in seconds', 'sessions_data': 'List of data definition for all sessions', 'mask_file': 'Input n-ary mask file (= parcellation). ' 'Only positive integers are allowed. \n' 'All zeros are treated as background positions.' } parametersToShow = ['tr', 'sessions_data', 'mask_file'] if pyhrf.__usemode__ == 'devel': parametersToShow += ['background_label'] def __init__(self, onsets, bold, tr, sessionsScans, roiMask, graphs=None, stimDurations=None, meta_obj=None, simulation=None, backgroundLabel=0, data_files=None, data_type=None, edge_lengths=None, mask_loaded_from_file=False, extra_data=None): logger.info('Creation of FmriData object ...') if isinstance(bold, xndarray): logger.info('bold shape: %s', str(bold.data.shape)) else: logger.info('bold shape: %s', str(bold.shape)) logger.info('roi mask shape: %s', str(roiMask.shape)) logger.info('unique(mask): %s', str(np.unique(roiMask))) sessionsDurations = [len(ss) * tr for ss in sessionsScans] self.paradigm = Paradigm(onsets, sessionsDurations, stimDurations) self.tr = tr self.sessionsScans = sessionsScans self.extra_data = extra_data or {} if backgroundLabel is None: backgroundLabel = 0 self.backgroundLabel = backgroundLabel logger.info('backgroundLabel: %d', self.backgroundLabel) self.store_mask_sparse(roiMask) m = self.np_roi_mask if isinstance(bold, xndarray): if bold.data.ndim > 2: # volumic data print '----------------' if data_type is None: data_type = 'volume' assert roiMask.ndim == 3 if TIME_AXIS == 0: bold = bold.data[:, m[0], m[1], m[2]] else: # TIME_AXIS = 3 bold = bold.data[m[0], m[1], m[2], :].transpose() else: # surfacic or already flatten data assert bold.data.ndim == 2 if len(m[0]) != bold.data.shape[1]: bold = bold.data[:, m[0]] else: bold = bold.data else: if bold.ndim > 2: # volumic data if data_type is None: data_type = 'volume' assert roiMask.ndim == 3 if TIME_AXIS == 0: bold = bold[:, m[0], m[1], m[2]] else: # TIME_AXIS = 3 bold = bold[m[0], m[1], m[2], :].transpose() else: # surfacic or already flatten data assert bold.ndim == 2 if len(m[0]) != bold.shape[1]: bold = bold[:, m[0]] self.data_type = data_type logger.info('extracted bold shape (without background): %s', str(bold.shape)) self.bold = bold self.bold_full = bold self.bold_avg = None self.graphs = graphs self.edge_lengths = edge_lengths self.graphs_full = graphs self.graphs_avg = None self.meta_obj = meta_obj self.simulation = simulation self.nbConditions = len(self.paradigm.stimOnsets) self.nbSessions = len(sessionsScans) self.mask_loaded_from_file = mask_loaded_from_file if data_files is None: data_files = [] self.data_files = data_files def get_extra_data(self, label, default): return self.extra_data.get(label, default) def set_extra_data(self, label, value): self.extra_data[label] = value def get_condition_names(self): return self.paradigm.stimOnsets.keys() def store_mask_sparse(self, roiMask): self.np_roi_mask = np.where(roiMask != self.backgroundLabel) self.roi_ids_in_mask = roiMask[self.np_roi_mask] self.nb_voxels_in_mask = len(self.roi_ids_in_mask) self.spatial_shape = roiMask.shape def get_roi_mask(self): roi_mask = np.zeros(self.spatial_shape, dtype=self.roi_ids_in_mask.dtype) + \ self.backgroundLabel roi_mask[self.np_roi_mask] = self.roi_ids_in_mask return roi_mask roiMask = property(get_roi_mask) # def __getstate__(self): # return dict((k, v) for (k, v) in self.__dict__.iteritems() \ # if k != 'roiMask') def get_nb_rois(self): """ Return the number of parcels (background id is discarded) """ s = set(np.unique(self.roi_ids_in_mask)).discard(0) return len(s) @PickleableStaticMethod def from_vol_files(self, mask_file=DEFAULT_MASK_VOL_FILE, paradigm_csv_file=DEFAULT_PARADIGM_CSV, bold_files=[DEFAULT_BOLD_VOL_FILE], tr=DEFAULT_BOLD_VOL_TR, background_label=None, paradigm_csv_delim=None): paradigm = Paradigm.from_csv(paradigm_csv_file, delim=paradigm_csv_delim) durations = paradigm.stimDurations onsets = paradigm.stimOnsets m, mmo, mlf, b, ss = load_vol_bold_and_mask(bold_files, mask_file) mask = m mask_meta_obj = mmo mask_loaded_from_file = mlf bold = b sessionScans = ss fd = FmriData(onsets, bold, tr, sessionScans, mask, stimDurations=durations, meta_obj=mask_meta_obj, data_files=bold_files + [mask_file, paradigm_csv_file], data_type='volume', mask_loaded_from_file=mask_loaded_from_file, backgroundLabel=background_label) fd.set_init(FmriData.from_vol_files, mask_file=mask_file, paradigm_csv_file=paradigm_csv_file, bold_files=bold_files, tr=tr, background_label=background_label, paradigm_csv_delim=paradigm_csv_delim) return fd @PickleableStaticMethod def from_vol_files_rel(self, mask_file, paradigm_csv_file, bold_files, tr, rel_conditions): paradigm = Paradigm.from_csv(paradigm_csv_file) durations = OrderedDict() onsets = OrderedDict() for i in xrange(len(rel_conditions)): durations[rel_conditions[i]] = paradigm.stimDurations[ rel_conditions[i]] onsets[rel_conditions[i]] = paradigm.stimOnsets[rel_conditions[i]] m, mmo, mlf, b, ss = load_vol_bold_and_mask(bold_files, mask_file) mask = m mask_meta_obj = mmo mask_loaded_from_file = mlf bold = b sessionScans = ss fd = FmriData(onsets, bold, tr, sessionScans, mask, stimDurations=durations, meta_obj=mask_meta_obj, data_files=bold_files + [mask_file, paradigm_csv_file], data_type='volume', mask_loaded_from_file=mask_loaded_from_file) fd.set_init(FmriData.from_vol_files, mask_file=mask_file, paradigm_csv_file=paradigm_csv_file, bold_files=bold_files, tr=tr) return fd @PickleableStaticMethod def from_vol_ui(self, sessions_data=[FMRISessionVolumicData()], tr=DEFAULT_BOLD_VOL_TR, mask_file=DEFAULT_MASK_VOL_FILE, background_label=None): """ Convenient creation function intended to be used for XML I/O. 'session_data' is a list of FMRISessionVolumicData objects. 'tr' is the repetition time. 'mask_file' is a path to a functional mask file. This represents the following hierarchy: - FMRIData: - list of session data: [ * data for session 1: - onsets for session 1, - durations for session 1, - fmri data file for session 1 (nii) * data for session 2: - onsets for session 2, - durations for session 2, - fmri data file for session 2 (nii) ], - repetition time - mask file """ logger.info('Load volumic data ...') logger.info('Input sessions data:') logger.debug(sessions_data) sda = stack_trees([sda.to_dict() for sda in sessions_data]) onsets = sda['onsets'] durations = sda['durations'] bold_files = sda['bold_file'] # FIXME: HACKS!! if isinstance(onsets.values()[0][0], list): for i in xrange(len(onsets.keys())): onsets[onsets.keys()[i]] = onsets[onsets.keys()[i]][0] if isinstance(durations.values()[0][0], list): for i in xrange(len(durations.keys())): durations[durations.keys()[i]] = \ durations[durations.keys()[i]][0] if len(durations.values()[0][0].shape) > 1: for i in xrange(len(durations.keys())): durations.values()[i][0] = durations.values()[i][0][0] if len(onsets.keys()) == 1: onsets[onsets.keys()[0]] = onsets[onsets.keys()[0]][0] durations[onsets.keys()[0]] = durations[onsets.keys()[0]][0] if isinstance(durations, list) and durations[0] is None: durations = None mask, mmo, mlf, bold, session_scans = \ load_vol_bold_and_mask(bold_files, mask_file) mask_meta_obj = mmo mask_loaded_from_file = mlf fmri_data = FmriData(onsets, bold, tr, session_scans, mask, stimDurations=durations, meta_obj=mask_meta_obj, data_files=bold_files + [mask_file], backgroundLabel=background_label, data_type='volume', mask_loaded_from_file=mask_loaded_from_file) fmri_data.set_init(FmriData.from_vol_ui, sessions_data=sessions_data, tr=tr, mask_file=mask_file, background_label=background_label) return fmri_data @classmethod def from_surf_files(self, paradigm_csv_file=DEFAULT_PARADIGM_CSV, bold_files=None, tr=DEFAULT_BOLD_SURF_TR, mesh_file=DEFAULT_MESH_FILE, mask_file=None): """Return FmriData representation from surf files""" if bold_files is None: bold_files = [DEFAULT_BOLD_SURF_FILE] paradigm = Paradigm.from_csv(paradigm_csv_file) durations = paradigm.stimDurations onsets = paradigm.stimOnsets mask, mask_meta_obj, _, bold, session_scans, graphs, edge_lengths = \ load_surf_bold_mask(bold_files, mesh_file, mask_file) fmri_data = FmriData(onsets, bold, tr, session_scans, mask, graphs, stimDurations=durations, meta_obj=mask_meta_obj, data_files=bold_files + [mask_file, mesh_file], data_type='surface', edge_lengths=edge_lengths) fmri_data.set_init(FmriData.from_surf_files, paradigm_csv_file=paradigm_csv_file, bold_files=bold_files, tr=tr, mesh_file=mesh_file, mask_file=mask_file) return fmri_data @classmethod def from_surf_ui(cls, sessions_data=None, tr=DEFAULT_BOLD_SURF_TR, mask_file=DEFAULT_MASK_SURF_FILE, mesh_file=DEFAULT_MESH_FILE): """ Convenient creation function intended to be used for XML I/O. 'session_data' is a list of FMRISessionVolumicData objects. 'tr' is the time of repetition. 'mask_file' is a path to a functional mask file. This represents the following hierarchy: - FMRIData: - list of session data: [ * data for session 1: - onsets for session 1, - durations for session 1, - fmri data file for session 1 (gii) * data for session 2: - onsets for session 2, - durations for session 2, - fmri data file for session 2 (gii) ], - time of repetition - mask file - mesh file """ if sessions_data is None: sessions_data = [FMRISessionSurfacicData()] logger.info('Load surfacic data...') sda = stack_trees([sda.to_dict() for sda in sessions_data]) onsets = sda['onsets'] durations = sda['durations'] bold_files = sda['bold_file'] if isinstance(durations, list) and durations[0] is None: durations = None (mask, mask_meta_obj, _, bold, session_scans, graphs, edge_lengths) = load_surf_bold_mask(bold_files, mesh_file, mask_file) fmri_data = FmriData(onsets, bold, tr, session_scans, mask, graphs, stimDurations=durations, meta_obj=mask_meta_obj, data_files=bold_files + [mask_file, mesh_file], data_type='surface', edge_lengths=edge_lengths) fmri_data.set_init(FmriData.from_surf_ui, sessions_data=sessions_data, tr=tr, mask_file=mask_file, mesh_file=mesh_file) return fmri_data @classmethod def from_simu_ui(cls, sessions_data=None): if sessions_data is None: sessions_data = [FMRISessionSimulationData()] # load simu.pck -> b logger.debug('from_simu_ui\n' 'simulation file: %s', sessions_data[0].simulation_file) bs = [cPickle.load(file(sd.simulation_file)) for sd in sessions_data] # print 'condName:',b.conditions # print 'onsets:',b.onsets # print 'durations:',b.durations # print 'b:',b # print 'b type is :', type(b) fds = [] for b in bs: fd = FmriData.from_simulation_dict(b) fds.append(fd) fds = merge_fmri_sessions(fds) fds.set_init(FmriData.from_simu_ui, sessions_data=sessions_data) return fds @classmethod def from_simulation_dict(self, simulation, mask=None): from pyhrf.tools._io import read_volume bold = simulation['bold'] if isinstance(bold, xndarray): bold = bold.reorient(['time', 'voxel']) nvox = bold.data.shape[1] ss = [range(bold.data.shape[0])] # one session print 'BOLD SHAPE=', bold.data.shape else: nvox = bold.shape[1] ss = [range(bold.shape[0])] # one session onsets = simulation['paradigm'].stimOnsets # onsets = dict(zip(ons.keys(),ons.values()])) durations = simulation['paradigm'].stimDurations #durations = dict(zip(dur.keys(),[o for o in dur.values()])) # print '' # print 'onsets:' # print onsets # print '' tr = simulation['tr'] s = simulation labelsVol = s.get('labels_vol', np.ones((1, nvox,))) if mask is None: if isinstance(labelsVol, xndarray): default_mshape = labelsVol.data.shape[1:] else: default_mshape = labelsVol.shape[1:] # print 'default_mask_shape:', default_mshape roiMask = simulation.get('mask', np.ones(default_mshape, dtype=np.int32)) else: roiMask = read_volume(mask)[0] # print 'roiMask:', roiMask.shape if len(roiMask.shape) == 3: data_type = 'volume' else: data_type = 'surface' # simulation ?? return FmriData(onsets, bold, tr, ss, roiMask, stimDurations=durations, simulation=[simulation], data_type=data_type) def get_data_files(self): return self.data_files def save(self, output_dir): """ Save paradigm to output_dir/paradigm.csv, BOLD to output_dir/bold.nii, mask to output_dir/mask.nii #TODO: handle multi-session Return: tuple of file names in this order: (paradigm, bold, mask) """ from pyhrf.tools._io import write_volume, write_texture paradigm_file = op.join(output_dir, 'paradigm.csv') self.paradigm.save_csv(paradigm_file) if self.data_type == 'volume': # unflatten bold bold_vol = expand_array_in_mask(self.bold, self.roiMask, 1) bold_vol = np.rollaxis(bold_vol, 0, 4) bold_file = op.join(output_dir, 'bold.nii') write_volume(bold_vol, bold_file, self.meta_obj) mask_file = op.join(output_dir, 'mask.nii') write_volume(self.roiMask, mask_file, self.meta_obj) elif self.data_type == 'surface': # TODO surface bold_file = op.join(output_dir, 'bold.gii') write_texture(self.bold_vol, bold_file, self.meta_obj) pass return paradigm_file, bold_file, mask_file def build_graphs(self, force=False): logger.debug('FmriData.build_graphs (self.graphs is None ? %s ) ...', str(self.graphs is None)) logger.debug('data_type: %s', self.data_type) if self.graphs is None or force: if self.data_type == 'volume': logger.info('Building graph from volume ...') to_discard = [self.backgroundLabel] self.graphs = parcels_to_graphs(self.roiMask, kerMask3D_6n, toDiscard=to_discard) logger.info('Graph built (%d rois)!', len(self.graphs.keys())) self.edge_lentghs = dict([(i, [[1] * len(nl) for nl in g]) for i, g in self.graphs.items()]) elif self.data_type == 'surface': if self.graphs is not None: return self.graphs else: raise Exception('Graph is not set for surface data!') def get_roi_id(self): """ In case of FMRI data containing only one ROI, return the id of this ROI. If data contains several ROIs then raise an exception """ # roi_ids_in_mask = set(self.roiMask.flatten()) # if self.backgroundLabel in roi_ids_in_mask: # roi_ids_in_mask.remove(self.backgroundLabel) # roi_ids_in_mask = list(roi_ids_in_mask) unique_roi_ids = np.unique(self.roi_ids_in_mask) if len(unique_roi_ids) > 1: raise Exception('FMRI data contains more than one ROI') return unique_roi_ids[0] def get_nb_vox_in_mask(self): return self.nb_voxels_in_mask # return (self.roiMask != self.backgroundLabel).sum() def get_graph(self): self.build_graphs(force=True) if len(self.graphs) == 1: return self.graphs[self.graphs.keys()[0]] else: return self.graphs def roi_split(self, mask=None): if mask is None: mask = self.roiMask assert mask.shape == self.roiMask.shape onsets = self.paradigm.stimOnsets durations = self.paradigm.stimDurations in_mask = mask[np.where(mask != self.backgroundLabel)] data_rois = [] for roiId in np.unique(mask): if roiId != self.backgroundLabel: mroi = np.where(mask == roiId) roiMask = np.zeros_like(mask) + self.backgroundLabel roiMask[mroi] = roiId mroi_bold = np.where(in_mask == roiId) roiBold = self.bold[:, mroi_bold[0]] roiGraph = None if self.graphs is not None: roiGraph = self.graphs[roiId] logger.info('graph for roi %s has %d nodes', roiId, len(roiGraph)) else: logger.info('graph for roi %s is None', (roiId)) simulation = get_roi_simulation( self.simulation, in_mask, roiId) data_rois.append(FmriData(onsets, roiBold, self.tr, self.sessionsScans, roiMask, {roiId: roiGraph}, durations, self.meta_obj, simulation, self.backgroundLabel, self.data_files, self.data_type)) return data_rois def discard_small_rois(self, min_size): too_small_rois = [i for i in np.unique(self.roi_ids_in_mask) if (self.roi_ids_in_mask == i).sum() < min_size] logger.info(" %d too small ROIs are discarded (size < %d)", len(too_small_rois), min_size) self.discard_rois(too_small_rois) def discard_rois(self, roi_ids): roiMask = self.roiMask for roi_id in roi_ids: mroi = np.where(roiMask == roi_id) roiMask[mroi] = self.backgroundLabel self.store_mask_sparse(roiMask) if self.graphs is not None: self.build_graphs(force=True) def keep_only_rois(self, roiIds): roiToKeep = set(np.unique(roiIds)) roiToRemove = set( np.unique(self.roi_ids_in_mask)).difference(roiToKeep) self.discard_rois(roiToRemove) def get_joined_onsets(self): return self.paradigm.get_joined_onsets() def get_joined_durations(self): return self.paradigm.get_joined_durations() # TODO : fix average computing -> handle sparse representation of mask def compute_average(self): # raise NotImplementedError("TODO : fix average computing -> "\ # "handle sparse representation of mask") in_mask = self.roiMask[np.where(self.roiMask != self.backgroundLabel)] bg_lab = self.backgroundLabel roi_ids_in_mask = set(self.roiMask.flatten()) roi_ids_in_mask.remove(bg_lab) self.mask_avg = np.array(sorted(roi_ids_in_mask)) self.bold_avg = np.zeros((self.bold.shape[0], self.mask_avg.size)) for i, roi_id in enumerate(self.mask_avg): mroi = np.where(in_mask == roi_id) self.bold_avg[:, i] = self.bold[:, mroi[0]].mean(1) if self.graphs_avg is None and self.graphs is not None: # average scenario -> only one position per roi: self.graphs_avg = [[]] * len(self.graph) self.graph = self.graphs_avg def average(self, flag=True): # raise NotImplementedError("TODO : fix average computing -> "\ # "handle sparse representation of mask") self.average_flag = flag if self.average_flag: if self.bold_avg is None: self.compute_average() self.bold = self.bold_avg self.graphs = self.graphs_avg #self.roiMask = self.mask_avg else: self.bold = self.bold_full self.graphs = self.graphs_full #self.roiMask = self.roiMask_full def getSummary(self, long=False): """ """ bg_lab = self.backgroundLabel parcel_sizes = np.bincount(self.roiMask.flatten()) s = '' s += self.paradigm.get_info(long=long) roiIds = np.unique(self.roiMask) s += ' - geometry: %s [%s]\n' % (str(self.roiMask.shape), string.join(MRI3Daxes, ',')) s += ' - graph computed: %s\n' % str(self.graphs is not None) s += ' - %d rois - [%d' % (len(roiIds), roiIds[0]) if len(roiIds) > 1: s += '...%d]\n' % (sorted(roiIds)[-1]) else: s += ']\n' s += ' - background label: %d\n' % (self.backgroundLabel) bg_size = (self.roiMask == bg_lab).sum() s += ' - background size: %d\n' % bg_size s += ' - nb voxels (without background): %d\n' \ % (self.roiMask.size - bg_size) if self.meta_obj is not None: if isinstance(self.meta_obj, dict) and \ self.meta_obj.has_key('voxel_size'): s += ' - voxel size : %s\n' % str(self.meta_obj['voxel_size']) biggest_parcel = np.argmax(parcel_sizes) # print 'biggest_parcel:', biggest_parcel s += ' - biggest parcel : %d (size=%d)\n' \ % (biggest_parcel, parcel_sizes[biggest_parcel]) s += ' - nb sessions: %d\n' % self.nbSessions s += ' - scans per session:\n' for si, ss in enumerate(self.sessionsScans): s += ' sess %d -> [%d...%d] (%d)\n' % (si, ss[0], ss[-1], len(ss)) # print 'type tr:', self.tr, type(self.tr) s += ' - tr : %1.2f\n' % self.tr if long: in_mask = self.roiMask[np.where(self.roiMask != bg_lab)] # print 'in_mask:', in_mask.size # print roiIds # print self.bold.keys() for i in np.unique(in_mask): mroi = np.where(in_mask == i) bold_roi = self.bold[:, mroi[0]] s += ' .. roid %d: size=%d \n' \ % (i, parcel_sizes[i]) s += ' bold: %1.2f(s%1.2f)[%1.2f;%1.2f]\n' \ % (bold_roi.mean(), bold_roi.std(), bold_roi.min(), bold_roi.max()) return s def __repr__(self): """ Return a readable string representation of the object. Ensures that if 2 objects are instanciated with the same parameters they yield the same representation. """ r = self.__class__.__name__ + '(' r += 'onsets=' + repr(self.paradigm.stimOnsets) + ',' r += 'bold=' + repr(self.bold) + ',' r += 'tr=' + repr(self.tr) + ',' r += 'sessionsScans=' + repr(self.sessionsScans) + ',' r += 'roiMask=' + repr(self.roiMask) + ',' r += 'graph=' + repr(self.graphs) + ',' r += 'stimDurations=' + repr(self.paradigm.stimDurations) + ',' r += 'meta_obj=' + repr(self.meta_obj) # + ',' #r += 'simulation=' + repr(self.simulation) # TODO: make proper 'readable' __repr__ function for BoldModel object r += ')' return r
class FmriData(XmlInitable): """ Attributes: onsets -- a dictionary mapping a stimulus name to a list of session onsets. Each item of this list is a 1D numpy float array of onsets for a given session. stimDurations -- same as 'onsets' but stores durations of stimuli roiMask -- numpy int array of roi labels (0 stands for the background). shape depends on the data form (3D volumic or 1D surfacic) bold -- either a 4D numpy float array with axes [sag,cor,ax,scan] and then spatial axes must have the same shape as roiMask, Or a 2D numpy float array with axes [scan, position] and position axis must have the same length as the number of positions within roiMask (without background). Sessions are stacked in the scan axis sessionsScans -- a list of session indexes along scan axis. tr -- Time of repetition of the BOLD signal simulation -- if not None then it should be a list of simulation instance. meta_obj -- extra information associated to data """ parametersComments = { 'tr': 'repetition time in seconds', 'sessions_data': 'List of data definition for all sessions', 'mask_file': 'Input n-ary mask file (= parcellation). ' 'Only positive integers are allowed. \n' 'All zeros are treated as background positions.' } parametersToShow = ['tr', 'sessions_data', 'mask_file'] if pyhrf.__usemode__ == 'devel': parametersToShow += ['background_label'] def __init__(self, onsets, bold, tr, sessionsScans, roiMask, graphs=None, stimDurations=None, meta_obj=None, simulation=None, backgroundLabel=0, data_files=None, data_type=None, edge_lengths=None, mask_loaded_from_file=False, extra_data=None): logger.info('Creation of FmriData object ...') if isinstance(bold, xndarray): logger.info('bold shape: %s', str(bold.data.shape)) else: logger.info('bold shape: %s', str(bold.shape)) logger.info('roi mask shape: %s', str(roiMask.shape)) logger.info('unique(mask): %s', str(np.unique(roiMask))) sessionsDurations = [len(ss) * tr for ss in sessionsScans] self.paradigm = Paradigm(onsets, sessionsDurations, stimDurations) self.tr = tr self.sessionsScans = sessionsScans self.extra_data = extra_data or {} if backgroundLabel is None: backgroundLabel = 0 self.backgroundLabel = backgroundLabel logger.info('backgroundLabel: %d', self.backgroundLabel) self.store_mask_sparse(roiMask) m = self.np_roi_mask if isinstance(bold, xndarray): if bold.data.ndim > 2: # volumic data print '----------------' if data_type is None: data_type = 'volume' assert roiMask.ndim == 3 if TIME_AXIS == 0: bold = bold.data[:, m[0], m[1], m[2]] else: # TIME_AXIS = 3 bold = bold.data[m[0], m[1], m[2], :].transpose() else: # surfacic or already flatten data assert bold.data.ndim == 2 if len(m[0]) != bold.data.shape[1]: bold = bold.data[:, m[0]] else: bold = bold.data else: if bold.ndim > 2: # volumic data if data_type is None: data_type = 'volume' assert roiMask.ndim == 3 if TIME_AXIS == 0: bold = bold[:, m[0], m[1], m[2]] else: # TIME_AXIS = 3 bold = bold[m[0], m[1], m[2], :].transpose() else: # surfacic or already flatten data assert bold.ndim == 2 if len(m[0]) != bold.shape[1]: bold = bold[:, m[0]] self.data_type = data_type logger.info('extracted bold shape (without background): %s', str(bold.shape)) self.bold = bold self.bold_full = bold self.bold_avg = None self.graphs = graphs self.edge_lengths = edge_lengths self.graphs_full = graphs self.graphs_avg = None self.meta_obj = meta_obj self.simulation = simulation self.nbConditions = len(self.paradigm.stimOnsets) self.nbSessions = len(sessionsScans) self.mask_loaded_from_file = mask_loaded_from_file if data_files is None: data_files = [] self.data_files = data_files def get_extra_data(self, label, default): return self.extra_data.get(label, default) def set_extra_data(self, label, value): self.extra_data[label] = value def get_condition_names(self): return self.paradigm.stimOnsets.keys() def store_mask_sparse(self, roiMask): self.np_roi_mask = np.where(roiMask != self.backgroundLabel) self.roi_ids_in_mask = roiMask[self.np_roi_mask] self.nb_voxels_in_mask = len(self.roi_ids_in_mask) self.spatial_shape = roiMask.shape def get_roi_mask(self): roi_mask = np.zeros(self.spatial_shape, dtype=self.roi_ids_in_mask.dtype) + \ self.backgroundLabel roi_mask[self.np_roi_mask] = self.roi_ids_in_mask return roi_mask roiMask = property(get_roi_mask) # def __getstate__(self): # return dict((k, v) for (k, v) in self.__dict__.iteritems() \ # if k != 'roiMask') def get_nb_rois(self): """ Return the number of parcels (background id is discarded) """ s = set(np.unique(self.roi_ids_in_mask)).discard(0) return len(s) @PickleableStaticMethod def from_vol_files(self, mask_file=DEFAULT_MASK_VOL_FILE, paradigm_csv_file=DEFAULT_PARADIGM_CSV, bold_files=[DEFAULT_BOLD_VOL_FILE], tr=DEFAULT_BOLD_VOL_TR, background_label=None, paradigm_csv_delim=None): paradigm = Paradigm.from_csv(paradigm_csv_file, delim=paradigm_csv_delim) durations = paradigm.stimDurations onsets = paradigm.stimOnsets m, mmo, mlf, b, ss = load_vol_bold_and_mask(bold_files, mask_file) mask = m mask_meta_obj = mmo mask_loaded_from_file = mlf bold = b sessionScans = ss fd = FmriData(onsets, bold, tr, sessionScans, mask, stimDurations=durations, meta_obj=mask_meta_obj, data_files=bold_files + [mask_file, paradigm_csv_file], data_type='volume', mask_loaded_from_file=mask_loaded_from_file, backgroundLabel=background_label) fd.set_init(FmriData.from_vol_files, mask_file=mask_file, paradigm_csv_file=paradigm_csv_file, bold_files=bold_files, tr=tr, background_label=background_label, paradigm_csv_delim=paradigm_csv_delim) return fd @PickleableStaticMethod def from_vol_files_rel(self, mask_file, paradigm_csv_file, bold_files, tr, rel_conditions): paradigm = Paradigm.from_csv(paradigm_csv_file) durations = OrderedDict() onsets = OrderedDict() for i in xrange(len(rel_conditions)): durations[rel_conditions[i]] = paradigm.stimDurations[ rel_conditions[i]] onsets[rel_conditions[i]] = paradigm.stimOnsets[rel_conditions[i]] m, mmo, mlf, b, ss = load_vol_bold_and_mask(bold_files, mask_file) mask = m mask_meta_obj = mmo mask_loaded_from_file = mlf bold = b sessionScans = ss fd = FmriData(onsets, bold, tr, sessionScans, mask, stimDurations=durations, meta_obj=mask_meta_obj, data_files=bold_files + [mask_file, paradigm_csv_file], data_type='volume', mask_loaded_from_file=mask_loaded_from_file) fd.set_init(FmriData.from_vol_files, mask_file=mask_file, paradigm_csv_file=paradigm_csv_file, bold_files=bold_files, tr=tr) return fd @PickleableStaticMethod def from_vol_ui(self, sessions_data=[FMRISessionVolumicData()], tr=DEFAULT_BOLD_VOL_TR, mask_file=DEFAULT_MASK_VOL_FILE, background_label=None): """ Convenient creation function intended to be used for XML I/O. 'session_data' is a list of FMRISessionVolumicData objects. 'tr' is the repetition time. 'mask_file' is a path to a functional mask file. This represents the following hierarchy: - FMRIData: - list of session data: [ * data for session 1: - onsets for session 1, - durations for session 1, - fmri data file for session 1 (nii) * data for session 2: - onsets for session 2, - durations for session 2, - fmri data file for session 2 (nii) ], - repetition time - mask file """ logger.info('Load volumic data ...') logger.info('Input sessions data:') logger.debug(sessions_data) sda = stack_trees([sda.to_dict() for sda in sessions_data]) onsets = sda['onsets'] durations = sda['durations'] bold_files = sda['bold_file'] # FIXME: HACKS!! if isinstance(onsets.values()[0][0], list): for i in xrange(len(onsets.keys())): onsets[onsets.keys()[i]] = onsets[onsets.keys()[i]][0] if isinstance(durations.values()[0][0], list): for i in xrange(len(durations.keys())): durations[durations.keys()[i]] = \ durations[durations.keys()[i]][0] if len(durations.values()[0][0].shape) > 1: for i in xrange(len(durations.keys())): durations.values()[i][0] = durations.values()[i][0][0] if len(onsets.keys()) == 1: onsets[onsets.keys()[0]] = onsets[onsets.keys()[0]][0] durations[onsets.keys()[0]] = durations[onsets.keys()[0]][0] if isinstance(durations, list) and durations[0] is None: durations = None mask, mmo, mlf, bold, session_scans = \ load_vol_bold_and_mask(bold_files, mask_file) mask_meta_obj = mmo mask_loaded_from_file = mlf fmri_data = FmriData(onsets, bold, tr, session_scans, mask, stimDurations=durations, meta_obj=mask_meta_obj, data_files=bold_files + [mask_file], backgroundLabel=background_label, data_type='volume', mask_loaded_from_file=mask_loaded_from_file) fmri_data.set_init(FmriData.from_vol_ui, sessions_data=sessions_data, tr=tr, mask_file=mask_file, background_label=background_label) return fmri_data @classmethod def from_surf_files(self, paradigm_csv_file=DEFAULT_PARADIGM_CSV, bold_files=None, tr=DEFAULT_BOLD_SURF_TR, mesh_file=DEFAULT_MESH_FILE, mask_file=None): """Return FmriData representation from surf files""" if bold_files is None: bold_files = [DEFAULT_BOLD_SURF_FILE] paradigm = Paradigm.from_csv(paradigm_csv_file) durations = paradigm.stimDurations onsets = paradigm.stimOnsets mask, mask_meta_obj, _, bold, session_scans, graphs, edge_lengths = \ load_surf_bold_mask(bold_files, mesh_file, mask_file) fmri_data = FmriData(onsets, bold, tr, session_scans, mask, graphs, stimDurations=durations, meta_obj=mask_meta_obj, data_files=bold_files + [mask_file, mesh_file], data_type='surface', edge_lengths=edge_lengths) fmri_data.set_init(FmriData.from_surf_files, paradigm_csv_file=paradigm_csv_file, bold_files=bold_files, tr=tr, mesh_file=mesh_file, mask_file=mask_file) return fmri_data @classmethod def from_surf_ui(cls, sessions_data=None, tr=DEFAULT_BOLD_SURF_TR, mask_file=DEFAULT_MASK_SURF_FILE, mesh_file=DEFAULT_MESH_FILE): """ Convenient creation function intended to be used for XML I/O. 'session_data' is a list of FMRISessionVolumicData objects. 'tr' is the time of repetition. 'mask_file' is a path to a functional mask file. This represents the following hierarchy: - FMRIData: - list of session data: [ * data for session 1: - onsets for session 1, - durations for session 1, - fmri data file for session 1 (gii) * data for session 2: - onsets for session 2, - durations for session 2, - fmri data file for session 2 (gii) ], - time of repetition - mask file - mesh file """ if sessions_data is None: sessions_data = [FMRISessionSurfacicData()] logger.info('Load surfacic data...') sda = stack_trees([sda.to_dict() for sda in sessions_data]) onsets = sda['onsets'] durations = sda['durations'] bold_files = sda['bold_file'] if isinstance(durations, list) and durations[0] is None: durations = None (mask, mask_meta_obj, _, bold, session_scans, graphs, edge_lengths) = load_surf_bold_mask(bold_files, mesh_file, mask_file) fmri_data = FmriData(onsets, bold, tr, session_scans, mask, graphs, stimDurations=durations, meta_obj=mask_meta_obj, data_files=bold_files + [mask_file, mesh_file], data_type='surface', edge_lengths=edge_lengths) fmri_data.set_init(FmriData.from_surf_ui, sessions_data=sessions_data, tr=tr, mask_file=mask_file, mesh_file=mesh_file) return fmri_data @classmethod def from_simu_ui(cls, sessions_data=None): if sessions_data is None: sessions_data = [FMRISessionSimulationData()] # load simu.pck -> b logger.debug('from_simu_ui\n' 'simulation file: %s', sessions_data[0].simulation_file) bs = [cPickle.load(file(sd.simulation_file)) for sd in sessions_data] # print 'condName:',b.conditions # print 'onsets:',b.onsets # print 'durations:',b.durations # print 'b:',b # print 'b type is :', type(b) fds = [] for b in bs: fd = FmriData.from_simulation_dict(b) fds.append(fd) fds = merge_fmri_sessions(fds) fds.set_init(FmriData.from_simu_ui, sessions_data=sessions_data) return fds @classmethod def from_simulation_dict(self, simulation, mask=None): from pyhrf.tools._io import read_volume bold = simulation['bold'] if isinstance(bold, xndarray): bold = bold.reorient(['time', 'voxel']) nvox = bold.data.shape[1] ss = [range(bold.data.shape[0])] # one session print 'BOLD SHAPE=', bold.data.shape else: nvox = bold.shape[1] ss = [range(bold.shape[0])] # one session onsets = simulation['paradigm'].stimOnsets # onsets = dict(zip(ons.keys(),ons.values()])) durations = simulation['paradigm'].stimDurations #durations = dict(zip(dur.keys(),[o for o in dur.values()])) # print '' # print 'onsets:' # print onsets # print '' tr = simulation['tr'] s = simulation labelsVol = s.get('labels_vol', np.ones(( 1, nvox, ))) if mask is None: if isinstance(labelsVol, xndarray): default_mshape = labelsVol.data.shape[1:] else: default_mshape = labelsVol.shape[1:] # print 'default_mask_shape:', default_mshape roiMask = simulation.get( 'mask', np.ones(default_mshape, dtype=np.int32)) else: roiMask = read_volume(mask)[0] # print 'roiMask:', roiMask.shape if len(roiMask.shape) == 3: data_type = 'volume' else: data_type = 'surface' # simulation ?? return FmriData(onsets, bold, tr, ss, roiMask, stimDurations=durations, simulation=[simulation], data_type=data_type) def get_data_files(self): return self.data_files def save(self, output_dir): """ Save paradigm to output_dir/paradigm.csv, BOLD to output_dir/bold.nii, mask to output_dir/mask.nii #TODO: handle multi-session Return: tuple of file names in this order: (paradigm, bold, mask) """ from pyhrf.tools._io import write_volume, write_texture paradigm_file = op.join(output_dir, 'paradigm.csv') self.paradigm.save_csv(paradigm_file) if self.data_type == 'volume': # unflatten bold bold_vol = expand_array_in_mask(self.bold, self.roiMask, 1) bold_vol = np.rollaxis(bold_vol, 0, 4) bold_file = op.join(output_dir, 'bold.nii') write_volume(bold_vol, bold_file, self.meta_obj) mask_file = op.join(output_dir, 'mask.nii') write_volume(self.roiMask, mask_file, self.meta_obj) elif self.data_type == 'surface': # TODO surface bold_file = op.join(output_dir, 'bold.gii') write_texture(self.bold_vol, bold_file, self.meta_obj) pass return paradigm_file, bold_file, mask_file def build_graphs(self, force=False): logger.debug('FmriData.build_graphs (self.graphs is None ? %s ) ...', str(self.graphs is None)) logger.debug('data_type: %s', self.data_type) if self.graphs is None or force: if self.data_type == 'volume': logger.info('Building graph from volume ...') to_discard = [self.backgroundLabel] self.graphs = parcels_to_graphs(self.roiMask, kerMask3D_6n, toDiscard=to_discard) logger.info('Graph built (%d rois)!', len(self.graphs.keys())) self.edge_lentghs = dict([(i, [[1] * len(nl) for nl in g]) for i, g in self.graphs.items()]) elif self.data_type == 'surface': if self.graphs is not None: return self.graphs else: raise Exception('Graph is not set for surface data!') def get_roi_id(self): """ In case of FMRI data containing only one ROI, return the id of this ROI. If data contains several ROIs then raise an exception """ # roi_ids_in_mask = set(self.roiMask.flatten()) # if self.backgroundLabel in roi_ids_in_mask: # roi_ids_in_mask.remove(self.backgroundLabel) # roi_ids_in_mask = list(roi_ids_in_mask) unique_roi_ids = np.unique(self.roi_ids_in_mask) if len(unique_roi_ids) > 1: raise Exception('FMRI data contains more than one ROI') return unique_roi_ids[0] def get_nb_vox_in_mask(self): return self.nb_voxels_in_mask # return (self.roiMask != self.backgroundLabel).sum() def get_graph(self): self.build_graphs(force=True) if len(self.graphs) == 1: return self.graphs[self.graphs.keys()[0]] else: return self.graphs def roi_split(self, mask=None): if mask is None: mask = self.roiMask assert mask.shape == self.roiMask.shape onsets = self.paradigm.stimOnsets durations = self.paradigm.stimDurations in_mask = mask[np.where(mask != self.backgroundLabel)] data_rois = [] for roiId in np.unique(mask): if roiId != self.backgroundLabel: mroi = np.where(mask == roiId) roiMask = np.zeros_like(mask) + self.backgroundLabel roiMask[mroi] = roiId mroi_bold = np.where(in_mask == roiId) roiBold = self.bold[:, mroi_bold[0]] roiGraph = None if self.graphs is not None: roiGraph = self.graphs[roiId] logger.info('graph for roi %s has %d nodes', roiId, len(roiGraph)) else: logger.info('graph for roi %s is None', (roiId)) simulation = get_roi_simulation(self.simulation, in_mask, roiId) data_rois.append( FmriData(onsets, roiBold, self.tr, self.sessionsScans, roiMask, {roiId: roiGraph}, durations, self.meta_obj, simulation, self.backgroundLabel, self.data_files, self.data_type)) return data_rois def discard_small_rois(self, min_size): too_small_rois = [ i for i in np.unique(self.roi_ids_in_mask) if (self.roi_ids_in_mask == i).sum() < min_size ] logger.info(" %d too small ROIs are discarded (size < %d)", len(too_small_rois), min_size) self.discard_rois(too_small_rois) def discard_rois(self, roi_ids): roiMask = self.roiMask for roi_id in roi_ids: mroi = np.where(roiMask == roi_id) roiMask[mroi] = self.backgroundLabel self.store_mask_sparse(roiMask) if self.graphs is not None: self.build_graphs(force=True) def keep_only_rois(self, roiIds): roiToKeep = set(np.unique(roiIds)) roiToRemove = set(np.unique( self.roi_ids_in_mask)).difference(roiToKeep) self.discard_rois(roiToRemove) def get_joined_onsets(self): return self.paradigm.get_joined_onsets() def get_joined_durations(self): return self.paradigm.get_joined_durations() # TODO : fix average computing -> handle sparse representation of mask def compute_average(self): # raise NotImplementedError("TODO : fix average computing -> "\ # "handle sparse representation of mask") in_mask = self.roiMask[np.where(self.roiMask != self.backgroundLabel)] bg_lab = self.backgroundLabel roi_ids_in_mask = set(self.roiMask.flatten()) roi_ids_in_mask.remove(bg_lab) self.mask_avg = np.array(sorted(roi_ids_in_mask)) self.bold_avg = np.zeros((self.bold.shape[0], self.mask_avg.size)) for i, roi_id in enumerate(self.mask_avg): mroi = np.where(in_mask == roi_id) self.bold_avg[:, i] = self.bold[:, mroi[0]].mean(1) if self.graphs_avg is None and self.graphs is not None: # average scenario -> only one position per roi: self.graphs_avg = [[]] * len(self.graph) self.graph = self.graphs_avg def average(self, flag=True): # raise NotImplementedError("TODO : fix average computing -> "\ # "handle sparse representation of mask") self.average_flag = flag if self.average_flag: if self.bold_avg is None: self.compute_average() self.bold = self.bold_avg self.graphs = self.graphs_avg #self.roiMask = self.mask_avg else: self.bold = self.bold_full self.graphs = self.graphs_full #self.roiMask = self.roiMask_full def getSummary(self, long=False): """ """ bg_lab = self.backgroundLabel parcel_sizes = np.bincount(self.roiMask.flatten()) s = '' s += self.paradigm.get_info(long=long) roiIds = np.unique(self.roiMask) s += ' - geometry: %s [%s]\n' % (str( self.roiMask.shape), string.join(MRI3Daxes, ',')) s += ' - graph computed: %s\n' % str(self.graphs is not None) s += ' - %d rois - [%d' % (len(roiIds), roiIds[0]) if len(roiIds) > 1: s += '...%d]\n' % (sorted(roiIds)[-1]) else: s += ']\n' s += ' - background label: %d\n' % (self.backgroundLabel) bg_size = (self.roiMask == bg_lab).sum() s += ' - background size: %d\n' % bg_size s += ' - nb voxels (without background): %d\n' \ % (self.roiMask.size - bg_size) if self.meta_obj is not None: if isinstance(self.meta_obj, dict) and \ self.meta_obj.has_key('voxel_size'): s += ' - voxel size : %s\n' % str(self.meta_obj['voxel_size']) biggest_parcel = np.argmax(parcel_sizes) # print 'biggest_parcel:', biggest_parcel s += ' - biggest parcel : %d (size=%d)\n' \ % (biggest_parcel, parcel_sizes[biggest_parcel]) s += ' - nb sessions: %d\n' % self.nbSessions s += ' - scans per session:\n' for si, ss in enumerate(self.sessionsScans): s += ' sess %d -> [%d...%d] (%d)\n' % (si, ss[0], ss[-1], len(ss)) # print 'type tr:', self.tr, type(self.tr) s += ' - tr : %1.2f\n' % self.tr if long: in_mask = self.roiMask[np.where(self.roiMask != bg_lab)] # print 'in_mask:', in_mask.size # print roiIds # print self.bold.keys() for i in np.unique(in_mask): mroi = np.where(in_mask == i) bold_roi = self.bold[:, mroi[0]] s += ' .. roid %d: size=%d \n' \ % (i, parcel_sizes[i]) s += ' bold: %1.2f(s%1.2f)[%1.2f;%1.2f]\n' \ % (bold_roi.mean(), bold_roi.std(), bold_roi.min(), bold_roi.max()) return s def __repr__(self): """ Return a readable string representation of the object. Ensures that if 2 objects are instanciated with the same parameters they yield the same representation. """ r = self.__class__.__name__ + '(' r += 'onsets=' + repr(self.paradigm.stimOnsets) + ',' r += 'bold=' + repr(self.bold) + ',' r += 'tr=' + repr(self.tr) + ',' r += 'sessionsScans=' + repr(self.sessionsScans) + ',' r += 'roiMask=' + repr(self.roiMask) + ',' r += 'graph=' + repr(self.graphs) + ',' r += 'stimDurations=' + repr(self.paradigm.stimDurations) + ',' r += 'meta_obj=' + repr(self.meta_obj) # + ',' #r += 'simulation=' + repr(self.simulation) # TODO: make proper 'readable' __repr__ function for BoldModel object r += ')' return r