antspymm 1.1.8__py3-none-any.whl → 1.1.9__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 +4 -0
- antspymm/mm.py +388 -112
- {antspymm-1.1.8.dist-info → antspymm-1.1.9.dist-info}/METADATA +1 -1
- antspymm-1.1.9.dist-info/RECORD +7 -0
- antspymm-1.1.8.dist-info/RECORD +0 -7
- {antspymm-1.1.8.dist-info → antspymm-1.1.9.dist-info}/LICENSE +0 -0
- {antspymm-1.1.8.dist-info → antspymm-1.1.9.dist-info}/WHEEL +0 -0
- {antspymm-1.1.8.dist-info → antspymm-1.1.9.dist-info}/top_level.txt +0 -0
antspymm/__init__.py
CHANGED
@@ -108,5 +108,9 @@ from .mm import remove_elements_from_numpy_array
|
|
108
108
|
from .mm import remove_volumes_from_timeseries
|
109
109
|
from .mm import impute_timeseries
|
110
110
|
from .mm import impute_dwi
|
111
|
+
from .mm import scrub_dwi
|
111
112
|
from .mm import timeseries_n3
|
112
113
|
from .mm import calculate_CBF
|
114
|
+
from .mm import estimate_optimal_pca_components
|
115
|
+
from .mm import filter_df
|
116
|
+
|
antspymm/mm.py
CHANGED
@@ -111,7 +111,7 @@ import re
|
|
111
111
|
import datetime as dt
|
112
112
|
from collections import Counter
|
113
113
|
import tempfile
|
114
|
-
|
114
|
+
import warnings
|
115
115
|
|
116
116
|
from dipy.core.histeq import histeq
|
117
117
|
import dipy.reconst.dti as dti
|
@@ -686,7 +686,7 @@ def collect_blind_qc_by_modality( modality_path, set_index_to_fn=True ):
|
|
686
686
|
temp=pd.read_csv(fns[k])
|
687
687
|
if not 'filename' in temp.keys():
|
688
688
|
temp['filename']=fns[k]
|
689
|
-
jdf=pd.concat( [jdf,temp])
|
689
|
+
jdf=pd.concat( [jdf,temp], axis=0, ignore_index=False )
|
690
690
|
if set_index_to_fn:
|
691
691
|
jdf.reset_index(drop=True)
|
692
692
|
if "Unnamed: 0" in jdf.columns:
|
@@ -3151,7 +3151,8 @@ def joint_dti_recon(
|
|
3151
3151
|
dewarp_modality = 'FA',
|
3152
3152
|
denoise=False,
|
3153
3153
|
fit_method='WLS',
|
3154
|
-
impute =
|
3154
|
+
impute = False,
|
3155
|
+
scrub = True,
|
3155
3156
|
verbose = False ):
|
3156
3157
|
"""
|
3157
3158
|
1. pass in subject data and 1mm JHU atlas/labels
|
@@ -3204,6 +3205,8 @@ def joint_dti_recon(
|
|
3204
3205
|
|
3205
3206
|
impute : boolean
|
3206
3207
|
|
3208
|
+
scrub : boolean
|
3209
|
+
|
3207
3210
|
verbose : boolean
|
3208
3211
|
|
3209
3212
|
Returns
|
@@ -3291,8 +3294,12 @@ def joint_dti_recon(
|
|
3291
3294
|
|
3292
3295
|
if impute:
|
3293
3296
|
img_LRdwp=impute_dwi( img_LRdwp, verbose=True )
|
3297
|
+
elif scrub:
|
3298
|
+
img_LRdwp, reg_LR['bvals'], reg_LR['bvecs'] = scrub_dwi( img_LRdwp, reg_LR['bvals'], reg_LR['bvecs'], verbose=True )
|
3294
3299
|
if impute and img_RL is not None:
|
3295
3300
|
img_RLdwp=impute_dwi( img_RLdwp, verbose=True )
|
3301
|
+
elif scrub and img_RL is not None:
|
3302
|
+
img_RLdwp, reg_RL['bvals'], reg_RL['bvecs'] = scrub_dwi( img_RLdwp, reg_RL['bvals'], reg_RL['bvecs'], verbose=True )
|
3296
3303
|
|
3297
3304
|
if img_RL is not None:
|
3298
3305
|
img_LRdwp, bval_LR, bvec_LR = merge_dwi_data(
|
@@ -4171,7 +4178,7 @@ def dwi_streamline_connectivity_old(
|
|
4171
4178
|
pathdfw,
|
4172
4179
|
Mdfw,
|
4173
4180
|
Tdfw,
|
4174
|
-
Ctdfw ], axis=1 )
|
4181
|
+
Ctdfw ], axis=1, ignore_index=False )
|
4175
4182
|
|
4176
4183
|
return {
|
4177
4184
|
'connectivity': allconnexwide,
|
@@ -4236,7 +4243,7 @@ def hierarchical_modality_summary(
|
|
4236
4243
|
if verbose:
|
4237
4244
|
print( mappedw.keys() )
|
4238
4245
|
if mydf.shape[0] > 0:
|
4239
|
-
mydf = pd.concat( [ mydf, mappedw], axis=1 )
|
4246
|
+
mydf = pd.concat( [ mydf, mappedw], axis=1, ignore_index=False )
|
4240
4247
|
else:
|
4241
4248
|
mydf = mappedw
|
4242
4249
|
return mydf
|
@@ -4596,9 +4603,52 @@ def neuromelanin( list_nm_images, t1, t1_head, t1lab, brain_stem_dilation=8,
|
|
4596
4603
|
'NM_count': len( list_nm_images )
|
4597
4604
|
}
|
4598
4605
|
|
4606
|
+
|
4607
|
+
|
4608
|
+
def estimate_optimal_pca_components(data, variance_threshold=0.80, plot=False):
|
4609
|
+
"""
|
4610
|
+
Estimate the optimal number of PCA components to represent the given data.
|
4611
|
+
|
4612
|
+
:param data: The data matrix (samples x features).
|
4613
|
+
:param variance_threshold: Threshold for cumulative explained variance (default 0.95).
|
4614
|
+
:param plot: If True, plot the cumulative explained variance graph (default False).
|
4615
|
+
:return: The optimal number of principal components.
|
4616
|
+
"""
|
4617
|
+
import numpy as np
|
4618
|
+
from sklearn.decomposition import PCA
|
4619
|
+
import matplotlib.pyplot as plt
|
4620
|
+
|
4621
|
+
# Perform PCA
|
4622
|
+
pca = PCA()
|
4623
|
+
pca.fit(data)
|
4624
|
+
|
4625
|
+
# Calculate cumulative explained variance
|
4626
|
+
cumulative_variance = np.cumsum(pca.explained_variance_ratio_)
|
4627
|
+
|
4628
|
+
# Determine the number of components for desired explained variance
|
4629
|
+
n_components = np.where(cumulative_variance >= variance_threshold)[0][0] + 1
|
4630
|
+
|
4631
|
+
# Optionally plot the explained variance
|
4632
|
+
if plot:
|
4633
|
+
plt.figure(figsize=(8, 4))
|
4634
|
+
plt.plot(cumulative_variance, linewidth=2)
|
4635
|
+
plt.axhline(y=variance_threshold, color='r', linestyle='--')
|
4636
|
+
plt.axvline(x=n_components - 1, color='r', linestyle='--')
|
4637
|
+
plt.xlabel('Number of Components')
|
4638
|
+
plt.ylabel('Cumulative Explained Variance')
|
4639
|
+
plt.title('Explained Variance by Number of Principal Components')
|
4640
|
+
plt.show()
|
4641
|
+
|
4642
|
+
return n_components
|
4643
|
+
|
4644
|
+
|
4599
4645
|
def resting_state_fmri_networks( fmri, fmri_template, t1, t1segmentation,
|
4600
|
-
f=[0.
|
4601
|
-
|
4646
|
+
f=[0.008,0.1], FD_threshold=0.5, spa = None, spt = None,
|
4647
|
+
nc = 0.90, type_of_transform='Rigid',
|
4648
|
+
outlier_threshold=0.50,
|
4649
|
+
ica_components = 0,
|
4650
|
+
impute = False,
|
4651
|
+
scrub = True,
|
4602
4652
|
verbose=False ):
|
4603
4653
|
"""
|
4604
4654
|
Compute resting state network correlation maps based on the J Power labels.
|
@@ -4618,14 +4668,20 @@ def resting_state_fmri_networks( fmri, fmri_template, t1, t1segmentation,
|
|
4618
4668
|
|
4619
4669
|
f : band pass limits for frequency filtering
|
4620
4670
|
|
4621
|
-
spa : gaussian smoothing for spatial component
|
4671
|
+
spa : gaussian smoothing for spatial component (physical coordinates)
|
4622
4672
|
|
4623
4673
|
spt : gaussian smoothing for temporal component
|
4624
4674
|
|
4625
|
-
nc : number of components for compcor filtering
|
4675
|
+
nc : number of components for compcor filtering; if less than 1 we estimate on the fly based on explained variance
|
4626
4676
|
|
4627
4677
|
type_of_transform : SyN or Rigid
|
4628
4678
|
|
4679
|
+
ica_components : integer if greater than 0 then include ica components
|
4680
|
+
|
4681
|
+
impute : boolean if True, then use imputation
|
4682
|
+
|
4683
|
+
scrub : boolean if True, then use censoring (scrubbing)
|
4684
|
+
|
4629
4685
|
verbose : boolean
|
4630
4686
|
|
4631
4687
|
Returns
|
@@ -4633,16 +4689,66 @@ def resting_state_fmri_networks( fmri, fmri_template, t1, t1segmentation,
|
|
4633
4689
|
a dictionary containing the derived network maps
|
4634
4690
|
|
4635
4691
|
"""
|
4692
|
+
|
4693
|
+
import numpy as np
|
4694
|
+
# Assuming core and utils are modules or packages with necessary functions
|
4695
|
+
|
4696
|
+
def compute_tSTD(M, quantile, x=0, axis=0):
|
4697
|
+
stdM = np.std(M, axis=axis)
|
4698
|
+
# set bad values to x
|
4699
|
+
stdM[stdM == 0] = x
|
4700
|
+
stdM[np.isnan(stdM)] = x
|
4701
|
+
tt = round(quantile * 100)
|
4702
|
+
threshold_std = np.percentile(stdM, tt)
|
4703
|
+
return {'tSTD': stdM, 'threshold_std': threshold_std}
|
4704
|
+
|
4705
|
+
def get_compcor_matrix(boldImage, mask, quantile):
|
4706
|
+
"""
|
4707
|
+
Compute the compcor matrix.
|
4708
|
+
|
4709
|
+
:param boldImage: The bold image.
|
4710
|
+
:param mask: The mask to apply, if None, it will be computed.
|
4711
|
+
:param quantile: Quantile for computing threshold in tSTD.
|
4712
|
+
:return: The compor matrix.
|
4713
|
+
"""
|
4714
|
+
if mask is None:
|
4715
|
+
temp = ants.slice_image(boldImage, axis=boldImage.dimension - 1, idx=0)
|
4716
|
+
mask = ants.get_mask(temp)
|
4717
|
+
|
4718
|
+
imagematrix = ants.timeseries_to_matrix(boldImage, mask)
|
4719
|
+
temp = compute_tSTD(imagematrix, quantile, 0)
|
4720
|
+
tsnrmask = ants.make_image(mask, temp['tSTD'])
|
4721
|
+
tsnrmask = ants.threshold_image(tsnrmask, temp['threshold_std'], temp['tSTD'].max())
|
4722
|
+
M = ants.timeseries_to_matrix(boldImage, tsnrmask)
|
4723
|
+
return M
|
4724
|
+
|
4725
|
+
|
4726
|
+
from sklearn.decomposition import FastICA
|
4727
|
+
def find_indices(lst, value):
|
4728
|
+
return [index for index, element in enumerate(lst) if element > value]
|
4729
|
+
|
4730
|
+
def mean_of_list(lst):
|
4731
|
+
if not lst: # Check if the list is not empty
|
4732
|
+
return 0 # Return 0 or appropriate value for an empty list
|
4733
|
+
return sum(lst) / len(lst)
|
4734
|
+
fmrispc = list(ants.get_spacing( fmri ))
|
4735
|
+
if spa is None:
|
4736
|
+
spa = mean_of_list( fmrispc[0:3] ) * 1.0
|
4737
|
+
if spt is None:
|
4738
|
+
spt = fmrispc[3] * 0.5
|
4739
|
+
|
4636
4740
|
import numpy as np
|
4637
4741
|
import pandas as pd
|
4638
4742
|
import re
|
4639
4743
|
import math
|
4744
|
+
# point data resources
|
4640
4745
|
A = np.zeros((1,1))
|
4641
4746
|
powers_areal_mni_itk = pd.read_csv( get_data('powers_mni_itk', target_extension=".csv")) # power coordinates
|
4642
4747
|
fmri = ants.iMath( fmri, 'Normalize' )
|
4643
4748
|
bmask = antspynet.brain_extraction( fmri_template, 'bold' ).threshold_image(0.5,1).iMath("FillHoles")
|
4644
4749
|
if verbose:
|
4645
4750
|
print("Begin rsfmri motion correction")
|
4751
|
+
# mot-co
|
4646
4752
|
corrmo = timeseries_reg(
|
4647
4753
|
fmri, fmri_template,
|
4648
4754
|
type_of_transform=type_of_transform,
|
@@ -4654,18 +4760,21 @@ def resting_state_fmri_networks( fmri, fmri_template, t1, t1segmentation,
|
|
4654
4760
|
syn_metric='cc',
|
4655
4761
|
syn_sampling=2,
|
4656
4762
|
reg_iterations=[40,20,5] )
|
4763
|
+
|
4657
4764
|
if verbose:
|
4658
4765
|
print("End rsfmri motion correction")
|
4766
|
+
print("big code block below does anatomically based mapping")
|
4659
4767
|
|
4660
|
-
|
4661
|
-
|
4662
|
-
|
4663
|
-
|
4664
|
-
|
4768
|
+
high_motion_count=(corrmo['FD'] > FD_threshold ).sum()
|
4769
|
+
high_motion_pct=high_motion_count / fmri.shape[3]
|
4770
|
+
|
4771
|
+
# filter mask based on TSNR
|
4665
4772
|
mytsnr = tsnr( corrmo['motion_corrected'], bmask )
|
4666
4773
|
mytsnrThresh = np.quantile( mytsnr.numpy(), 0.995 )
|
4667
4774
|
tsnrmask = ants.threshold_image( mytsnr, 0, mytsnrThresh ).morphology("close",2)
|
4668
4775
|
bmask = bmask * tsnrmask
|
4776
|
+
|
4777
|
+
# anatomical mapping
|
4669
4778
|
und = fmri_template * bmask
|
4670
4779
|
t1reg = ants.registration( und, t1, "SyNBold" )
|
4671
4780
|
if verbose:
|
@@ -4682,14 +4791,7 @@ def resting_state_fmri_networks( fmri, fmri_template, t1, t1segmentation,
|
|
4682
4791
|
ants.threshold_image( t1segmentation, 3, 3 ) ).morphology("erode",1)
|
4683
4792
|
csfAndWM = ants.apply_transforms( und, csfAndWM,
|
4684
4793
|
t1reg['fwdtransforms'], interpolator = 'nearestNeighbor' ) * bmask
|
4685
|
-
|
4686
|
-
# get falff and alff
|
4687
|
-
mycompcor = ants.compcor( corrmo['motion_corrected'],
|
4688
|
-
ncompcor=nc, quantile=0.90, mask = csfAndWM,
|
4689
|
-
filter_type='polynomial', degree=2 )
|
4690
|
-
|
4691
4794
|
nt = corrmo['motion_corrected'].shape[3]
|
4692
|
-
|
4693
4795
|
myvoxes = range(powers_areal_mni_itk.shape[0])
|
4694
4796
|
anat = powers_areal_mni_itk['Anatomy']
|
4695
4797
|
syst = powers_areal_mni_itk['SystemName']
|
@@ -4703,26 +4805,98 @@ def resting_state_fmri_networks( fmri, fmri_template, t1, t1segmentation,
|
|
4703
4805
|
locations = pts2bold.iloc[:,:3].values
|
4704
4806
|
ptImg = ants.make_points_image( locations, bmask, radius = 2 )
|
4705
4807
|
|
4808
|
+
# optional smoothing
|
4706
4809
|
tr = ants.get_spacing( corrmo['motion_corrected'] )[3]
|
4707
|
-
|
4708
|
-
|
4709
|
-
|
4710
|
-
|
4810
|
+
smth = ( spa, spa, spa, spt ) # this is for sigmaInPhysicalCoordinates = TRUE
|
4811
|
+
simg = ants.smooth_image( corrmo['motion_corrected'], smth, sigma_in_physical_coordinates = True )
|
4812
|
+
|
4813
|
+
ants.image_write(corrmo['motion_corrected'],'/tmp/tempZZZ.nii.gz')
|
4711
4814
|
|
4815
|
+
# collect censoring indices
|
4816
|
+
hlinds = find_indices( corrmo['FD'], FD_threshold )
|
4817
|
+
if verbose:
|
4818
|
+
print("high motion indices")
|
4819
|
+
print( hlinds )
|
4820
|
+
if outlier_threshold < 1.0 and outlier_threshold > 0.0:
|
4821
|
+
fmrimotcorr, hlinds2 = loop_timeseries_censoring( corrmo['motion_corrected'],
|
4822
|
+
threshold=outlier_threshold, verbose=verbose )
|
4823
|
+
hlinds.extend( hlinds2 )
|
4824
|
+
hlinds = list(set(hlinds)) # make unique
|
4825
|
+
|
4826
|
+
# nuisance
|
4827
|
+
globalmat = ants.timeseries_to_matrix( corrmo['motion_corrected'], bmask )
|
4828
|
+
globalsignal = globalmat.mean( axis = 1 )
|
4829
|
+
del globalmat
|
4830
|
+
compcorquantile=0.975
|
4831
|
+
if nc < 1:
|
4832
|
+
globalmat = get_compcor_matrix( corrmo['motion_corrected'], csfAndWM, compcorquantile )
|
4833
|
+
nc = estimate_optimal_pca_components( data=globalmat, variance_threshold=nc)
|
4834
|
+
del globalmat
|
4835
|
+
if verbose:
|
4836
|
+
print("include compcor components as nuisance: " + str(nc))
|
4837
|
+
mycompcor = ants.compcor( corrmo['motion_corrected'],
|
4838
|
+
ncompcor=nc, quantile=compcorquantile, mask = csfAndWM,
|
4839
|
+
filter_type='polynomial', degree=1 )
|
4712
4840
|
nuisance = mycompcor[ 'components' ]
|
4841
|
+
|
4842
|
+
if ica_components > 0:
|
4843
|
+
if verbose:
|
4844
|
+
print("include ica components as nuisance: " + str(ica_components))
|
4845
|
+
ica = FastICA(n_components=ica_components, max_iter=10000, tol=0.001, random_state=42 )
|
4846
|
+
globalmat = ants.timeseries_to_matrix( corrmo['motion_corrected'], csfAndWM )
|
4847
|
+
nuisance_ica = ica.fit_transform(globalmat) # Reconstruct signals
|
4848
|
+
nuisance = np.c_[ nuisance, nuisance_ica ]
|
4849
|
+
del globalmat
|
4850
|
+
|
4851
|
+
# concat all nuisance data
|
4713
4852
|
nuisance = np.c_[ nuisance, mycompcor['basis'] ]
|
4714
4853
|
nuisance = np.c_[ nuisance, corrmo['FD'] ]
|
4854
|
+
nuisance = np.c_[ nuisance, globalsignal ]
|
4855
|
+
|
4856
|
+
# bandpass any data collected before here -- if bandpass requested
|
4857
|
+
if f[0] > 0 and f[1] < 1.0:
|
4858
|
+
if verbose:
|
4859
|
+
print( "bandpass: " + str(f[0]) + " <=> " + str( f[1] ) )
|
4860
|
+
globalmat = ants.timeseries_to_matrix( corrmo['motion_corrected'], bmask )
|
4861
|
+
globalmat = ants.bandpass_filter_matrix( globalmat, tr = tr, lowf=f[0], highf=f[1] ) # some would argue against this
|
4862
|
+
corrmo['motion_corrected'] = ants.matrix_to_timeseries( corrmo['motion_corrected'], globalmat, bmask )
|
4863
|
+
globalmat = ants.timeseries_to_matrix( simg, bmask )
|
4864
|
+
globalmat = ants.bandpass_filter_matrix( globalmat, tr = tr, lowf=f[0], highf=f[1] ) # some would argue against this
|
4865
|
+
simg = ants.matrix_to_timeseries( simg, globalmat, bmask )
|
4866
|
+
nuisance = ants.bandpass_filter_matrix( nuisance, tr = tr, lowf=f[0], highf=f[1] ) # some would argue against this
|
4867
|
+
|
4868
|
+
nuisanceall = nuisance.copy()
|
4869
|
+
if len( hlinds ) > 0 :
|
4870
|
+
if impute and not scrub:
|
4871
|
+
corrmo['FD'] = replace_elements_in_numpy_array( corrmo['FD'], hlinds, corrmo['FD'].mean() )
|
4872
|
+
corrmo['motion_corrected'] = impute_timeseries( corrmo['motion_corrected'], hlinds, method='linear')
|
4873
|
+
simg = simgimp = impute_timeseries( simg, hlinds, method='linear')
|
4874
|
+
elif scrub:
|
4875
|
+
corrmo['FD'] = remove_elements_from_numpy_array( corrmo['FD'], hlinds )
|
4876
|
+
corrmo['motion_corrected'] = remove_volumes_from_timeseries( corrmo['motion_corrected'], hlinds )
|
4877
|
+
simgimp = impute_timeseries( simg, hlinds, method='linear')
|
4878
|
+
nuisance = remove_elements_from_numpy_array( nuisance, hlinds )
|
4879
|
+
simg = remove_volumes_from_timeseries( simg, hlinds )
|
4880
|
+
else:
|
4881
|
+
simgimp = simg
|
4882
|
+
else:
|
4883
|
+
simgimp = simg
|
4884
|
+
|
4885
|
+
if verbose:
|
4886
|
+
print("now regress nuisance")
|
4715
4887
|
|
4716
|
-
gmmat = ants.timeseries_to_matrix(
|
4717
|
-
gmmat = ants.
|
4718
|
-
|
4719
|
-
|
4888
|
+
gmmat = ants.timeseries_to_matrix( simgimp, bmask )
|
4889
|
+
gmmat = ants.regress_components( gmmat, nuisanceall )
|
4890
|
+
simgimp = ants.matrix_to_timeseries(simgimp, gmmat, bmask)
|
4891
|
+
|
4892
|
+
gmmat = ants.timeseries_to_matrix( simg, bmask )
|
4720
4893
|
gmmat = ants.regress_components( gmmat, nuisance )
|
4721
|
-
|
4722
|
-
gsrbold = ants.matrix_to_timeseries(simg, gmmat, gmseg)
|
4894
|
+
simg = ants.matrix_to_timeseries(simg, gmmat, bmask)
|
4723
4895
|
|
4724
|
-
|
4896
|
+
# falff/alff stuff
|
4897
|
+
myfalff=alff_image( simgimp, bmask )
|
4725
4898
|
|
4899
|
+
# structure the output data
|
4726
4900
|
outdict = {}
|
4727
4901
|
outdict['meanBold'] = und
|
4728
4902
|
outdict['pts2bold'] = pts2bold
|
@@ -4741,7 +4915,7 @@ def resting_state_fmri_networks( fmri, fmri_template, t1, t1segmentation,
|
|
4741
4915
|
roiLabel = "ROI" + str(pts2bold.loc[i,'ROI']) + '_' + netLabel
|
4742
4916
|
roiNames.append( roiLabel )
|
4743
4917
|
ptImage = ants.make_points_image(pts2bold.iloc[[i],:3].values, bmask, radius=1).threshold_image( 1, 1e9 )
|
4744
|
-
meanROI[:,i] = ants.timeseries_to_matrix(
|
4918
|
+
meanROI[:,i] = ants.timeseries_to_matrix( simg, ptImage).mean(axis=1)
|
4745
4919
|
|
4746
4920
|
# get full correlation matrix
|
4747
4921
|
corMat = np.corrcoef(meanROI, rowvar=False)
|
@@ -4768,14 +4942,12 @@ def resting_state_fmri_networks( fmri, fmri_template, t1, t1segmentation,
|
|
4768
4942
|
dfnImg = ants.make_points_image(pts2bold.iloc[ww,:3].values, bmask, radius=1).threshold_image( 1, 1e9 )
|
4769
4943
|
if dfnImg.max() >= 1:
|
4770
4944
|
dfnmat = ants.timeseries_to_matrix( simg, ants.threshold_image( dfnImg, 1, dfnImg.max() ) )
|
4771
|
-
dfnmat = ants.bandpass_filter_matrix( dfnmat, tr = tr, lowf=f[0], highf=f[1] )
|
4772
|
-
dfnmat = ants.regress_components( dfnmat, nuisance )
|
4773
4945
|
dfnsignal = dfnmat.mean( axis = 1 )
|
4774
4946
|
gmmatDFNCorr = np.zeros( gmmat.shape[1] )
|
4775
4947
|
for k in range( gmmat.shape[1] ):
|
4776
4948
|
gmmatDFNCorr[ k ] = pearsonr( dfnsignal, gmmat[:,k] )[0]
|
4777
|
-
corrImg = ants.make_image(
|
4778
|
-
outdict[ netname ] = corrImg
|
4949
|
+
corrImg = ants.make_image( bmask, gmmatDFNCorr )
|
4950
|
+
outdict[ netname ] = corrImg * gmseg
|
4779
4951
|
else:
|
4780
4952
|
outdict[ netname ] = None
|
4781
4953
|
ct = ct + 1
|
@@ -4789,7 +4961,6 @@ def resting_state_fmri_networks( fmri, fmri_template, t1, t1segmentation,
|
|
4789
4961
|
netnamei = re.sub( " ", "", networks[numofnets[i]] )
|
4790
4962
|
netnamei = re.sub( "-", "", netnamei )
|
4791
4963
|
newnames.append( netnamei )
|
4792
|
-
binmask = ants.threshold_image( outdict[ netnamei ], 0.2, 1.0 )
|
4793
4964
|
ww = np.where( powers_areal_mni_itk['SystemName'] == networks[numofnets[i]] )[0]
|
4794
4965
|
dfnImg = ants.make_points_image(pts2bold.iloc[ww,:3].values, bmask, radius=1).threshold_image( 1, 1e9 )
|
4795
4966
|
for j in range( len( numofnets ) ):
|
@@ -4808,6 +4979,7 @@ def resting_state_fmri_networks( fmri, fmri_template, t1, t1segmentation,
|
|
4808
4979
|
outdict['corr'] = A
|
4809
4980
|
outdict['corr_wide'] = A_wide
|
4810
4981
|
outdict['brainmask'] = bmask
|
4982
|
+
outdict['gmmask'] = gmseg
|
4811
4983
|
outdict['alff'] = myfalff['alff']
|
4812
4984
|
outdict['falff'] = myfalff['falff']
|
4813
4985
|
# add global mean and standard deviation for post-hoc z-scoring
|
@@ -4834,16 +5006,17 @@ def resting_state_fmri_networks( fmri, fmri_template, t1, t1segmentation,
|
|
4834
5006
|
trimmask = ants.iMath( bmask, "ME",2)
|
4835
5007
|
edgemask = ants.iMath( bmask, "ME",1) - trimmask
|
4836
5008
|
outdict['motion_corrected'] = corrmo['motion_corrected']
|
4837
|
-
outdict['brain_mask'] = bmask
|
4838
5009
|
outdict['nuisance'] = rsfNuisance
|
4839
5010
|
outdict['tsnr'] = mytsnr
|
4840
5011
|
outdict['ssnr'] = slice_snr( corrmo['motion_corrected'], csfAndWM, gmseg )
|
4841
5012
|
outdict['dvars'] = dvars( corrmo['motion_corrected'], gmseg )
|
4842
|
-
outdict['high_motion_count'] =
|
4843
|
-
outdict['high_motion_pct'] =
|
5013
|
+
outdict['high_motion_count'] = high_motion_count
|
5014
|
+
outdict['high_motion_pct'] = high_motion_pct
|
4844
5015
|
outdict['FD_max'] = rsfNuisance['FD'].max()
|
4845
5016
|
outdict['FD_mean'] = rsfNuisance['FD'].mean()
|
4846
5017
|
outdict['bold_evr'] = antspyt1w.patch_eigenvalue_ratio( und, 512, [16,16,16], evdepth = 0.9, mask = bmask )
|
5018
|
+
outdict['n_outliers'] = len(hlinds)
|
5019
|
+
outdict['nc'] = nc
|
4847
5020
|
return outdict
|
4848
5021
|
|
4849
5022
|
|
@@ -5015,8 +5188,9 @@ def bold_perfusion_minimal(
|
|
5015
5188
|
bmask = bmask * ants.iMath( tsnrmask, "FillHoles" )
|
5016
5189
|
fmrimotcorr=corrmo['motion_corrected']
|
5017
5190
|
und = fmri_template * bmask
|
5191
|
+
compcorquantile = 0.975
|
5018
5192
|
mycompcor = ants.compcor( fmrimotcorr,
|
5019
|
-
ncompcor=nc, quantile=
|
5193
|
+
ncompcor=nc, quantile=compcorquantile, mask = bmask,
|
5020
5194
|
filter_type='polynomial', degree=2 )
|
5021
5195
|
tr = ants.get_spacing( fmrimotcorr )[3]
|
5022
5196
|
simg = ants.smooth_image(fmrimotcorr, spa, sigma_in_physical_coordinates = True )
|
@@ -5347,8 +5521,9 @@ def bold_perfusion( fmri, t1head, t1, t1segmentation, t1dktcit,
|
|
5347
5521
|
t1reg['fwdtransforms'], interpolator = 'nearestNeighbor' ) * bmask
|
5348
5522
|
wmseg = ants.apply_transforms( und, wmseg,
|
5349
5523
|
t1reg['fwdtransforms'], interpolator = 'nearestNeighbor' ) * bmask
|
5524
|
+
compcorquantile = 0.975
|
5350
5525
|
mycompcor = ants.compcor( fmrimotcorr,
|
5351
|
-
ncompcor=nc, quantile=
|
5526
|
+
ncompcor=nc, quantile=compcorquantile, mask = csfAndWM,
|
5352
5527
|
filter_type='polynomial', degree=2 )
|
5353
5528
|
tr = ants.get_spacing( fmrimotcorr )[3]
|
5354
5529
|
simg = ants.smooth_image(fmrimotcorr, spa, sigma_in_physical_coordinates = True )
|
@@ -5477,7 +5652,7 @@ Where:
|
|
5477
5652
|
{'cbf' : df_cbf},
|
5478
5653
|
col_names = ['Mean'] )
|
5479
5654
|
df_cbf = df_cbf.add_prefix('cbf_')
|
5480
|
-
df_perf = pd.concat( [df_perf,df_cbf], axis=1 )
|
5655
|
+
df_perf = pd.concat( [df_perf,df_cbf], axis=1, ignore_index=False )
|
5481
5656
|
if verbose:
|
5482
5657
|
print("perfusion dataframe end")
|
5483
5658
|
|
@@ -5501,6 +5676,7 @@ Where:
|
|
5501
5676
|
outdict['bold_evr'] = antspyt1w.patch_eigenvalue_ratio( und, 512, [16,16,16], evdepth = 0.9, mask = bmask )
|
5502
5677
|
outdict['t1reg'] = t1reg
|
5503
5678
|
outdict['outlier_volumes']=hlinds
|
5679
|
+
outdict['n_outliers']=len(hlinds)
|
5504
5680
|
outdict['negative_voxels']=negative_voxels
|
5505
5681
|
return outdict
|
5506
5682
|
|
@@ -5744,8 +5920,10 @@ def mm(
|
|
5744
5920
|
# build a template then join the images
|
5745
5921
|
if verbose:
|
5746
5922
|
print("initial average for rsf")
|
5747
|
-
rsfavg1=
|
5748
|
-
|
5923
|
+
rsfavg1, hlinds = loop_timeseries_censoring( rsf_image1, 0.1 )
|
5924
|
+
rsfavg1=get_average_rsf(rsfavg1)
|
5925
|
+
rsfavg2, hlinds = loop_timeseries_censoring( rsf_image2, 0.1 )
|
5926
|
+
rsfavg2=get_average_rsf(rsfavg2)
|
5749
5927
|
if verbose:
|
5750
5928
|
print("template average for rsf")
|
5751
5929
|
init_temp = ants.image_clone( rsfavg1 )
|
@@ -5765,7 +5943,8 @@ def mm(
|
|
5765
5943
|
rsf_image = rsf_image2
|
5766
5944
|
elif len( rsf_image ) == 1:
|
5767
5945
|
rsf_image = rsf_image[0]
|
5768
|
-
boldTemplate=
|
5946
|
+
boldTemplate, hlinds = loop_timeseries_censoring( rsf_image, 0.1 )
|
5947
|
+
boldTemplate = get_average_rsf(boldTemplate)
|
5769
5948
|
if rsf_image.shape[3] > 10: # FIXME - better heuristic?
|
5770
5949
|
output_dict['rsf'] = resting_state_fmri_networks(
|
5771
5950
|
rsf_image,
|
@@ -6037,7 +6216,7 @@ def write_mm( output_prefix, mm, mm_norm=None, t1wide=None, separator='_', verbo
|
|
6037
6216
|
fat1derk,
|
6038
6217
|
mdt1derk,
|
6039
6218
|
cnxderk
|
6040
|
-
], axis=1 )
|
6219
|
+
], axis=1, ignore_index=False )
|
6041
6220
|
mm_wide = mm_wide.copy()
|
6042
6221
|
if mm['NM'] is not None:
|
6043
6222
|
mm_wide['NM_avg_signaltonoise'] = mm['NM']['NM_avg_signaltonoise']
|
@@ -6066,7 +6245,7 @@ def write_mm( output_prefix, mm, mm_norm=None, t1wide=None, separator='_', verbo
|
|
6066
6245
|
mm_wide['flair_evr'] = mm['flair']['wmh_evr']
|
6067
6246
|
mm_wide['flair_SNR'] = mm['flair']['wmh_SNR']
|
6068
6247
|
if mm['rsf'] is not None:
|
6069
|
-
mynets = list([ 'meanBold', '
|
6248
|
+
mynets = list([ 'meanBold', 'brainmask', 'motion_corrected', 'alff', 'falff',
|
6070
6249
|
'CinguloopercularTaskControl', 'DefaultMode', 'MemoryRetrieval',
|
6071
6250
|
'VentralAttention', 'Visual', 'FrontoparietalTaskControl', 'Salience',
|
6072
6251
|
'Subcortical', 'DorsalAttention', 'tsnr'] )
|
@@ -6075,7 +6254,7 @@ def write_mm( output_prefix, mm, mm_norm=None, t1wide=None, separator='_', verbo
|
|
6075
6254
|
myop = output_prefix + separator + mykey + '.nii.gz'
|
6076
6255
|
image_write_with_thumbnail( rsfpro[mykey], myop, thumb=True )
|
6077
6256
|
rsfpro['corr_wide'].set_index( mm_wide.index, inplace=True )
|
6078
|
-
mm_wide = pd.concat( [ mm_wide, rsfpro['corr_wide'] ], axis=1 )
|
6257
|
+
mm_wide = pd.concat( [ mm_wide, rsfpro['corr_wide'] ], axis=1, ignore_index=False )
|
6079
6258
|
# falff and alff
|
6080
6259
|
search_key='alffPoint'
|
6081
6260
|
alffkeys = [key for key, val in rsfpro.items() if search_key in key]
|
@@ -6085,14 +6264,17 @@ def write_mm( output_prefix, mm, mm_norm=None, t1wide=None, separator='_', verbo
|
|
6085
6264
|
mm_wide['rsf_dvars_mean'] = rsfpro['dvars'].mean()
|
6086
6265
|
mm_wide['rsf_ssnr_mean'] = rsfpro['ssnr'].mean()
|
6087
6266
|
mm_wide['rsf_high_motion_count'] = rsfpro['high_motion_count']
|
6088
|
-
|
6267
|
+
mm_wide['rsf_high_motion_pct'] = rsfpro['high_motion_pct']
|
6089
6268
|
mm_wide['rsf_evr'] = rsfpro['bold_evr']
|
6269
|
+
mm_wide['rsf_n_outliers'] = rsfpro['n_outliers']
|
6090
6270
|
mm_wide['rsf_FD_mean'] = rsfpro['FD_mean']
|
6091
6271
|
mm_wide['rsf_FD_max'] = rsfpro['FD_max']
|
6092
6272
|
mm_wide['rsf_alff_mean'] = rsfpro['alff_mean']
|
6093
6273
|
mm_wide['rsf_alff_sd'] = rsfpro['alff_sd']
|
6094
6274
|
mm_wide['rsf_falff_mean'] = rsfpro['falff_mean']
|
6095
6275
|
mm_wide['rsf_falff_sd'] = rsfpro['falff_sd']
|
6276
|
+
mm_wide['rsf_nc'] = rsfpro['nc']
|
6277
|
+
mm_wide['rsf_n_outliers'] = rsfpro['n_outliers']
|
6096
6278
|
ofn = output_prefix + separator + 'rsfcorr.csv'
|
6097
6279
|
rsfpro['corr'].to_csv( ofn )
|
6098
6280
|
# apply same principle to new correlation matrix, doesn't need to be incorporated with mm_wide
|
@@ -6126,11 +6308,12 @@ def write_mm( output_prefix, mm, mm_norm=None, t1wide=None, separator='_', verbo
|
|
6126
6308
|
mm_wide['ssnr_mean'] = perfpro['ssnr'].mean()
|
6127
6309
|
mm_wide['high_motion_count'] = perfpro['high_motion_count']
|
6128
6310
|
mm_wide['evr'] = perfpro['bold_evr']
|
6311
|
+
mm_wide['n_outliers'] = perfpro['n_outliers']
|
6129
6312
|
mm_wide['FD_mean'] = perfpro['FD_mean']
|
6130
6313
|
mm_wide['FD_max'] = perfpro['FD_max']
|
6131
6314
|
if 'perf_dataframe' in perfpro.keys():
|
6132
6315
|
pderk = perfpro['perf_dataframe'].iloc[: , 1:]
|
6133
|
-
mm_wide = pd.concat( [ mm_wide, pderk ], axis=1 )
|
6316
|
+
mm_wide = pd.concat( [ mm_wide, pderk ], axis=1, ignore_index=False )
|
6134
6317
|
else:
|
6135
6318
|
print("FIXME - perfusion dataframe")
|
6136
6319
|
for mykey in ['perfusion','cbf']:
|
@@ -7585,7 +7768,7 @@ def read_mm_csv( x, is_t1=False, colprefix=None, separator='-', verbose=False ):
|
|
7585
7768
|
return None
|
7586
7769
|
if colprefix is not None:
|
7587
7770
|
xdf.columns=colprefix + xdf.columns
|
7588
|
-
return pd.concat( [df,xdf], axis=1 )
|
7771
|
+
return pd.concat( [df,xdf], axis=1, ignore_index=False )
|
7589
7772
|
|
7590
7773
|
def merge_wides_to_study_dataframe( sdf, processing_dir, separator='-', sid_is_int=True, id_is_int=True, date_is_int=True, report_missing=False,
|
7591
7774
|
progress=False, verbose=False ):
|
@@ -7678,7 +7861,7 @@ progress=False, verbose=False ):
|
|
7678
7861
|
# mm.index=csvrow.index
|
7679
7862
|
uidname = mod_name + '_mmwide_filename'
|
7680
7863
|
mm[ uidname ] = rootid
|
7681
|
-
csvrow=pd.concat( [csvrow,mm], axis=1 )
|
7864
|
+
csvrow=pd.concat( [csvrow,mm], axis=1, ignore_index=False )
|
7682
7865
|
else:
|
7683
7866
|
if verbose and report_missing:
|
7684
7867
|
print( nrgwidefn + " absent")
|
@@ -7688,7 +7871,7 @@ progress=False, verbose=False ):
|
|
7688
7871
|
else:
|
7689
7872
|
csvrow=csvrow.loc[:,~csvrow.columns.duplicated()]
|
7690
7873
|
alldf = alldf.loc[:,~alldf.columns.duplicated()]
|
7691
|
-
alldf = pd.concat( [alldf, csvrow], axis=0, ignore_index=True)
|
7874
|
+
alldf = pd.concat( [alldf, csvrow], axis=0, ignore_index=True )
|
7692
7875
|
return alldf
|
7693
7876
|
|
7694
7877
|
def assemble_modality_specific_dataframes( mm_wide_csvs, hierdfin, nrg_modality, separator='-', progress=None, verbose=False ):
|
@@ -7708,7 +7891,7 @@ def assemble_modality_specific_dataframes( mm_wide_csvs, hierdfin, nrg_modality,
|
|
7708
7891
|
for y in fnsnm:
|
7709
7892
|
temp=read_mm_csv( y, colprefix=moddersub+'_', is_t1=False, separator=separator, verbose=verbose )
|
7710
7893
|
if temp is not None:
|
7711
|
-
nmdf=pd.concat( [nmdf, temp], axis=0)
|
7894
|
+
nmdf=pd.concat( [nmdf, temp], axis=0, ignore_index=False )
|
7712
7895
|
return nmdf
|
7713
7896
|
|
7714
7897
|
def bind_wide_mm_csvs( mm_wide_csvs, merge=True, separator='-', verbose = 0 ) :
|
@@ -7733,7 +7916,7 @@ def bind_wide_mm_csvs( mm_wide_csvs, merge=True, separator='-', verbose = 0 ) :
|
|
7733
7916
|
for y in mm_wide_csvs:
|
7734
7917
|
temp=read_mm_csv( y, colprefix='T1Hier_', separator=separator, is_t1=True )
|
7735
7918
|
if temp is not None:
|
7736
|
-
hierdf=pd.concat( [hierdf, temp], axis=0)
|
7919
|
+
hierdf=pd.concat( [hierdf, temp], axis=0, ignore_index=False )
|
7737
7920
|
if verbose > 0:
|
7738
7921
|
mypro=50
|
7739
7922
|
else:
|
@@ -7846,8 +8029,8 @@ def threaded_bind_wide_mm_csvs( mm_wide_csvs, n_workers ):
|
|
7846
8029
|
results = []
|
7847
8030
|
for future in futures.as_completed(to_do):
|
7848
8031
|
res0, res1 = future.result()
|
7849
|
-
alldf=pd.concat( [alldf, res0 ], axis=0 )
|
7850
|
-
alldfavg=pd.concat( [alldfavg, res1 ], axis=0 )
|
8032
|
+
alldf=pd.concat( [alldf, res0 ], axis=0, ignore_index=False )
|
8033
|
+
alldfavg=pd.concat( [alldfavg, res1 ], axis=0, ignore_index=False )
|
7851
8034
|
return alldf, alldfavg
|
7852
8035
|
|
7853
8036
|
|
@@ -7858,6 +8041,9 @@ def get_names_from_data_frame(x, demogIn, exclusions=None):
|
|
7858
8041
|
antspymm.get_names_from_data_frame( ['a','e'], df )
|
7859
8042
|
antspymm.get_names_from_data_frame( ['e'], df, exclusions='N' )
|
7860
8043
|
"""
|
8044
|
+
# Check if x is a string and convert it to a list
|
8045
|
+
if isinstance(x, str):
|
8046
|
+
x = [x]
|
7861
8047
|
def get_unique( qq ):
|
7862
8048
|
unique = []
|
7863
8049
|
for number in qq:
|
@@ -7936,7 +8122,7 @@ def average_mm_df( jmm_in, diagnostic_n=25, corr_thresh=0.9, verbose=False ):
|
|
7936
8122
|
jmm.loc[k, dt0[1:]] = nanList * len(v1)
|
7937
8123
|
if verbose:
|
7938
8124
|
print( joinDiagnosticsLoc )
|
7939
|
-
joinDiagnostics = pd.concat( [joinDiagnostics, joinDiagnosticsLoc], axis=0)
|
8125
|
+
joinDiagnostics = pd.concat( [joinDiagnostics, joinDiagnosticsLoc], axis=0, ignore_index=False )
|
7940
8126
|
|
7941
8127
|
if verbose:
|
7942
8128
|
print("do DTI")
|
@@ -7990,7 +8176,7 @@ def average_mm_df( jmm_in, diagnostic_n=25, corr_thresh=0.9, verbose=False ):
|
|
7990
8176
|
jmm.loc[k, dt0[1:]] = nanList * len( dt0[1:] )
|
7991
8177
|
if verbose:
|
7992
8178
|
print( joinDiagnosticsLoc )
|
7993
|
-
joinDiagnostics = pd.concat( [joinDiagnostics, joinDiagnosticsLoc], axis=0)
|
8179
|
+
joinDiagnostics = pd.concat( [joinDiagnostics, joinDiagnosticsLoc], axis=0, ignore_index=False )
|
7994
8180
|
|
7995
8181
|
|
7996
8182
|
# first task - sort by u_hier_id
|
@@ -8049,7 +8235,8 @@ def average_mm_df( jmm_in, diagnostic_n=25, corr_thresh=0.9, verbose=False ):
|
|
8049
8235
|
jmmUniq.loc[u][fl_names[1:]] = temp.mean(axis=0)
|
8050
8236
|
else:
|
8051
8237
|
jmmUniq.loc[u][fl_names[1:]] = nanList * temp.shape[1]
|
8052
|
-
joinDiagnostics = pd.concat( [joinDiagnostics, joinDiagnosticsLoc],
|
8238
|
+
joinDiagnostics = pd.concat( [joinDiagnostics, joinDiagnosticsLoc],
|
8239
|
+
axis=0, ignore_index=False )
|
8053
8240
|
|
8054
8241
|
return jmmUniq, jmm, joinDiagnostics
|
8055
8242
|
|
@@ -8453,7 +8640,7 @@ def blind_image_assessment(
|
|
8453
8640
|
viz_filename_use = re.sub( ".png", "_slice"+str(jjj).zfill(4)+".png", viz_filename )
|
8454
8641
|
ants.plot_ortho( image, crop=False, filename=viz_filename_use, flat=True, xyz_lines=False, orient_labels=False, xyz_pad=0, title=ttl, titlefontsize=12, title_dy=-0.02,textfontcolor='red' )
|
8455
8642
|
df = pd.DataFrame([[ mystem, noizlevel, snrref, cnrref, psnrref, ssimref, mymi, asym_err, myevr, msk_vol, spc[0], spc[1], spc[2],org[0], org[1], org[2], image.shape[0], image.shape[1], image.shape[2], jjj, modality, mriseries, mrimfg, mrimodel ]], columns=['filename', 'noise', 'snr', 'cnr', 'psnr', 'ssim', 'mi', 'reflection_err', 'EVR', 'msk_vol', 'spc0','spc1','spc2','org0','org1','org2','dimx','dimy','dimz','slice','modality', 'mriseries', 'mrimfg', 'mrimodel' ])
|
8456
|
-
outdf = pd.concat( [outdf, df ], axis=0 )
|
8643
|
+
outdf = pd.concat( [outdf, df ], axis=0, ignore_index=False )
|
8457
8644
|
if verbose:
|
8458
8645
|
print( outdf )
|
8459
8646
|
if viz_filename is not None:
|
@@ -8638,12 +8825,22 @@ def replace_elements_in_numpy_array(original_array, indices_to_replace, new_valu
|
|
8638
8825
|
if original_array is None:
|
8639
8826
|
return None
|
8640
8827
|
|
8828
|
+
max_index = original_array.size if original_array.ndim == 1 else original_array.shape[0]
|
8829
|
+
|
8830
|
+
# Filter out invalid indices and check for any out-of-bounds indices
|
8831
|
+
valid_indices = []
|
8832
|
+
for idx in indices_to_replace:
|
8833
|
+
if idx < max_index:
|
8834
|
+
valid_indices.append(idx)
|
8835
|
+
else:
|
8836
|
+
warnings.warn(f"Warning: Index {idx} is out of bounds and will be ignored.")
|
8837
|
+
|
8641
8838
|
if original_array.ndim == 1:
|
8642
8839
|
# Replace elements in a 1D array
|
8643
|
-
original_array[
|
8840
|
+
original_array[valid_indices] = new_value
|
8644
8841
|
elif original_array.ndim == 2:
|
8645
8842
|
# Replace rows in a 2D array
|
8646
|
-
original_array[
|
8843
|
+
original_array[valid_indices, :] = new_value
|
8647
8844
|
else:
|
8648
8845
|
raise ValueError("original_array must be either 1D or 2D.")
|
8649
8846
|
|
@@ -8699,13 +8896,14 @@ def remove_volumes_from_timeseries(time_series, volumes_to_remove):
|
|
8699
8896
|
return ants.copy_image_info( time_series, filtered_time_series )
|
8700
8897
|
|
8701
8898
|
|
8702
|
-
def impute_timeseries(time_series, volumes_to_impute, method='linear'):
|
8899
|
+
def impute_timeseries(time_series, volumes_to_impute, method='linear', verbose=False):
|
8703
8900
|
"""
|
8704
8901
|
Impute specified volumes from a time series with interpolated values.
|
8705
8902
|
|
8706
8903
|
:param time_series: ANTsImage representing the time series (4D image).
|
8707
8904
|
:param volumes_to_impute: List of volume indices to impute.
|
8708
8905
|
:param method: Interpolation method ('linear' or other methods if implemented).
|
8906
|
+
:param verbose: boolean
|
8709
8907
|
:return: ANTsImage with specified volumes imputed.
|
8710
8908
|
"""
|
8711
8909
|
if not isinstance(time_series, ants.ANTsImage):
|
@@ -8716,25 +8914,36 @@ def impute_timeseries(time_series, volumes_to_impute, method='linear'):
|
|
8716
8914
|
|
8717
8915
|
# Convert time_series to numpy for manipulation
|
8718
8916
|
time_series_np = time_series.numpy()
|
8917
|
+
total_volumes = time_series_np.shape[3]
|
8918
|
+
|
8919
|
+
# Create a complement list of volumes not to impute
|
8920
|
+
volumes_not_to_impute = [i for i in range(total_volumes) if i not in volumes_to_impute]
|
8921
|
+
|
8922
|
+
# Define the lower and upper bounds
|
8923
|
+
min_valid_index = min(volumes_not_to_impute)
|
8924
|
+
max_valid_index = max(volumes_not_to_impute)
|
8719
8925
|
|
8720
8926
|
for vol_idx in volumes_to_impute:
|
8721
8927
|
# Ensure the volume index is within the valid range
|
8722
|
-
if vol_idx < 0 or vol_idx >=
|
8928
|
+
if vol_idx < 0 or vol_idx >= total_volumes:
|
8723
8929
|
raise ValueError(f"Volume index {vol_idx} is out of bounds.")
|
8724
8930
|
|
8725
|
-
# Find
|
8726
|
-
|
8727
|
-
|
8931
|
+
# Find the nearest valid lower index within the bounds
|
8932
|
+
lower_candidates = [v for v in volumes_not_to_impute if v <= vol_idx]
|
8933
|
+
lower_idx = max(lower_candidates) if lower_candidates else min_valid_index
|
8934
|
+
|
8935
|
+
# Find the nearest valid upper index within the bounds
|
8936
|
+
upper_candidates = [v for v in volumes_not_to_impute if v >= vol_idx]
|
8937
|
+
upper_idx = min(upper_candidates) if upper_candidates else max_valid_index
|
8938
|
+
|
8939
|
+
if verbose:
|
8940
|
+
print(f"Imputing volume {vol_idx} using indices {lower_idx} and {upper_idx}")
|
8728
8941
|
|
8729
8942
|
if method == 'linear':
|
8730
8943
|
# Linear interpolation between the two nearest volumes
|
8731
|
-
|
8732
|
-
|
8733
|
-
|
8734
|
-
else:
|
8735
|
-
lower_volume = time_series_np[..., lower_idx]
|
8736
|
-
upper_volume = time_series_np[..., upper_idx]
|
8737
|
-
interpolated_volume = (lower_volume + upper_volume) / 2
|
8944
|
+
lower_volume = time_series_np[..., lower_idx]
|
8945
|
+
upper_volume = time_series_np[..., upper_idx]
|
8946
|
+
interpolated_volume = (lower_volume + upper_volume) / 2
|
8738
8947
|
else:
|
8739
8948
|
# Placeholder for other interpolation methods
|
8740
8949
|
raise NotImplementedError("Currently, only linear interpolation is implemented.")
|
@@ -8748,7 +8957,6 @@ def impute_timeseries(time_series, volumes_to_impute, method='linear'):
|
|
8748
8957
|
|
8749
8958
|
return imputed_time_series
|
8750
8959
|
|
8751
|
-
|
8752
8960
|
def impute_dwi( dwi, threshold = 0.20, verbose=False ):
|
8753
8961
|
"""
|
8754
8962
|
Identify bad volumes in a dwi and impute them fully automatically.
|
@@ -8777,6 +8985,36 @@ def impute_dwi( dwi, threshold = 0.20, verbose=False ):
|
|
8777
8985
|
return dwi
|
8778
8986
|
return impute_timeseries( dwi, complement )
|
8779
8987
|
|
8988
|
+
def scrub_dwi( dwi, bval, bvec, threshold = 0.20, verbose=False ):
|
8989
|
+
"""
|
8990
|
+
Identify bad volumes in a dwi and impute them fully automatically.
|
8991
|
+
|
8992
|
+
:param dwi: ANTsImage representing the time series (4D image).
|
8993
|
+
:param bval: bval array
|
8994
|
+
:param bvec: bvec array
|
8995
|
+
:param threshold: threshold (0,1) for outlierness (lower means impute more data)
|
8996
|
+
:param verbose: boolean
|
8997
|
+
:return: ANTsImage automatically imputed.
|
8998
|
+
"""
|
8999
|
+
list1 = segment_timeseries_by_meanvalue( dwi )['highermeans']
|
9000
|
+
looped, list2 = loop_timeseries_censoring( dwi, threshold )
|
9001
|
+
if verbose:
|
9002
|
+
print( list1 )
|
9003
|
+
print( list2 )
|
9004
|
+
# Convert lists to sets
|
9005
|
+
set1 = set(list(list1))
|
9006
|
+
set2 = set(list(list2))
|
9007
|
+
# Find the intersection
|
9008
|
+
intersection = set1 & set2
|
9009
|
+
# Find the complement of the intersection
|
9010
|
+
complement = list( (set1 | set2) - intersection )
|
9011
|
+
if verbose:
|
9012
|
+
print( "scrubbing:")
|
9013
|
+
print( complement )
|
9014
|
+
if len( complement ) == 0:
|
9015
|
+
return dwi, bval, bvec
|
9016
|
+
return remove_volumes_from_timeseries( dwi, complement ), remove_elements_from_numpy_array( bval, complement ), remove_elements_from_numpy_array( bvec, complement )
|
9017
|
+
|
8780
9018
|
|
8781
9019
|
def flatten_time_series(time_series):
|
8782
9020
|
"""
|
@@ -9207,6 +9445,42 @@ def brainmap_figure(statistical_df, data_dictionary_path, output_prefix, brain_i
|
|
9207
9445
|
return addem
|
9208
9446
|
|
9209
9447
|
|
9448
|
+
def filter_df(indf, myprefix):
|
9449
|
+
"""
|
9450
|
+
Process and filter a pandas DataFrame, removing certain columns,
|
9451
|
+
filtering based on data types, computing the mean of numeric columns,
|
9452
|
+
and adding a prefix to column names.
|
9453
|
+
|
9454
|
+
Parameters:
|
9455
|
+
indf (pandas.DataFrame): The input DataFrame to be processed.
|
9456
|
+
myprefix (str): A string prefix to be added to the column names
|
9457
|
+
of the processed DataFrame.
|
9458
|
+
|
9459
|
+
Steps:
|
9460
|
+
1. Removes columns with names containing 'Unnamed'.
|
9461
|
+
2. If the DataFrame has no rows, it returns the empty DataFrame.
|
9462
|
+
3. Filters out columns based on the type of the first element,
|
9463
|
+
keeping those that are of type `object`, `int`, or `float`.
|
9464
|
+
4. Removes columns that are of `object` dtype.
|
9465
|
+
5. Calculates the mean of the remaining columns, skipping NaN values.
|
9466
|
+
6. Adds the specified `myprefix` to the column names.
|
9467
|
+
|
9468
|
+
Returns:
|
9469
|
+
pandas.DataFrame: A transformed DataFrame with a single row containing
|
9470
|
+
the mean values of the filtered columns, and with
|
9471
|
+
column names prefixed as specified.
|
9472
|
+
"""
|
9473
|
+
indf = indf.loc[:, ~indf.columns.str.contains('Unnamed*', na=False, regex=True)]
|
9474
|
+
if indf.shape[0] == 0:
|
9475
|
+
return indf
|
9476
|
+
nums = [isinstance(indf[col].iloc[0], (object, int, float)) for col in indf.columns]
|
9477
|
+
indf = indf.loc[:, nums]
|
9478
|
+
indf = indf.loc[:, indf.dtypes != 'object']
|
9479
|
+
indf = pd.DataFrame(indf.mean(axis=0, skipna=True)).T
|
9480
|
+
indf = indf.add_prefix(myprefix)
|
9481
|
+
return indf
|
9482
|
+
|
9483
|
+
|
9210
9484
|
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 ):
|
9211
9485
|
"""
|
9212
9486
|
Aggregate ANTsPyMM results from the specified CSV file and save the aggregated results to a new CSV file.
|
@@ -9235,15 +9509,6 @@ def aggregate_antspymm_results(input_csv, subject_col='subjectID', date_col='dat
|
|
9235
9509
|
import numpy as np
|
9236
9510
|
from glob import glob
|
9237
9511
|
|
9238
|
-
def filter_df( indf, myprefix ):
|
9239
|
-
nums = [isinstance(indf[col].iloc[0], (int, float)) for col in indf.columns]
|
9240
|
-
indf = indf.loc[:, nums]
|
9241
|
-
indf=indf.loc[:, indf.dtypes != 'object' ]
|
9242
|
-
indf = indf.loc[:, ~indf.columns.str.contains('Unnamed*', na=False, regex=True)]
|
9243
|
-
indf = pd.DataFrame(indf.mean(axis=0, skipna=True)).T
|
9244
|
-
indf = indf.add_prefix( myprefix )
|
9245
|
-
return( indf )
|
9246
|
-
|
9247
9512
|
def myread_csv(x, cnms):
|
9248
9513
|
"""
|
9249
9514
|
Reads a CSV file and returns a DataFrame excluding specified columns.
|
@@ -9339,13 +9604,13 @@ def aggregate_antspymm_results(input_csv, subject_col='subjectID', date_col='dat
|
|
9339
9604
|
t1df = filter_df( t1df, mymod+'_')
|
9340
9605
|
dflist = dflist + [t1df]
|
9341
9606
|
|
9342
|
-
hdf = pd.concat( dflist, axis=1)
|
9607
|
+
hdf = pd.concat( dflist, axis=1, ignore_index=False )
|
9343
9608
|
if verbose:
|
9344
9609
|
print( df.loc[locind,'filename'] )
|
9345
9610
|
if myct == 1:
|
9346
9611
|
subdf = df.iloc[[x]]
|
9347
9612
|
hdf.index = subdf.index.copy()
|
9348
|
-
df = pd.concat( [df,hdf], axis=1)
|
9613
|
+
df = pd.concat( [df,hdf], axis=1, ignore_index=False )
|
9349
9614
|
else:
|
9350
9615
|
commcols = list(set(hdf.columns).intersection(df.columns))
|
9351
9616
|
df.loc[locind, commcols] = hdf.loc[0, commcols]
|
@@ -9400,14 +9665,18 @@ def aggregate_antspymm_results_sdf(
|
|
9400
9665
|
import numpy as np
|
9401
9666
|
from glob import glob
|
9402
9667
|
|
9403
|
-
def
|
9404
|
-
|
9405
|
-
|
9406
|
-
|
9407
|
-
|
9408
|
-
|
9409
|
-
|
9410
|
-
|
9668
|
+
def progress_reporter(current_step, total_steps, width=50):
|
9669
|
+
# Calculate the proportion of progress
|
9670
|
+
progress = current_step / total_steps
|
9671
|
+
# Calculate the number of 'filled' characters in the progress bar
|
9672
|
+
filled_length = int(width * progress)
|
9673
|
+
# Create the progress bar string
|
9674
|
+
bar = '█' * filled_length + '-' * (width - filled_length)
|
9675
|
+
# Print the progress bar with percentage
|
9676
|
+
print(f'\rProgress: |{bar}| {int(100 * progress)}%', end='\r')
|
9677
|
+
# Print a new line when the progress is complete
|
9678
|
+
if current_step == total_steps:
|
9679
|
+
print()
|
9411
9680
|
|
9412
9681
|
def myread_csv(x, cnms):
|
9413
9682
|
"""
|
@@ -9451,8 +9720,8 @@ def aggregate_antspymm_results_sdf(
|
|
9451
9720
|
myfn = os.path.basename( df['filename'].iloc[x] )
|
9452
9721
|
temp = myfn.split( splitsep )
|
9453
9722
|
# Generalized search paths
|
9454
|
-
sid0 = temp[0]
|
9455
|
-
sid = str(df[subject_col].iloc[x])
|
9723
|
+
sid0 = str( temp[0] )
|
9724
|
+
sid = str( df[subject_col].iloc[x] )
|
9456
9725
|
if sid0 != sid:
|
9457
9726
|
warnings.warn("OUTER: the id derived from the filename " + sid + " does not match the id stored in the data frame " + sid )
|
9458
9727
|
warnings.warn( "filename is : " + myfn )
|
@@ -9480,18 +9749,20 @@ def aggregate_antspymm_results_sdf(
|
|
9480
9749
|
dfout = pd.DataFrame()
|
9481
9750
|
myct = 0
|
9482
9751
|
for x in range( df.shape[0]):
|
9483
|
-
print("\n\n-------------------------------------------------")
|
9484
9752
|
if verbose:
|
9753
|
+
print("\n\n-------------------------------------------------")
|
9485
9754
|
print(f"{x}...")
|
9755
|
+
else:
|
9756
|
+
progress_reporter(x, df.shape[0], width=500)
|
9486
9757
|
locind = df.index[x]
|
9487
9758
|
myfn = os.path.basename( df['filename'].iloc[x] )
|
9488
|
-
sid = df[subject_col].iloc[x]
|
9759
|
+
sid = str( df[subject_col].iloc[x] )
|
9489
9760
|
tempB = myfn.split( splitsep )
|
9490
|
-
sid0 = tempB[1]
|
9491
|
-
if sid0 != sid:
|
9492
|
-
warnings.warn("INNER: the id derived from the filename " + sid + " does not match the id stored in the data frame " + sid0 )
|
9493
|
-
warnings.warn( "filename is : " + myfn )
|
9494
|
-
warnings.warn( "sid is : " + sid )
|
9761
|
+
sid0 = str(tempB[1])
|
9762
|
+
if sid0 != sid and verbose:
|
9763
|
+
warnings.warn("INNER: the id derived from the filename " + str(sid) + " does not match the id stored in the data frame " + str(sid0) )
|
9764
|
+
warnings.warn( "filename is : " + str(myfn) )
|
9765
|
+
warnings.warn( "sid is : " + str(sid) )
|
9495
9766
|
warnings.warn( "x is : " + str(x) )
|
9496
9767
|
warnings.warn( "index is : " + str(locind) )
|
9497
9768
|
myproj = str(df[project_col].iloc[x])
|
@@ -9526,7 +9797,8 @@ def aggregate_antspymm_results_sdf(
|
|
9526
9797
|
dflist = [hdf]
|
9527
9798
|
|
9528
9799
|
for mymod in vmoddict.keys():
|
9529
|
-
|
9800
|
+
if verbose:
|
9801
|
+
print("\n\n************************* " + mymod + " *************************")
|
9530
9802
|
modalityclass = vmoddict[ mymod ]
|
9531
9803
|
if wild_card_modality_id:
|
9532
9804
|
mymodid = '*'
|
@@ -9539,7 +9811,8 @@ def aggregate_antspymm_results_sdf(
|
|
9539
9811
|
temp = mymodid.split( idsep )
|
9540
9812
|
mymodid = temp[ len( temp )-1 ]
|
9541
9813
|
else:
|
9542
|
-
|
9814
|
+
if verbose:
|
9815
|
+
print("missing")
|
9543
9816
|
continue
|
9544
9817
|
if verbose:
|
9545
9818
|
print( "modality id is " + mymodid + " for modality " + modalityclass + ' modality specific subj ' + sid + ' modality specific id is ' + myid + " its date " + mydate )
|
@@ -9552,7 +9825,10 @@ def aggregate_antspymm_results_sdf(
|
|
9552
9825
|
print( modsearch )
|
9553
9826
|
t1wfn = sorted( glob( modsearch ) )
|
9554
9827
|
if len( t1wfn ) > 1:
|
9555
|
-
|
9828
|
+
nlarge = len(t1wfn)
|
9829
|
+
t1wfn = [ t1wfn[ len(t1wfn)-1 ] ]
|
9830
|
+
warnings.warn("there are " + str( nlarge ) + " number of wide fns with search path " + modsearch + " we take the last of these " + t1wfn[0] )
|
9831
|
+
# raise ValueError("there are " + str( len( t1wfn ) ) + " number of wide fns with search path " + modsearch )
|
9556
9832
|
if len( t1wfn ) == 1:
|
9557
9833
|
if verbose:
|
9558
9834
|
print(t1wfn)
|
@@ -9563,13 +9839,13 @@ def aggregate_antspymm_results_sdf(
|
|
9563
9839
|
if verbose:
|
9564
9840
|
print( " cannot find " + modsearch )
|
9565
9841
|
|
9566
|
-
hdf = pd.concat( dflist, axis=1)
|
9842
|
+
hdf = pd.concat( dflist, axis=1, ignore_index=False)
|
9567
9843
|
if verbose:
|
9568
9844
|
print( "count: " + str( myct ) )
|
9569
9845
|
subdf = df.iloc[[x]]
|
9570
9846
|
hdf.index = subdf.index.copy()
|
9571
|
-
subdf = pd.concat( [subdf,hdf], axis=1)
|
9572
|
-
dfout = pd.concat( [dfout,subdf], axis=0)
|
9847
|
+
subdf = pd.concat( [subdf,hdf], axis=1, ignore_index=False)
|
9848
|
+
dfout = pd.concat( [dfout,subdf], axis=0, ignore_index=False )
|
9573
9849
|
badnames = get_names_from_data_frame( ['Unnamed'], dfout )
|
9574
9850
|
dfout=dfout.drop(badnames, axis=1)
|
9575
9851
|
return( dfout )
|
@@ -0,0 +1,7 @@
|
|
1
|
+
antspymm/__init__.py,sha256=xQWo4DJQ0uK0_7G0kjgrj7SZoar5oB1FCV6jeTpTDcc,3805
|
2
|
+
antspymm/mm.py,sha256=Z1tcO04yl3CHmCbQpDdZocllIZbOw6wRGM-sKEcXcIQ,405265
|
3
|
+
antspymm-1.1.9.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
4
|
+
antspymm-1.1.9.dist-info/METADATA,sha256=FgaDoUndsazM2rNGB5ZG-s3x9pt2e5TFnMDWumUDoT8,14162
|
5
|
+
antspymm-1.1.9.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
6
|
+
antspymm-1.1.9.dist-info/top_level.txt,sha256=iyD1sRhCKzfwKRJLq5ZUeV9xsv1cGQl8Ejp6QwXM1Zg,9
|
7
|
+
antspymm-1.1.9.dist-info/RECORD,,
|
antspymm-1.1.8.dist-info/RECORD
DELETED
@@ -1,7 +0,0 @@
|
|
1
|
-
antspymm/__init__.py,sha256=qKqcY0wEcRsFFNAlz6jP5g6EVWtbVHh1_YbpSb5nQaU,3704
|
2
|
-
antspymm/mm.py,sha256=IqeWKjrtRY4iS3U07JZlmfc6nKDsOzNLMPYy3Mj4Qes,393899
|
3
|
-
antspymm-1.1.8.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
4
|
-
antspymm-1.1.8.dist-info/METADATA,sha256=qqYU8JQ8R_84LqLwo5aeViciGkoY8EbiPE7_s8AUlJA,14162
|
5
|
-
antspymm-1.1.8.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
6
|
-
antspymm-1.1.8.dist-info/top_level.txt,sha256=iyD1sRhCKzfwKRJLq5ZUeV9xsv1cGQl8Ejp6QwXM1Zg,9
|
7
|
-
antspymm-1.1.8.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|