From e1ff7c42f252d3af5228a1896a0649a559299d82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Haitz=20Legarreta=20Gorro=C3=B1o?= Date: Sat, 15 Jul 2023 16:08:37 -0400 Subject: [PATCH] ENH: Build bundle list dynamically depending on atlas version Build bundle list dynamically depending on atlas version. Add the accompanying files: - The atlas bundle data (bundle label, short and long names) as CSV files. - The utilities functions required to read the bundle data. - Provide some level of encapsulation when adding the methods. Add a utility script to query the bundles corresponding to the files in an atlas available in a local disk. Add the corresponding tests. --- ...wm_append_clusters_to_anatomical_tracts.py | 43 ++++- .../tests/test_wm_query_atlas_bundle_names.py | 6 + utilities/wm_query_atlas_bundles_names.py | 67 +++++++ whitematteranalysis/anatomy/__init__.py | 0 .../anatomy/org_atlas_utils.py | 177 ++++++++++++++++++ whitematteranalysis/anatomy/tests/__init__.py | 0 .../anatomy/tests/test_org_atlas_utils.py | 160 ++++++++++++++++ whitematteranalysis/data/__init__.py | 0 whitematteranalysis/data/atlas/__init__.py | 0 .../data/atlas/org_atlas_bundles_v1_1.csv | 81 ++++++++ .../data/atlas/org_atlas_bundles_v1_1_1.csv | 81 ++++++++ .../data/atlas/org_atlas_bundles_v1_2.csv | 81 ++++++++ .../data/atlas/org_atlas_bundles_v1_3a.csv | 83 ++++++++ .../data/atlas/org_atlas_bundles_v1_3b.csv | 81 ++++++++ .../data/atlas/org_atlas_bundles_v1_4.csv | 83 ++++++++ .../data/atlas/org_atlas_version.json | 8 + .../data/atlas/tests/__init__.py | 0 .../data/atlas/tests/test_utils.py | 17 ++ whitematteranalysis/data/atlas/utils.py | 30 +++ whitematteranalysis/fileio/__init__.py | 0 whitematteranalysis/fileio/utils.py | 33 ++++ 21 files changed, 1026 insertions(+), 5 deletions(-) create mode 100644 utilities/tests/test_wm_query_atlas_bundle_names.py create mode 100644 utilities/wm_query_atlas_bundles_names.py create mode 100644 whitematteranalysis/anatomy/__init__.py create mode 100644 whitematteranalysis/anatomy/org_atlas_utils.py create mode 100644 whitematteranalysis/anatomy/tests/__init__.py create mode 100644 whitematteranalysis/anatomy/tests/test_org_atlas_utils.py create mode 100644 whitematteranalysis/data/__init__.py create mode 100644 whitematteranalysis/data/atlas/__init__.py create mode 100644 whitematteranalysis/data/atlas/org_atlas_bundles_v1_1.csv create mode 100644 whitematteranalysis/data/atlas/org_atlas_bundles_v1_1_1.csv create mode 100644 whitematteranalysis/data/atlas/org_atlas_bundles_v1_2.csv create mode 100644 whitematteranalysis/data/atlas/org_atlas_bundles_v1_3a.csv create mode 100644 whitematteranalysis/data/atlas/org_atlas_bundles_v1_3b.csv create mode 100644 whitematteranalysis/data/atlas/org_atlas_bundles_v1_4.csv create mode 100644 whitematteranalysis/data/atlas/org_atlas_version.json create mode 100644 whitematteranalysis/data/atlas/tests/__init__.py create mode 100644 whitematteranalysis/data/atlas/tests/test_utils.py create mode 100644 whitematteranalysis/data/atlas/utils.py create mode 100644 whitematteranalysis/fileio/__init__.py create mode 100644 whitematteranalysis/fileio/utils.py diff --git a/bin/wm_append_clusters_to_anatomical_tracts.py b/bin/wm_append_clusters_to_anatomical_tracts.py index d459e367..e9104ad3 100755 --- a/bin/wm_append_clusters_to_anatomical_tracts.py +++ b/bin/wm_append_clusters_to_anatomical_tracts.py @@ -8,6 +8,34 @@ import vtk import whitematteranalysis as wma +import pandas as pd + +from whitematteranalysis.data.atlas.utils import ( + ORGAtlasVersion, + get_local_atlas_bundle_fname, +) +from whitematteranalysis.anatomy.org_atlas_utils import ( + ORGAtlasBundleFileHeading, + get_hemispheric_mono_bundles, + get_commissural_augmented_bundles, + add_org_atlas_prefix, + get_bundle_short_name, +) + + +def get_hemispheric_mono_bundle_names(_df): + + hemis_mono_df = get_hemispheric_mono_bundles(_df) + hemis_names = hemis_mono_df[ORGAtlasBundleFileHeading.SHORT_NAME.value].values.tolist() + return add_org_atlas_prefix(hemis_names) + + +def get_commissural_bundle_names(_df): + + com_df = get_commissural_augmented_bundles(_df) + com_names = get_bundle_short_name(com_df, com_df[ + ORGAtlasBundleFileHeading.ID.value].values) + return add_org_atlas_prefix(com_names) def _build_arg_parser(): @@ -24,6 +52,12 @@ def _build_arg_parser(): parser.add_argument( 'outputDirectory', help='The output directory should be a new empty directory. It will be created if needed.') + parser.add_argument( + '--version', + choices=ORGAtlasVersion._member_names_, + default=ORGAtlasVersion.V1_2.name, + help="Atlas version.", + ) return parser @@ -105,12 +139,11 @@ def output_appended_tract(cluster_vtp_list, outputfile): wma.io.write_polydata(pd_appended_cluster, outputfile) - hemispheric_tracts = ["T_AF", "T_CB", "T_CPC", "T_MdLF", "T_PLIC", "T_SLF-I", "T_SLF-II", "T_SLF-III", "T_EC", "T_EmC", "T_ICP", "T_ILF", "T_IOFF", "T_UF", - "T_Intra-CBLM-I&P", "T_Intra-CBLM-PaT", "T_CR-F", "T_CR-P", "T_CST", "T_SF", "T_SO", "T_SP", "T_TF", "T_TO", "T_TP", - "T_Sup-F", "T_Sup-FP", "T_Sup-O", "T_Sup-OT", "T_Sup-P", "T_Sup-PO", "T_Sup-PT", "T_Sup-T"] - - commissural_tracts = ["T_CC1", "T_CC2", "T_CC3", "T_CC4", "T_CC5", "T_CC6", "T_CC7", "T_MCP"] + fname = get_local_atlas_bundle_fname(ORGAtlasVersion(args.version)) + df = pd.read_csv(fname, sep=",") + hemispheric_tracts = get_hemispheric_mono_bundle_names(df) + commissural_tracts = get_commissural_bundle_names(df) print(f"<{os.path.basename(__file__)}> hemispheric tracts (left and right): ") tract_idx = 1 diff --git a/utilities/tests/test_wm_query_atlas_bundle_names.py b/utilities/tests/test_wm_query_atlas_bundle_names.py new file mode 100644 index 00000000..811fedda --- /dev/null +++ b/utilities/tests/test_wm_query_atlas_bundle_names.py @@ -0,0 +1,6 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +def test_help_option(script_runner): + ret = script_runner.run(["wm_query_atlas_bundles_names.py", "--help"]) + assert ret.success diff --git a/utilities/wm_query_atlas_bundles_names.py b/utilities/wm_query_atlas_bundles_names.py new file mode 100644 index 00000000..7abd04ea --- /dev/null +++ b/utilities/wm_query_atlas_bundles_names.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +"""Query the atlas bundle names. + +e.g. python wm_query_atlas_bundles.py \ + /mnt/data/atlas/ORG-Atlas-1.4/ORG-800FC-100HCP/ \ + /mnt/data/atlas/ORG-Atlas-1.4/bundle_names_default.txt \ + DEFAULT + + python wm_query_atlas_bundles.py \ + /mnt/data/atlas/ORG-Atlas-1.4/ORG-800FC-100HCP-separated/AnatomicalTracts/ \ + /mnt/data/atlas/ORG-Atlas-1.4/bundle_names_separated.txt \ + SEPARATED +""" + +import argparse +from pathlib import Path + +from whitematteranalysis.anatomy.org_atlas_utils import ( + AtlasAvailability, + query_bundle_names, +) +from whitematteranalysis.fileio.utils import save2txt + + +def _build_arg_parser(): + + parser = argparse.ArgumentParser( + description=__doc__, formatter_class=argparse.RawTextHelpFormatter + ) + parser.add_argument("in_path", type=Path, help="Input path.") + parser.add_argument( + "out_fname", + help="Output filename (*.txt).", + type=Path, + ) + parser.add_argument( + "atlas_availability", + choices=AtlasAvailability._member_names_, + help="Atlas availability.", + ) + + return parser + + +def _parse_args(parser): + + args = parser.parse_args() + + return args + + +def main(): + + parser = _build_arg_parser() + args = _parse_args(parser) + + bundle_names = query_bundle_names( + args.in_path, + AtlasAvailability.__getitem__(args.atlas_availability), + ) + save2txt(args.out_fname, bundle_names) + + +if __name__ == "__main__": + main() diff --git a/whitematteranalysis/anatomy/__init__.py b/whitematteranalysis/anatomy/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/whitematteranalysis/anatomy/org_atlas_utils.py b/whitematteranalysis/anatomy/org_atlas_utils.py new file mode 100644 index 00000000..096638a4 --- /dev/null +++ b/whitematteranalysis/anatomy/org_atlas_utils.py @@ -0,0 +1,177 @@ +# -*- coding: utf-8 -*- + +import enum + +import pandas as pd + +from whitematteranalysis.fileio.utils import ( + SlicerFileExtension, + VTKFileExtension, + find_filenames, +) + +atlas_bundle_file_prefix = "T_" +nonatlas_bundle_names = ["T_FalsePositive"] + + +class Hemisphere(enum.Enum): + LEFT = "left" + RIGHT = "right" + + +class AtlasAvailability(enum.Enum): + DEFAULT = "default" + SEPARATED = "separated" + + +class ORGAtlasBundleType(enum.Enum): + ASS = "Association" + CER = "Cerebellar" + COM = "Commissural" + PRO = "Projection" + STR = "Striatal" + SUP = "Superficial" + + +class ORGAtlasBundleFileHeading(enum.Enum): + ID = "id" + SHORT_NAME = "short_name" + LONG_NAME = "long_name" + + +class ORGAtlasBundleRange(enum.Enum): + ASO = (101, 199) + CER = (201, 299) + COM = (301, 399) + PRO = (401, 499) + STR = (501, 599) + SUP = (601, 699) + + @staticmethod + def get_range_low(name): + return ORGAtlasBundleRange(name).value[0] + + @staticmethod + def get_range_high(name): + return ORGAtlasBundleRange(name).value[1] + + +def get_bundles(df, bundle_id): + return df[df[ORGAtlasBundleFileHeading.ID.value].isin(bundle_id)] + + +def get_bundle_feature(df, bundle_id, column): + return get_bundles(df, bundle_id)[column].values.tolist() + + +def get_bundle_long_name(df, bundle_id): + return get_bundle_feature(df, bundle_id, ORGAtlasBundleFileHeading.LONG_NAME.value) + + +def get_bundle_short_name(df, bundle_id): + return get_bundle_feature(df, bundle_id, ORGAtlasBundleFileHeading.SHORT_NAME.value) + + +def get_bundle_type(df, bundle_type): + return df[ + df[ + ORGAtlasBundleFileHeading.ID.value].between( + ORGAtlasBundleRange.get_range_low(bundle_type), + ORGAtlasBundleRange.get_range_high(bundle_type) + ) + ] + + +def get_association_bundles(df): + return get_bundle_type(df, ORGAtlasBundleRange.ASO) + + +def get_cerebellar_bundles(df): + return get_bundle_type(df, ORGAtlasBundleRange.CER) + + +def get_commissural_bundles(df): + return get_bundle_type(df, ORGAtlasBundleRange.COM) + + +def get_commissural_augmented_bundles(df): + com = get_commissural_bundles(df) + # Add the MCP + mcp = get_bundles(df, [209]) + + return pd.concat([com, mcp], ignore_index=True) + + +def get_hemispheric_bundles(df): + aso = get_association_bundles(df) + cer = get_cerebellar_bundles(df) + # Remove the MCP + cer = cer.drop(cer[cer[ORGAtlasBundleFileHeading.ID.value] == 209].index) + stl = get_striatal_bundles(df) + pro = get_projection_bundles(df) + sup = get_superficial_bundles(df) + + return pd.concat([aso, cer, stl, pro, sup], ignore_index=True) + + +def get_hemispheric_mono_bundles(df): + hem_mono = get_hemispheric_bundles(df) + + # Remove all right values + hem_mono = hem_mono.drop(hem_mono.loc[hem_mono[ORGAtlasBundleFileHeading.SHORT_NAME.value].str.contains(Hemisphere.RIGHT.value)].index) + + # Drop the left substring + short_name_substr = "_" + Hemisphere.LEFT.value + column = ORGAtlasBundleFileHeading.SHORT_NAME.value + hem_mono[column] = hem_mono[column].str.replace(short_name_substr, "") + long_name_substr = " " + Hemisphere.LEFT.value + column = ORGAtlasBundleFileHeading.LONG_NAME.value + hem_mono[column] = hem_mono[column].str.replace(long_name_substr, "") + + # Strip the ID as it makes no longer sense + hem_mono.drop(ORGAtlasBundleFileHeading.ID.value, axis=1, inplace=True) + + return hem_mono + + +def get_projection_bundles(df): + return get_bundle_type(df, ORGAtlasBundleRange.PRO) + + +def get_striatal_bundles(df): + return get_bundle_type(df, ORGAtlasBundleRange.STR) + + +def get_superficial_bundles(df): + return get_bundle_type(df, ORGAtlasBundleRange.SUP) + + +def query_bundle_names_from_anatomical_tracts(path): + bundle_names = find_filenames(path, VTKFileExtension.VTP, stem=True) + return bundle_names + + +def query_bundle_names_from_scene_files(path): + bundle_names = find_filenames(path, SlicerFileExtension.MRML, stem=True) + + # Remove non-atlas filenames if present + [bundle_names.remove(elem) for elem in nonatlas_bundle_names] + bundle_names = [elem for elem in bundle_names if elem.startswith(atlas_bundle_file_prefix)] + + return bundle_names + + +def add_org_atlas_prefix(bundles): + return [atlas_bundle_file_prefix + elem for elem in bundles] + + +def query_bundle_names(path, atlas_availability): + + if atlas_availability == AtlasAvailability.DEFAULT: + return query_bundle_names_from_scene_files(path) + elif atlas_availability == AtlasAvailability.SEPARATED: + return query_bundle_names_from_anatomical_tracts(path) + else: + raise ValueError( + f"Unsupported value:\n" + f"Found: {atlas_availability}; Available: {AtlasAvailability.__members__}") diff --git a/whitematteranalysis/anatomy/tests/__init__.py b/whitematteranalysis/anatomy/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/whitematteranalysis/anatomy/tests/test_org_atlas_utils.py b/whitematteranalysis/anatomy/tests/test_org_atlas_utils.py new file mode 100644 index 00000000..936c7fe0 --- /dev/null +++ b/whitematteranalysis/anatomy/tests/test_org_atlas_utils.py @@ -0,0 +1,160 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import pandas as pd + +from whitematteranalysis.anatomy.org_atlas_utils import ( + ORGAtlasBundleFileHeading, + get_association_bundles, + get_bundle_long_name, + get_bundle_short_name, + get_cerebellar_bundles, + get_commissural_bundles, + get_commissural_augmented_bundles, + get_hemispheric_bundles, + get_hemispheric_mono_bundles, + get_striatal_bundles, + get_projection_bundles, + get_superficial_bundles, +) +from whitematteranalysis.data.atlas.utils import ( + ORGAtlasVersion, + get_local_atlas_bundle_fname, +) + + +def _check_bundle_count(method_name, expected_bndl_count): + + version = ORGAtlasVersion.__members__.values() + + for ver, expected_count in zip(version, expected_bndl_count): + fname = get_local_atlas_bundle_fname(ver) + df = pd.read_csv(fname, sep=",") + cer = method_name(df) + obtained_count = len(cer) + + assert obtained_count == expected_count + + +def _check_bundle_name(method_name, version, bundle_id, expected_name): + + fname = get_local_atlas_bundle_fname(version) + df = pd.read_csv(fname, sep=",") + + obtained_name = method_name(df, bundle_id) + + assert obtained_name == expected_name + + +def test_wma_get_association_bundles(): + + expected_bndl_count = [20, 20, 20, 20, 20, 20] + _check_bundle_count(get_association_bundles, expected_bndl_count) + + +def test_wma_get_bundle_long_name(): + + version = ORGAtlasVersion.V1_2 + + bundle_id = [201] + method_name = get_bundle_long_name + expected_name = ["cortico - ponto - cerebellar left"] + _check_bundle_name(method_name, version, bundle_id, expected_name) + + fname = get_local_atlas_bundle_fname(version) + df = pd.read_csv(fname, sep=",") + stl = get_striatal_bundles(df) + bundle_id = stl[ORGAtlasBundleFileHeading.ID.value].values + + expected_name = ["external capsule left", "external capsule right"] + _check_bundle_name(method_name, version, bundle_id, expected_name) + + +def test_wma_get_bundle_short_name(): + + version = ORGAtlasVersion.V1_2 + + bundle_id = [201] + method_name = get_bundle_short_name + expected_name = ["CPC_left"] + _check_bundle_name(method_name, version, bundle_id, expected_name) + + fname = get_local_atlas_bundle_fname(version) + df = pd.read_csv(fname, sep=",") + stl = get_striatal_bundles(df) + bundle_id = stl[ORGAtlasBundleFileHeading.ID.value].values + + expected_name = ["EC_left", "EC_right"] + _check_bundle_name(method_name, version, bundle_id, expected_name) + + +def test_wma_get_cerebellar_bundles(): + + expected_bndl_count = [9, 9, 9, 9, 9, 9, 9] + _check_bundle_count(get_cerebellar_bundles, expected_bndl_count) + + +def test_wma_get_commissural_bundles(): + + expected_bndl_count = [7, 7, 7, 7, 7, 7] + _check_bundle_count(get_commissural_bundles, expected_bndl_count) + + +def test_wma_get_commissural_augmented_bundles(): + + expected_count = 8 + + version = ORGAtlasVersion.V1_2 + fname = get_local_atlas_bundle_fname(version) + df = pd.read_csv(fname, sep=",") + + com_aug = get_commissural_augmented_bundles(df) + obtained_count = len(com_aug) + + assert obtained_count == expected_count + + +def test_wma_get_hemispheric_bundles(): + + expected_count = 66 + + version = ORGAtlasVersion.V1_2 + fname = get_local_atlas_bundle_fname(version) + df = pd.read_csv(fname, sep=",") + + com_aug = get_hemispheric_bundles(df) + obtained_count = len(com_aug) + + assert obtained_count == expected_count + + +def test_wma_get_hemispheric_mono_bundles(): + + expected_count = 33 + + version = ORGAtlasVersion.V1_2 + fname = get_local_atlas_bundle_fname(version) + df = pd.read_csv(fname, sep=",") + + com_aug = get_hemispheric_mono_bundles(df) + obtained_count = len(com_aug) + + assert obtained_count == expected_count + + +def test_wma_get_striatal_bundles(): + + expected_bndl_count = [2, 2, 2, 2, 2, 2] + _check_bundle_count(get_striatal_bundles, expected_bndl_count) + + +def test_wma_get_projection_bundles(): + + expected_bndl_count = [20, 20, 20, 22, 20, 22] + _check_bundle_count(get_projection_bundles, expected_bndl_count) + + +def test_wma_get_superficial_bundles(): + + expected_bndl_count = [16, 16, 16, 16, 16, 16] + _check_bundle_count(get_superficial_bundles, expected_bndl_count) diff --git a/whitematteranalysis/data/__init__.py b/whitematteranalysis/data/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/whitematteranalysis/data/atlas/__init__.py b/whitematteranalysis/data/atlas/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/whitematteranalysis/data/atlas/org_atlas_bundles_v1_1.csv b/whitematteranalysis/data/atlas/org_atlas_bundles_v1_1.csv new file mode 100644 index 00000000..b2680767 --- /dev/null +++ b/whitematteranalysis/data/atlas/org_atlas_bundles_v1_1.csv @@ -0,0 +1,81 @@ +id,short_name,long_name + +101,AF_left,arcuate fasciculus left +102,AF_right,arcuate fasciculus right +103,CB_left,cingulum bundle left +104,CB_right,cingulum bundle right +105,EmC_left,extreme capsule left +106,EmC_right,extreme capsule right +107,ILF_left,inferior longitudinal fasciculus left +108,ILF_right,inferior longitudinal fasciculus left +109,IOFF_left,inferior occipito-frontal fasciculus left +110,IOFF_right,inferior occipito-frontal fasciculus left +111,MdLF_left,middle longitudinal fasciculus left +112,MdLF_right,middle longitudinal fasciculus right +113,SLF-I_left,superior longitudinal fasciculus I left +114,SLF-I_right,superior longitudinal fasciculus I right +115,SLF-II_left,superior longitudinal fasciculus II left +116,SLF-II_right,superior longitudinal fasciculus II right +117,SLF-III_left,superior longitudinal fasciculus III left +118,SLF-III_right,superior longitudinal fasciculus III right +119,UF_left,uncinate fasciculus left +120,UF_right,uncinate fasciculus right + +201,CPC_left,cortico - ponto - cerebellar left +202,CPC_right,cortico - ponto - cerebellar right +203,ICP_left,inferior cerebellar peduncle left +204,ICP_right,inferior cerebellar peduncle right +205,Intra-CBLM-I&P_left,intracerebellar input and Purkinje tract left +206,Intra-CBLM-I&P_right,intracerebellar input and Purkinje tract right +207,Intra-CBLM-PaT_left,intracerebellar parallel tract left +208,Intra-CBLM-PaT_right,intracerebellar parallel tract right +209,MCP,middle cerebellar peduncle + +301,CC1,corpus callosum 1 +302,CC2,corpus callosum 2 +303,CC3,corpus callosum 3 +304,CC4,corpus callosum 4 +305,CC5,corpus callosum 5 +306,CC6,corpus callosum 6 +307,CC7,corpus callosum 7 + +401,CR-F_left,corona-radiata-frontal left +402,CR-F_right,corona-radiata-frontal right +403,CR-P_left,corona-radiata-parietal left +404,CR-P_right,corona-radiata-parietal right +405,CST_left,corticospinal tract left +406,CST_right,corticospinal tract right +407,PLIC_left,posterior limb of internal capsule left +408,PLIC_right,posterior limb of internal capsule right +409,SF_left,striato-frontal left +410,SF_right,striato-frontal right +411,SO_left,striato-occipital left +412,SO_right,striato-occipital right +413,SP_left,striato-parietal left +414,SP_right,striato-parietal right +415,TF_left,thalamo-frontal left +416,TF_right,thalamo-frontal right +417,TO_left,thalamo-occipital left +418,TO_right,thalamo-occipital right +419,TP_left,thalamo-parietal left +420,TP_right,thalamo-parietal right + +501,EC_left,external capsule left +502,EC_right,external capsule right + +601,Sup-F_left,superficial-frontal left +602,Sup-F_right,superficial-frontal right +603,Sup-FP_left,superficial-frontal-parietal left +604,Sup-FP_right,superficial-frontal-parietal right +605,Sup-O_left,superficial-occipital left +606,Sup-O_right,superficial-occipital right +607,Sup-OT_left,superficial-occipital-temporal left +608,Sup-OT_right,superficial-occipital-temporal right +609,Sup-P_left,superficial-parietal left +610,Sup-P_right,superficial-parietal right +611,Sup-PO_left,superficial-parietal-occipital left +612,Sup-PO_right,superficial-parietal-occipital right +613,Sup-PT_left,superficial-parietal-temporal left +614,Sup-PT_right,superficial-parietal-temporal right +615,Sup-T_left,superficial-temporal left +616,Sup-T_right,superficial-temporal right diff --git a/whitematteranalysis/data/atlas/org_atlas_bundles_v1_1_1.csv b/whitematteranalysis/data/atlas/org_atlas_bundles_v1_1_1.csv new file mode 100644 index 00000000..b2680767 --- /dev/null +++ b/whitematteranalysis/data/atlas/org_atlas_bundles_v1_1_1.csv @@ -0,0 +1,81 @@ +id,short_name,long_name + +101,AF_left,arcuate fasciculus left +102,AF_right,arcuate fasciculus right +103,CB_left,cingulum bundle left +104,CB_right,cingulum bundle right +105,EmC_left,extreme capsule left +106,EmC_right,extreme capsule right +107,ILF_left,inferior longitudinal fasciculus left +108,ILF_right,inferior longitudinal fasciculus left +109,IOFF_left,inferior occipito-frontal fasciculus left +110,IOFF_right,inferior occipito-frontal fasciculus left +111,MdLF_left,middle longitudinal fasciculus left +112,MdLF_right,middle longitudinal fasciculus right +113,SLF-I_left,superior longitudinal fasciculus I left +114,SLF-I_right,superior longitudinal fasciculus I right +115,SLF-II_left,superior longitudinal fasciculus II left +116,SLF-II_right,superior longitudinal fasciculus II right +117,SLF-III_left,superior longitudinal fasciculus III left +118,SLF-III_right,superior longitudinal fasciculus III right +119,UF_left,uncinate fasciculus left +120,UF_right,uncinate fasciculus right + +201,CPC_left,cortico - ponto - cerebellar left +202,CPC_right,cortico - ponto - cerebellar right +203,ICP_left,inferior cerebellar peduncle left +204,ICP_right,inferior cerebellar peduncle right +205,Intra-CBLM-I&P_left,intracerebellar input and Purkinje tract left +206,Intra-CBLM-I&P_right,intracerebellar input and Purkinje tract right +207,Intra-CBLM-PaT_left,intracerebellar parallel tract left +208,Intra-CBLM-PaT_right,intracerebellar parallel tract right +209,MCP,middle cerebellar peduncle + +301,CC1,corpus callosum 1 +302,CC2,corpus callosum 2 +303,CC3,corpus callosum 3 +304,CC4,corpus callosum 4 +305,CC5,corpus callosum 5 +306,CC6,corpus callosum 6 +307,CC7,corpus callosum 7 + +401,CR-F_left,corona-radiata-frontal left +402,CR-F_right,corona-radiata-frontal right +403,CR-P_left,corona-radiata-parietal left +404,CR-P_right,corona-radiata-parietal right +405,CST_left,corticospinal tract left +406,CST_right,corticospinal tract right +407,PLIC_left,posterior limb of internal capsule left +408,PLIC_right,posterior limb of internal capsule right +409,SF_left,striato-frontal left +410,SF_right,striato-frontal right +411,SO_left,striato-occipital left +412,SO_right,striato-occipital right +413,SP_left,striato-parietal left +414,SP_right,striato-parietal right +415,TF_left,thalamo-frontal left +416,TF_right,thalamo-frontal right +417,TO_left,thalamo-occipital left +418,TO_right,thalamo-occipital right +419,TP_left,thalamo-parietal left +420,TP_right,thalamo-parietal right + +501,EC_left,external capsule left +502,EC_right,external capsule right + +601,Sup-F_left,superficial-frontal left +602,Sup-F_right,superficial-frontal right +603,Sup-FP_left,superficial-frontal-parietal left +604,Sup-FP_right,superficial-frontal-parietal right +605,Sup-O_left,superficial-occipital left +606,Sup-O_right,superficial-occipital right +607,Sup-OT_left,superficial-occipital-temporal left +608,Sup-OT_right,superficial-occipital-temporal right +609,Sup-P_left,superficial-parietal left +610,Sup-P_right,superficial-parietal right +611,Sup-PO_left,superficial-parietal-occipital left +612,Sup-PO_right,superficial-parietal-occipital right +613,Sup-PT_left,superficial-parietal-temporal left +614,Sup-PT_right,superficial-parietal-temporal right +615,Sup-T_left,superficial-temporal left +616,Sup-T_right,superficial-temporal right diff --git a/whitematteranalysis/data/atlas/org_atlas_bundles_v1_2.csv b/whitematteranalysis/data/atlas/org_atlas_bundles_v1_2.csv new file mode 100644 index 00000000..b2680767 --- /dev/null +++ b/whitematteranalysis/data/atlas/org_atlas_bundles_v1_2.csv @@ -0,0 +1,81 @@ +id,short_name,long_name + +101,AF_left,arcuate fasciculus left +102,AF_right,arcuate fasciculus right +103,CB_left,cingulum bundle left +104,CB_right,cingulum bundle right +105,EmC_left,extreme capsule left +106,EmC_right,extreme capsule right +107,ILF_left,inferior longitudinal fasciculus left +108,ILF_right,inferior longitudinal fasciculus left +109,IOFF_left,inferior occipito-frontal fasciculus left +110,IOFF_right,inferior occipito-frontal fasciculus left +111,MdLF_left,middle longitudinal fasciculus left +112,MdLF_right,middle longitudinal fasciculus right +113,SLF-I_left,superior longitudinal fasciculus I left +114,SLF-I_right,superior longitudinal fasciculus I right +115,SLF-II_left,superior longitudinal fasciculus II left +116,SLF-II_right,superior longitudinal fasciculus II right +117,SLF-III_left,superior longitudinal fasciculus III left +118,SLF-III_right,superior longitudinal fasciculus III right +119,UF_left,uncinate fasciculus left +120,UF_right,uncinate fasciculus right + +201,CPC_left,cortico - ponto - cerebellar left +202,CPC_right,cortico - ponto - cerebellar right +203,ICP_left,inferior cerebellar peduncle left +204,ICP_right,inferior cerebellar peduncle right +205,Intra-CBLM-I&P_left,intracerebellar input and Purkinje tract left +206,Intra-CBLM-I&P_right,intracerebellar input and Purkinje tract right +207,Intra-CBLM-PaT_left,intracerebellar parallel tract left +208,Intra-CBLM-PaT_right,intracerebellar parallel tract right +209,MCP,middle cerebellar peduncle + +301,CC1,corpus callosum 1 +302,CC2,corpus callosum 2 +303,CC3,corpus callosum 3 +304,CC4,corpus callosum 4 +305,CC5,corpus callosum 5 +306,CC6,corpus callosum 6 +307,CC7,corpus callosum 7 + +401,CR-F_left,corona-radiata-frontal left +402,CR-F_right,corona-radiata-frontal right +403,CR-P_left,corona-radiata-parietal left +404,CR-P_right,corona-radiata-parietal right +405,CST_left,corticospinal tract left +406,CST_right,corticospinal tract right +407,PLIC_left,posterior limb of internal capsule left +408,PLIC_right,posterior limb of internal capsule right +409,SF_left,striato-frontal left +410,SF_right,striato-frontal right +411,SO_left,striato-occipital left +412,SO_right,striato-occipital right +413,SP_left,striato-parietal left +414,SP_right,striato-parietal right +415,TF_left,thalamo-frontal left +416,TF_right,thalamo-frontal right +417,TO_left,thalamo-occipital left +418,TO_right,thalamo-occipital right +419,TP_left,thalamo-parietal left +420,TP_right,thalamo-parietal right + +501,EC_left,external capsule left +502,EC_right,external capsule right + +601,Sup-F_left,superficial-frontal left +602,Sup-F_right,superficial-frontal right +603,Sup-FP_left,superficial-frontal-parietal left +604,Sup-FP_right,superficial-frontal-parietal right +605,Sup-O_left,superficial-occipital left +606,Sup-O_right,superficial-occipital right +607,Sup-OT_left,superficial-occipital-temporal left +608,Sup-OT_right,superficial-occipital-temporal right +609,Sup-P_left,superficial-parietal left +610,Sup-P_right,superficial-parietal right +611,Sup-PO_left,superficial-parietal-occipital left +612,Sup-PO_right,superficial-parietal-occipital right +613,Sup-PT_left,superficial-parietal-temporal left +614,Sup-PT_right,superficial-parietal-temporal right +615,Sup-T_left,superficial-temporal left +616,Sup-T_right,superficial-temporal right diff --git a/whitematteranalysis/data/atlas/org_atlas_bundles_v1_3a.csv b/whitematteranalysis/data/atlas/org_atlas_bundles_v1_3a.csv new file mode 100644 index 00000000..d3d2ad72 --- /dev/null +++ b/whitematteranalysis/data/atlas/org_atlas_bundles_v1_3a.csv @@ -0,0 +1,83 @@ +id,short_name,long_name + +101,AF_left,arcuate fasciculus left +102,AF_right,arcuate fasciculus right +103,CB_left,cingulum bundle left +104,CB_right,cingulum bundle right +105,EmC_left,extreme capsule left +106,EmC_right,extreme capsule right +107,ILF_left,inferior longitudinal fasciculus left +108,ILF_right,inferior longitudinal fasciculus left +109,IOFF_left,inferior occipito-frontal fasciculus left +110,IOFF_right,inferior occipito-frontal fasciculus left +111,MdLF_left,middle longitudinal fasciculus left +112,MdLF_right,middle longitudinal fasciculus right +113,SLF-I_left,superior longitudinal fasciculus I left +114,SLF-I_right,superior longitudinal fasciculus I right +115,SLF-II_left,superior longitudinal fasciculus II left +116,SLF-II_right,superior longitudinal fasciculus II right +117,SLF-III_left,superior longitudinal fasciculus III left +118,SLF-III_right,superior longitudinal fasciculus III right +119,UF_left,uncinate fasciculus left +120,UF_right,uncinate fasciculus right + +201,CPC_left,cortico - ponto - cerebellar left +202,CPC_right,cortico - ponto - cerebellar right +203,ICP_left,inferior cerebellar peduncle left +204,ICP_right,inferior cerebellar peduncle right +205,Intra-CBLM-I&P_left,intracerebellar input and Purkinje tract left +206,Intra-CBLM-I&P_right,intracerebellar input and Purkinje tract right +207,Intra-CBLM-PaT_left,intracerebellar parallel tract left +208,Intra-CBLM-PaT_right,intracerebellar parallel tract right +209,MCP,middle cerebellar peduncle + +301,CC1,corpus callosum 1 +302,CC2,corpus callosum 2 +303,CC3,corpus callosum 3 +304,CC4,corpus callosum 4 +305,CC5,corpus callosum 5 +306,CC6,corpus callosum 6 +307,CC7,corpus callosum 7 + +401,CR-F_left,corona-radiata-frontal left +402,CR-F_right,corona-radiata-frontal right +403,CR-P_left,corona-radiata-parietal left +404,CR-P_right,corona-radiata-parietal right +405,CST_left,corticospinal tract left +406,CST_right,corticospinal tract right +407,PLIC_left,posterior limb of internal capsule left +408,PLIC_right,posterior limb of internal capsule right +409,SF_left,striato-frontal left +410,SF_right,striato-frontal right +411,SO_left,striato-occipital left +412,SO_right,striato-occipital right +413,SP_left,striato-parietal left +414,SP_right,striato-parietal right +415,TF_left,thalamo-frontal left +416,TF_right,thalamo-frontal right +417,TO_left,thalamo-occipital left +418,TO_right,thalamo-occipital right +419,TP_left,thalamo-parietal left +420,TP_right,thalamo-parietal right +421,TT_left,thalamo-temporal left +422,TT_right,thalamo-temporal right + +501,EC_left,external capsule left +502,EC_right,external capsule right + +601,Sup-F_left,superficial-frontal left +602,Sup-F_right,superficial-frontal right +603,Sup-FP_left,superficial-frontal-parietal left +604,Sup-FP_right,superficial-frontal-parietal right +605,Sup-O_left,superficial-occipital left +606,Sup-O_right,superficial-occipital right +607,Sup-OT_left,superficial-occipital-temporal left +608,Sup-OT_right,superficial-occipital-temporal right +609,Sup-P_left,superficial-parietal left +610,Sup-P_right,superficial-parietal right +611,Sup-PO_left,superficial-parietal-occipital left +612,Sup-PO_right,superficial-parietal-occipital right +613,Sup-PT_left,superficial-parietal-temporal left +614,Sup-PT_right,superficial-parietal-temporal right +615,Sup-T_left,superficial-temporal left +616,Sup-T_right,superficial-temporal right diff --git a/whitematteranalysis/data/atlas/org_atlas_bundles_v1_3b.csv b/whitematteranalysis/data/atlas/org_atlas_bundles_v1_3b.csv new file mode 100644 index 00000000..b2680767 --- /dev/null +++ b/whitematteranalysis/data/atlas/org_atlas_bundles_v1_3b.csv @@ -0,0 +1,81 @@ +id,short_name,long_name + +101,AF_left,arcuate fasciculus left +102,AF_right,arcuate fasciculus right +103,CB_left,cingulum bundle left +104,CB_right,cingulum bundle right +105,EmC_left,extreme capsule left +106,EmC_right,extreme capsule right +107,ILF_left,inferior longitudinal fasciculus left +108,ILF_right,inferior longitudinal fasciculus left +109,IOFF_left,inferior occipito-frontal fasciculus left +110,IOFF_right,inferior occipito-frontal fasciculus left +111,MdLF_left,middle longitudinal fasciculus left +112,MdLF_right,middle longitudinal fasciculus right +113,SLF-I_left,superior longitudinal fasciculus I left +114,SLF-I_right,superior longitudinal fasciculus I right +115,SLF-II_left,superior longitudinal fasciculus II left +116,SLF-II_right,superior longitudinal fasciculus II right +117,SLF-III_left,superior longitudinal fasciculus III left +118,SLF-III_right,superior longitudinal fasciculus III right +119,UF_left,uncinate fasciculus left +120,UF_right,uncinate fasciculus right + +201,CPC_left,cortico - ponto - cerebellar left +202,CPC_right,cortico - ponto - cerebellar right +203,ICP_left,inferior cerebellar peduncle left +204,ICP_right,inferior cerebellar peduncle right +205,Intra-CBLM-I&P_left,intracerebellar input and Purkinje tract left +206,Intra-CBLM-I&P_right,intracerebellar input and Purkinje tract right +207,Intra-CBLM-PaT_left,intracerebellar parallel tract left +208,Intra-CBLM-PaT_right,intracerebellar parallel tract right +209,MCP,middle cerebellar peduncle + +301,CC1,corpus callosum 1 +302,CC2,corpus callosum 2 +303,CC3,corpus callosum 3 +304,CC4,corpus callosum 4 +305,CC5,corpus callosum 5 +306,CC6,corpus callosum 6 +307,CC7,corpus callosum 7 + +401,CR-F_left,corona-radiata-frontal left +402,CR-F_right,corona-radiata-frontal right +403,CR-P_left,corona-radiata-parietal left +404,CR-P_right,corona-radiata-parietal right +405,CST_left,corticospinal tract left +406,CST_right,corticospinal tract right +407,PLIC_left,posterior limb of internal capsule left +408,PLIC_right,posterior limb of internal capsule right +409,SF_left,striato-frontal left +410,SF_right,striato-frontal right +411,SO_left,striato-occipital left +412,SO_right,striato-occipital right +413,SP_left,striato-parietal left +414,SP_right,striato-parietal right +415,TF_left,thalamo-frontal left +416,TF_right,thalamo-frontal right +417,TO_left,thalamo-occipital left +418,TO_right,thalamo-occipital right +419,TP_left,thalamo-parietal left +420,TP_right,thalamo-parietal right + +501,EC_left,external capsule left +502,EC_right,external capsule right + +601,Sup-F_left,superficial-frontal left +602,Sup-F_right,superficial-frontal right +603,Sup-FP_left,superficial-frontal-parietal left +604,Sup-FP_right,superficial-frontal-parietal right +605,Sup-O_left,superficial-occipital left +606,Sup-O_right,superficial-occipital right +607,Sup-OT_left,superficial-occipital-temporal left +608,Sup-OT_right,superficial-occipital-temporal right +609,Sup-P_left,superficial-parietal left +610,Sup-P_right,superficial-parietal right +611,Sup-PO_left,superficial-parietal-occipital left +612,Sup-PO_right,superficial-parietal-occipital right +613,Sup-PT_left,superficial-parietal-temporal left +614,Sup-PT_right,superficial-parietal-temporal right +615,Sup-T_left,superficial-temporal left +616,Sup-T_right,superficial-temporal right diff --git a/whitematteranalysis/data/atlas/org_atlas_bundles_v1_4.csv b/whitematteranalysis/data/atlas/org_atlas_bundles_v1_4.csv new file mode 100644 index 00000000..d3d2ad72 --- /dev/null +++ b/whitematteranalysis/data/atlas/org_atlas_bundles_v1_4.csv @@ -0,0 +1,83 @@ +id,short_name,long_name + +101,AF_left,arcuate fasciculus left +102,AF_right,arcuate fasciculus right +103,CB_left,cingulum bundle left +104,CB_right,cingulum bundle right +105,EmC_left,extreme capsule left +106,EmC_right,extreme capsule right +107,ILF_left,inferior longitudinal fasciculus left +108,ILF_right,inferior longitudinal fasciculus left +109,IOFF_left,inferior occipito-frontal fasciculus left +110,IOFF_right,inferior occipito-frontal fasciculus left +111,MdLF_left,middle longitudinal fasciculus left +112,MdLF_right,middle longitudinal fasciculus right +113,SLF-I_left,superior longitudinal fasciculus I left +114,SLF-I_right,superior longitudinal fasciculus I right +115,SLF-II_left,superior longitudinal fasciculus II left +116,SLF-II_right,superior longitudinal fasciculus II right +117,SLF-III_left,superior longitudinal fasciculus III left +118,SLF-III_right,superior longitudinal fasciculus III right +119,UF_left,uncinate fasciculus left +120,UF_right,uncinate fasciculus right + +201,CPC_left,cortico - ponto - cerebellar left +202,CPC_right,cortico - ponto - cerebellar right +203,ICP_left,inferior cerebellar peduncle left +204,ICP_right,inferior cerebellar peduncle right +205,Intra-CBLM-I&P_left,intracerebellar input and Purkinje tract left +206,Intra-CBLM-I&P_right,intracerebellar input and Purkinje tract right +207,Intra-CBLM-PaT_left,intracerebellar parallel tract left +208,Intra-CBLM-PaT_right,intracerebellar parallel tract right +209,MCP,middle cerebellar peduncle + +301,CC1,corpus callosum 1 +302,CC2,corpus callosum 2 +303,CC3,corpus callosum 3 +304,CC4,corpus callosum 4 +305,CC5,corpus callosum 5 +306,CC6,corpus callosum 6 +307,CC7,corpus callosum 7 + +401,CR-F_left,corona-radiata-frontal left +402,CR-F_right,corona-radiata-frontal right +403,CR-P_left,corona-radiata-parietal left +404,CR-P_right,corona-radiata-parietal right +405,CST_left,corticospinal tract left +406,CST_right,corticospinal tract right +407,PLIC_left,posterior limb of internal capsule left +408,PLIC_right,posterior limb of internal capsule right +409,SF_left,striato-frontal left +410,SF_right,striato-frontal right +411,SO_left,striato-occipital left +412,SO_right,striato-occipital right +413,SP_left,striato-parietal left +414,SP_right,striato-parietal right +415,TF_left,thalamo-frontal left +416,TF_right,thalamo-frontal right +417,TO_left,thalamo-occipital left +418,TO_right,thalamo-occipital right +419,TP_left,thalamo-parietal left +420,TP_right,thalamo-parietal right +421,TT_left,thalamo-temporal left +422,TT_right,thalamo-temporal right + +501,EC_left,external capsule left +502,EC_right,external capsule right + +601,Sup-F_left,superficial-frontal left +602,Sup-F_right,superficial-frontal right +603,Sup-FP_left,superficial-frontal-parietal left +604,Sup-FP_right,superficial-frontal-parietal right +605,Sup-O_left,superficial-occipital left +606,Sup-O_right,superficial-occipital right +607,Sup-OT_left,superficial-occipital-temporal left +608,Sup-OT_right,superficial-occipital-temporal right +609,Sup-P_left,superficial-parietal left +610,Sup-P_right,superficial-parietal right +611,Sup-PO_left,superficial-parietal-occipital left +612,Sup-PO_right,superficial-parietal-occipital right +613,Sup-PT_left,superficial-parietal-temporal left +614,Sup-PT_right,superficial-parietal-temporal right +615,Sup-T_left,superficial-temporal left +616,Sup-T_right,superficial-temporal right diff --git a/whitematteranalysis/data/atlas/org_atlas_version.json b/whitematteranalysis/data/atlas/org_atlas_version.json new file mode 100644 index 00000000..04179cfe --- /dev/null +++ b/whitematteranalysis/data/atlas/org_atlas_version.json @@ -0,0 +1,8 @@ +{ + "V1_1": "org_atlas_bundles_v1_1.csv", + "V1_1_1": "org_atlas_bundles_v1_1_1.csv", + "V1_2": "org_atlas_bundles_v1_2.csv", + "V1_3_A": "org_atlas_bundles_v1_3a.csv", + "V1_3_B": "org_atlas_bundles_v1_3b.csv", + "V1_4": "org_atlas_bundles_v1_4.csv" +} diff --git a/whitematteranalysis/data/atlas/tests/__init__.py b/whitematteranalysis/data/atlas/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/whitematteranalysis/data/atlas/tests/test_utils.py b/whitematteranalysis/data/atlas/tests/test_utils.py new file mode 100644 index 00000000..3d217f48 --- /dev/null +++ b/whitematteranalysis/data/atlas/tests/test_utils.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import os + +from whitematteranalysis.data.atlas.utils import ( + ORGAtlasVersion, + get_local_atlas_bundle_fname, +) + + +def test_get_local_atlas_bundle_fname(): + + version = ORGAtlasVersion.__members__.values() + assert [ + os.path.exists(get_local_atlas_bundle_fname(ver)) for ver in version + ] diff --git a/whitematteranalysis/data/atlas/utils.py b/whitematteranalysis/data/atlas/utils.py new file mode 100644 index 00000000..85a4e365 --- /dev/null +++ b/whitematteranalysis/data/atlas/utils.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- + +import enum +import json +import pathlib +import sys + +if sys.version_info < (3, 10): + from importlib_resources import files +else: + from importlib.resources import files + + +class ORGAtlasVersion(enum.Enum): + V1_1 = "V1_1" + V1_1_1 = "V1_1_1" + V1_2 = "V1_2" + V1_3_A = "V1_3_A" + V1_3_B = "V1_3_B" + V1_4 = "V1_4" + + +def get_local_atlas_bundle_fname(_atlas): + + path = files(__package__).joinpath("org_atlas_version.json") + + with path.open() as f: + org_atlas_version = json.load(f) + + return pathlib.Path(str(path)).parent.joinpath(org_atlas_version[_atlas.value]) diff --git a/whitematteranalysis/fileio/__init__.py b/whitematteranalysis/fileio/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/whitematteranalysis/fileio/utils.py b/whitematteranalysis/fileio/utils.py new file mode 100644 index 00000000..2b6e1c7f --- /dev/null +++ b/whitematteranalysis/fileio/utils.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- + +import enum +import pathlib + +fname_sep = "." + + +class SlicerFileExtension(enum.Enum): + MRML = "mrml" + + +class VTKFileExtension(enum.Enum): + VTP = "vtp" + + +def build_suffix(extension): + + return fname_sep + extension.value + + +def find_filenames(path, extension, stem=False): + filenames = sorted(list(pathlib.Path(path).glob("*" + build_suffix(extension)))) + if stem: + return [elem.stem for elem in filenames] + else: + return filenames + + +def save2txt(fname, sequence): + + with open(fname, "w") as f: + f.write("\n".join(sequence))