def make_age_maps(data_file, info_file, out_name): """ 对每个顶点,计算跨同一年龄被试的平均和sem,分别保存在 out_name-mean.dscalar.nii, out_name-sem.dscalar.nii中 Args: data_file (str): end with .dscalar.nii shape=(n_subj, LR_count_32k) info_file (str): subject info file out_name (str): filename to save """ # prepare data_maps = nib.load(data_file).get_fdata() info_df = pd.read_csv(info_file) ages = np.array(info_df['age in years']) ages_uniq = np.unique(ages) n_age = len(ages_uniq) # calculate mean_maps = np.ones((n_age, LR_count_32k)) * np.nan sem_maps = np.ones((n_age, LR_count_32k)) * np.nan for age_idx, age in enumerate(ages_uniq): data = data_maps[ages == age] mean_maps[age_idx] = np.mean(data, 0) sem_maps[age_idx] = sem(data, 0) # save map_names = [str(i) for i in ages_uniq] reader = CiftiReader(mmp_map_file) save2cifti(f'{out_name}-mean.dscalar.nii', mean_maps, reader.brain_models(), map_names) save2cifti(f'{out_name}-sem.dscalar.nii', sem_maps, reader.brain_models(), map_names)
def vtx_corr_col(data_file1, atlas_name, roi_name, data_file2, column, idx_col, out_file): """ 计算data_file1中指定atlas ROI内的所有顶点序列和data_file2中指定column序列的相关 Args: data_file1 (str): end with .dscalar.nii shape=(N, LR_count_32k) atlas_name (str): roi_name (str): data_file2 (str): end with .csv shape=(N, n_col) column (str): idx_col (int): specify index column of csv file If None, means no index column. """ # prepare reader = CiftiReader(data_file1) maps = reader.get_data() atlas = Atlas(atlas_name) assert atlas.maps.shape == (1, LR_count_32k) roi_idx_map = atlas.maps[0] == atlas.roi2label[roi_name] maps = maps[:, roi_idx_map] df = pd.read_csv(data_file2, index_col=idx_col) col_vec = np.array(df[column]) col_vec = np.expand_dims(col_vec, 0) # calculate data = np.ones((1, LR_count_32k)) * np.nan data[0, roi_idx_map] = 1 - cdist(col_vec, maps.T, 'correlation')[0] # save save2cifti(out_file, data, reader.brain_models())
def merge_smoothed_data(dataset_name, meas_name, sigma): """ 合并我平滑过后的cifti文件 Args: dataset_name (str): HCPD | HCPA meas_name (str): thickness | myelin sigma (float): the size of the gaussian surface smoothing kernel in mm """ # outputs out_file = pjoin(work_dir, f'{dataset_name}_{meas_name}_{sigma}mm.dscalar.nii') # prepare src_dir = pjoin(work_dir, f'{dataset_name}_{meas_name}_{sigma}mm') src_file = pjoin(src_dir, '{sid}.dscalar.nii') df = pd.read_csv(dataset_name2info[dataset_name]) n_subj = df.shape[0] data = np.zeros((n_subj, LR_count_32k), np.float64) # calculate for subj_idx, subj_id in enumerate(df['subID']): time1 = time.time() meas_file = src_file.format(sid=subj_id) data[subj_idx] = nib.load(meas_file).get_fdata()[0] print(f'Finished: {subj_idx+1}/{n_subj},' f'cost: {time.time() - time1} seconds.') # save mmp_reader = CiftiReader(mmp_map_file) save2cifti(out_file, data, mmp_reader.brain_models(), df['subID'])
def make_non_outlier_map(fpath, thr, roi_name, out_file_mask=None, out_file_prob=None): """ 将同时在thr%以上的被试中被认定为outlier的顶点判定为跨被试的outlier If out_file_mask is not None, save mask map. (.dlabel.nii or .npy) If out_file_prob is not None, save prob map. (.dscalar.nii) """ # prepare data = np.load(fpath) n_subj, n_vtx = data.shape atlas1 = Atlas('Cole_visual_LR') atlas2 = Atlas('Cole_visual_ROI') assert atlas1.maps.shape == (1, LR_count_32k) assert atlas2.maps.shape == (1, LR_count_32k) roi_idx_map = atlas1.maps[0] == atlas1.roi2label[roi_name] if roi_name == 'R_cole_visual': prefix = 'R_' elif roi_name == 'L_cole_visual': prefix = 'L_' else: raise ValueError("error roi_name:", roi_name) mmp_reader = CiftiReader(mmp_map_file) mmp_lbl_tab = mmp_reader.label_tables()[0] # calculate if out_file_mask is not None: data_tmp = np.sum(data, axis=0) outlier_vec = data_tmp > thr / 100 * n_subj print(f'#outliers/total: {np.sum(outlier_vec)}/{n_vtx}') mask_npy = np.zeros(LR_count_32k, bool) mask_npy[roi_idx_map] = ~outlier_vec if out_file_mask.endswith('.npy'): np.save(out_file_mask, mask_npy) elif out_file_mask.endswith('.dlabel.nii'): mask_cii = atlas2.maps.copy() mask_cii[0, ~mask_npy] = np.nan lbl_tab = nib.cifti2.cifti2.Cifti2LabelTable() for roi, lbl in atlas2.roi2label.items(): if roi.startswith(prefix): lbl_tab[lbl] = mmp_lbl_tab[lbl] save2cifti(out_file_mask, mask_cii, mmp_reader.brain_models(), label_tables=[lbl_tab]) else: raise ValueError("Not supported file name:", out_file_mask) if out_file_prob is not None: data_tmp = np.mean(data, axis=0) prob_map = np.ones((1, LR_count_32k), dtype=np.float64) * np.nan prob_map[0, roi_idx_map] = data_tmp assert out_file_prob.endswith('.dscalar.nii') save2cifti(out_file_prob, prob_map, mmp_reader.brain_models())
def pca(data_file, atlas_name, roi_name, n_component, axis, out_name): """ 对n_subj x n_vtx形状的矩阵进行PCA降维 Args: data_file (str): end with .dscalar.nii shape=(n_subj, LR_count_32k) atlas_name (str): include ROIs' labels and mask map roi_name (str): 决定选用哪个区域内的顶点来参与PCA n_component (int): the number of components axis (str): vertex | subject vertex: 对顶点数量进行降维,得到几个主成分时间序列, 观察某个主成分在各顶点上的权重,刻画其空间分布。 subject: 对被试数量进行降维,得到几个主成分map, 观察某个主成分在各被试上的权重,按年龄排序即可得到时间序列。 out_name (str): output name If axis=vertex, output 1. n_subj x n_component out_name.csv 2. n_component x LR_count_32k out_name.dscalar.nii 3. out_name.pkl with fitted PCA model """ # prepare component_names = [f'C{i}' for i in range(1, n_component + 1)] meas_maps = nib.load(data_file).get_fdata() atlas = Atlas(atlas_name) assert atlas.maps.shape == (1, LR_count_32k) roi_idx_map = atlas.maps[0] == atlas.roi2label[roi_name] meas_maps = meas_maps[:, roi_idx_map] bms = CiftiReader(mmp_map_file).brain_models() # calculate pca = PCA(n_components=n_component) data = np.ones((n_component, LR_count_32k), np.float64) * np.nan if axis == 'vertex': X = meas_maps pca.fit(X) Y = pca.transform(X) df = pd.DataFrame(data=Y, columns=component_names) data[:, roi_idx_map] = pca.components_ elif axis == 'subject': X = meas_maps.T pca.fit(X) Y = pca.transform(X) df = pd.DataFrame(data=pca.components_.T, columns=component_names) data[:, roi_idx_map] = Y.T else: raise ValueError('Invalid axis:', axis) # save df.to_csv(f'{out_name}.csv', index=False) save2cifti(f'{out_name}.dscalar.nii', data, bms, component_names) pkl.dump(pca, open(f'{out_name}.pkl', 'wb'))
def separate_networks(): """ 把ColeNetwork的12个网络分到单独的map里。 每个map的MMP parcel的label保留原来的样子。 需要注意的是multimodal_glasser的MMP_mpmLR32k.dlabel.nii中, ROI label的编号1~180是右脑,181~360是左脑。0对应的是??? 而cortex_parcel_network_assignments.mat中0~359的index是左脑在先 """ import numpy as np import nibabel as nib from scipy.io import loadmat from cxy_visual_dev.lib.ColeNet import get_name_label_of_ColeNetwork from magicbox.io.io import CiftiReader, save2cifti # inputs mmp_file = '/nfs/p1/atlases/multimodal_glasser/surface/'\ 'MMP_mpmLR32k.dlabel.nii' roi2net_file = pjoin(cole_dir, 'cortex_parcel_network_assignments.mat') # outputs out_file = pjoin(work_dir, 'networks.dlabel.nii') # load mmp_reader = CiftiReader(mmp_file) mmp_map = mmp_reader.get_data()[0] lbl_tab_raw = mmp_reader.label_tables()[0] roi2net = loadmat(roi2net_file)['netassignments'][:, 0] roi2net = np.r_[roi2net[180:], roi2net[:180]] net_labels = np.unique(roi2net) # prepare data = np.zeros((len(net_labels), len(mmp_map)), dtype=np.uint16) map_names = [] label_tables = [] net_lbl2name = {} for name, lbl in zip(*get_name_label_of_ColeNetwork()): net_lbl2name[lbl] = name # calculate for net_idx, net_lbl in enumerate(net_labels): roi_labels = np.where(roi2net == net_lbl)[0] + 1 lbl_tab = nib.cifti2.cifti2.Cifti2LabelTable() lbl_tab[0] = lbl_tab_raw[0] for roi_lbl in roi_labels: data[net_idx, mmp_map == roi_lbl] = roi_lbl lbl_tab[roi_lbl] = lbl_tab_raw[roi_lbl] map_names.append(net_lbl2name[net_lbl]) label_tables.append(lbl_tab) # save save2cifti(out_file, data, mmp_reader.brain_models(), map_names, label_tables=label_tables)
def zscore_data(data_file, out_file): """ 对每个被试做全脑zscore Args: data_file (str): .dscalar.nii out_file (str): .dscalar.nii """ reader = CiftiReader(data_file) data = reader.get_data() data = zscore(data, 1) save2cifti(out_file, data, reader.brain_models(), reader.map_names())
def kendall2cifti(data_file, rois, atlas_name, out_file): """ 把指定ROI的Tau值和p值存成cifti格式 方便可视化在大脑上 """ # prepare df = pd.read_csv(data_file, index_col=0) atlas = Atlas(atlas_name) assert atlas.maps.shape == (1, LR_count_32k) out_data = np.ones((2, LR_count_32k)) * np.nan # calculate for roi in rois: mask = atlas.maps[0] == atlas.roi2label[roi] out_data[0, mask] = df.loc['tau', roi] out_data[1, mask] = -np.log10(df.loc['p', roi]) # save save2cifti(out_file, out_data, CiftiReader(mmp_map_file).brain_models(), ['tau', '-lg(p)'])
def polyfit(data_file, info_file, deg, out_file): """ 对时间序列进行多项式拟合 Args: data_file (str): .csv | .dscalar.nii If is .csv, fit each column with ages. If is .dscalar.nii, fit each vertex with ages. info_file (str): .csv deg (int): degree of polynomial out_file (str): file to output same postfix with data_file """ # prepare if data_file.endswith('.csv'): assert out_file.endswith('.csv') reader = pd.read_csv(data_file) data = np.array(reader) elif data_file.endswith('.dscalar.nii'): assert out_file.endswith('.dscalar.nii') reader = CiftiReader(data_file) data = reader.get_data() else: raise ValueError(1) # calculate ages = np.array(pd.read_csv(info_file)['age in years']) coefs = np.polyfit(ages, data, deg) n_row = coefs.shape[0] if deg == 1: assert n_row == 2 row_names = ['coef', 'intercept'] else: row_names = [''] * n_row raise Warning("Can't provide row names for degree:", deg) # save if out_file.endswith('.csv'): df = pd.DataFrame(coefs, row_names, reader.columns) df.to_csv(out_file) else: save2cifti(out_file, coefs, reader.brain_models(), row_names)
def separate_networks(): """ 把ColeNetwork的12个网络分到单独的map里。 每个map的MMP parcel的label保留原来的样子。 需要注意的是multimodal_glasser的MMP_mpmLR32k.dlabel.nii中, ROI label的编号1~180是右脑,181~360是左脑。0对应的是??? 而cortex_parcel_network_assignments.mat中0~359的index是左脑在先 """ # outputs out_file = pjoin(work_dir, 'networks.dlabel.nii') # load mmp_reader = CiftiReader(mmp_map_file) mmp_map = mmp_reader.get_data()[0] lbl_tab_raw = mmp_reader.label_tables()[0] roi2net = loadmat(cole_net_assignment_file)['netassignments'][:, 0] roi2net = np.r_[roi2net[180:], roi2net[:180]] net_labels = np.unique(roi2net) # prepare data = np.zeros((len(net_labels), len(mmp_map)), dtype=np.uint16) map_names = [] label_tables = [] # calculate for net_idx, net_lbl in enumerate(net_labels): roi_labels = np.where(roi2net == net_lbl)[0] + 1 lbl_tab = nib.cifti2.cifti2.Cifti2LabelTable() lbl_tab[0] = lbl_tab_raw[0] for roi_lbl in roi_labels: data[net_idx, mmp_map == roi_lbl] = roi_lbl lbl_tab[roi_lbl] = lbl_tab_raw[roi_lbl] map_names.append(cole_label2name[net_lbl]) label_tables.append(lbl_tab) # save save2cifti(out_file, data, mmp_reader.brain_models(), map_names, label_tables=label_tables)
def merge_data(dataset_name, meas_name): """ 把所有被试的数据合并到一个cifti文件里 Args: dataset_name (str): HCPD | HCPA meas_name (str): thickness | myelin """ # outputs out_file = pjoin(work_dir, f'{dataset_name}_{meas_name}.dscalar.nii') # prepare dataset_dir = dataset_name2dir[dataset_name] meas2file = { 'myelin': pjoin( dataset_dir, 'fmriresults01/{sid}_V1_MR/MNINonLinear/fsaverage_LR32k/' '{sid}_V1_MR.MyelinMap_BC_MSMAll.32k_fs_LR.dscalar.nii'), 'thickness': pjoin( dataset_dir, 'fmriresults01/{sid}_V1_MR/MNINonLinear/fsaverage_LR32k/' '{sid}_V1_MR.thickness_MSMAll.32k_fs_LR.dscalar.nii') } df = pd.read_csv(dataset_name2info[dataset_name]) n_subj = df.shape[0] data = np.zeros((n_subj, LR_count_32k), np.float64) # calculate for subj_idx, subj_id in enumerate(df['subID']): time1 = time.time() meas_file = meas2file[meas_name].format(sid=subj_id) data[subj_idx] = nib.load(meas_file).get_fdata()[0] print(f'Finished: {subj_idx+1}/{n_subj},' f'cost: {time.time() - time1} seconds.') # save mmp_reader = CiftiReader(mmp_map_file) save2cifti(out_file, data, mmp_reader.brain_models(), df['subID'])
def mask_maps(data_file, atlas_name, roi_name, out_file): """ 把data map在指定atlas的ROI以外的部分全赋值为nan Args: data_file (str): end with .dscalar.nii shape=(n_map, LR_count_32k) atlas_name (str): roi_name (str): out_file (str): """ # prepare reader = CiftiReader(data_file) data = reader.get_data() atlas = Atlas(atlas_name) assert atlas.maps.shape == (1, LR_count_32k) roi_idx_map = atlas.maps[0] == atlas.roi2label[roi_name] # calculate data[:, ~roi_idx_map] = np.nan # save save2cifti(out_file, data, reader.brain_models(), reader.map_names())