From dfed1e38d5e6b221ef681ca6cd721a734c99476c Mon Sep 17 00:00:00 2001 From: Ehsan Karimi <39439514+ehkarimi@users.noreply.github.com> Date: Sat, 10 Dec 2022 08:03:08 -0500 Subject: [PATCH 1/4] Update io.py there was a problem with reading the stats files --- nibabel/freesurfer/io.py | 56 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/nibabel/freesurfer/io.py b/nibabel/freesurfer/io.py index e2f48d88eb..b7d294b120 100644 --- a/nibabel/freesurfer/io.py +++ b/nibabel/freesurfer/io.py @@ -1,10 +1,13 @@ -""" Read / write FreeSurfer geometry, morphometry, label, annotation formats +""" Read / write FreeSurfer geometry, morphometry, label, stats, annotation formats """ +from __future__ import annotations import warnings import numpy as np import getpass import time +import re +import pandas as pd from collections import OrderedDict from ..openers import Opener @@ -622,3 +625,54 @@ def _serialize_volume_info(volume_info): strings.append( f'{key:6s} = {val[0]:.10g} {val[1]:.10g} {val[2]:.10g}\n'.encode('utf-8')) return b''.join(strings) + + +class StatsFileReader: + + @staticmethod + def read_stats_file(file_path): + """Extracts stats from stats files except '*curv.stats' files + + Parameters + ---------- + file_path: str, required + + Returns + ------- + + """ + with open(file_path, 'r') as f: + for line in f: + if re.findall(r'ColHeaders .*', line): + parameters = line.split() + break + f.close() + stats = np.loadtxt(file_path, comments='#', dtype=str) + df_stats = pd.DataFrame(stats, columns=parameters[2:]) + df_stats.set_index('StructName', drop=True, inplace=True) + return df_stats + + @staticmethod + def read_stats_file_both_hemispheres(file_path: str): + """Extracts stats data of both hemisphers and merges them + + Parameters + ---------- + file_path: str, required + Path of the stats file belong to left (lh) or right(rh) hemisphere + + Returns + ------- + df_both_hemispheres: pd.DataFrame + Stats data of both hemisphers + + Examples + -------- + >>> df_stats_a2009 = StatsFileReader.read_stats_file(r'lh.aparc.a2009s.stats') + + """ + df_left = StatsFileReader.read_stats_file(file_path.replace('rh', 'lh')) + df_right = StatsFileReader.read_stats_file(file_path.replace('lh', 'rh')) + df_both_hemispheres = pd.merge(df_left, df_right, suffixes=('_lh', '_rh'), how='outer', left_index=True, + right_index=True) + return df_both_hemispheres From 84d6e047cb4e928dc15b88ad8dc277bc12c87669 Mon Sep 17 00:00:00 2001 From: Ehsan Karimi <39439514+ehkarimi@users.noreply.github.com> Date: Sat, 10 Dec 2022 12:04:20 -0500 Subject: [PATCH 2/4] Stats file reader functions are added --- nibabel/freesurfer/io.py | 100 +++++++++++++++++++-------------------- 1 file changed, 49 insertions(+), 51 deletions(-) diff --git a/nibabel/freesurfer/io.py b/nibabel/freesurfer/io.py index b7d294b120..048dd3bdfa 100644 --- a/nibabel/freesurfer/io.py +++ b/nibabel/freesurfer/io.py @@ -6,8 +6,7 @@ import numpy as np import getpass import time -import re -import pandas as pd +import re from collections import OrderedDict from ..openers import Opener @@ -626,53 +625,52 @@ def _serialize_volume_info(volume_info): f'{key:6s} = {val[0]:.10g} {val[1]:.10g} {val[2]:.10g}\n'.encode('utf-8')) return b''.join(strings) +def read_stats_file(file_path): + """Extracts stats from stats files except '*curv.stats' files -class StatsFileReader: - - @staticmethod - def read_stats_file(file_path): - """Extracts stats from stats files except '*curv.stats' files - - Parameters - ---------- - file_path: str, required - - Returns - ------- - - """ - with open(file_path, 'r') as f: - for line in f: - if re.findall(r'ColHeaders .*', line): - parameters = line.split() - break - f.close() - stats = np.loadtxt(file_path, comments='#', dtype=str) - df_stats = pd.DataFrame(stats, columns=parameters[2:]) - df_stats.set_index('StructName', drop=True, inplace=True) - return df_stats - - @staticmethod - def read_stats_file_both_hemispheres(file_path: str): - """Extracts stats data of both hemisphers and merges them - - Parameters - ---------- - file_path: str, required - Path of the stats file belong to left (lh) or right(rh) hemisphere - - Returns - ------- - df_both_hemispheres: pd.DataFrame - Stats data of both hemisphers - - Examples - -------- - >>> df_stats_a2009 = StatsFileReader.read_stats_file(r'lh.aparc.a2009s.stats') - - """ - df_left = StatsFileReader.read_stats_file(file_path.replace('rh', 'lh')) - df_right = StatsFileReader.read_stats_file(file_path.replace('lh', 'rh')) - df_both_hemispheres = pd.merge(df_left, df_right, suffixes=('_lh', '_rh'), how='outer', left_index=True, - right_index=True) - return df_both_hemispheres + Parameters + ---------- + file_path: str, required + + Examples + -------- + >>> stats_a2009, column_names = read_stats_file(r'lh.aparc.a2009s.stats') + + """ + with open(file_path, 'r') as f: + for line in f: + if re.findall(r'ColHeaders .*', line): + parameters = line.split() + break + f.close() + stats = np.loadtxt(file_path, comments='#', dtype=str) + column_names = parameters[2:] + return stats, column_names + + +def read_stats_file_both_hemispheres(file_path: str): + """Extracts stats data of both hemispheres and merges them + + Parameters + ---------- + file_path: str, required + Path of the stats file belong to left (lh) or right(rh) hemisphere + + Returns + ------- + stats_both_hemispheres: ndarray + Stats data of both hemisphers + column_naems: ndarray + Name of columns + + Examples + -------- + >>> stats_a2009, column_names = read_stats_file_both_hemispheres(r'lh.aparc.a2009s.stats') + + """ + stats_left, columns_left = read_stats_file(file_path.replace('rh', 'lh')) + stats_right, columns_right = read_stats_file(file_path.replace('lh', 'rh')) + stats_both_hemispheres = np.concatenate((stats_left, stats_right[:, 1:]), axis=1) + column_names = [col_name + '_left' for col_name in columns_left] + [col_name + '_right' for col_name in + columns_right[1:]] + return stats_both_hemispheres, column_names From 8880a1ae4a2ead0cb3ff04e6ef633b4694dcbddf Mon Sep 17 00:00:00 2001 From: "Simon(Ehsan) Karimi" <39439514+simkarwin@users.noreply.github.com> Date: Wed, 5 Apr 2023 03:53:57 -0400 Subject: [PATCH 3/4] Update nibabel/freesurfer/io.py Co-authored-by: Chris Markiewicz --- nibabel/freesurfer/io.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/nibabel/freesurfer/io.py b/nibabel/freesurfer/io.py index 048dd3bdfa..bcf10ccdbd 100644 --- a/nibabel/freesurfer/io.py +++ b/nibabel/freesurfer/io.py @@ -639,13 +639,10 @@ def read_stats_file(file_path): """ with open(file_path, 'r') as f: for line in f: - if re.findall(r'ColHeaders .*', line): - parameters = line.split() + if line.startswith('# ColHeaders '): + columns = line.split()[2:] break - f.close() - stats = np.loadtxt(file_path, comments='#', dtype=str) - column_names = parameters[2:] - return stats, column_names + return np.genfromtxt(f, dtype=None, names=columns, encoding='utf-8') def read_stats_file_both_hemispheres(file_path: str): From 97107b7b8ba71e385dc39db8d57e9883050922c3 Mon Sep 17 00:00:00 2001 From: "Simon(Ehsan) Karimi" <39439514+simkarwin@users.noreply.github.com> Date: Wed, 5 Apr 2023 03:54:29 -0400 Subject: [PATCH 4/4] Update nibabel/freesurfer/io.py Co-authored-by: Chris Markiewicz --- nibabel/freesurfer/io.py | 1 - 1 file changed, 1 deletion(-) diff --git a/nibabel/freesurfer/io.py b/nibabel/freesurfer/io.py index bcf10ccdbd..dda6117f5b 100644 --- a/nibabel/freesurfer/io.py +++ b/nibabel/freesurfer/io.py @@ -6,7 +6,6 @@ import numpy as np import getpass import time -import re from collections import OrderedDict from ..openers import Opener