def load_surf_bold_mask(bold_files, mesh_file, mask_file=None): from pyhrf.tools._io import read_mesh, read_texture, discard_bad_data logger.info('Load mesh: ' + mesh_file) coords, triangles, coord_sys = read_mesh(mesh_file) logger.debug('Build graph...') fgraph = graph_from_mesh(triangles) assert graph_is_sane(fgraph) logger.info('Mesh has %d nodes', len(fgraph)) logger.debug('Compute length of edges ... ') edges_l = np.array([np.array([distance(coords[i], coords[n], coord_sys.xform) for n in nl]) for i, nl in enumerate(fgraph)], dtype=object) if mask_file is None or not op.exists(mask_file): logger.warning('Mask file %s does not exist. Taking ' 'all nodes ...', mask_file) mask = np.ones(len(fgraph)) mask_meta_obj = None mask_loaded_from_file = False else: mask, mask_meta_obj = read_texture(mask_file) mask_loaded_from_file = True if not (np.round(mask) == mask).all(): raise Exception("Mask is not n-ary") if len(mask) != len(fgraph): raise Exception('Size of mask (%d) is different from size ' 'of graph (%d)' % (len(mask), len(fgraph))) mask = mask.astype(np.int32) if mask.min() == -1: mask += 1 # Split graph into rois: graphs = {} edge_lengths = {} for roi_id in np.unique(mask): mroi = np.where(mask == roi_id) graph, _ = sub_graph(fgraph, mroi[0]) edge_lengths[roi_id] = edges_l[mroi] graphs[roi_id] = graph # Load BOLD: last_scan = 0 session_scans = [] bolds = [] for bold_file in bold_files: logger.info('load bold: %s', bold_file) bold, _ = read_texture(bold_file) logger.info('bold shape: %s', str(bold.shape)) bolds.append(bold) session_scans.append(np.arange(last_scan, last_scan + bold.shape[0], dtype=int)) last_scan += bold.shape[0] bold = np.concatenate(tuple(bolds)) if len(fgraph) != bold.shape[1]: raise Exception('Nb positions not consistent between BOLD (%d) ' 'and mesh (%d)' % (bold.shape[1], len(fgraph))) # discard bad data (bold with var=0 and nan values): discard_bad_data(bold, mask, time_axis=0) return mask, mask_meta_obj, mask_loaded_from_file, bold, session_scans, \ graphs, edge_lengths
def load_fmri_surf_data(boldFiles, meshFile, roiMaskFile=None): """ Load FMRI BOLD surface data from files. Arguments: boldFiles -- pathes to 2D texture data files (ie multisession data). roiMaskFile -- a path to a 1D texture data file. meshFile -- a path to a mesh file Return: A tuple (graphs, bolds, sessionScans, roiMask, dataHeader) graphs -- a dict {roiId:roiGraph}. Each roiGraph is a list of neighbours list bold -- a dict {roiId:bold}. Each bold is a 2D numpy float array with axes [time,position] sessionScans -- a list of scan indexes for every session roiMask -- a 1D numpy int array defining ROIs (0 stands for the background) dataHeader -- the header from the BOLD data file """ #Load ROIs: pyhrf.verbose(1, 'load roi mask: ' + roiMaskFile) #roiMask = Texture.read(roiMaskFile).data.astype(int) roiMask,_ = read_texture(roiMaskFile) pyhrf.verbose(1, 'roi mask shape: ' + str(roiMask.shape)) #Load BOLD: lastScan = 0 sessionScans = [] bolds = [] for boldFile in boldFiles: pyhrf.verbose(1, 'load bold: ' + boldFile) b,_ = read_texture(boldFile) pyhrf.verbose(1, 'bold shape: ' + str(b.shape)) bolds.append(b) sessionScans.append(np.arange(lastScan, lastScan+b.shape[0], dtype=int)) lastScan += b.shape[0] bold = np.concatenate(tuple(bolds)) # discard bad data (bold with var=0 and nan values): discard_bad_data(bold, roiMask, time_axis=0) #Load mesh: pyhrf.verbose(1, 'load mesh: ' + meshFile) coords,triangles,coord_sys = read_mesh(meshFile) #from soma import aims # mesh = aims.read(meshFile) # triangles = [t.arraydata() for t in mesh.polygon().list()] pyhrf.verbose(3, 'building graph ... ') wholeGraph = graph_from_mesh(triangles) assert graph_is_sane(wholeGraph) pyhrf.verbose(1, 'Mesh has %d nodes' %len(wholeGraph)) assert len(roiMask) == len(wholeGraph) assert bold.shape[1] == len(wholeGraph) pyhrf.verbose(3, 'Computing length of edges ... ') edges_l = np.array([np.array([distance(coords[i],coords[n],coord_sys.xform) \ for n in nl]) \ for i,nl in enumerate(wholeGraph)], dtype=object) #Split bold and graph into rois: roiBold = {} graphs = {} edge_lengthes = {} for roiId in np.unique(roiMask): mroi = np.where(roiMask==roiId) g, nm = sub_graph(wholeGraph, mroi[0]) edge_lengthes[roiId] = edges_l[mroi] graphs[roiId] = g roiBold[roiId] = bold[:, mroi[0]].astype(np.float32) return graphs, roiBold, sessionScans, roiMask, edge_lengthes
def parcellation_ward_spatial(func_data, n_clusters, graph=None): """ Make parcellation based upon ward hierarchical clustering from scikit-learn Inputs: - func_data: functional data: array of shape (nb_positions, dim_feature_1, [dim_feature2, ...]) - n_clusters: chosen number of clusters to create - graph: adjacency list defining neighbours (if None, no connectivity defined: clustering is spatially independent) Output: parcellation labels """ from sklearn.cluster import Ward from pyhrf.graph import graph_to_sparse_matrix, sub_graph #from pyhrf.tools import cartesian # print 'graph:' # print graph if graph is not None: #print 'connectivity;' #print connectivity.todense() labels = np.zeros(len(graph), dtype=np.int32) ccs = connected_components(graph) n_tot = len(graph) * 1. ncs = np.zeros(len(ccs), dtype=np.int32) for icc,cc in enumerate(ccs): nc = int(np.round(n_clusters * len(cc)/n_tot)) if nc == 0: nc = 1 ncs[icc] = nc max_nc = np.argmax(ncs) ncs[max_nc] = n_clusters - sum(ncs[0:max_nc]) - sum(ncs[max_nc+1:]) assert sum(ncs) == n_clusters assert (ncs > 0).all() pyhrf.verbose(1, 'Found %d connected components (CC) of sizes: %s' \ %(len(ccs), ' ,'.join([str(len(cc)) for cc in ccs]))) pyhrf.verbose(1, 'Nb of clusters to search in each CC: %s' \ %' ,'.join(map(str,ncs))) for nc,cc in zip(ncs,ccs): #print 'cc:', len(cc) #print 'cartesian:', list(cartesian(cc,cc)) if len(cc) < 2: continue if len(cc) < len(graph): cc_graph,_ = sub_graph(graph, cc) else: cc_graph = graph cc_connectivity = graph_to_sparse_matrix(cc_graph) #print 'compute subslice ...' # sub_slice = tuple(np.array(list(cartesian(cc,cc))).T) #indexes of the subpart of the connectivity matrix #print 'sub_slice:' #print sub_slice #print 'subslice connectivity matrix ...' #cc_connectivity = connectivity.tolil()[sub_slice].reshape((len(cc),len(cc))).tocoo() #indexes applied to the matrix connectivity (coo unsubscriptable) #print 'cc_connectivity' #print cc_connectivity.todense() cc_data = func_data[cc] pyhrf.verbose(2, 'Launch spatial Ward (nclusters=%d) '\ ' on data of shape %s' %(nc, str(cc_data.shape))) ward_object = Ward(n_clusters=nc, connectivity=cc_connectivity).fit(cc_data) labels[cc] += ward_object.labels_ + 1 + labels.max() else: ward_object = Ward(n_clusters=n_clusters).fit(func_data) # connectivity=None labels = ward_object.labels_ + 1 return labels
def parcellation_ward_spatial(func_data, n_clusters, graph=None): """ Make parcellation based upon ward hierarchical clustering from scikit-learn Inputs: - func_data: functional data: array of shape (nb_positions, dim_feature_1, [dim_feature2, ...]) - n_clusters: chosen number of clusters to create - graph: adjacency list defining neighbours (if None, no connectivity defined: clustering is spatially independent) Output: parcellation labels """ try: # sklearn version < 0.17 from sklearn.cluster import Ward as AgglomerativeClustering except ImportError: from sklearn.cluster import AgglomerativeClustering from pyhrf.graph import graph_to_sparse_matrix, sub_graph if graph is not None: labels = np.zeros(len(graph), dtype=np.int32) ccs = connected_components(graph) n_tot = len(graph) * 1. ncs = np.zeros(len(ccs), dtype=np.int32) for icc, cc in enumerate(ccs): nc = int(np.round(n_clusters * len(cc) / n_tot)) if nc == 0: nc = 1 ncs[icc] = nc max_nc = np.argmax(ncs) ncs[max_nc] = n_clusters - sum(ncs[0:max_nc]) - sum(ncs[max_nc + 1:]) assert sum(ncs) == n_clusters assert (ncs > 0).all() logger.info('Found %d connected components (CC) of sizes: %s', len(ccs), ' ,'.join([str(len(cc)) for cc in ccs])) logger.info('Nb of clusters to search in each CC: %s', ' ,'.join(map(str, ncs))) for nc, cc in zip(ncs, ccs): if len(cc) < 2: continue if len(cc) < len(graph): cc_graph, _ = sub_graph(graph, cc) else: cc_graph = graph cc_connectivity = graph_to_sparse_matrix(cc_graph) cc_data = func_data[cc] logger.info('Launch spatial Ward (nclusters=%d) on data of shape %s', nc, str(cc_data.shape)) ward_object = AgglomerativeClustering( n_clusters=nc, connectivity=cc_connectivity ).fit(cc_data) labels[cc] += ward_object.labels_ + 1 + labels.max() else: ward_object = AgglomerativeClustering( n_clusters=n_clusters ).fit(func_data) # connectivity=None labels = ward_object.labels_ + 1 return labels
def test_single_surface_PFPS_ML(self): """PF estimation method : path sampling. ML on p(label|beta). topology from a surfacic RDI """ # generate a field: beta = 0.4 nbClasses = 2 print 'generating potts ..., beta =', beta # grab surfacic data: from pyhrf.graph import graph_from_mesh, sub_graph, graph_is_sane from pyhrf.tools._io.tio import Texture from soma import aims print 'import done' roiId = 20 mfn = pyhrf.get_data_file_name('right_hemisphere.mesh') print 'mesh file:', mfn mesh = aims.read(mfn) print 'mesh read' triangles = [t.arraydata() for t in mesh.polygon().list()] print 'building graph ... ' wholeGraph = graph_from_mesh(triangles) roiMaskFile = pyhrf.get_data_file_name('roimask_gyrii_tuned.tex') roiMask = Texture.read(roiMaskFile).data.astype(int) mroi = np.where(roiMask==roiId) g, nm = sub_graph(wholeGraph, mroi[0]) print "g:", len(g), len(g[0]) nnodes = len(g) points = np.vstack([v.arraydata() for v in mesh.vertex().list()]) weights = [[1./dist(points[j],points[k]) for k in g[j]] for j in xrange(nnodes)] print "weights:", len(weights), len(weights[0]) if 1: for j in xrange(nnodes): s = sum(weights[j]) * 1. for k in xrange(len(weights[j])): weights[j][k] = weights[j][k]/s * len(weights[j]) labels = genPotts(g, beta, nbClasses, weights=weights) print labels # partition function estimation gridLnz = Cpt_Vec_Estim_lnZ_Graph(g, nbClasses, GraphWeight=weights) print 'gridLnz with weights:' print gridLnz # beta estimation be, pb = beta_estim_obs_field(g, labels, gridLnz, 'ML', weights) print 'betaML:', be weights = None gridLnz = Cpt_Vec_Estim_lnZ_Graph(g, nbClasses, GraphWeight=weights) print 'gridLnz without weights:' print gridLnz # beta estimation be, pb = beta_estim_obs_field(g, labels, gridLnz, 'ML', weights) print 'betaML:', be gridPace = gridLnz[1][1] - gridLnz[1][0] assert abs(be-beta) <= gridPace
def load_surf_bold_mask(bold_files, mesh_file, mask_file=None): from pyhrf.tools._io import read_mesh, read_texture, discard_bad_data logger.info('Load mesh: ' + mesh_file) coords, triangles, coord_sys = read_mesh(mesh_file) logger.debug('Build graph...') fgraph = graph_from_mesh(triangles) assert graph_is_sane(fgraph) logger.info('Mesh has %d nodes', len(fgraph)) logger.debug('Compute length of edges ... ') edges_l = np.array([ np.array([distance(coords[i], coords[n], coord_sys.xform) for n in nl]) for i, nl in enumerate(fgraph) ], dtype=object) if mask_file is None or not op.exists(mask_file): logger.warning('Mask file %s does not exist. Taking ' 'all nodes ...', mask_file) mask = np.ones(len(fgraph)) mask_meta_obj = None mask_loaded_from_file = False else: mask, mask_meta_obj = read_texture(mask_file) mask_loaded_from_file = True if not (np.round(mask) == mask).all(): raise Exception("Mask is not n-ary") if len(mask) != len(fgraph): raise Exception('Size of mask (%d) is different from size ' 'of graph (%d)' % (len(mask), len(fgraph))) mask = mask.astype(np.int32) if mask.min() == -1: mask += 1 # Split graph into rois: graphs = {} edge_lengths = {} for roi_id in np.unique(mask): mroi = np.where(mask == roi_id) graph, _ = sub_graph(fgraph, mroi[0]) edge_lengths[roi_id] = edges_l[mroi] graphs[roi_id] = graph # Load BOLD: last_scan = 0 session_scans = [] bolds = [] for bold_file in bold_files: logger.info('load bold: %s', bold_file) bold, _ = read_texture(bold_file) logger.info('bold shape: %s', str(bold.shape)) bolds.append(bold) session_scans.append( np.arange(last_scan, last_scan + bold.shape[0], dtype=int)) last_scan += bold.shape[0] bold = np.concatenate(tuple(bolds)) if len(fgraph) != bold.shape[1]: raise Exception('Nb positions not consistent between BOLD (%d) ' 'and mesh (%d)' % (bold.shape[1], len(fgraph))) # discard bad data (bold with var=0 and nan values): discard_bad_data(bold, mask, time_axis=0) return mask, mask_meta_obj, mask_loaded_from_file, bold, session_scans, \ graphs, edge_lengths
def parcellation_ward_spatial(func_data, n_clusters, graph=None): """ Make parcellation based upon ward hierarchical clustering from scikit-learn Inputs: - func_data: functional data: array of shape (nb_positions, dim_feature_1, [dim_feature2, ...]) - n_clusters: chosen number of clusters to create - graph: adjacency list defining neighbours (if None, no connectivity defined: clustering is spatially independent) Output: parcellation labels """ try: # sklearn version < 0.17 from sklearn.cluster import Ward as AgglomerativeClustering except ImportError: from sklearn.cluster import AgglomerativeClustering from pyhrf.graph import graph_to_sparse_matrix, sub_graph if graph is not None: labels = np.zeros(len(graph), dtype=np.int32) ccs = connected_components(graph) n_tot = len(graph) * 1. ncs = np.zeros(len(ccs), dtype=np.int32) for icc, cc in enumerate(ccs): nc = int(np.round(n_clusters * len(cc) / n_tot)) if nc == 0: nc = 1 ncs[icc] = nc max_nc = np.argmax(ncs) ncs[max_nc] = n_clusters - sum(ncs[0:max_nc]) - sum(ncs[max_nc + 1:]) assert sum(ncs) == n_clusters assert (ncs > 0).all() logger.info('Found %d connected components (CC) of sizes: %s', len(ccs), ' ,'.join([str(len(cc)) for cc in ccs])) logger.info('Nb of clusters to search in each CC: %s', ' ,'.join(map(str, ncs))) for nc, cc in zip(ncs, ccs): if len(cc) < 2: continue if len(cc) < len(graph): cc_graph, _ = sub_graph(graph, cc) else: cc_graph = graph cc_connectivity = graph_to_sparse_matrix(cc_graph) cc_data = func_data[cc] logger.info( 'Launch spatial Ward (nclusters=%d) on data of shape %s', nc, str(cc_data.shape)) ward_object = AgglomerativeClustering( n_clusters=nc, connectivity=cc_connectivity).fit(cc_data) labels[cc] += ward_object.labels_ + 1 + labels.max() else: ward_object = AgglomerativeClustering(n_clusters=n_clusters).fit( func_data) # connectivity=None labels = ward_object.labels_ + 1 return labels