antspymm 1.1.1__py3-none-any.whl → 1.1.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- antspymm/__init__.py +6 -0
- antspymm/mm.py +938 -23
- {antspymm-1.1.1.dist-info → antspymm-1.1.3.dist-info}/METADATA +21 -2
- antspymm-1.1.3.dist-info/RECORD +7 -0
- {antspymm-1.1.1.dist-info → antspymm-1.1.3.dist-info}/WHEEL +1 -1
- antspymm-1.1.1.dist-info/RECORD +0 -7
- {antspymm-1.1.1.dist-info → antspymm-1.1.3.dist-info}/LICENSE +0 -0
- {antspymm-1.1.1.dist-info → antspymm-1.1.3.dist-info}/top_level.txt +0 -0
antspymm/__init__.py
CHANGED
@@ -56,6 +56,8 @@ from .mm import average_mm_df
|
|
56
56
|
from .mm import get_names_from_data_frame
|
57
57
|
from .mm import read_mm_csv
|
58
58
|
from .mm import assemble_modality_specific_dataframes
|
59
|
+
from .mm import aggregate_antspymm_results
|
60
|
+
from .mm import aggregate_antspymm_results_sdf
|
59
61
|
from .mm import mc_denoise
|
60
62
|
from .mm import mc_reg
|
61
63
|
from .mm import dti_reg
|
@@ -90,3 +92,7 @@ from .mm import collect_blind_qc_by_modality
|
|
90
92
|
from .mm import get_valid_modalities
|
91
93
|
from .mm import study_dataframe_from_matched_dataframe
|
92
94
|
from .mm import merge_wides_to_study_dataframe
|
95
|
+
from .mm import map_scalar_to_labels
|
96
|
+
from .mm import template_figure_with_overlay
|
97
|
+
from .mm import brainmap_figure
|
98
|
+
from .mm import bold_perfusion
|
antspymm/mm.py
CHANGED
@@ -79,6 +79,8 @@ __all__ = ['version',
|
|
79
79
|
'novelty_detection_loop',
|
80
80
|
'novelty_detection_quantile',
|
81
81
|
'generate_mm_dataframe',
|
82
|
+
'aggregate_antspymm_results',
|
83
|
+
'aggregate_antspymm_results_sdf',
|
82
84
|
'study_dataframe_from_matched_dataframe',
|
83
85
|
'merge_wides_to_study_dataframe',
|
84
86
|
'wmh']
|
@@ -159,11 +161,11 @@ def get_valid_modalities( long=False, asString=False, qc=False ):
|
|
159
161
|
asString - concat list to string
|
160
162
|
"""
|
161
163
|
if long:
|
162
|
-
mymod = ["T1w", "NM2DMT", "rsfMRI", "rsfMRI_LR", "rsfMRI_RL", "DTI", "DTI_LR","DTI_RL","T2Flair", "dwi", "func" ]
|
164
|
+
mymod = ["T1w", "NM2DMT", "rsfMRI", "rsfMRI_LR", "rsfMRI_RL", "DTI", "DTI_LR","DTI_RL","T2Flair", "dwi", "func", "perf" ]
|
163
165
|
elif qc:
|
164
|
-
mymod = [ 'T1w', 'T2Flair', 'NM2DMT','DTIdwi','DTIb0', 'rsfMRI']
|
166
|
+
mymod = [ 'T1w', 'T2Flair', 'NM2DMT','DTIdwi','DTIb0', 'rsfMRI', "perf" ]
|
165
167
|
else:
|
166
|
-
mymod = ["T1w", "NM2DMT", "DTI","T2Flair", "rsfMRI" ]
|
168
|
+
mymod = ["T1w", "NM2DMT", "DTI","T2Flair", "rsfMRI", "perf" ]
|
167
169
|
if not asString:
|
168
170
|
return mymod
|
169
171
|
else:
|
@@ -184,7 +186,8 @@ def generate_mm_dataframe(
|
|
184
186
|
flair_filename=[],
|
185
187
|
rsf_filenames=[],
|
186
188
|
dti_filenames=[],
|
187
|
-
nm_filenames=[]
|
189
|
+
nm_filenames=[],
|
190
|
+
perf_filename=[]
|
188
191
|
):
|
189
192
|
from os.path import exists
|
190
193
|
valid_modalities = get_valid_modalities()
|
@@ -219,6 +222,17 @@ def generate_mm_dataframe(
|
|
219
222
|
flair_filename=flair_filename[0]
|
220
223
|
if flair_filename is not None and not "lair" in flair_filename:
|
221
224
|
raise ValueError("flair is not flair filename " + flair_filename)
|
225
|
+
## perfusion
|
226
|
+
if perf_filename is not None:
|
227
|
+
if isinstance(perf_filename,list):
|
228
|
+
if (len(perf_filename) == 0):
|
229
|
+
perf_filename=None
|
230
|
+
else:
|
231
|
+
print("Take first entry from perf_filename list")
|
232
|
+
perf_filename=perf_filename[0]
|
233
|
+
if perf_filename is not None and not "perf" in perf_filename:
|
234
|
+
raise ValueError("perf_filename is not perf filename " + perf_filename)
|
235
|
+
|
222
236
|
for k in nm_filenames:
|
223
237
|
if k is not None:
|
224
238
|
if not "NM" in k:
|
@@ -231,7 +245,10 @@ def generate_mm_dataframe(
|
|
231
245
|
if k is not None:
|
232
246
|
if not "fMRI" in k and not "func" in k:
|
233
247
|
raise ValueError("rsfMRI/func is not rsfmri filename " + k)
|
234
|
-
|
248
|
+
if perf_filename is not None:
|
249
|
+
if not "perf" in perf_filename:
|
250
|
+
raise ValueError("perf_filename is not a valid perfusion (perf) filename " + k)
|
251
|
+
allfns = [t1_filename] + [flair_filename] + nm_filenames + dti_filenames + rsf_filenames + [perf_filename]
|
235
252
|
for k in allfns:
|
236
253
|
if k is not None:
|
237
254
|
if not isinstance(k, str):
|
@@ -247,7 +264,8 @@ def generate_mm_dataframe(
|
|
247
264
|
source_image_directory,
|
248
265
|
output_image_directory,
|
249
266
|
t1_filename,
|
250
|
-
flair_filename
|
267
|
+
flair_filename,
|
268
|
+
perf_filename]
|
251
269
|
mydata0 = coredata + rsf_filenames + dti_filenames
|
252
270
|
mydata = mydata0 + nm_filenames
|
253
271
|
corecols = [
|
@@ -259,7 +277,8 @@ def generate_mm_dataframe(
|
|
259
277
|
'sourcedir',
|
260
278
|
'outputdir',
|
261
279
|
'filename',
|
262
|
-
'flairid'
|
280
|
+
'flairid',
|
281
|
+
'perfid']
|
263
282
|
mycols0 = corecols + [
|
264
283
|
'rsfid1', 'rsfid2',
|
265
284
|
'dtid1', 'dtid2']
|
@@ -268,10 +287,6 @@ def generate_mm_dataframe(
|
|
268
287
|
'nmid6', 'nmid7','nmid8', 'nmid9', 'nmid10', 'nmid11'
|
269
288
|
]
|
270
289
|
mycols = mycols0 + nmext
|
271
|
-
print(len(mydata0))
|
272
|
-
print(len(nm_filenames))
|
273
|
-
print(len(mycols0))
|
274
|
-
print(len(nmext))
|
275
290
|
studycsv = pd.DataFrame([ mydata ],
|
276
291
|
columns=mycols)
|
277
292
|
return studycsv
|
@@ -343,6 +358,10 @@ def nrg_2_bids( nrg_filename ):
|
|
343
358
|
bids_modality_folder = 'func'
|
344
359
|
bids_modality_filename = 'func'
|
345
360
|
|
361
|
+
if nrg_modality == 'perf' :
|
362
|
+
bids_modality_folder = 'perf'
|
363
|
+
bids_modality_filename = 'perf'
|
364
|
+
|
346
365
|
bids_suffix = nrg_suffix[1:]
|
347
366
|
bids_filename = f'{bids_subject}_{bids_session}_{bids_modality_filename}.{bids_suffix}'
|
348
367
|
|
@@ -385,6 +404,9 @@ def bids_2_nrg( bids_filename, project_name, date, nrg_modality=None ):
|
|
385
404
|
if bids_modality == 'func' and nrg_modality is None :
|
386
405
|
nrg_modality = 'rsfMRI'
|
387
406
|
|
407
|
+
if bids_modality == 'perf' and nrg_modality is None :
|
408
|
+
nrg_modality = 'perf'
|
409
|
+
|
388
410
|
nrg_suffix = bids_suffix[1:]
|
389
411
|
nrg_filename = f'{project_name}-{nrg_subject_id}-{date}-{nrg_modality}-{nrg_image_id}.{nrg_suffix}'
|
390
412
|
|
@@ -1833,7 +1855,128 @@ def mc_reg(
|
|
1833
1855
|
"FD": FD,
|
1834
1856
|
}
|
1835
1857
|
|
1836
|
-
def
|
1858
|
+
def map_scalar_to_labels(dataframe, label_image_template):
|
1859
|
+
"""
|
1860
|
+
Map scalar values from a DataFrame to associated integer image labels.
|
1861
|
+
|
1862
|
+
Parameters:
|
1863
|
+
- dataframe (pd.DataFrame): A Pandas DataFrame containing a label column and scalar_value column.
|
1864
|
+
- label_image_template (ants.ANTsImage): ANTs image with (at least some of) the same values as labels.
|
1865
|
+
|
1866
|
+
Returns:
|
1867
|
+
- ants.ANTsImage: A label image with scalar values mapped to associated integer labels.
|
1868
|
+
"""
|
1869
|
+
|
1870
|
+
# Create an empty label image with the same geometry as the template
|
1871
|
+
mapped_label_image = label_image_template.clone() * 0.0
|
1872
|
+
|
1873
|
+
# Loop through DataFrame and map scalar values to labels
|
1874
|
+
for index, row in dataframe.iterrows():
|
1875
|
+
label = int(row['label']) # Assuming the DataFrame has a 'label' column
|
1876
|
+
scalar_value = row['scalar_value'] # Replace with your column name
|
1877
|
+
mapped_label_image[label_image_template == label] = scalar_value
|
1878
|
+
|
1879
|
+
return mapped_label_image
|
1880
|
+
|
1881
|
+
|
1882
|
+
def template_figure_with_overlay(scalar_label_df, prefix, outputfilename=None, template='cit168', xyz=None, mask_dilation=25, padding=12, verbose=True):
|
1883
|
+
"""
|
1884
|
+
Process and visualize images with mapped scalar values.
|
1885
|
+
|
1886
|
+
Parameters:
|
1887
|
+
- scalar_label_df (pd.DataFrame): A Pandas DataFrame containing scalar values and labels.
|
1888
|
+
- prefix (str): The prefix for input image files.
|
1889
|
+
- template (str, optional): Template for selecting image data (default is 'cit168').
|
1890
|
+
- xyz (str, optional): The integer index of the slices to display.
|
1891
|
+
- mask_dilation (int, optional): Dilation factor for creating a mask (default is 25).
|
1892
|
+
- padding (int, optional): Padding value for the mapped images (default is 12).
|
1893
|
+
- verbose (bool, optional): Enable verbose mode for printing (default is True).
|
1894
|
+
|
1895
|
+
Example Usage:
|
1896
|
+
>>> scalar_label_df = pd.DataFrame({'label': [1, 2, 3], 'scalar_value': [0.5, 0.8, 1.2]})
|
1897
|
+
>>> prefix = '../PPMI_template0_'
|
1898
|
+
>>> process_and_visualize_images(scalar_label_df, prefix, template='cit168', xyz=None, mask_dilation=25, padding=12, verbose=True)
|
1899
|
+
"""
|
1900
|
+
|
1901
|
+
# Template image paths
|
1902
|
+
template_paths = {
|
1903
|
+
'cit168': 'cit168lab.nii.gz',
|
1904
|
+
'bf': 'bf.nii.gz',
|
1905
|
+
'cerebellum': 'cerebellum.nii.gz',
|
1906
|
+
'mtl': 'mtl.nii.gz',
|
1907
|
+
'ctx': 'dkt_cortex.nii.gz',
|
1908
|
+
'jhuwm': 'JHU_wm.nii.gz'
|
1909
|
+
}
|
1910
|
+
|
1911
|
+
if template not in template_paths:
|
1912
|
+
print( "Valid options:")
|
1913
|
+
print( template_paths )
|
1914
|
+
raise ValueError(f"Template option '{template}' does not exist.")
|
1915
|
+
|
1916
|
+
template_image_path = template_paths[template]
|
1917
|
+
template_image = ants.image_read(f'{prefix}{template_image_path}')
|
1918
|
+
|
1919
|
+
# Load image data
|
1920
|
+
edgeimg = ants.image_read(f'{prefix}edge.nii.gz')
|
1921
|
+
dktimg = ants.image_read(f'{prefix}dkt_parcellation.nii.gz')
|
1922
|
+
segimg = ants.image_read(f'{prefix}tissue_segmentation.nii.gz')
|
1923
|
+
ttl = ''
|
1924
|
+
|
1925
|
+
# Load and process the template image
|
1926
|
+
ventricles = ants.threshold_image(dktimg, 4, 4) + ants.threshold_image(dktimg, 43, 43)
|
1927
|
+
seggm = ants.mask_image(segimg, segimg, [2, 4], binarize=False)
|
1928
|
+
edgeimg = edgeimg.clone()
|
1929
|
+
edgeimg[edgeimg == 0] = ventricles[edgeimg == 0]
|
1930
|
+
segwm = ants.threshold_image(segimg, 3, 4).morphology("open", 1)
|
1931
|
+
|
1932
|
+
# Define cropping mask
|
1933
|
+
cmask = ants.threshold_image(template_image, 1, 1.e9).iMath("MD", mask_dilation)
|
1934
|
+
|
1935
|
+
mapped_image = map_scalar_to_labels(scalar_label_df, template_image)
|
1936
|
+
tcrop = ants.crop_image(template_image, cmask)
|
1937
|
+
toviz = ants.crop_image(mapped_image, cmask)
|
1938
|
+
seggm = ants.crop_image(edgeimg, cmask)
|
1939
|
+
|
1940
|
+
# Map scalar values to labels and visualize
|
1941
|
+
toviz = ants.pad_image(toviz, pad_width=(padding, padding, padding))
|
1942
|
+
seggm = ants.pad_image(seggm, pad_width=(padding, padding, padding))
|
1943
|
+
tcrop = ants.pad_image(tcrop, pad_width=(padding, padding, padding))
|
1944
|
+
|
1945
|
+
if xyz is None:
|
1946
|
+
if template == 'cit168':
|
1947
|
+
xyz=[140, 89, 94]
|
1948
|
+
elif template == 'bf':
|
1949
|
+
xyz=[114,92,76]
|
1950
|
+
elif template == 'cerebellum':
|
1951
|
+
xyz=[169, 128, 137]
|
1952
|
+
elif template == 'mtl':
|
1953
|
+
xyz=[154, 112, 113]
|
1954
|
+
elif template == 'ctx':
|
1955
|
+
xyz=[233, 190, 174]
|
1956
|
+
elif template == 'jhuwm':
|
1957
|
+
xyz=[146, 133, 182]
|
1958
|
+
|
1959
|
+
if verbose:
|
1960
|
+
print("plot xyz for " + template )
|
1961
|
+
print( xyz )
|
1962
|
+
|
1963
|
+
if outputfilename is None:
|
1964
|
+
temp = ants.plot_ortho( seggm, overlay=toviz, crop=False,
|
1965
|
+
xyz=xyz, cbar_length=0.2, cbar_vertical=False,
|
1966
|
+
flat=True, xyz_lines=False, resample=False, orient_labels=False,
|
1967
|
+
title=ttl, titlefontsize=12, title_dy=-0.02, textfontcolor='red',
|
1968
|
+
cbar=True, allow_xyz_change=False)
|
1969
|
+
else:
|
1970
|
+
temp = ants.plot_ortho( seggm, overlay=toviz, crop=False,
|
1971
|
+
xyz=xyz, cbar_length=0.2, cbar_vertical=False,
|
1972
|
+
flat=True, xyz_lines=False, resample=False, orient_labels=False,
|
1973
|
+
title=ttl, titlefontsize=12, title_dy=-0.02, textfontcolor='red',
|
1974
|
+
cbar=True, allow_xyz_change=False, filename=outputfilename )
|
1975
|
+
seggm = temp['image']
|
1976
|
+
toviz = temp['overlay']
|
1977
|
+
return { "underlay": seggm, 'overlay': toviz, 'seg': tcrop }
|
1978
|
+
|
1979
|
+
def get_data( name=None, force_download=False, version=19, target_extension='.csv' ):
|
1837
1980
|
"""
|
1838
1981
|
Get ANTsPyMM data filename
|
1839
1982
|
|
@@ -2187,7 +2330,9 @@ def get_average_rsf( x, min_t=10, max_t=35 ):
|
|
2187
2330
|
bavg = bavg + ants.registration(oavg,b0,'Rigid',outprefix=ofn)['warpedmovout']
|
2188
2331
|
import shutil
|
2189
2332
|
shutil.rmtree(output_directory, ignore_errors=True )
|
2190
|
-
|
2333
|
+
bavg = ants.iMath( bavg, 'Normalize' )
|
2334
|
+
return bavg
|
2335
|
+
# return ants.n4_bias_field_correction(bavg, mask=ants.get_mask( bavg ) )
|
2191
2336
|
|
2192
2337
|
|
2193
2338
|
def get_average_dwi_b0( x, fixed_b0=None, fixed_dwi=None, fast=False ):
|
@@ -4214,7 +4359,6 @@ def resting_state_fmri_networks( fmri, fmri_template, t1, t1segmentation,
|
|
4214
4359
|
reg_iterations=[40,20,5] )
|
4215
4360
|
if verbose:
|
4216
4361
|
print("End rsfmri motion correction")
|
4217
|
-
# ants.image_write( corrmo['motion_corrected'], '/tmp/temp.nii.gz' )
|
4218
4362
|
|
4219
4363
|
mytsnr = tsnr( corrmo['motion_corrected'], bmask )
|
4220
4364
|
mytsnrThresh = np.quantile( mytsnr.numpy(), 0.995 )
|
@@ -4224,8 +4368,6 @@ def resting_state_fmri_networks( fmri, fmri_template, t1, t1segmentation,
|
|
4224
4368
|
t1reg = ants.registration( und, t1, "SyNBold" )
|
4225
4369
|
if verbose:
|
4226
4370
|
print("t1 2 bold done")
|
4227
|
-
# ants.image_write( und, '/tmp/template_bold_masked.nii.gz' )
|
4228
|
-
# ants.image_write( t1reg['warpedmovout'], '/tmp/t1tobold.nii.gz' )
|
4229
4371
|
boldseg = ants.apply_transforms( und, t1segmentation,
|
4230
4372
|
t1reg['fwdtransforms'], interpolator = 'genericLabel' ) * bmask
|
4231
4373
|
gmseg = ants.threshold_image( t1segmentation, 2, 2 )
|
@@ -4403,6 +4545,216 @@ def resting_state_fmri_networks( fmri, fmri_template, t1, t1segmentation,
|
|
4403
4545
|
return outdict
|
4404
4546
|
|
4405
4547
|
|
4548
|
+
def bold_perfusion( fmri, fmri_template, t1head, t1, t1segmentation, t1dktcit, f=[0.0,math.inf], FD_threshold=0.5, spa = 1.5, nc = 6, type_of_transform='Rigid', tc='alternating', deepmask=False, add_FD_to_nuisance=False, verbose=False ):
|
4549
|
+
"""
|
4550
|
+
Estimate perfusion from a BOLD time series image. Will attempt to figure out the T-C labels from the data.
|
4551
|
+
|
4552
|
+
Arguments
|
4553
|
+
---------
|
4554
|
+
fmri : BOLD fmri antsImage
|
4555
|
+
|
4556
|
+
fmri_template : reference space for BOLD
|
4557
|
+
|
4558
|
+
t1head : ANTsImage
|
4559
|
+
input 3-D T1 brain image (not brain extracted)
|
4560
|
+
|
4561
|
+
t1 : ANTsImage
|
4562
|
+
input 3-D T1 brain image (brain extracted)
|
4563
|
+
|
4564
|
+
t1segmentation : ANTsImage
|
4565
|
+
t1 segmentation - a six tissue segmentation image in T1 space
|
4566
|
+
|
4567
|
+
t1dktcit : ANTsImage
|
4568
|
+
t1 dkt cortex plus cit parcellation
|
4569
|
+
|
4570
|
+
f : band pass limits for frequency filtering
|
4571
|
+
|
4572
|
+
spa : gaussian smoothing for spatial and temporal component e.g. (1,1,1,0) in physical space coordinates
|
4573
|
+
|
4574
|
+
nc : number of components for compcor filtering
|
4575
|
+
|
4576
|
+
type_of_transform : SyN or Rigid
|
4577
|
+
|
4578
|
+
tc: string either alternating or split (default is alternating ie CTCTCT; split is CCCCTTTT)
|
4579
|
+
|
4580
|
+
deepmask: boolean
|
4581
|
+
|
4582
|
+
add_FD_to_nuisance: boolean
|
4583
|
+
|
4584
|
+
verbose : boolean
|
4585
|
+
|
4586
|
+
Returns
|
4587
|
+
---------
|
4588
|
+
a dictionary containing the derived network maps
|
4589
|
+
|
4590
|
+
"""
|
4591
|
+
import numpy as np
|
4592
|
+
import pandas as pd
|
4593
|
+
import re
|
4594
|
+
import math
|
4595
|
+
from sklearn.linear_model import LinearRegression
|
4596
|
+
|
4597
|
+
ex_path = os.path.expanduser( "~/.antspyt1w/" )
|
4598
|
+
cnxcsvfn = ex_path + "dkt_cortex_cit_deep_brain.csv"
|
4599
|
+
|
4600
|
+
def replicate_list(user_list, target_size):
|
4601
|
+
# Calculate the number of times the list should be replicated
|
4602
|
+
replication_factor = target_size // len(user_list)
|
4603
|
+
# Replicate the list and handle any remaining elements
|
4604
|
+
replicated_list = user_list * replication_factor
|
4605
|
+
remaining_elements = target_size % len(user_list)
|
4606
|
+
replicated_list += user_list[:remaining_elements]
|
4607
|
+
return replicated_list
|
4608
|
+
|
4609
|
+
def one_hot_encode(char_list):
|
4610
|
+
unique_chars = list(set(char_list))
|
4611
|
+
encoding_dict = {char: [1 if char == c else 0 for c in unique_chars] for char in unique_chars}
|
4612
|
+
encoded_matrix = np.array([encoding_dict[char] for char in char_list])
|
4613
|
+
return encoded_matrix
|
4614
|
+
|
4615
|
+
A = np.zeros((1,1))
|
4616
|
+
fmri = ants.iMath( fmri, 'Normalize' )
|
4617
|
+
if deepmask:
|
4618
|
+
bmask = antspynet.brain_extraction( fmri_template, 'bold' ).threshold_image(0.5,1).morphology("close",2).iMath("FillHoles")
|
4619
|
+
else:
|
4620
|
+
rig = ants.registration( fmri_template, t1head, 'BOLDRigid' )
|
4621
|
+
bmask = ants.apply_transforms( fmri_template, ants.threshold_image(t1segmentation,1,6), rig['fwdtransforms'][0], interpolator='genericLabel' )
|
4622
|
+
if verbose:
|
4623
|
+
print("Begin perfusion motion correction")
|
4624
|
+
mytrim=4 # trim will guarantee an even length
|
4625
|
+
if fmri.shape[3] % 2 == 1:
|
4626
|
+
mytrim = 5
|
4627
|
+
corrmo = timeseries_reg(
|
4628
|
+
fmri, fmri_template,
|
4629
|
+
type_of_transform=type_of_transform,
|
4630
|
+
total_sigma=0.0,
|
4631
|
+
fdOffset=2.0,
|
4632
|
+
trim = mytrim,
|
4633
|
+
output_directory=None,
|
4634
|
+
verbose=verbose,
|
4635
|
+
syn_metric='cc',
|
4636
|
+
syn_sampling=2,
|
4637
|
+
reg_iterations=[40,20,5] )
|
4638
|
+
if verbose:
|
4639
|
+
print("End rsfmri motion correction")
|
4640
|
+
|
4641
|
+
ntp = corrmo['motion_corrected'].shape[3]
|
4642
|
+
if tc == 'alternating':
|
4643
|
+
tclist = replicate_list( ['C','T'], ntp )
|
4644
|
+
else:
|
4645
|
+
tclist = replicate_list( ['C'], int(ntp/2) ) + replicate_list( ['T'], int(ntp/2) )
|
4646
|
+
|
4647
|
+
tclist = one_hot_encode( tclist )
|
4648
|
+
mytsnr = tsnr( corrmo['motion_corrected'], bmask )
|
4649
|
+
mytsnrThresh = np.quantile( mytsnr.numpy(), 0.995 )
|
4650
|
+
tsnrmask = ants.threshold_image( mytsnr, 0, mytsnrThresh ).morphology("close",2)
|
4651
|
+
bmask = bmask * ants.iMath( tsnrmask, "FillHoles" )
|
4652
|
+
und = fmri_template * bmask
|
4653
|
+
t1reg = ants.registration( und, t1, "SyNBold" )
|
4654
|
+
if verbose:
|
4655
|
+
print("t1 2 bold done")
|
4656
|
+
boldseg = ants.apply_transforms( und, t1segmentation,
|
4657
|
+
t1reg['fwdtransforms'], interpolator = 'genericLabel' ) * bmask
|
4658
|
+
dktseg = ants.apply_transforms( und, t1dktcit,
|
4659
|
+
t1reg['fwdtransforms'], interpolator = 'genericLabel' ) * bmask
|
4660
|
+
gmseg = ants.threshold_image( t1segmentation, 2, 2 )
|
4661
|
+
gmseg = gmseg + ants.threshold_image( t1segmentation, 4, 4 )
|
4662
|
+
gmseg = ants.threshold_image( gmseg, 1, 4 )
|
4663
|
+
gmseg = ants.iMath( gmseg, 'MD', 1 )
|
4664
|
+
gmseg = ants.apply_transforms( und, gmseg,
|
4665
|
+
t1reg['fwdtransforms'], interpolator = 'genericLabel' ) * bmask
|
4666
|
+
csfAndWM = ( ants.threshold_image( t1segmentation, 1, 1 ) +
|
4667
|
+
ants.threshold_image( t1segmentation, 3, 3 ) ).morphology("erode",1)
|
4668
|
+
csfAndWM = ants.apply_transforms( und, csfAndWM,
|
4669
|
+
t1reg['fwdtransforms'], interpolator = 'nearestNeighbor' ) * bmask
|
4670
|
+
|
4671
|
+
mycompcor = ants.compcor( corrmo['motion_corrected'],
|
4672
|
+
ncompcor=nc, quantile=0.90, mask = csfAndWM,
|
4673
|
+
filter_type='polynomial', degree=2 )
|
4674
|
+
|
4675
|
+
nt = corrmo['motion_corrected'].shape[3]
|
4676
|
+
tr = ants.get_spacing( corrmo['motion_corrected'] )[3]
|
4677
|
+
highMotionTimes = np.where( corrmo['FD'] >= 1.0 )
|
4678
|
+
goodtimes = np.where( corrmo['FD'] < 0.5 )
|
4679
|
+
simg = ants.smooth_image(corrmo['motion_corrected'],
|
4680
|
+
spa, sigma_in_physical_coordinates = True )
|
4681
|
+
|
4682
|
+
nuisance = mycompcor[ 'components' ]
|
4683
|
+
nuisance = np.c_[ nuisance, mycompcor['basis'] ]
|
4684
|
+
if add_FD_to_nuisance:
|
4685
|
+
nuisance = np.c_[ nuisance, corrmo['FD'] ]
|
4686
|
+
|
4687
|
+
if verbose:
|
4688
|
+
print("make sure nuisance is independent of TC")
|
4689
|
+
nuisance = ants.regress_components( nuisance, tclist )
|
4690
|
+
|
4691
|
+
regression_mask = bmask.clone()
|
4692
|
+
gmmat = ants.timeseries_to_matrix( simg, regression_mask )
|
4693
|
+
if f[0] > 0 and f[1] < 1: # some would argue against this
|
4694
|
+
gmmat = ants.bandpass_filter_matrix( gmmat, tr = tr, lowf=f[0], highf=f[1] )
|
4695
|
+
# gmmat = ants.regress_components( gmmat, nuisance )
|
4696
|
+
# Perform linear regression to estimate perfusion
|
4697
|
+
regression_model = LinearRegression()
|
4698
|
+
regvars = np.hstack( (nuisance, tclist ))
|
4699
|
+
coefind = regvars.shape[1]-1
|
4700
|
+
regvars = regvars[:,range(coefind)]
|
4701
|
+
regression_model.fit( regvars, gmmat )
|
4702
|
+
coefind = regression_model.coef_.shape[1]-1
|
4703
|
+
perfimg = ants.make_image( regression_mask, regression_model.coef_[:,coefind] )
|
4704
|
+
meangmval = ( perfimg[ gmseg == 1 ] ).mean()
|
4705
|
+
if meangmval < 0:
|
4706
|
+
perfimg = perfimg * (-1.0)
|
4707
|
+
meangmval = ( perfimg[ gmseg == 1 ] ).mean()
|
4708
|
+
if verbose:
|
4709
|
+
print("Coefficients:", regression_model.coef_)
|
4710
|
+
print("Coef mean", regression_model.coef_.mean(axis=0))
|
4711
|
+
print( regression_model.coef_.shape )
|
4712
|
+
print( perfimg.max() )
|
4713
|
+
gsrbold = ants.matrix_to_timeseries(simg, gmmat, regression_mask)
|
4714
|
+
outdict = {}
|
4715
|
+
outdict['meanBold'] = und
|
4716
|
+
outdict['brainmask'] = bmask
|
4717
|
+
rsfNuisance = pd.DataFrame( nuisance )
|
4718
|
+
rsfNuisance['FD']=corrmo['FD']
|
4719
|
+
|
4720
|
+
|
4721
|
+
nonbrainmask = ants.iMath( bmask, "MD",2) - bmask
|
4722
|
+
trimmask = ants.iMath( bmask, "ME",2)
|
4723
|
+
edgemask = ants.iMath( bmask, "ME",1) - trimmask
|
4724
|
+
|
4725
|
+
if verbose:
|
4726
|
+
print("perfusion dataframe begin")
|
4727
|
+
df_perf = antspyt1w.map_intensity_to_dataframe(
|
4728
|
+
'dkt_cortex_cit_deep_brain',
|
4729
|
+
perfimg,
|
4730
|
+
dktseg)
|
4731
|
+
df_perf = antspyt1w.merge_hierarchical_csvs_to_wide_format(
|
4732
|
+
{'perf' : df_perf},
|
4733
|
+
col_names = ['Mean'] )
|
4734
|
+
if verbose:
|
4735
|
+
print("perfusion dataframe end")
|
4736
|
+
print( df_perf )
|
4737
|
+
|
4738
|
+
outdict['perfusion']=perfimg
|
4739
|
+
outdict['perfusion_gm_mean']=meangmval
|
4740
|
+
outdict['perf_dataframe']=df_perf
|
4741
|
+
outdict['motion_corrected'] = corrmo['motion_corrected']
|
4742
|
+
outdict['gmseg'] = gmseg
|
4743
|
+
outdict['gsrbold'] = gsrbold
|
4744
|
+
outdict['brain_mask'] = bmask
|
4745
|
+
outdict['nuisance'] = rsfNuisance
|
4746
|
+
outdict['tsnr'] = mytsnr
|
4747
|
+
outdict['ssnr'] = slice_snr( corrmo['motion_corrected'], csfAndWM, gmseg )
|
4748
|
+
outdict['dvars'] = dvars( corrmo['motion_corrected'], gmseg )
|
4749
|
+
outdict['high_motion_count'] = (rsfNuisance['FD'] > FD_threshold ).sum()
|
4750
|
+
outdict['high_motion_pct'] = (rsfNuisance['FD'] > FD_threshold ).sum() / rsfNuisance.shape[0]
|
4751
|
+
outdict['FD_max'] = rsfNuisance['FD'].max()
|
4752
|
+
outdict['FD_mean'] = rsfNuisance['FD'].mean()
|
4753
|
+
outdict['bold_evr'] = antspyt1w.patch_eigenvalue_ratio( und, 512, [16,16,16], evdepth = 0.9, mask = bmask )
|
4754
|
+
outdict['t1reg'] = t1reg
|
4755
|
+
return outdict
|
4756
|
+
|
4757
|
+
|
4406
4758
|
|
4407
4759
|
def write_bvals_bvecs(bvals, bvecs, prefix ):
|
4408
4760
|
''' Write FSL FDT bvals and bvecs files
|
@@ -4474,6 +4826,7 @@ def mm(
|
|
4474
4826
|
flair_image=None,
|
4475
4827
|
nm_image_list=None,
|
4476
4828
|
dw_image=[], bvals=[], bvecs=[],
|
4829
|
+
perfusion_image=None,
|
4477
4830
|
srmodel=None,
|
4478
4831
|
do_tractography = False,
|
4479
4832
|
do_kk = False,
|
@@ -4510,6 +4863,8 @@ def mm(
|
|
4510
4863
|
|
4511
4864
|
bvecs : list of bvecs file names
|
4512
4865
|
|
4866
|
+
perfusion_image : single perfusion image
|
4867
|
+
|
4513
4868
|
srmodel : optional srmodel
|
4514
4869
|
|
4515
4870
|
do_tractography : boolean
|
@@ -4578,7 +4933,8 @@ def mm(
|
|
4578
4933
|
'FA_summ' : None,
|
4579
4934
|
'MD_summ' : None,
|
4580
4935
|
'tractography' : None,
|
4581
|
-
'tractography_connectivity' : None
|
4936
|
+
'tractography_connectivity' : None,
|
4937
|
+
'perf' : None,
|
4582
4938
|
}
|
4583
4939
|
normalization_dict = {
|
4584
4940
|
'kk_norm': None,
|
@@ -4586,6 +4942,7 @@ def mm(
|
|
4586
4942
|
'DTI_norm': None,
|
4587
4943
|
'FA_norm' : None,
|
4588
4944
|
'MD_norm' : None,
|
4945
|
+
'perf_norm' : None,
|
4589
4946
|
'alff_norm' : None,
|
4590
4947
|
'falff_norm' : None,
|
4591
4948
|
'CinguloopercularTaskControl_norm' : None,
|
@@ -4606,6 +4963,19 @@ def mm(
|
|
4606
4963
|
print('kk')
|
4607
4964
|
output_dict['kk'] = antspyt1w.kelly_kapowski_thickness( hier['brain_n4_dnz'],
|
4608
4965
|
labels=hier['dkt_parc']['dkt_cortex'], iterations=45 )
|
4966
|
+
if perfusion_image is not None:
|
4967
|
+
boldTemplate=get_average_rsf(perfusion_image)
|
4968
|
+
if perfusion_image.shape[3] > 8: # FIXME - better heuristic?
|
4969
|
+
output_dict['perf'] = bold_perfusion(
|
4970
|
+
perfusion_image,
|
4971
|
+
boldTemplate,
|
4972
|
+
t1_image,
|
4973
|
+
hier['brain_n4_dnz'],
|
4974
|
+
t1atropos,
|
4975
|
+
hier['dkt_parc']['dkt_cortex'] + hier['cit168lab'],
|
4976
|
+
f=[0.0,math.inf],
|
4977
|
+
spa = (1.0, 1.0, 1.0, 0.0),
|
4978
|
+
nc = 6, verbose=verbose )
|
4609
4979
|
################################## do the rsf .....
|
4610
4980
|
if len(rsf_image) > 0:
|
4611
4981
|
rsf_image = [i for i in rsf_image if i is not None]
|
@@ -4786,7 +5156,7 @@ def mm(
|
|
4786
5156
|
if verbose:
|
4787
5157
|
print('normalization')
|
4788
5158
|
# might reconsider this template space - cropped and/or higher res?
|
4789
|
-
template = ants.resample_image( template, [1,1,1], use_voxels=False )
|
5159
|
+
# template = ants.resample_image( template, [1,1,1], use_voxels=False )
|
4790
5160
|
# t1reg = ants.registration( template, hier['brain_n4_dnz'], "antsRegistrationSyNQuickRepro[s]")
|
4791
5161
|
t1reg = do_normalization
|
4792
5162
|
if do_kk:
|
@@ -4812,6 +5182,11 @@ def mm(
|
|
4812
5182
|
normalization_dict[rsfkey] = ants.apply_transforms(
|
4813
5183
|
group_template, rsfpro[netid],
|
4814
5184
|
group_transform+rsfrig['fwdtransforms'] )
|
5185
|
+
if output_dict['perf'] is not None: # zizzer
|
5186
|
+
comptx = group_transform + output_dict['perf']['t1reg']['invtransforms']
|
5187
|
+
normalization_dict['perf_norm'] = ants.apply_transforms( group_template,
|
5188
|
+
output_dict['perf']['perfusion'], comptx,
|
5189
|
+
whichtoinvert=[False,False,True,False] )
|
4815
5190
|
if nm_image_list is not None:
|
4816
5191
|
nmpro = output_dict['NM']
|
4817
5192
|
nmrig = nmpro['t1_to_NM_transform'] # this is an inverse tx
|
@@ -4872,6 +5247,7 @@ def write_mm( output_prefix, mm, mm_norm=None, t1wide=None, separator='_', verbo
|
|
4872
5247
|
image_write_with_thumbnail( mm['NM'][mykey], tempfn, thumb=False )
|
4873
5248
|
|
4874
5249
|
faderk = mdderk = fat1derk = mdt1derk = None
|
5250
|
+
|
4875
5251
|
if mm['DTI'] is not None:
|
4876
5252
|
mydti = mm['DTI']
|
4877
5253
|
myop = output_prefix + separator
|
@@ -4984,6 +5360,26 @@ def write_mm( output_prefix, mm, mm_norm=None, t1wide=None, separator='_', verbo
|
|
4984
5360
|
# mm_wide.to_csv( fdfn )
|
4985
5361
|
else:
|
4986
5362
|
mm_wide['dti_FD_mean'] = mm_wide['dti_FD_max'] = 'NA'
|
5363
|
+
|
5364
|
+
if mm['perf'] is not None:
|
5365
|
+
perfpro = mm['perf']
|
5366
|
+
mm_wide['gm_mean'] = perfpro['perfusion_gm_mean']
|
5367
|
+
mm_wide['tsnr_mean'] = perfpro['tsnr'].mean()
|
5368
|
+
mm_wide['dvars_mean'] = perfpro['dvars'].mean()
|
5369
|
+
mm_wide['ssnr_mean'] = perfpro['ssnr'].mean()
|
5370
|
+
mm_wide['high_motion_count'] = perfpro['high_motion_count']
|
5371
|
+
mm_wide['evr'] = perfpro['bold_evr']
|
5372
|
+
mm_wide['FD_mean'] = perfpro['FD_mean']
|
5373
|
+
mm_wide['FD_max'] = perfpro['FD_max']
|
5374
|
+
if 'perf_dataframe' in perfpro.keys():
|
5375
|
+
pderk = perfpro['perf_dataframe'].iloc[: , 1:]
|
5376
|
+
mm_wide = pd.concat( [ mm_wide, pderk ], axis=1 )
|
5377
|
+
else:
|
5378
|
+
print("FIXME - perfusion dataframe")
|
5379
|
+
mykey='perfusion'
|
5380
|
+
tempfn = output_prefix + separator + mykey + '.nii.gz'
|
5381
|
+
image_write_with_thumbnail( mm['perf'][mykey], tempfn )
|
5382
|
+
|
4987
5383
|
mmwidefn = output_prefix + separator + 'mmwide.csv'
|
4988
5384
|
mm_wide.to_csv( mmwidefn )
|
4989
5385
|
if verbose:
|
@@ -5490,7 +5886,7 @@ def mm_nrg(
|
|
5490
5886
|
write_mm( output_prefix=mymm, mm=tabPro, mm_norm=normPro, t1wide=t1wide, separator=mysep, verbose=True )
|
5491
5887
|
for mykey in normPro.keys():
|
5492
5888
|
if normPro[mykey] is not None:
|
5493
|
-
if visualize and normPro[mykey].components == 1:
|
5889
|
+
if visualize and normPro[mykey].components == 1 and False:
|
5494
5890
|
ants.plot( template, normPro[mykey], axis=2, nslices=21, ncol=7, crop=True, title=mykey, filename=mymm+mysep+mykey+".png" )
|
5495
5891
|
if overmodX == nrg_modality_list[ len( nrg_modality_list ) - 1 ]:
|
5496
5892
|
return
|
@@ -5639,6 +6035,8 @@ def mm_csv(
|
|
5639
6035
|
imfns=['filename']
|
5640
6036
|
elif locmod == 'T2Flair':
|
5641
6037
|
imfns=['flairid']
|
6038
|
+
elif locmod == 'perf':
|
6039
|
+
imfns=['perfid']
|
5642
6040
|
elif locmod == 'NM2DMT':
|
5643
6041
|
imfns=[]
|
5644
6042
|
for i in range(11):
|
@@ -5797,6 +6195,9 @@ def mm_csv(
|
|
5797
6195
|
hier['brain_n4_dnz'],
|
5798
6196
|
normalization_template_transform_type,
|
5799
6197
|
outprefix = normout, verbose=False )
|
6198
|
+
myjac = ants.create_jacobian_determinant_image( template,
|
6199
|
+
greg['fwdtransforms'][0], do_log=True, geom=True )
|
6200
|
+
image_write_with_thumbnail( myjac, normout + "logjacobian.nii.gz", thumb=False )
|
5800
6201
|
if verbose:
|
5801
6202
|
print("end group template registration")
|
5802
6203
|
else:
|
@@ -5974,6 +6375,22 @@ def mm_csv(
|
|
5974
6375
|
axis=2, nslices=maxslice, ncol=7, crop=True, title='DefaultMode', filename=mymm+mysep+"boldDefaultMode.png" )
|
5975
6376
|
ants.plot( tabPro['rsf']['meanBold'], tabPro['rsf']['FrontoparietalTaskControl'],
|
5976
6377
|
axis=2, nslices=maxslice, ncol=7, crop=True, title='FrontoparietalTaskControl', filename=mymm+mysep+"boldFrontoparietalTaskControl.png" )
|
6378
|
+
if ( mymod == 'perf' ) and ishapelen == 4:
|
6379
|
+
dowrite=True
|
6380
|
+
tabPro, normPro = mm( t1, hier,
|
6381
|
+
perfusion_image=img,
|
6382
|
+
srmodel=None,
|
6383
|
+
do_tractography=False,
|
6384
|
+
do_kk=False,
|
6385
|
+
do_normalization=templateTx,
|
6386
|
+
group_template = normalization_template,
|
6387
|
+
group_transform = groupTx,
|
6388
|
+
test_run=test_run,
|
6389
|
+
verbose=True )
|
6390
|
+
if tabPro['perf'] is not None and visualize:
|
6391
|
+
maxslice = np.min( [21, tabPro['perf']['meanBold'].shape[2] ] )
|
6392
|
+
ants.plot( tabPro['perf']['perfusion'],
|
6393
|
+
axis=2, nslices=maxslice, ncol=7, crop=True, title='perfusion image', filename=mymm+mysep+"perfusion.png" )
|
5977
6394
|
if ( mymod == 'DTI_LR' or mymod == 'DTI_RL' or mymod == 'DTI' ) and ishapelen == 4:
|
5978
6395
|
bvalfn = re.sub( '.nii.gz', '.bval' , myimg )
|
5979
6396
|
bvecfn = re.sub( '.nii.gz', '.bvec' , myimg )
|
@@ -6037,7 +6454,7 @@ def mm_csv(
|
|
6037
6454
|
write_mm( output_prefix=mymm, mm=tabPro, mm_norm=normPro, t1wide=t1wide, separator=mysep )
|
6038
6455
|
for mykey in normPro.keys():
|
6039
6456
|
if normPro[mykey] is not None and normPro[mykey].components == 1:
|
6040
|
-
if visualize:
|
6457
|
+
if visualize and False:
|
6041
6458
|
ants.plot( template, normPro[mykey], axis=2, nslices=21, ncol=7, crop=True, title=mykey, filename=mymm+mysep+mykey+".png" )
|
6042
6459
|
if overmodX == nrg_modality_list[ len( nrg_modality_list ) - 1 ]:
|
6043
6460
|
return
|
@@ -6445,7 +6862,7 @@ progress=False, verbose=False ):
|
|
6445
6862
|
"""
|
6446
6863
|
extend a study data frame with wide outputs
|
6447
6864
|
|
6448
|
-
sdf : the input study dataframe
|
6865
|
+
sdf : the input study dataframe from antspymm QC output
|
6449
6866
|
|
6450
6867
|
processing_dir: the directory location of the processed data
|
6451
6868
|
|
@@ -6468,8 +6885,8 @@ progress=False, verbose=False ):
|
|
6468
6885
|
for k in range(len(musthavecols)):
|
6469
6886
|
if not musthavecols[k] in sdf.keys():
|
6470
6887
|
raise ValueError('sdf is missing column ' +musthavecols[k] + ' in merge_wides_to_study_dataframe' )
|
6471
|
-
possible_iids = [ 'imageID', 'imageID', 'imageID', 'flairid', 'dtid1', 'dtid2', 'rsfid1', 'rsfid2', 'nmid1', 'nmid2', 'nmid3', 'nmid4', 'nmid5', 'nmid6', 'nmid7', 'nmid8', 'nmid9', 'nmid10' ]
|
6472
|
-
modality_ids = [ 'T1wHierarchical', 'T1wHierarchicalSR', 'T1w', 'T2Flair', 'DTI', 'DTI', 'rsfMRI', 'rsfMRI', 'NM2DMT', 'NM2DMT', 'NM2DMT', 'NM2DMT', 'NM2DMT', 'NM2DMT', 'NM2DMT', 'NM2DMT', 'NM2DMT', 'NM2DMT']
|
6888
|
+
possible_iids = [ 'imageID', 'imageID', 'imageID', 'flairid', 'dtid1', 'dtid2', 'rsfid1', 'rsfid2', 'nmid1', 'nmid2', 'nmid3', 'nmid4', 'nmid5', 'nmid6', 'nmid7', 'nmid8', 'nmid9', 'nmid10', 'perfid' ]
|
6889
|
+
modality_ids = [ 'T1wHierarchical', 'T1wHierarchicalSR', 'T1w', 'T2Flair', 'DTI', 'DTI', 'rsfMRI', 'rsfMRI', 'NM2DMT', 'NM2DMT', 'NM2DMT', 'NM2DMT', 'NM2DMT', 'NM2DMT', 'NM2DMT', 'NM2DMT', 'NM2DMT', 'NM2DMT', 'perf']
|
6473
6890
|
alldf=pd.DataFrame()
|
6474
6891
|
for myk in sdf.index:
|
6475
6892
|
if progress > 0 and int(myk) % int(progress) == 0:
|
@@ -7640,3 +8057,501 @@ def novelty_detection_quantile(df_train, df_test):
|
|
7640
8057
|
temp = (myqs[mykey][0] > df_train[mykey]).sum() / n
|
7641
8058
|
myqs[mykey] = abs( temp - 0.5 ) / 0.5
|
7642
8059
|
return myqs
|
8060
|
+
|
8061
|
+
|
8062
|
+
def brainmap_figure(statistical_df, data_dictionary_path, output_prefix, brain_image, overlay_cmap='bwr', nslices=21, ncol=7, edge_image_dilation = 0, black_bg=True, axes = [0,1,2], fixed_overlay_range=None, crop=True, verbose=False ):
|
8063
|
+
"""
|
8064
|
+
Create figures based on statistical data and an underlying brain image.
|
8065
|
+
|
8066
|
+
Assumes both ~/.antspyt1w and ~/.antspymm data is available
|
8067
|
+
|
8068
|
+
Parameters:
|
8069
|
+
- statistical_df (pandas dataframe): with 2 columns named anat and value
|
8070
|
+
the anat column should have names that meet *partial matching* criterion
|
8071
|
+
with respect to regions that are measured in antspymm. value will be
|
8072
|
+
the value to be displayed. if two examples of a given region exist in
|
8073
|
+
statistical_df, then the largest absolute value will be taken for display.
|
8074
|
+
- data_dictionary_path (str): Path to the data dictionary CSV file.
|
8075
|
+
- output_prefix (str): Prefix for the output figure filenames.
|
8076
|
+
- brain_image (antsImage): the brain image on which results will overlay.
|
8077
|
+
- overlay_cmap (str): see matplotlib
|
8078
|
+
- nslices (int): number of slices to show
|
8079
|
+
- ncol (int): number of columns to show
|
8080
|
+
- edge_image_dilation (int): integer greater than or equal to zero
|
8081
|
+
- black_bg (bool): boolean
|
8082
|
+
- axes (list): integer list typically [0,1,2] sagittal coronal axial
|
8083
|
+
- fixed_overlay_range (list): scalar pair will try to keep a constant cbar and will truncate the overlay at these min/max values
|
8084
|
+
- crop (bool): crops the image to display by the extent of the overlay
|
8085
|
+
- verbose (bool): boolean
|
8086
|
+
|
8087
|
+
Returns:
|
8088
|
+
an image with values mapped to the associated regions
|
8089
|
+
"""
|
8090
|
+
|
8091
|
+
# Read the statistical file
|
8092
|
+
zz = statistical_df
|
8093
|
+
|
8094
|
+
# Read the data dictionary from a CSV file
|
8095
|
+
mydict = pd.read_csv(data_dictionary_path)
|
8096
|
+
mydict = mydict[~mydict['Measurement'].str.contains("tractography-based connectivity", na=False)]
|
8097
|
+
|
8098
|
+
# Load image and process it
|
8099
|
+
edgeimg = ants.iMath(brain_image,"Normalize")
|
8100
|
+
if edge_image_dilation > 0:
|
8101
|
+
edgeimg = ants.iMath( edgeimg, "MD", edge_image_dilation)
|
8102
|
+
|
8103
|
+
# Define lists and data frames
|
8104
|
+
postfix = ['bf', 'deep_cit168lab', 'mtl', 'cerebellum', 'dkt_cortex','brainstem']
|
8105
|
+
atlas = ['BF', 'CIT168', 'MTL', 'TustisonCobra', 'desikan-killiany-tourville','brainstem']
|
8106
|
+
postdesc = ['nbm3CH13', 'CIT168_Reinf_Learn_v1_label_descriptions_pad', 'mtl_description', 'cerebellum', 'dkt','CIT168_T1w_700um_pad_adni_brainstem']
|
8107
|
+
statdf = pd.DataFrame({'img': postfix, 'atlas': atlas, 'csvdescript': postdesc})
|
8108
|
+
templateprefix = '~/.antspymm/PPMI_template0_'
|
8109
|
+
# Iterate through columns and create figures
|
8110
|
+
col2viz = 'value'
|
8111
|
+
if True:
|
8112
|
+
anattoshow = zz['anat'].unique()
|
8113
|
+
if verbose:
|
8114
|
+
print(col2viz)
|
8115
|
+
print(anattoshow)
|
8116
|
+
# Rest of your code for figure creation goes here...
|
8117
|
+
addem = edgeimg * 0
|
8118
|
+
for k in range(len(anattoshow)):
|
8119
|
+
if verbose:
|
8120
|
+
print(str(k) + " " + anattoshow[k] )
|
8121
|
+
mysub = zz[zz['anat'].str.contains(anattoshow[k])]
|
8122
|
+
vals2viz = mysub[col2viz].agg(['min', 'max'])
|
8123
|
+
vals2viz = vals2viz[abs(vals2viz).idxmax()]
|
8124
|
+
myext = None
|
8125
|
+
if 'dktcortex' in anattoshow[k]:
|
8126
|
+
myext = 'dkt_cortex'
|
8127
|
+
elif 'cit168' in anattoshow[k]:
|
8128
|
+
myext = 'deep_cit168lab'
|
8129
|
+
elif 'mtl' in anattoshow[k]:
|
8130
|
+
myext = 'mtl'
|
8131
|
+
elif 'cerebellum' in anattoshow[k]:
|
8132
|
+
myext = 'cerebellum'
|
8133
|
+
elif 'brainstem' in anattoshow[k]:
|
8134
|
+
myext = 'brainstem'
|
8135
|
+
elif any(item in anattoshow[k] for item in ['nbm', 'bf']):
|
8136
|
+
myext = 'bf'
|
8137
|
+
for j in postfix:
|
8138
|
+
if j == "dkt_cortex":
|
8139
|
+
j = 'dktcortex'
|
8140
|
+
if j == "deep_cit168lab":
|
8141
|
+
j = 'deep_cit168'
|
8142
|
+
anattoshow[k] = anattoshow[k].replace(j, "")
|
8143
|
+
if verbose:
|
8144
|
+
print( anattoshow[k] + " " + str( vals2viz ) )
|
8145
|
+
myatlas = atlas[postfix.index(myext)]
|
8146
|
+
correctdescript = postdesc[postfix.index(myext)]
|
8147
|
+
locfilename = templateprefix + myext + '.nii.gz'
|
8148
|
+
if verbose:
|
8149
|
+
print( locfilename )
|
8150
|
+
myatlas = ants.image_read(locfilename)
|
8151
|
+
atlasDescript = pd.read_csv(f"~/.antspyt1w/{correctdescript}.csv")
|
8152
|
+
atlasDescript['Description'] = atlasDescript['Description'].str.lower()
|
8153
|
+
atlasDescript['Description'] = atlasDescript['Description'].str.replace(" ", "_")
|
8154
|
+
atlasDescript['Description'] = atlasDescript['Description'].str.replace("_left_", "_")
|
8155
|
+
atlasDescript['Description'] = atlasDescript['Description'].str.replace("_right_", "_")
|
8156
|
+
atlasDescript['Description'] = atlasDescript['Description'].str.replace("_left", "")
|
8157
|
+
atlasDescript['Description'] = atlasDescript['Description'].str.replace("_right", "")
|
8158
|
+
if myext == 'cerebellum':
|
8159
|
+
atlasDescript['Description'] = atlasDescript['Description'].str.replace("l_", "")
|
8160
|
+
atlasDescript['Description'] = atlasDescript['Description'].str.replace("r_", "")
|
8161
|
+
whichindex = atlasDescript.index[atlasDescript['Description'] == anattoshow[k]].values[0]
|
8162
|
+
else:
|
8163
|
+
whichindex = atlasDescript.index[atlasDescript['Description'].str.contains(anattoshow[k])]
|
8164
|
+
|
8165
|
+
if type(whichindex) is np.int64:
|
8166
|
+
labelnums = atlasDescript.loc[whichindex, 'Label']
|
8167
|
+
else:
|
8168
|
+
labelnums = list(atlasDescript.loc[whichindex, 'Label'])
|
8169
|
+
if not isinstance(labelnums, list):
|
8170
|
+
labelnums=[labelnums]
|
8171
|
+
addemiszero = ants.threshold_image(addem, 0, 0)
|
8172
|
+
temp = ants.image_read(locfilename)
|
8173
|
+
temp = ants.mask_image(temp, temp, level=labelnums, binarize=True)
|
8174
|
+
temp[temp == 1] = (vals2viz)
|
8175
|
+
temp[addemiszero == 0] = 0
|
8176
|
+
addem = addem + temp
|
8177
|
+
|
8178
|
+
if verbose:
|
8179
|
+
print('Done Adding')
|
8180
|
+
for axx in axes:
|
8181
|
+
figfn=output_prefix+f"fig{col2viz}ax{axx}_py.jpg"
|
8182
|
+
if crop:
|
8183
|
+
cmask = ants.threshold_image( addem,1e-5, 1e9 ).iMath("MD",3) + ants.threshold_image( addem,-1e9, -1e-5 ).iMath("MD",3)
|
8184
|
+
addemC = ants.crop_image( addem, cmask )
|
8185
|
+
edgeimgC = ants.crop_image( edgeimg, cmask )
|
8186
|
+
else:
|
8187
|
+
addemC = addem
|
8188
|
+
edgeimgC = edgeimg
|
8189
|
+
if fixed_overlay_range is not None:
|
8190
|
+
addemC[0:3,0:3,0:3]=fixed_overlay_range[0]
|
8191
|
+
addemC[4:7,4:7,4:7]=fixed_overlay_range[1]
|
8192
|
+
addemC[ addemC < fixed_overlay_range[0] ] = fixed_overlay_range[0]
|
8193
|
+
addemC[ addemC > fixed_overlay_range[1] ] = fixed_overlay_range[1]
|
8194
|
+
ants.plot(edgeimgC, addemC, axis=axx, nslices=nslices, ncol=ncol,
|
8195
|
+
overlay_cmap=overlay_cmap, resample=False,
|
8196
|
+
filename=figfn, cbar=axx==axes[0], crop=True, black_bg=black_bg )
|
8197
|
+
if verbose:
|
8198
|
+
print(f"{col2viz} done")
|
8199
|
+
if verbose:
|
8200
|
+
print("DONE brain map figures")
|
8201
|
+
return addem
|
8202
|
+
|
8203
|
+
|
8204
|
+
def aggregate_antspymm_results(input_csv, subject_col='subjectID', date_col='date', image_col='imageID', date_column='ses-1', base_path="./Processed/ANTsExpArt/", hiervariable='T1wHierarchical', valid_modalities=None, verbose=False ):
|
8205
|
+
"""
|
8206
|
+
Aggregate ANTsPyMM results from the specified CSV file and save the aggregated results to a new CSV file.
|
8207
|
+
|
8208
|
+
Parameters:
|
8209
|
+
- input_csv (str): File path of the input CSV file containing ANTsPyMM QC results averaged and with outlier measurements.
|
8210
|
+
- subject_col (str): Name of the column to store subject IDs.
|
8211
|
+
- date_col (str): Name of the column to store date information.
|
8212
|
+
- image_col (str): Name of the column to store image IDs.
|
8213
|
+
- date_column (str): Name of the column representing the date information.
|
8214
|
+
- base_path (str): Base path for search paths. Defaults to "./Processed/ANTsExpArt/".
|
8215
|
+
- hiervariable (str) : the string variable denoting the Hierarchical output
|
8216
|
+
- valid_modalities (str array) : identifies for each modality; if None will be replaced by get_valid_modalities(long=True)
|
8217
|
+
- verbose : boolean
|
8218
|
+
|
8219
|
+
Note:
|
8220
|
+
This function is tested under limited circumstances. Use with caution.
|
8221
|
+
|
8222
|
+
Example usage:
|
8223
|
+
agg_df = aggregate_antspymm_results("qcdfaol.csv", subject_col='subjectID', date_col='date', image_col='imageID', date_column='ses-1', base_path="./Your/Custom/Path/")
|
8224
|
+
|
8225
|
+
Author:
|
8226
|
+
Avants and ChatGPT
|
8227
|
+
"""
|
8228
|
+
import pandas as pd
|
8229
|
+
import numpy as np
|
8230
|
+
from glob import glob
|
8231
|
+
|
8232
|
+
def filter_df( indf, myprefix ):
|
8233
|
+
nums = [isinstance(indf[col].iloc[0], (int, float)) for col in indf.columns]
|
8234
|
+
indf = indf.loc[:, nums]
|
8235
|
+
indf=indf.loc[:, indf.dtypes != 'object' ]
|
8236
|
+
indf = indf.loc[:, ~indf.columns.str.contains('Unnamed*', na=False, regex=True)]
|
8237
|
+
indf = pd.DataFrame(indf.mean(axis=0, skipna=True)).T
|
8238
|
+
indf = indf.add_prefix( myprefix )
|
8239
|
+
return( indf )
|
8240
|
+
|
8241
|
+
def myread_csv(x, cnms):
|
8242
|
+
"""
|
8243
|
+
Reads a CSV file and returns a DataFrame excluding specified columns.
|
8244
|
+
|
8245
|
+
Parameters:
|
8246
|
+
- x (str): File path of the input CSV file describing the blind QC output
|
8247
|
+
- cnms (list): List of column names to exclude from the DataFrame.
|
8248
|
+
|
8249
|
+
Returns:
|
8250
|
+
pd.DataFrame: DataFrame with specified columns excluded.
|
8251
|
+
"""
|
8252
|
+
df = pd.read_csv(x)
|
8253
|
+
return df.loc[:, ~df.columns.isin(cnms)]
|
8254
|
+
|
8255
|
+
import warnings
|
8256
|
+
# Warning message for untested function
|
8257
|
+
warnings.warn("Warning: This function is not well tested. Use with caution.")
|
8258
|
+
|
8259
|
+
if valid_modalities is None:
|
8260
|
+
valid_modalities = get_valid_modalities('long')
|
8261
|
+
|
8262
|
+
# Read the input CSV file
|
8263
|
+
df = pd.read_csv(input_csv)
|
8264
|
+
|
8265
|
+
# Filter rows where modality is 'T1w'
|
8266
|
+
df = df[df['modality'] == 'T1w']
|
8267
|
+
badnames = get_names_from_data_frame( ['Unnamed'], df )
|
8268
|
+
df=df.drop(badnames, axis=1)
|
8269
|
+
|
8270
|
+
# Add new columns for subject ID, date, and image ID
|
8271
|
+
df[subject_col] = np.nan
|
8272
|
+
df[date_col] = date_column
|
8273
|
+
df[image_col] = np.nan
|
8274
|
+
df = df.astype({subject_col: str, date_col: str, image_col: str })
|
8275
|
+
|
8276
|
+
# if verbose:
|
8277
|
+
# print( df.shape )
|
8278
|
+
# print( df.dtypes )
|
8279
|
+
|
8280
|
+
# prefilter df for data that exists
|
8281
|
+
keep = np.tile( False, df.shape[0] )
|
8282
|
+
for x in range(df.shape[0]):
|
8283
|
+
temp = df['fn'].iloc[x].split("_")
|
8284
|
+
# Generalized search paths
|
8285
|
+
path_template = f"{base_path}{temp[0]}/{date_column}/*/*/*"
|
8286
|
+
hierfn = sorted(glob( path_template + "-" + hiervariable + "-*wide.csv" ) )
|
8287
|
+
if len( hierfn ) > 0:
|
8288
|
+
keep[x]=True
|
8289
|
+
|
8290
|
+
|
8291
|
+
df=df[keep]
|
8292
|
+
|
8293
|
+
if verbose:
|
8294
|
+
print( "original input had shape " + str( df.shape[0] ) + " (T1 only) and we find " + str( (keep).sum() ) + " with hierarchical output defined by variable: " + hiervariable )
|
8295
|
+
print( df.shape )
|
8296
|
+
|
8297
|
+
myct = 0
|
8298
|
+
for x in range( df.shape[0]):
|
8299
|
+
if verbose:
|
8300
|
+
print(f"{x}...")
|
8301
|
+
locind = df.index[x]
|
8302
|
+
temp = df['fn'].iloc[x].split("_")
|
8303
|
+
if verbose:
|
8304
|
+
print( temp )
|
8305
|
+
df[subject_col].iloc[x]=temp[0]
|
8306
|
+
df[date_col].iloc[x]=date_column
|
8307
|
+
df[image_col].iloc[x]=temp[1]
|
8308
|
+
|
8309
|
+
# Generalized search paths
|
8310
|
+
path_template = f"{base_path}{temp[0]}/{date_column}/*/*/*"
|
8311
|
+
if verbose:
|
8312
|
+
print(path_template)
|
8313
|
+
hierfn = sorted(glob( path_template + "-" + hiervariable + "-*wide.csv" ) )
|
8314
|
+
if len( hierfn ) > 0:
|
8315
|
+
hdf=t1df=dtdf=rsdf=perfdf=nmdf=flairdf=None
|
8316
|
+
if verbose:
|
8317
|
+
print(hierfn)
|
8318
|
+
hdf = pd.read_csv(hierfn[0])
|
8319
|
+
badnames = get_names_from_data_frame( ['Unnamed'], hdf )
|
8320
|
+
hdf=hdf.drop(badnames, axis=1)
|
8321
|
+
nums = [isinstance(hdf[col].iloc[0], (int, float)) for col in hdf.columns]
|
8322
|
+
corenames = list(np.array(hdf.columns)[nums])
|
8323
|
+
hdf.loc[:, nums] = hdf.loc[:, nums].add_prefix("T1Hier_")
|
8324
|
+
myct = myct + 1
|
8325
|
+
dflist = [hdf]
|
8326
|
+
|
8327
|
+
for mymod in valid_modalities:
|
8328
|
+
t1wfn = sorted(glob( path_template+ "-" + mymod + "-*wide.csv" ) )
|
8329
|
+
if len( t1wfn ) > 0 :
|
8330
|
+
if verbose:
|
8331
|
+
print(t1wfn)
|
8332
|
+
t1df = myread_csv(t1wfn[0], corenames)
|
8333
|
+
t1df = filter_df( t1df, mymod+'_')
|
8334
|
+
dflist = dflist + [t1df]
|
8335
|
+
|
8336
|
+
hdf = pd.concat( dflist, axis=1)
|
8337
|
+
if verbose:
|
8338
|
+
print( df.loc[locind,'fn'] )
|
8339
|
+
if myct == 1:
|
8340
|
+
subdf = df.iloc[[x]]
|
8341
|
+
hdf.index = subdf.index.copy()
|
8342
|
+
df = pd.concat( [df,hdf], axis=1)
|
8343
|
+
else:
|
8344
|
+
commcols = list(set(hdf.columns).intersection(df.columns))
|
8345
|
+
df.loc[locind, commcols] = hdf.loc[0, commcols]
|
8346
|
+
badnames = get_names_from_data_frame( ['Unnamed'], df )
|
8347
|
+
df=df.drop(badnames, axis=1)
|
8348
|
+
return( df )
|
8349
|
+
|
8350
|
+
def aggregate_antspymm_results_sdf(
|
8351
|
+
study_df,
|
8352
|
+
project_col='projectID',
|
8353
|
+
subject_col='subjectID',
|
8354
|
+
date_col='date',
|
8355
|
+
image_col='imageID',
|
8356
|
+
base_path="./",
|
8357
|
+
hiervariable='T1wHierarchical',
|
8358
|
+
splitsep='-',
|
8359
|
+
idsep='-',
|
8360
|
+
wild_card_modality_id=False,
|
8361
|
+
verbose=False ):
|
8362
|
+
"""
|
8363
|
+
Aggregate ANTsPyMM results from the specified study data frame and store the aggregated results in a new data frame. This assumes data is organized on disk
|
8364
|
+
as follows: rootdir/projectID/subjectID/date/outputid/imageid/ where
|
8365
|
+
outputid is modality-specific and created by ANTsPyMM processing.
|
8366
|
+
|
8367
|
+
Parameters:
|
8368
|
+
- study_df (pandas df): pandas data frame, output of generate_mm_dataframe.
|
8369
|
+
- project_col (str): Name of the column that stores the project ID
|
8370
|
+
- subject_col (str): Name of the column to store subject IDs.
|
8371
|
+
- date_col (str): Name of the column to store date information.
|
8372
|
+
- image_col (str): Name of the column to store image IDs.
|
8373
|
+
- base_path (str): Base path for searching for processing outputs of ANTsPyMM.
|
8374
|
+
- hiervariable (str) : the string variable denoting the Hierarchical output
|
8375
|
+
- splitsep (str): the separator used to split the filename
|
8376
|
+
- idsep (str): the separator used to partition subjectid date and imageid
|
8377
|
+
for example, if idsep is - then we have subjectid-date-imageid
|
8378
|
+
- wild_card_modality_id (bool): keep if False for safer execution
|
8379
|
+
- verbose : boolean
|
8380
|
+
|
8381
|
+
Note:
|
8382
|
+
This function is tested under limited circumstances. Use with caution.
|
8383
|
+
|
8384
|
+
Example usage:
|
8385
|
+
agg_df = aggregate_antspymm_results_sdf( studydf, subject_col='subjectID', date_col='date', image_col='imageID', base_path="./Your/Custom/Path/")
|
8386
|
+
|
8387
|
+
Author:
|
8388
|
+
Avants and ChatGPT
|
8389
|
+
"""
|
8390
|
+
import pandas as pd
|
8391
|
+
import numpy as np
|
8392
|
+
from glob import glob
|
8393
|
+
|
8394
|
+
def filter_df( indf, myprefix ):
|
8395
|
+
nums = [isinstance(indf[col].iloc[0], (int, float)) for col in indf.columns]
|
8396
|
+
indf = indf.loc[:, nums]
|
8397
|
+
indf=indf.loc[:, indf.dtypes != 'object' ]
|
8398
|
+
indf = indf.loc[:, ~indf.columns.str.contains('Unnamed*', na=False, regex=True)]
|
8399
|
+
indf = pd.DataFrame(indf.mean(axis=0, skipna=True)).T
|
8400
|
+
indf = indf.add_prefix( myprefix )
|
8401
|
+
return( indf )
|
8402
|
+
|
8403
|
+
def myread_csv(x, cnms):
|
8404
|
+
"""
|
8405
|
+
Reads a CSV file and returns a DataFrame excluding specified columns.
|
8406
|
+
|
8407
|
+
Parameters:
|
8408
|
+
- x (str): File path of the input CSV file describing the blind QC output
|
8409
|
+
- cnms (list): List of column names to exclude from the DataFrame.
|
8410
|
+
|
8411
|
+
Returns:
|
8412
|
+
pd.DataFrame: DataFrame with specified columns excluded.
|
8413
|
+
"""
|
8414
|
+
df = pd.read_csv(x)
|
8415
|
+
return df.loc[:, ~df.columns.isin(cnms)]
|
8416
|
+
|
8417
|
+
import warnings
|
8418
|
+
# Warning message for untested function
|
8419
|
+
warnings.warn("Warning: This function is not well tested. Use with caution.")
|
8420
|
+
|
8421
|
+
# if valid_modalities is None:
|
8422
|
+
valid_modalities = get_valid_modalities('long')
|
8423
|
+
vmoddict = {}
|
8424
|
+
# Add key-value pairs
|
8425
|
+
vmoddict['imageID'] = 'T1w'
|
8426
|
+
vmoddict['flairid'] = 'T2Flair'
|
8427
|
+
vmoddict['perfid'] = 'perf'
|
8428
|
+
vmoddict['rsfid1'] = 'rsfMRI'
|
8429
|
+
vmoddict['dtid1'] = 'DTI'
|
8430
|
+
vmoddict['nmid1'] = 'NM2DMT'
|
8431
|
+
|
8432
|
+
# Filter rows where modality is 'T1w'
|
8433
|
+
df = study_df[study_df['modality'] == 'T1w']
|
8434
|
+
badnames = get_names_from_data_frame( ['Unnamed'], df )
|
8435
|
+
df=df.drop(badnames, axis=1)
|
8436
|
+
# prefilter df for data that exists
|
8437
|
+
keep = np.tile( False, df.shape[0] )
|
8438
|
+
for x in range(df.shape[0]):
|
8439
|
+
myfn = os.path.basename( df['filename'].iloc[x] )
|
8440
|
+
temp = myfn.split( splitsep )
|
8441
|
+
# Generalized search paths
|
8442
|
+
sid0 = temp[0]
|
8443
|
+
sid = str(df[subject_col].iloc[x])
|
8444
|
+
if sid0 != sid:
|
8445
|
+
warnings.warn("the id derived from the filename " + sid + " does not match the id stored in the data frame " + sid )
|
8446
|
+
myproj = str(df[project_col].iloc[x])
|
8447
|
+
mydate = str(df[date_col].iloc[x])
|
8448
|
+
myid = str(df[image_col].iloc[x])
|
8449
|
+
path_template = base_path + "/" + myproj + "/" + sid + "/" + mydate + '/' + hiervariable + '/' + str(myid) + "/"
|
8450
|
+
hierfn = sorted(glob( path_template + "*" + hiervariable + "*wide.csv" ) )
|
8451
|
+
if len( hierfn ) > 0:
|
8452
|
+
keep[x]=True
|
8453
|
+
|
8454
|
+
df=df[keep]
|
8455
|
+
|
8456
|
+
if not df.index.is_unique:
|
8457
|
+
warnings.warn("data frame does not have unique indices. we therefore reset the index to allow the function to continue on." )
|
8458
|
+
df = df.reset_index()
|
8459
|
+
|
8460
|
+
|
8461
|
+
if verbose:
|
8462
|
+
print( "original input had shape " + str( df.shape[0] ) + " (T1 only) and we find " + str( (keep).sum() ) + " with hierarchical output defined by variable: " + hiervariable )
|
8463
|
+
print( df.shape )
|
8464
|
+
|
8465
|
+
myct = 0
|
8466
|
+
for x in range( df.shape[0]):
|
8467
|
+
print("\n\n-------------------------------------------------")
|
8468
|
+
if verbose:
|
8469
|
+
print(f"{x}...")
|
8470
|
+
locind = df.index[x]
|
8471
|
+
myfn = os.path.basename( df['filename'].iloc[x] )
|
8472
|
+
sid = df[subject_col].iloc[x]
|
8473
|
+
if sid0 != sid:
|
8474
|
+
warnings.warn("the id derived from the filename " + sid + " does not match the id stored in the data frame " + sid )
|
8475
|
+
myproj = str(df[project_col].iloc[x])
|
8476
|
+
mydate = str(df[date_col].iloc[x])
|
8477
|
+
myid = str(df[image_col].iloc[x])
|
8478
|
+
if verbose:
|
8479
|
+
print( myfn )
|
8480
|
+
print( temp )
|
8481
|
+
print( "id " + sid )
|
8482
|
+
path_template = base_path + "/" + myproj + "/" + sid + "/" + mydate + '/' + hiervariable + '/' + str(myid) + "/"
|
8483
|
+
searchhier = path_template + "*" + hiervariable + "*wide.csv"
|
8484
|
+
if verbose:
|
8485
|
+
print( searchhier )
|
8486
|
+
hierfn = sorted( glob( searchhier ) )
|
8487
|
+
if len( hierfn ) > 1:
|
8488
|
+
raise ValueError("there are " + str( len( hierfn ) ) + " number of hier fns with search path " + searchhier )
|
8489
|
+
if len( hierfn ) == 1:
|
8490
|
+
hdf=t1df=dtdf=rsdf=perfdf=nmdf=flairdf=None
|
8491
|
+
if verbose:
|
8492
|
+
print(hierfn)
|
8493
|
+
hdf = pd.read_csv(hierfn[0])
|
8494
|
+
badnames = get_names_from_data_frame( ['Unnamed'], hdf )
|
8495
|
+
hdf=hdf.drop(badnames, axis=1)
|
8496
|
+
nums = [isinstance(hdf[col].iloc[0], (int, float)) for col in hdf.columns]
|
8497
|
+
corenames = list(np.array(hdf.columns)[nums])
|
8498
|
+
hdf.loc[:, nums] = hdf.loc[:, nums].add_prefix("T1Hier_")
|
8499
|
+
myct = myct + 1
|
8500
|
+
hdf = hdf.add_prefix( "T1Hier_" )
|
8501
|
+
dflist = [hdf]
|
8502
|
+
|
8503
|
+
for mymod in vmoddict.keys():
|
8504
|
+
print("\n\n************************* " + mymod + " *************************")
|
8505
|
+
modalityclass = vmoddict[ mymod ]
|
8506
|
+
if wild_card_modality_id:
|
8507
|
+
mymodid = '*'
|
8508
|
+
else:
|
8509
|
+
mymodid = str( df[mymod].iloc[x] )
|
8510
|
+
if mymodid.lower() != "nan" and mymodid.lower() != "na":
|
8511
|
+
mymodid = os.path.basename( mymodid )
|
8512
|
+
mymodid = os.path.splitext( mymodid )[0]
|
8513
|
+
mymodid = os.path.splitext( mymodid )[0]
|
8514
|
+
temp = mymodid.split( idsep )
|
8515
|
+
mymodid = temp[ len( temp )-1 ]
|
8516
|
+
else:
|
8517
|
+
print("missing")
|
8518
|
+
continue
|
8519
|
+
if verbose:
|
8520
|
+
print( "modality id is " + mymodid + " for modality " + modalityclass )
|
8521
|
+
modalityclasssearch = modalityclass
|
8522
|
+
if modalityclass in ['rsfMRI','DTI']:
|
8523
|
+
modalityclasssearch=modalityclass+"*"
|
8524
|
+
path_template_m = base_path + "/" + myproj + "/" + sid + "/" + mydate + '/' + modalityclasssearch + '/' + mymodid + "/"
|
8525
|
+
modsearch = path_template_m + "*" + modalityclasssearch + "*wide.csv"
|
8526
|
+
if verbose:
|
8527
|
+
print( modsearch )
|
8528
|
+
t1wfn = sorted( glob( modsearch ) )
|
8529
|
+
if len( t1wfn ) > 1:
|
8530
|
+
raise ValueError("there are " + str( len( t1wfn ) ) + " number of wide fns with search path " + modsearch )
|
8531
|
+
if len( t1wfn ) == 1:
|
8532
|
+
if verbose:
|
8533
|
+
print(t1wfn)
|
8534
|
+
t1df = myread_csv(t1wfn[0], corenames)
|
8535
|
+
t1df = filter_df( t1df, modalityclass+'_')
|
8536
|
+
dflist = dflist + [t1df]
|
8537
|
+
else:
|
8538
|
+
if verbose:
|
8539
|
+
print( " cannot find " + modsearch )
|
8540
|
+
|
8541
|
+
hdf = pd.concat( dflist, axis=1)
|
8542
|
+
if verbose:
|
8543
|
+
print( "count: " + str( myct ) )
|
8544
|
+
if myct == 1:
|
8545
|
+
subdf = df.iloc[[x]]
|
8546
|
+
hdf.index = subdf.index.copy()
|
8547
|
+
print( hdf.index )
|
8548
|
+
print( df.index )
|
8549
|
+
df = pd.concat( [df,hdf], axis=1)
|
8550
|
+
else:
|
8551
|
+
commcols = list(set(hdf.columns).intersection(df.columns))
|
8552
|
+
df.loc[locind, commcols] = hdf.loc[0, commcols]
|
8553
|
+
badnames = get_names_from_data_frame( ['Unnamed'], df )
|
8554
|
+
df=df.drop(badnames, axis=1)
|
8555
|
+
return( df )
|
8556
|
+
|
8557
|
+
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: antspymm
|
3
|
-
Version: 1.1.
|
3
|
+
Version: 1.1.3
|
4
4
|
Summary: multi-channel/time-series medical image processing with antspyx
|
5
5
|
Home-page: https://github.com/stnava/ANTsPyMM
|
6
6
|
Author: Avants, Gosselin, Tustison, Reardon
|
@@ -18,10 +18,13 @@ Requires-Dist: dipy
|
|
18
18
|
Requires-Dist: nibabel
|
19
19
|
Requires-Dist: scipy
|
20
20
|
Requires-Dist: siq
|
21
|
-
Requires-Dist:
|
21
|
+
Requires-Dist: scikit-learn
|
22
22
|
|
23
23
|
# ANTsPyMM
|
24
24
|
|
25
|
+
|
26
|
+
[mapping](https://imgur.com/a/XzpXI3i)
|
27
|
+
|
25
28
|
## processing utilities for timeseries/multichannel images - mostly neuroimaging
|
26
29
|
|
27
30
|
the outputs of these processes can be used for data inspection/cleaning/triage
|
@@ -243,6 +246,13 @@ studycsv = antspymm.generate_mm_dataframe(
|
|
243
246
|
rsf_filenames=[fns[2]])
|
244
247
|
studycsv2 = studycsv.dropna(axis=1)
|
245
248
|
mmrun = antspymm.mm_csv( studycsv2, mysep='_' )
|
249
|
+
|
250
|
+
# aggregate the data after you've run on many subjects
|
251
|
+
# studycsv_all would be the vstacked studycsv2 data frames
|
252
|
+
zz=antspymm.aggregate_antspymm_results_sdf( studycsv_all,
|
253
|
+
subject_col='subjectID', date_col='date', image_col='imageID', base_path=bd,
|
254
|
+
splitsep='_', idsep='-', wild_card_modality_id=True, verbose=True)
|
255
|
+
|
246
256
|
```
|
247
257
|
|
248
258
|
## NRG example
|
@@ -426,6 +436,15 @@ for f in folders:
|
|
426
436
|
pdoc -o ./docs antspymm --html
|
427
437
|
```
|
428
438
|
|
439
|
+
## ssl error
|
440
|
+
|
441
|
+
if you get an odd certificate error when calling `force_download`, try:
|
442
|
+
|
443
|
+
```python
|
444
|
+
import ssl
|
445
|
+
ssl._create_default_https_context = ssl._create_unverified_context
|
446
|
+
``
|
447
|
+
|
429
448
|
## to publish a release
|
430
449
|
|
431
450
|
```
|
@@ -0,0 +1,7 @@
|
|
1
|
+
antspymm/__init__.py,sha256=wck10IhO1ZFxNqz4bTIHFP7cqYosRKBI8bKIsZzRwfs,3166
|
2
|
+
antspymm/mm.py,sha256=sYXNst5xri6vFDzvuqDB6avuwkKoq3GTEsvm0RLUuPU,347923
|
3
|
+
antspymm-1.1.3.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
4
|
+
antspymm-1.1.3.dist-info/METADATA,sha256=bFp7u3Bd85Sq4Nc_TvvzxfYDhyU9Uxj4T9yzDcDK26I,14153
|
5
|
+
antspymm-1.1.3.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
6
|
+
antspymm-1.1.3.dist-info/top_level.txt,sha256=iyD1sRhCKzfwKRJLq5ZUeV9xsv1cGQl8Ejp6QwXM1Zg,9
|
7
|
+
antspymm-1.1.3.dist-info/RECORD,,
|
antspymm-1.1.1.dist-info/RECORD
DELETED
@@ -1,7 +0,0 @@
|
|
1
|
-
antspymm/__init__.py,sha256=BTNN_iisXoz2on4gVcAQWFB_qJYDM-yqZOJU1xho9sw,2931
|
2
|
-
antspymm/mm.py,sha256=SX1eYoKPmZ6QId0GZBIiztywWJAjNX2lUy9uihyuFG4,308416
|
3
|
-
antspymm-1.1.1.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
4
|
-
antspymm-1.1.1.dist-info/METADATA,sha256=wxrVbMj17gBEbDV9Nuh2Df8S-XPKTH35qS5iZcvPKic,13598
|
5
|
-
antspymm-1.1.1.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
|
6
|
-
antspymm-1.1.1.dist-info/top_level.txt,sha256=iyD1sRhCKzfwKRJLq5ZUeV9xsv1cGQl8Ejp6QwXM1Zg,9
|
7
|
-
antspymm-1.1.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|