Skip to content

Commit

Permalink
More work.
Browse files Browse the repository at this point in the history
  • Loading branch information
tsalo committed Dec 3, 2024
1 parent 496f0cd commit 5e55ba4
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 101 deletions.
45 changes: 45 additions & 0 deletions src/smripost_linc/utils/boilerplate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
"""Functions for generating boilerplate text."""


def describe_atlases(atlases):
"""Build a text description of the atlases that will be used."""
from smripost_linc.utils.utils import list_to_str

atlas_descriptions = {
'Glasser': 'the Glasser atlas [@Glasser_2016]',
'Gordon': 'the Gordon atlas [@Gordon_2014]',
'Tian': 'the Tian subcortical atlas [@tian2020topographic]',
'HCP': 'the HCP CIFTI subcortical atlas [@glasser2013minimal]',
'MIDB': (
'the MIDB precision brain atlas derived from ABCD data and thresholded at 75% '
'probability [@hermosillo2022precision]'
),
'MyersLabonte': (
'the Myers-Labonte infant atlas thresholded at 50% probability [@myers2023functional]'
),
}

atlas_strings = []
described_atlases = []
atlases_4s = [atlas for atlas in atlases if str(atlas).startswith('4S')]
described_atlases += atlases_4s
if atlases_4s:
parcels = [int(str(atlas[2:-7])) for atlas in atlases_4s]
s = (
'the Schaefer Supplemented with Subcortical Structures (4S) atlas '
'[@Schaefer_2017;@pauli2018high;@king2019functional;@najdenovska2018vivo;'
'@glasser2013minimal] '
f'at {len(atlases_4s)} different resolutions ({list_to_str(parcels)} parcels)'
)
atlas_strings.append(s)

for k, v in atlas_descriptions.items():
if k in atlases:
atlas_strings.append(v)
described_atlases.append(k)

undescribed_atlases = [atlas for atlas in atlases if atlas not in described_atlases]
for atlas in undescribed_atlases:
atlas_strings.append(f'the {atlas} atlas')

return list_to_str(atlas_strings)
14 changes: 14 additions & 0 deletions src/smripost_linc/utils/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,3 +227,17 @@ def _convert_to_tsv(in_file):
arr = np.loadtxt(in_file)
np.savetxt(out_file, arr, delimiter='\t')
return out_file


def list_to_str(lst):
"""Convert a list to a pretty string."""
if not lst:
raise ValueError('Zero-length list provided.')

lst_str = [str(item) for item in lst]
if len(lst_str) == 1:
return lst_str[0]
elif len(lst_str) == 2:
return ' and '.join(lst_str)
else:
return f"{', '.join(lst_str[:-1])}, and {lst_str[-1]}"
101 changes: 0 additions & 101 deletions src/smripost_linc/workflows/parcellation.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,107 +11,6 @@
from smripost_linc.interfaces.bids import BIDSURI


def remove_non_alphabetic(input_string):
"""Use regular expression to remove non-alphabetic characters."""
import re

clean_string = re.sub(r'[^a-zA-Z_0-9]', '', input_string.replace(' ', '_'))
return clean_string


def fake_neuroparc_from_nifti(nifti_file):
"""Create a fake neuroparc JSON from a nifti file."""
import nibabel as nb
import numpy as np

img = nb.load(nifti_file)
unique_labels = np.unique(img.get_fdata().astype(np.int32))
return {str(label): {} for label in unique_labels}


def fill_missing_parc(spec):
maxval = max(map(int, spec.keys()))
for key in range(maxval):
strkey = str(key)
if strkey not in spec:
spec[strkey] = {'label': 'Unknown'}
return spec


def ctab_from_neuroparc_json(neuroparc_json_file=None, atlas_nifti_file=None):
"""Extract colors and labels from a neuroparc JSON file."""
import json

if neuroparc_json_file is not None:
with open(neuroparc_json_file) as jsonf:
initial_specs = json.load(jsonf)
if 'MetaData' in initial_specs:
del initial_specs['MetaData']
else:
initial_specs = fake_neuroparc_from_nifti(atlas_nifti_file)

parc_specs = fill_missing_parc(initial_specs)
# Get a mapping from ints to label names from neuroparc
int_to_label_map = {}
for key, value in parc_specs.items():
if not key.isnumeric():
continue
key = int(key)
label = value.get('label') or f'region{key:05d}'
int_to_label_map[key] = label

int_to_label_map[0] = 'Unknown'
labels = [
remove_non_alphabetic(int_to_label_map[key]) for key in sorted(int_to_label_map.keys())
]
colors = _create_colors(len(labels))
return colors, labels


def create_annots(nifti_file, atlas, json_file=None):
"""Create .annot files from a nifti file and a json file."""
import nibabel as nb
import numpy as np
from neuromaps import transforms

lh_gii, rh_gii = transforms.mni152_to_fsaverage(
nifti_file,
fsavg_density='164k',
method='nearest',
)
colors, names = ctab_from_neuroparc_json(
neuroparc_json_file=json_file,
atlas_nifti_file=nifti_file,
)
lh_annot = f'annots/lh.{atlas}.annot'
nb.freesurfer.write_annot(
lh_annot,
labels=lh_gii.agg_data().astype(np.int32),
ctab=colors,
names=names,
fill_ctab=True,
)
rh_annot = f'annots/rh.{atlas}.annot'
nb.freesurfer.write_annot(
rh_annot,
labels=rh_gii.agg_data().astype(np.int32),
ctab=colors,
names=names,
fill_ctab=True,
)
return lh_annot, rh_annot


def select_first(inlist):
"""Select the first element of a list."""
return inlist[0]


def select_second(inlist):
"""Select the second element of a list."""
return inlist[1]


def init_load_atlases_wf(name='load_atlases_wf'):
"""Load atlases, warp them to fsnative, and convert them to annot files.
Expand Down

0 comments on commit 5e55ba4

Please sign in to comment.