def write_average_face_values_per_label( input_indices_vtk, input_values_vtk="", area_file="", output_stem="", exclude_values=[-1], background_value=-1 ): """ Write out a separate VTK file for each integer (>-1) in (the first) scalar list of an input VTK file. Optionally write the values drawn from a second VTK file. Parameters ---------- input_indices_vtk : string path of the input VTK file that contains indices as scalars input_values_vtk : string path of the input VTK file that contains values as scalars output_stem : string path and stem of the output VTK file exclude_values : list or array values to exclude background_value : integer or float background value in output VTK files scalar_name : string name of a lookup table of scalars values Examples -------- >>> import os >>> from mindboggle.utils.io_table import write_average_face_values_per_label >>> path = os.environ['MINDBOGGLE_DATA'] >>> input_indices_vtk = os.path.join(path, 'allen', 'labels', 'lh.DKTatlas100.gcs.vtk') >>> input_values_vtk = os.path.join(path, 'allen', 'shapes', 'lh.thickness.vtk') >>> area_file = os.path.join(path, 'allen', 'shapes', 'lh.pial.area.vtk') >>> output_stem = 'labels_thickness' >>> exclude_values = [-1] >>> background_value = -1 >>> # >>> write_average_face_values_per_label(input_indices_vtk, >>> input_values_vtk, area_file, output_stem, exclude_values, background_value) >>> # >>> # View: >>> #example_vtk = os.path.join(os.getcwd(), output_stem + '0.vtk') >>> #from mindboggle.utils.plots import plot_vtk >>> #plot_vtk(example_vtk) """ import os import numpy as np from mindboggle.utils.io_vtk import read_scalars, read_vtk, write_vtk from mindboggle.utils.io_table import write_columns from mindboggle.utils.mesh import remove_faces # Load VTK file: faces, lines, indices, points, npoints, scalars, scalar_names, foo1 = read_vtk(input_indices_vtk, True, True) if area_file: area_scalars, name = read_scalars(area_file, True, True) print("Explode the scalar list in {0}".format(os.path.basename(input_indices_vtk))) if input_values_vtk != input_indices_vtk: values, name = read_scalars(input_values_vtk, True, True) print( "Explode the scalar list of values in {0} " "with the scalar list of indices in {1}".format( os.path.basename(input_values_vtk), os.path.basename(input_indices_vtk) ) ) else: values = np.copy(scalars) # Loop through unique (non-excluded) scalar values: unique_scalars = [int(x) for x in np.unique(scalars) if x not in exclude_values] for scalar in unique_scalars: keep_indices = [x for sublst in faces for x in sublst] new_faces = remove_faces(faces, keep_indices) # Create array and indices for scalar value: select_scalars = np.copy(scalars) select_scalars[scalars != scalar] = background_value scalar_indices = [i for i, x in enumerate(select_scalars) if x == scalar] print(" Scalar {0}: {1} vertices".format(scalar, len(scalar_indices))) # --------------------------------------------------------------------- # For each face, average vertex values: # --------------------------------------------------------------------- output_table = os.path.join(os.getcwd(), output_stem + str(scalar) + ".csv") columns = [] for face in new_faces: values = [] for index in face: if area_file: values.append(scalars[index] / area_scalars[index]) else: values.append(scalars[index]) columns.append(np.mean(values)) # ----------------------------------------------------------------- # Write to table: # ----------------------------------------------------------------- write_columns(columns, "", output_table, delimiter=",", quote=False)
def write_vertex_measures( table_file, labels_or_file, sulci=[], fundi=[], affine_transform_file="", transform_format="itk", area_file="", mean_curvature_file="", travel_depth_file="", geodesic_depth_file="", convexity_file="", thickness_file="", delimiter=",", ): """ Make a table of shape values per vertex. Parameters ---------- table_file : output filename (without path) labels_or_file : list or string label number for each vertex or name of VTK file with index scalars sulci : list of integers indices to sulci, one per vertex, with -1 indicating no sulcus fundi : list of integers indices to fundi, one per vertex, with -1 indicating no fundus affine_transform_file : string affine transform file to standard space transform_format : string format for transform file Ex: 'txt' for text, 'itk' for ITK, and 'mat' for Matlab format area_file : string name of VTK file with surface area scalar values mean_curvature_file : string name of VTK file with mean curvature scalar values travel_depth_file : string name of VTK file with travel depth scalar values geodesic_depth_file : string name of VTK file with geodesic depth scalar values convexity_file : string name of VTK file with convexity scalar values thickness_file : string name of VTK file with thickness scalar values delimiter : string delimiter between columns, such as ',' Returns ------- shape_table : table file name for vertex shape values Examples -------- >>> import os >>> from mindboggle.utils.io_vtk import read_scalars >>> from mindboggle.tables.all_shapes import write_vertex_measures >>> # >>> table_file = 'vertex_shapes.csv' >>> path = os.environ['MINDBOGGLE_DATA'] >>> labels_or_file = os.path.join(path, 'arno', 'labels', 'lh.labels.DKT25.manual.vtk') >>> sulci_file = os.path.join(path, 'arno', 'features', 'sulci.vtk') >>> fundi_file = os.path.join(path, 'arno', 'features', 'fundi.vtk') >>> sulci, name = read_scalars(sulci_file) >>> fundi, name = read_scalars(fundi_file) >>> affine_transform_file = os.path.join(path, 'arno', 'mri', >>> 't1weighted_brain.MNI152Affine.txt') >>> transform_format = 'itk' >>> area_file = os.path.join(path, 'arno', 'shapes', 'lh.pial.area.vtk') >>> mean_curvature_file = os.path.join(path, 'arno', 'shapes', 'lh.pial.mean_curvature.vtk') >>> travel_depth_file = os.path.join(path, 'arno', 'shapes', 'lh.pial.travel_depth.vtk') >>> geodesic_depth_file = os.path.join(path, 'arno', 'shapes', 'lh.pial.geodesic_depth.vtk') >>> convexity_file = '' >>> thickness_file = '' >>> delimiter = ',' >>> # >>> write_vertex_measures(table_file, labels_or_file, sulci, fundi, >>> affine_transform_file, transform_format, area_file, >>> mean_curvature_file, travel_depth_file, geodesic_depth_file, >>> convexity_file, thickness_file, delimiter) """ import os import numpy as np from mindboggle.utils.io_vtk import read_scalars, read_vtk, apply_affine_transform from mindboggle.utils.io_table import write_columns # Make sure inputs are lists: if isinstance(labels_or_file, np.ndarray): labels = labels_or_file.tolist() elif isinstance(labels_or_file, list): labels = labels_or_file elif isinstance(labels_or_file, str): labels, name = read_scalars(labels_or_file) if isinstance(sulci, np.ndarray): sulci = sulci.tolist() if isinstance(fundi, np.ndarray): fundi = fundi.tolist() # Feature names and corresponding feature lists: feature_names = ["label", "sulcus", "fundus"] feature_lists = [labels, sulci, fundi] # Shape names corresponding to shape files below: shape_names = ["area", "mean curvature", "travel depth", "geodesic depth", "convexity", "thickness"] # Load shape files as a list of numpy arrays of per-vertex shape values: shape_files = [ area_file, mean_curvature_file, travel_depth_file, geodesic_depth_file, convexity_file, thickness_file, ] # Append columns of per-vertex scalar values: columns = [] column_names = [] for ifeature, values in enumerate(feature_lists): if values: columns.append(values) column_names.append(feature_names[ifeature]) first_pass = True for ishape, shape_file in enumerate(shape_files): if os.path.exists(shape_file): if first_pass: u1, u2, u3, points, u4, scalars, u5, u6 = read_vtk(shape_file) columns.append(points) column_names.append("coordinates") first_pass = False if affine_transform_file: affine_points, foo1 = apply_affine_transform(affine_transform_file, points, transform_format) columns.append(affine_points) column_names.append("coordinates in standard space") else: scalars, name = read_scalars(shape_file) if len(scalars): columns.append(scalars) column_names.append(shape_names[ishape]) # Prepend with column of indices and write table shapes_table = os.path.join(os.getcwd(), table_file) write_columns(range(len(columns[0])), "index", shapes_table, delimiter) write_columns(columns, column_names, shapes_table, delimiter, quote=True, input_table=shapes_table) return shapes_table
def write_face_vertex_averages(input_file, area_file="", delimiter=","): """ Make table of average vertex values per face. Parameters ---------- input_file : string name of VTK file with scalars to average area_file : string name of VTK file with surface area scalar values delimiter : string delimiter between columns, such as ',' Returns ------- output_table : string output table filename Examples -------- >>> import os >>> from mindboggle.utils.io_vtk import read_scalars >>> from mindboggle.utils.io_table import write_face_vertex_averages >>> path = os.environ['MINDBOGGLE_DATA'] >>> #input_file = os.path.join(path, 'arno', 'shapes', 'lh.pial.mean_curvature.vtk') >>> #input_file = os.path.join(path, 'arno', 'shapes', 'lh.pial.travel_depth.vtk') >>> input_file = os.path.join(path, 'arno', 'shapes', 'lh.thickness.vtk') >>> area_file = os.path.join(path, 'arno', 'shapes', 'lh.pial.area.vtk') >>> delimiter = ',' >>> # >>> write_face_vertex_averages(input_file, area_file, delimiter) """ import os import numpy as np from mindboggle.utils.io_vtk import read_vtk, read_scalars from mindboggle.utils.io_table import write_columns faces, lines, indices, points, npoints, scalars, name, input_vtk = read_vtk(input_file, True, True) if area_file: area_scalars, name = read_scalars(area_file, True, True) # --------------------------------------------------------------------- # For each face, average vertex values: # --------------------------------------------------------------------- output_table = os.path.join(os.getcwd(), "average_face_values.csv") columns = [] for face in faces: values = [] for index in face: if area_file: values.append(scalars[index] / area_scalars[index]) else: values.append(scalars[index]) columns.append(np.mean(values)) # ----------------------------------------------------------------- # Write to table: # ----------------------------------------------------------------- write_columns(columns, "", output_table, delimiter, quote=False) return output_table
def alternate_columns_from_tables(table_files, write_table=True, output_table='', delimiter=','): """ Alternate columns from a list of tables and make a new table. This program assumes that the tables consist of only numbers. Parameters ---------- table_files : list of strings table files (full paths) write_table : Boolean write output table? output_table : string output table file name delimiter : string delimiter between output table columns, such as ',' Returns ------- columns : list of lists of floats or integers columns of data output_table : string output table file name Examples -------- >>> from mindboggle.utils.io_table import alternate_columns_from_tables >>> table_files = ['/drop/MB/data/arno/tables/label_shapes.csv', >>> '/drop/MB/data/arno/tables/label_shapes.csv'] >>> write_table = True >>> output_table = '' >>> delimiter = ',' >>> columns, output_table = alternate_columns_from_tables(table_files, write_table, output_table, delimiter) """ import os import csv from mindboggle.utils.io_table import write_columns #------------------------------------------------------------------------- # Construct a list of all tables: #------------------------------------------------------------------------- tables = [] for table_file in table_files: if not os.path.exists(table_file): raise(IOError(table_file + " not found")) else: reader = csv.reader(open(table_file, 'rb'), delimiter=',', quotechar='"') tables.append([list(x) for x in zip(*reader)]) #------------------------------------------------------------------------- # Alternate columns: #------------------------------------------------------------------------- columns = [] for icolumn, column in enumerate(tables[0]): for table in tables: columns.append(table[icolumn]) #------------------------------------------------------------------------- # Write table: #------------------------------------------------------------------------- if write_table and columns: if all([len(x) == len(columns[0]) for x in columns]): if not output_table: output_table = os.path.join(os.getcwd(), 'alternating_columns.csv') write_columns(columns, column_names='', delimiter=delimiter, quote=True, input_table='', output_table=output_table) else: print('Columns do not have the same length.') return columns, output_table
def write_shape_stats( labels_or_file, sulci=[], fundi=[], affine_transform_file="", transform_format="itk", area_file="", mean_curvature_file="", travel_depth_file="", geodesic_depth_file="", convexity_file="", thickness_file="", labels_spectra=[], labels_spectra_IDs=[], sulci_spectra=[], sulci_spectra_IDs=[], exclude_labels=[-1], delimiter=",", ): """ Make tables of shape statistics per label, fundus, and/or sulcus. Parameters ---------- labels_or_file : list or string label number for each vertex or name of VTK file with index scalars sulci : list of integers indices to sulci, one per vertex, with -1 indicating no sulcus fundi : list of integers indices to fundi, one per vertex, with -1 indicating no fundus affine_transform_file : string affine transform file to standard space transform_format : string format for transform file Ex: 'txt' for text, 'itk' for ITK, and 'mat' for Matlab format area_file : string name of VTK file with surface area scalar values mean_curvature_file : string name of VTK file with mean curvature scalar values travel_depth_file : string name of VTK file with travel depth scalar values geodesic_depth_file : string name of VTK file with geodesic depth scalar values convexity_file : string name of VTK file with convexity scalar values thickness_file : string name of VTK file with thickness scalar values labels_spectra : list of lists of floats Laplace-Beltrami spectra for labeled regions labels_spectra_IDs : list of integers unique ID numbers (labels) for labels_spectra sulci_spectra : list of lists of floats Laplace-Beltrami spectra for sulci sulci_spectra_IDs : list of integers unique ID numbers (labels) for sulci_spectra exclude_labels : list of lists of integers indices to be excluded (in addition to -1) delimiter : string delimiter between columns, such as ',' Returns ------- label_table : string output table filename for label shapes sulcus_table : string output table filename for sulcus shapes fundus_table : string output table filename for fundus shapes Examples -------- >>> import os >>> from mindboggle.utils.io_vtk import read_scalars >>> from mindboggle.utils.io_table import write_shape_stats >>> path = os.environ['MINDBOGGLE_DATA'] >>> labels_or_file = os.path.join(path, 'arno', 'labels', 'lh.labels.DKT25.manual.vtk') >>> sulci_file = os.path.join(path, 'arno', 'features', 'sulci.vtk') >>> fundi_file = os.path.join(path, 'arno', 'features', 'fundi.vtk') >>> sulci, name = read_scalars(sulci_file) >>> fundi, name = read_scalars(fundi_file) >>> affine_transform_file = os.path.join(path, 'arno', 'mri', >>> # 'affine_to_template.mat') >>> 't1weighted_brain.MNI152Affine.txt') >>> #transform_format = 'mat' >>> transform_format = 'itk' >>> area_file = os.path.join(path, 'arno', 'shapes', 'lh.pial.area.vtk') >>> mean_curvature_file = os.path.join(path, 'arno', 'shapes', 'lh.pial.mean_curvature.vtk') >>> travel_depth_file = os.path.join(path, 'arno', 'shapes', 'lh.pial.travel_depth.vtk') >>> geodesic_depth_file = os.path.join(path, 'arno', 'shapes', 'lh.pial.geodesic_depth.vtk') >>> convexity_file = '' >>> thickness_file = '' >>> delimiter = ',' >>> # >>> import numpy as np >>> labels, name = read_scalars(labels_or_file) >>> labels_spectra = [[1,2,3] for x in labels] >>> labels_spectra_IDs = np.unique(labels).tolist() >>> sulci_spectra = [[1,2,3] for x in sulci] >>> sulci_spectra_IDs = np.unique(sulci).tolist() >>> exclude_labels = [-1] >>> # >>> write_shape_stats(labels_or_file, sulci, fundi, >>> affine_transform_file, transform_format, area_file, >>> mean_curvature_file, travel_depth_file, geodesic_depth_file, >>> convexity_file, thickness_file, labels_spectra, >>> labels_spectra_IDs, sulci_spectra, >>> sulci_spectra_IDs, exclude_labels, delimiter) """ import os import numpy as np from mindboggle.shapes.measure import means_per_label, stats_per_label, sum_per_label from mindboggle.utils.io_vtk import read_scalars, read_vtk, apply_affine_transform from mindboggle.utils.io_table import write_columns # Make sure inputs are lists: if isinstance(labels_or_file, np.ndarray): labels = labels_or_file.tolist() elif isinstance(labels_or_file, list): labels = labels_or_file elif isinstance(labels_or_file, str): labels, name = read_scalars(labels_or_file) if isinstance(sulci, np.ndarray): sulci = sulci.tolist() if isinstance(fundi, np.ndarray): fundi = fundi.tolist() # ------------------------------------------------------------------------- # Feature lists, shape names, and shape files: # ------------------------------------------------------------------------- # Feature lists: feature_lists = [labels, sulci, fundi] feature_names = ["label", "sulcus", "fundus"] spectra_lists = [labels_spectra, sulci_spectra] spectra_ID_lists = [labels_spectra_IDs, sulci_spectra_IDs] spectra_names = ["label spectrum", "sulcus spectrum"] table_names = ["label_shapes.csv", "sulcus_shapes.csv", "fundus_shapes.csv"] # Shape names corresponding to shape files below: shape_names = ["area", "mean curvature", "travel depth", "geodesic depth", "convexity", "thickness"] # Load shape files as a list of numpy arrays of per-vertex shape values: shape_files = [ area_file, mean_curvature_file, travel_depth_file, geodesic_depth_file, convexity_file, thickness_file, ] shape_arrays = [] column_names = [] first_pass = True area_array = [] for ishape, shape_file in enumerate(shape_files): if os.path.exists(shape_file): if first_pass: faces, lines, indices, points, npoints, scalars_array, name, input_vtk = read_vtk( shape_file, True, True ) points = np.array(points) first_pass = False if affine_transform_file: affine_points, foo1 = apply_affine_transform( affine_transform_file, points, transform_format, save_file=False ) affine_points = np.array(affine_points) else: scalars_array, name = read_scalars(shape_file, True, True) if scalars_array.size: shape_arrays.append(scalars_array) # Store area array: if ishape == 0: area_array = scalars_array.copy() # Initialize table file names: sulcus_table = None fundus_table = None # Loop through features / tables: for itable, feature_list in enumerate(feature_lists): table_column_names = [] # --------------------------------------------------------------------- # For each feature, construct a table of average shape values: # --------------------------------------------------------------------- table_file = os.path.join(os.getcwd(), table_names[itable]) if feature_list: feature_name = feature_names[itable] columns = [] # ----------------------------------------------------------------- # Mean positions in the original space: # ----------------------------------------------------------------- # Compute mean position per feature: positions, sdevs, label_list, foo = means_per_label(points, feature_list, exclude_labels, area_array) # Append mean position per feature to columns: table_column_names.append("mean position") columns.append(positions) # ----------------------------------------------------------------- # Mean positions in standard space: # ----------------------------------------------------------------- if affine_transform_file: # Compute standard space mean position per feature: standard_positions, sdevs, label_list, foo = means_per_label( affine_points, feature_list, exclude_labels, area_array ) # Append standard space mean position per feature to columns: table_column_names.append("mean position in standard space") columns.append(standard_positions) # ----------------------------------------------------------------- # Loop through shape measures: # ----------------------------------------------------------------- table_column_names.extend(column_names[:]) for ishape, shape_array in enumerate(shape_arrays): shape_name = shape_names[ishape] print(" Compute statistics on {0} {1}".format(feature_name, shape_name)) # Append shape names and values per feature to columns: pr = feature_name + ": " + shape_name + ": " if np.size(area_array): po = " (weighted)" else: po = "" # ------------------------------------------------------------- # Append total feature areas to columns: # ------------------------------------------------------------- if ishape == 0 and np.size(area_array): sums, label_list = sum_per_label(shape_array, feature_list, exclude_labels) table_column_names.append(pr + "total") columns.append(sums) # ------------------------------------------------------------- # Append feature shape statistics to columns: # ------------------------------------------------------------- else: medians, mads, means, sdevs, skews, kurts, lower_quarts, upper_quarts, label_list = stats_per_label( shape_array, feature_list, exclude_labels, area_array, precision=1 ) table_column_names.append(pr + "median" + po) table_column_names.append(pr + "median absolute deviation" + po) table_column_names.append(pr + "mean" + po) table_column_names.append(pr + "standard deviation" + po) table_column_names.append(pr + "skew" + po) table_column_names.append(pr + "kurtosis" + po) table_column_names.append(pr + "lower quartile" + po) table_column_names.append(pr + "upper quartile" + po) columns.append(medians) columns.append(mads) columns.append(means) columns.append(sdevs) columns.append(skews) columns.append(kurts) columns.append(lower_quarts) columns.append(upper_quarts) # ----------------------------------------------------------------- # Laplace-Beltrami spectra: # ----------------------------------------------------------------- if itable in [0, 1]: spectra = spectra_lists[itable] spectra_name = spectra_names[itable] spectra_IDs = spectra_ID_lists[itable] # Order spectra into a list: spectrum_list = [] for label in label_list: if label in spectra_IDs: spectrum = spectra[spectra_IDs.index(label)] spectrum_list.append(spectrum) else: spectrum_list.append("") # Append spectral shape name and values to relevant columns: columns.append(spectrum_list) table_column_names.append(spectra_name) # ----------------------------------------------------------------- # Write labels/IDs and values to table: # ----------------------------------------------------------------- # Write labels/IDs to table: write_columns(label_list, feature_name, table_file, delimiter) # Append columns of shape values to table: if columns: write_columns(columns, table_column_names, table_file, delimiter, quote=True, input_table=table_file) else: # Write something to table: write_columns([], "", table_file, delimiter) # --------------------------------------------------------------------- # Return correct table file name: # --------------------------------------------------------------------- if itable == 0: label_table = table_file elif itable == 1: sulcus_table = table_file elif itable == 2: fundus_table = table_file return label_table, sulcus_table, fundus_table
def write_vertex_measures(output_table, labels_or_file, sulci=[], fundi=[], affine_transform_file='', transform_format='itk', area_file='', mean_curvature_file='', travel_depth_file='', geodesic_depth_file='', freesurfer_convexity_file='', freesurfer_thickness_file='', delimiter=','): """ Make a table of shape values per vertex. Note :: This function is tailored for Mindboggle outputs. Parameters ---------- output_table : string output file (full path) labels_or_file : list or string label number for each vertex or name of VTK file with index scalars sulci : list of integers indices to sulci, one per vertex, with -1 indicating no sulcus fundi : list of integers indices to fundi, one per vertex, with -1 indicating no fundus affine_transform_file : string affine transform file to standard space transform_format : string format for transform file Ex: 'txt' for text, 'itk' for ITK, and 'mat' for Matlab format area_file : string name of VTK file with surface area scalar values mean_curvature_file : string name of VTK file with mean curvature scalar values travel_depth_file : string name of VTK file with travel depth scalar values geodesic_depth_file : string name of VTK file with geodesic depth scalar values freesurfer_convexity_file : string name of VTK file with FreeSurfer convexity scalar values freesurfer_thickness_file : string name of VTK file with FreeSurfer thickness scalar values delimiter : string delimiter between columns, such as ',' Returns ------- output_table : table file name for vertex shape values Examples -------- >>> import os >>> from mindboggle.utils.io_vtk import read_scalars >>> from mindboggle.utils.io_table import write_vertex_measures >>> # >>> output_table = ''#vertex_shapes.csv' >>> path = os.environ['MINDBOGGLE_DATA'] >>> labels_or_file = os.path.join(path, 'arno', 'labels', 'lh.labels.DKT25.manual.vtk') >>> sulci_file = os.path.join(path, 'arno', 'features', 'sulci.vtk') >>> fundi_file = os.path.join(path, 'arno', 'features', 'fundi.vtk') >>> sulci, name = read_scalars(sulci_file) >>> fundi, name = read_scalars(fundi_file) >>> affine_transform_file = os.path.join(path, 'arno', 'mri', >>> 't1weighted_brain.MNI152Affine.txt') >>> transform_format = 'itk' >>> area_file = os.path.join(path, 'arno', 'shapes', 'lh.pial.area.vtk') >>> mean_curvature_file = os.path.join(path, 'arno', 'shapes', 'lh.pial.mean_curvature.vtk') >>> travel_depth_file = os.path.join(path, 'arno', 'shapes', 'lh.pial.travel_depth.vtk') >>> geodesic_depth_file = os.path.join(path, 'arno', 'shapes', 'lh.pial.geodesic_depth.vtk') >>> freesurfer_convexity_file = '' >>> freesurfer_thickness_file = '' >>> delimiter = ',' >>> # >>> write_vertex_measures(output_table, labels_or_file, sulci, fundi, >>> affine_transform_file, transform_format, area_file, >>> mean_curvature_file, travel_depth_file, geodesic_depth_file, >>> freesurfer_convexity_file, freesurfer_thickness_file, delimiter) """ import os import numpy as np from mindboggle.utils.io_vtk import read_scalars, read_vtk, \ apply_affine_transform from mindboggle.utils.io_table import write_columns # Make sure inputs are lists: if isinstance(labels_or_file, np.ndarray): labels = [int(x) for x in labels_or_file] elif isinstance(labels_or_file, list): labels = labels_or_file elif isinstance(labels_or_file, str): labels, name = read_scalars(labels_or_file) if isinstance(sulci, np.ndarray): sulci = [int(x) for x in sulci] if isinstance(fundi, np.ndarray): fundi = [int(x) for x in fundi] if not labels and not sulci and not fundi: import sys sys.exit('No feature data to tabulate in write_vertex_measures().') # Feature names and corresponding feature lists: feature_names = ['Label', 'Sulcus', 'Fundus'] feature_lists = [labels, sulci, fundi] # Shape names corresponding to shape files below: shape_names = ['area', 'mean curvature', 'travel depth', 'geodesic depth', 'FreeSurfer convexity', 'FreeSurfer thickness'] # Load shape files as a list of numpy arrays of per-vertex shape values: shape_files = [area_file, mean_curvature_file, travel_depth_file, geodesic_depth_file, freesurfer_convexity_file, freesurfer_thickness_file] # Append columns of per-vertex scalar values: columns = [] column_names = [] for ifeature, values in enumerate(feature_lists): if values: columns.append(values) column_names.append(feature_names[ifeature]) first_pass = True for ishape, shape_file in enumerate(shape_files): if os.path.exists(shape_file): if first_pass: u1, u2, u3, points, u4, scalars, u5, u6 = read_vtk(shape_file) columns.append(points) column_names.append('coordinates') first_pass = False if affine_transform_file and transform_format: affine_points, \ foo1 = apply_affine_transform(affine_transform_file, points, transform_format, vtk_file_stem='') columns.append(affine_points) column_names.append('coordinates in standard space') else: scalars, name = read_scalars(shape_file) if len(scalars): columns.append(scalars) column_names.append(shape_names[ishape]) # Prepend with column of indices and write table if not output_table: output_table = os.path.join(os.getcwd(), 'vertices.csv') write_columns(range(len(columns[0])), 'Index', delimiter, quote=True, input_table='', output_table=output_table) write_columns(columns, column_names, delimiter, quote=True, input_table=output_table, output_table=output_table) if not os.path.exists(output_table): raise(IOError(output_table + " not found")) return output_table
def write_shape_stats(labels_or_file=[], sulci=[], fundi=[], affine_transform_file='', transform_format='itk', area_file='', normalize_by_area=True, mean_curvature_file='', travel_depth_file='', geodesic_depth_file='', freesurfer_convexity_file='', freesurfer_thickness_file='', labels_spectra=[], labels_spectra_IDs=[], sulci_spectra=[], sulci_spectra_IDs=[], labels_zernike=[], labels_zernike_IDs=[], sulci_zernike=[], sulci_zernike_IDs=[], exclude_labels=[-1], delimiter=','): """ Make tables of shape statistics per label, sulcus, and/or fundus. Note :: This function is tailored for Mindboggle outputs. Parameters ---------- labels_or_file : list or string label number for each vertex or name of VTK file with index scalars sulci : list of integers indices to sulci, one per vertex, with -1 indicating no sulcus fundi : list of integers indices to fundi, one per vertex, with -1 indicating no fundus affine_transform_file : string affine transform file to standard space transform_format : string format for transform file Ex: 'txt' for text, 'itk' for ITK, and 'mat' for Matlab format area_file : string name of VTK file with surface area scalar values normalize_by_area : Boolean normalize all shape measures by area of label/feature? mean_curvature_file : string name of VTK file with mean curvature scalar values travel_depth_file : string name of VTK file with travel depth scalar values geodesic_depth_file : string name of VTK file with geodesic depth scalar values freesurfer_convexity_file : string name of VTK file with FreeSurfer convexity scalar values freesurfer_thickness_file : string name of VTK file with FreeSurfer thickness scalar values labels_zernike : list of lists of floats Laplace-Beltrami spectra for labeled regions labels_spectra_IDs : list of integers unique ID numbers (labels) for labels_spectra sulci_spectra : list of lists of floats Laplace-Beltrami spectra for sulci sulci_spectra_IDs : list of integers unique ID numbers (labels) for sulci_spectra labels_zernike : list of lists of floats Zernike moments for labeled regions labels_zernike_IDs : list of integers unique ID numbers (labels) for labels_zernike sulci_zernike : list of lists of floats Zernike moments for sulci sulci_zernike_IDs : list of integers unique ID numbers (labels) for sulci_zernike exclude_labels : list of lists of integers indices to be excluded (in addition to -1) delimiter : string delimiter between columns, such as ',' Returns ------- label_table : string output table filename for label shapes sulcus_table : string output table filename for sulcus shapes fundus_table : string output table filename for fundus shapes Examples -------- >>> import os >>> from mindboggle.utils.io_vtk import read_scalars >>> from mindboggle.utils.io_table import write_shape_stats >>> path = os.environ['MINDBOGGLE_DATA'] >>> labels_or_file = os.path.join(path, 'arno', 'labels', 'lh.labels.DKT25.manual.vtk') >>> sulci_file = os.path.join(path, 'arno', 'features', 'sulci.vtk') >>> fundi_file = os.path.join(path, 'arno', 'features', 'fundi.vtk') >>> sulci, name = read_scalars(sulci_file) >>> fundi, name = read_scalars(fundi_file) >>> affine_transform_file = os.path.join(path, 'arno', 'mri', 't1weighted_brain.MNI152Affine.txt') >>> #transform_format = 'mat' >>> transform_format = 'itk' >>> area_file = os.path.join(path, 'arno', 'shapes', 'lh.pial.area.vtk') >>> normalize_by_area = True >>> mean_curvature_file = os.path.join(path, 'arno', 'shapes', 'lh.pial.mean_curvature.vtk') >>> travel_depth_file = os.path.join(path, 'arno', 'shapes', 'lh.pial.travel_depth.vtk') >>> geodesic_depth_file = os.path.join(path, 'arno', 'shapes', 'lh.pial.geodesic_depth.vtk') >>> freesurfer_convexity_file = '' >>> freesurfer_thickness_file = '' >>> delimiter = ',' >>> # >>> labels, name = read_scalars(labels_or_file) >>> labels_spectra = [] >>> labels_spectra_IDs = [] >>> sulci_spectra = [] >>> sulci_spectra_IDs = [] >>> labels_zernike = [] >>> labels_zernike_IDs = [] >>> sulci_zernike = [] >>> sulci_zernike_IDs = [] >>> exclude_labels = [-1] >>> # >>> write_shape_stats(labels_or_file, sulci, fundi, >>> affine_transform_file, transform_format, area_file, normalize_by_area, >>> mean_curvature_file, travel_depth_file, geodesic_depth_file, >>> freesurfer_convexity_file, freesurfer_thickness_file, >>> labels_spectra, labels_spectra_IDs, >>> sulci_spectra, sulci_spectra_IDs, >>> labels_zernike, labels_zernike_IDs, >>> sulci_zernike, sulci_zernike_IDs, >>> exclude_labels, delimiter) """ import os import numpy as np from mindboggle.utils.compute import means_per_label, stats_per_label, \ sum_per_label from mindboggle.utils.io_vtk import read_scalars, read_vtk, \ apply_affine_transform from mindboggle.utils.io_table import write_columns from mindboggle.LABELS import DKTprotocol dkt = DKTprotocol() # Make sure inputs are lists: if isinstance(labels_or_file, np.ndarray): labels = [int(x) for x in labels_or_file] elif isinstance(labels_or_file, list): labels = labels_or_file elif isinstance(labels_or_file, str): labels, name = read_scalars(labels_or_file) if isinstance(sulci, np.ndarray): sulci = [int(x) for x in sulci] if isinstance(fundi, np.ndarray): fundi = [int(x) for x in fundi] if not labels and not sulci and not fundi: import sys sys.exit('No feature data to tabulate in write_shape_stats().') #------------------------------------------------------------------------- # Feature lists, shape names, and shape files: #------------------------------------------------------------------------- # Feature lists: feature_lists = [labels, sulci, fundi] feature_names = ['Label', 'Sulcus', 'Fundus'] spectra_lists = [labels_spectra, sulci_spectra] spectra_ID_lists = [labels_spectra_IDs, sulci_spectra_IDs] zernike_lists = [labels_zernike, sulci_zernike] zernike_ID_lists = [labels_zernike_IDs, sulci_zernike_IDs] table_names = ['label_shapes.csv', 'sulcus_shapes.csv', 'fundus_shapes.csv'] # Shape names corresponding to shape files below: shape_names = ['area', 'mean curvature', 'travel depth', 'geodesic depth', 'FreeSurfer convexity', 'FreeSurfer thickness'] # Load shape files as a list of numpy arrays of per-vertex shape values: shape_files = [area_file, mean_curvature_file, travel_depth_file, geodesic_depth_file, freesurfer_convexity_file, freesurfer_thickness_file] shape_arrays = [] first_pass = True area_array = [] for ishape, shape_file in enumerate(shape_files): if os.path.exists(shape_file): if first_pass: faces, lines, indices, points, npoints, scalars_array, name, \ input_vtk = read_vtk(shape_file, True, True) points = np.array(points) first_pass = False if affine_transform_file and transform_format: affine_points, \ foo1 = apply_affine_transform(affine_transform_file, points, transform_format, vtk_file_stem='') affine_points = np.array(affine_points) else: scalars_array, name = read_scalars(shape_file, True, True) if scalars_array.size: shape_arrays.append(scalars_array) # Store area array: if ishape == 0: area_array = scalars_array.copy() if normalize_by_area: use_area = area_array else: use_area = [] # Initialize table file names: label_table = '' sulcus_table = '' fundus_table = '' # Loop through features / tables: for itable, feature_list in enumerate(feature_lists): column_names = [] #--------------------------------------------------------------------- # For each feature, construct a table of average shape values: #--------------------------------------------------------------------- if feature_list: feature_name = feature_names[itable] columns = [] #----------------------------------------------------------------- # Loop through shape measures: #----------------------------------------------------------------- column_names.extend(column_names[:]) for ishape, shape_array in enumerate(shape_arrays): shape = shape_names[ishape] print(' Compute statistics on {0} {1}...'. format(feature_name, shape)) #------------------------------------------------------------- # Append feature areas to columns: #------------------------------------------------------------- if ishape == 0 and np.size(area_array): sums, label_list = sum_per_label(shape_array, feature_list, exclude_labels) column_names.append(shape) columns.append(sums) #------------------------------------------------------------- # Append feature shape statistics to columns: #------------------------------------------------------------- else: medians, mads, means, sdevs, skews, kurts, \ lower_quarts, upper_quarts, \ label_list = stats_per_label(shape_array, feature_list, exclude_labels, area_array, precision=1) column_names.append(shape + ': median') column_names.append(shape + ': MAD') column_names.append(shape + ': mean') column_names.append(shape + ': SD') column_names.append(shape + ': skew') column_names.append(shape + ': kurtosis') column_names.append(shape + ': 25%') column_names.append(shape + ': 75%') columns.append(medians) columns.append(mads) columns.append(means) columns.append(sdevs) columns.append(skews) columns.append(kurts) columns.append(lower_quarts) columns.append(upper_quarts) #----------------------------------------------------------------- # Mean positions in the original space: #----------------------------------------------------------------- # Compute mean position per feature: positions, sdevs, label_list, foo = means_per_label(points, feature_list, exclude_labels, use_area) # Append mean position per feature to columns: column_names.append('mean position') columns.append(positions) #----------------------------------------------------------------- # Mean positions in standard space: #----------------------------------------------------------------- if affine_transform_file and transform_format: # Compute standard space mean position per feature: standard_positions, sdevs, label_list, \ foo = means_per_label(affine_points, feature_list, exclude_labels, use_area) # Append standard space mean position per feature to columns: column_names.append('mean position in standard space') columns.append(standard_positions) #----------------------------------------------------------------- # Label names: #----------------------------------------------------------------- if itable == 0: label_numbers = dkt.label_numbers label_names = dkt.label_names name_list = [] for label in label_list: name_list.append(label_names[label_numbers.index(label)]) #----------------------------------------------------------------- # Laplace-Beltrami spectra: #----------------------------------------------------------------- if itable in [0, 1]: spectra = spectra_lists[itable] if spectra: spectra_IDs = spectra_ID_lists[itable] # Order spectra into a list: spectrum_list = [] for label in label_list: if label in spectra_IDs: spectrum = spectra[spectra_IDs.index(label)] spectrum_list.append(spectrum) else: spectrum_list.append('') # Append spectral shape name and values to relevant columns: columns.append(spectrum_list) column_names.append('Laplace-Beltrami spectra') #----------------------------------------------------------------- # Zernike moments: #----------------------------------------------------------------- if itable in [0, 1]: zernike = zernike_lists[itable] if zernike: zernike_IDs = zernike_ID_lists[itable] # Order zernike into a list: spectrum_list = [] for label in label_list: if label in zernike_IDs: spectrum = zernike[zernike_IDs.index(label)] spectrum_list.append(spectrum) else: spectrum_list.append('') # Append Zernike shape name and values to relevant columns: columns.append(spectrum_list) column_names.append('Zernike moments') #----------------------------------------------------------------- # Write labels/IDs and values to table: #----------------------------------------------------------------- # Write labels/IDs to table: output_table = os.path.join(os.getcwd(), table_names[itable]) output_table = write_columns(label_list, feature_name, delimiter, quote=True, input_table='', output_table=output_table) if itable == 0: write_columns(name_list, 'Label name', delimiter, quote=True, input_table=output_table, output_table=output_table) # Append columns of shape values to table: if columns: write_columns(columns, column_names, delimiter, quote=True, input_table=output_table, output_table=output_table) if not os.path.exists(output_table): raise(IOError(output_table + " not found")) #----------------------------------------------------------------- # Return correct table file name: #----------------------------------------------------------------- if itable == 0: label_table = output_table elif itable == 1: sulcus_table = output_table elif itable == 2: fundus_table = output_table return label_table, sulcus_table, fundus_table
def select_column_from_tables(tables, column_name, label_name='', write_table=True, output_table='', delimiter=','): """ Select column from list of tables and make a new table. Parameters ---------- tables : list of strings table files (full paths) column_name : string column name to select label_name : string column name for column with labels (if empty, no label column added) write_table : Boolean write output table? output_table : string output table file name delimiter : string delimiter between output table columns, such as ',' Returns ------- tables : list of strings input table files (full paths) columns : list of lists of floats or integers columns of data column_name : string column name to select row_names : list of strings row labels (common strings in the label column of tables) row_names_title : string row_names column header output_table : string output table file name Examples -------- >>> from mindboggle.utils.io_table import select_column_from_tables >>> tables = ['/home/arno/mindboggled/tables/left/UM0029UMMR1R1_antsCorticalThickness/label_shapes.csv'] >>> column_name = 'label: FreeSurfer thickness: mean (weighted)' >>> #tables = ['/drop/tables/left/UM0029UMMR2R1_FS11212/vertices.csv', >>> # '/drop/tables/left/UM0029UMMR2R1_repositioned/vertices.csv'] >>> #column_name = "FreeSurfer thickness" >>> label_name = 'label' >>> write_table = True >>> output_table = '' >>> delimiter = ',' >>> # >>> select_column_from_tables(tables, column_name, label_name, >>> write_table, output_table, delimiter) """ import os import sys import csv from mindboggle.utils.io_table import write_columns #------------------------------------------------------------------------- # Construct a table: #------------------------------------------------------------------------- columns = [] row_names = [] row_names_title = '' first = True for input_table in tables: #--------------------------------------------------------------------- # Extract column from the table for each subject: #--------------------------------------------------------------------- if not os.path.exists(input_table): raise(IOError(input_table + " not found")) else: reader = csv.reader(open(input_table, 'rb'), delimiter=',', quotechar='"') input_columns = [list(x) for x in zip(*reader)] #----------------------------------------------------------------- # Extract column with table_name as its header: #----------------------------------------------------------------- icolumn_name = -1 icolumn_label = -1 for icolumn, column in enumerate(input_columns): # new_column = [] # rms = ['"', "'"] # for c in column: # for s in rms: # c = c.strip() # c = c.strip(s) # c = c.strip() # new_column.append(c) # column = new_column hdr = column[0] if hdr == column_name: icolumn_name = icolumn elif hdr == label_name: icolumn_label = icolumn if icolumn_name >= 0: columns.append(input_columns[icolumn_name][1::]) else: sys.exit('No column name "{0}".'.format(column_name)) #----------------------------------------------------------------- # Don't use the labels if label columns are unequal across tables: #----------------------------------------------------------------- if icolumn_label >= 0: if first: row_names = input_columns[icolumn_label][1::] row_names_title = input_columns[icolumn_label][0].strip() first = False elif input_columns[icolumn_label][1::] != row_names: print('Label columns are not the same across tables.') label_name = False #------------------------------------------------------------------------- # Write table: #------------------------------------------------------------------------- if write_table and columns: if all([len(x) == len(columns[0]) for x in columns]): labels = [os.path.basename(x) for x in tables] if not output_table: rms = ['"', '`', ',', '/', '<', '>', '?', ':', ';', '(', ')', '[', ']', '{', '}', '|', '\\', '!', '@', '#', '$', '%', '^', '&', '*', '=', '_'] table_name = column_name for s in rms: table_name = table_name.replace(s, '_') table_name = table_name.replace(' ', '') output_table = os.path.join(os.getcwd(), table_name + '.csv') output_table = output_table.replace('_.', '.') if label_name: write_columns(row_names, row_names_title, delimiter, quote=True, input_table='', output_table=output_table) write_columns(columns, labels, delimiter, quote=True, input_table=output_table, output_table=output_table) else: write_columns(columns, labels, delimiter, quote=True, input_table='', output_table=output_table) else: print('Not saving table.') return tables, columns, column_name, row_names, row_names_title, output_table
def select_column_from_tables(tables_dir, table_name, column_name, hemi, subjects, write_table=True, output_table='', delimiter=','): """ Select column from Mindboggle shape tables and make a new table. For example, extract the median travel depth column for a given feature (label region or sulcus ID) across a set of subjects, and make a table. Expects: <tables_dir>/['left','right']/<subject>/<table_name> Parameters ---------- tables_dir : string name of Mindboggle tables directory table_name : string name of Mindboggle table file column_name : string column name to select subjects : list of strings names of subjects processed by Mindboggle write_table : Boolean write output table? output_table : string output table file name delimiter : string delimiter between output table columns, such as ',' Returns ------- columns : list of lists of floats or integers columns of data output_table : string output table file name Examples -------- >>> import os >>> from mindboggle.utils.io_table import select_column_from_tables >>> tables_dir = os.path.join(os.environ['HOME'], 'mindboggled', 'tables') >>> table_name = "label_shapes.csv" >>> column_name = "label: thickness: median (weighted)" >>> hemi = 'left' >>> subjects = ['test', 'test_clean'] #['Twins-2-1'] >>> write_table = True >>> output_table = '' >>> delimiter = ',' >>> # >>> select_column_from_tables(tables_dir, table_name, column_name, hemi, >>> subjects, write_table, output_table, delimiter) ([['-1.04083', '-2.91968', '-3.82448', '-3.26286', '-4.81221', '-3.6451', '-3.38913', '-4.31545', '-3.0536', '-3.67473', '-3.10761', '-3.28', '-3.25178', '-3.81327', '-3.6395', '-2.95349', '-3.93486', '-4.22549', '-2.80147', '-1.12777', '-3.01129', '-2.95736', '-3.19688', '-3.16538', '-2.48648', '-3.99902', '-3.70333', '-2.76968', '-3.57815', '-3.61173', '-2.53391', '-2.15681']], '/Users/arno/Documents/Projects/Mindboggle/mindboggle/mindboggle/subjects_label_shapes.csv') """ import os import sys import csv from mindboggle.utils.io_table import write_columns #------------------------------------------------------------------------- # Construct a table: #------------------------------------------------------------------------- columns = [] column0 = [] first = True for subject in subjects: #--------------------------------------------------------------------- # Extract column from the table for each subject: #--------------------------------------------------------------------- input_table = os.path.join(tables_dir, hemi, subject, table_name) if not os.path.exists(input_table): raise(IOError(input_table + " not found")) else: reader = csv.reader(open(input_table, 'rb'), delimiter=',', quotechar='"') input_columns = [list(x) for x in zip(*reader)] #----------------------------------------------------------------- # Check to make sure first columns are the same across tables: #----------------------------------------------------------------- if first: column0 = input_columns[0] first = False elif input_columns[0] != column0: sys.exit('First columns of tables are not the same.') #----------------------------------------------------------------- # Extract column: #----------------------------------------------------------------- icolumn_name = None for icolumn, column in enumerate(input_columns): if column[0] == column_name: icolumn_name = icolumn if icolumn_name: columns.append(input_columns[icolumn_name][1::]) else: sys.exit('{0} is not a column name.'.format(column_name)) #------------------------------------------------------------------------- # Write table: #------------------------------------------------------------------------- if write_table and columns: if not output_table: output_table = os.path.join(os.getcwd(), 'subjects_' + table_name) write_columns(column0[1::], column0[0], delimiter, quote=True, input_table='', output_table=output_table) write_columns(columns, subjects, delimiter, quote=True, input_table=output_table, output_table=output_table) return columns, output_table
table_column_names.append(pr + 'skew' + po) table_column_names.append(pr + 'kurtosis' + po) table_column_names.append(pr + 'lower quartile' + po) table_column_names.append(pr + 'upper quartile' + po) """ columns.append(medians) """ columns.append(mads) columns.append(means) columns.append(sdevs) columns.append(skews) columns.append(kurts) columns.append(lower_quarts) columns.append(upper_quarts) """ #----------------------------------------------------------------- # Write labels and values to table: #----------------------------------------------------------------- # Write labels to table: write_columns(label_list, 'label', table_file, delimiter) # Append columns of shape values to table: if columns: write_columns(columns, table_column_names, table_file, delimiter, quote=True, input_table=table_file) else: # Write something to table: write_columns([], '', table_file, delimiter)