antspymm 1.1.7__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 +5 -0
- antspymm/mm.py +418 -111
- {antspymm-1.1.7.dist-info → antspymm-1.1.9.dist-info}/METADATA +3 -3
- antspymm-1.1.9.dist-info/RECORD +7 -0
- {antspymm-1.1.7.dist-info → antspymm-1.1.9.dist-info}/WHEEL +1 -1
- antspymm-1.1.7.dist-info/RECORD +0 -7
- {antspymm-1.1.7.dist-info → antspymm-1.1.9.dist-info}/LICENSE +0 -0
- {antspymm-1.1.7.dist-info → antspymm-1.1.9.dist-info}/top_level.txt +0 -0
antspymm/__init__.py
CHANGED
@@ -103,9 +103,14 @@ from .mm import docsamson
|
|
103
103
|
from .mm import enantiomorphic_filling_without_mask
|
104
104
|
from .mm import loop_timeseries_censoring
|
105
105
|
from .mm import score_fmri_censoring
|
106
|
+
from .mm import replace_elements_in_numpy_array
|
106
107
|
from .mm import remove_elements_from_numpy_array
|
107
108
|
from .mm import remove_volumes_from_timeseries
|
108
109
|
from .mm import impute_timeseries
|
109
110
|
from .mm import impute_dwi
|
111
|
+
from .mm import scrub_dwi
|
110
112
|
from .mm import timeseries_n3
|
111
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,10 +4603,53 @@ 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.
|
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,
|
4601
4652
|
verbose=False ):
|
4602
|
-
|
4603
4653
|
"""
|
4604
4654
|
Compute resting state network correlation maps based on the J Power labels.
|
4605
4655
|
This will output a map for each of the major network systems.
|
@@ -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,13 +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")
|
4767
|
+
|
4768
|
+
high_motion_count=(corrmo['FD'] > FD_threshold ).sum()
|
4769
|
+
high_motion_pct=high_motion_count / fmri.shape[3]
|
4659
4770
|
|
4771
|
+
# filter mask based on TSNR
|
4660
4772
|
mytsnr = tsnr( corrmo['motion_corrected'], bmask )
|
4661
4773
|
mytsnrThresh = np.quantile( mytsnr.numpy(), 0.995 )
|
4662
4774
|
tsnrmask = ants.threshold_image( mytsnr, 0, mytsnrThresh ).morphology("close",2)
|
4663
4775
|
bmask = bmask * tsnrmask
|
4776
|
+
|
4777
|
+
# anatomical mapping
|
4664
4778
|
und = fmri_template * bmask
|
4665
4779
|
t1reg = ants.registration( und, t1, "SyNBold" )
|
4666
4780
|
if verbose:
|
@@ -4677,14 +4791,7 @@ def resting_state_fmri_networks( fmri, fmri_template, t1, t1segmentation,
|
|
4677
4791
|
ants.threshold_image( t1segmentation, 3, 3 ) ).morphology("erode",1)
|
4678
4792
|
csfAndWM = ants.apply_transforms( und, csfAndWM,
|
4679
4793
|
t1reg['fwdtransforms'], interpolator = 'nearestNeighbor' ) * bmask
|
4680
|
-
|
4681
|
-
# get falff and alff
|
4682
|
-
mycompcor = ants.compcor( corrmo['motion_corrected'],
|
4683
|
-
ncompcor=nc, quantile=0.90, mask = csfAndWM,
|
4684
|
-
filter_type='polynomial', degree=2 )
|
4685
|
-
|
4686
4794
|
nt = corrmo['motion_corrected'].shape[3]
|
4687
|
-
|
4688
4795
|
myvoxes = range(powers_areal_mni_itk.shape[0])
|
4689
4796
|
anat = powers_areal_mni_itk['Anatomy']
|
4690
4797
|
syst = powers_areal_mni_itk['SystemName']
|
@@ -4698,26 +4805,98 @@ def resting_state_fmri_networks( fmri, fmri_template, t1, t1segmentation,
|
|
4698
4805
|
locations = pts2bold.iloc[:,:3].values
|
4699
4806
|
ptImg = ants.make_points_image( locations, bmask, radius = 2 )
|
4700
4807
|
|
4808
|
+
# optional smoothing
|
4701
4809
|
tr = ants.get_spacing( corrmo['motion_corrected'] )[3]
|
4702
|
-
|
4703
|
-
|
4704
|
-
smth = ( spa, spa, spa, spt ) # this is for sigmaInPhysicalCoordinates = F
|
4705
|
-
simg = ants.smooth_image(corrmo['motion_corrected'], smth, sigma_in_physical_coordinates = False )
|
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 )
|
4706
4812
|
|
4813
|
+
ants.image_write(corrmo['motion_corrected'],'/tmp/tempZZZ.nii.gz')
|
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 )
|
4707
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
|
4708
4852
|
nuisance = np.c_[ nuisance, mycompcor['basis'] ]
|
4709
4853
|
nuisance = np.c_[ nuisance, corrmo['FD'] ]
|
4854
|
+
nuisance = np.c_[ nuisance, globalsignal ]
|
4710
4855
|
|
4711
|
-
|
4712
|
-
|
4713
|
-
|
4714
|
-
|
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")
|
4887
|
+
|
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 )
|
4715
4893
|
gmmat = ants.regress_components( gmmat, nuisance )
|
4716
|
-
|
4717
|
-
gsrbold = ants.matrix_to_timeseries(simg, gmmat, gmseg)
|
4894
|
+
simg = ants.matrix_to_timeseries(simg, gmmat, bmask)
|
4718
4895
|
|
4719
|
-
|
4896
|
+
# falff/alff stuff
|
4897
|
+
myfalff=alff_image( simgimp, bmask )
|
4720
4898
|
|
4899
|
+
# structure the output data
|
4721
4900
|
outdict = {}
|
4722
4901
|
outdict['meanBold'] = und
|
4723
4902
|
outdict['pts2bold'] = pts2bold
|
@@ -4736,7 +4915,7 @@ def resting_state_fmri_networks( fmri, fmri_template, t1, t1segmentation,
|
|
4736
4915
|
roiLabel = "ROI" + str(pts2bold.loc[i,'ROI']) + '_' + netLabel
|
4737
4916
|
roiNames.append( roiLabel )
|
4738
4917
|
ptImage = ants.make_points_image(pts2bold.iloc[[i],:3].values, bmask, radius=1).threshold_image( 1, 1e9 )
|
4739
|
-
meanROI[:,i] = ants.timeseries_to_matrix(
|
4918
|
+
meanROI[:,i] = ants.timeseries_to_matrix( simg, ptImage).mean(axis=1)
|
4740
4919
|
|
4741
4920
|
# get full correlation matrix
|
4742
4921
|
corMat = np.corrcoef(meanROI, rowvar=False)
|
@@ -4763,14 +4942,12 @@ def resting_state_fmri_networks( fmri, fmri_template, t1, t1segmentation,
|
|
4763
4942
|
dfnImg = ants.make_points_image(pts2bold.iloc[ww,:3].values, bmask, radius=1).threshold_image( 1, 1e9 )
|
4764
4943
|
if dfnImg.max() >= 1:
|
4765
4944
|
dfnmat = ants.timeseries_to_matrix( simg, ants.threshold_image( dfnImg, 1, dfnImg.max() ) )
|
4766
|
-
dfnmat = ants.bandpass_filter_matrix( dfnmat, tr = tr, lowf=f[0], highf=f[1] )
|
4767
|
-
dfnmat = ants.regress_components( dfnmat, nuisance )
|
4768
4945
|
dfnsignal = dfnmat.mean( axis = 1 )
|
4769
4946
|
gmmatDFNCorr = np.zeros( gmmat.shape[1] )
|
4770
4947
|
for k in range( gmmat.shape[1] ):
|
4771
4948
|
gmmatDFNCorr[ k ] = pearsonr( dfnsignal, gmmat[:,k] )[0]
|
4772
|
-
corrImg = ants.make_image(
|
4773
|
-
outdict[ netname ] = corrImg
|
4949
|
+
corrImg = ants.make_image( bmask, gmmatDFNCorr )
|
4950
|
+
outdict[ netname ] = corrImg * gmseg
|
4774
4951
|
else:
|
4775
4952
|
outdict[ netname ] = None
|
4776
4953
|
ct = ct + 1
|
@@ -4784,7 +4961,6 @@ def resting_state_fmri_networks( fmri, fmri_template, t1, t1segmentation,
|
|
4784
4961
|
netnamei = re.sub( " ", "", networks[numofnets[i]] )
|
4785
4962
|
netnamei = re.sub( "-", "", netnamei )
|
4786
4963
|
newnames.append( netnamei )
|
4787
|
-
binmask = ants.threshold_image( outdict[ netnamei ], 0.2, 1.0 )
|
4788
4964
|
ww = np.where( powers_areal_mni_itk['SystemName'] == networks[numofnets[i]] )[0]
|
4789
4965
|
dfnImg = ants.make_points_image(pts2bold.iloc[ww,:3].values, bmask, radius=1).threshold_image( 1, 1e9 )
|
4790
4966
|
for j in range( len( numofnets ) ):
|
@@ -4803,6 +4979,7 @@ def resting_state_fmri_networks( fmri, fmri_template, t1, t1segmentation,
|
|
4803
4979
|
outdict['corr'] = A
|
4804
4980
|
outdict['corr_wide'] = A_wide
|
4805
4981
|
outdict['brainmask'] = bmask
|
4982
|
+
outdict['gmmask'] = gmseg
|
4806
4983
|
outdict['alff'] = myfalff['alff']
|
4807
4984
|
outdict['falff'] = myfalff['falff']
|
4808
4985
|
# add global mean and standard deviation for post-hoc z-scoring
|
@@ -4829,16 +5006,17 @@ def resting_state_fmri_networks( fmri, fmri_template, t1, t1segmentation,
|
|
4829
5006
|
trimmask = ants.iMath( bmask, "ME",2)
|
4830
5007
|
edgemask = ants.iMath( bmask, "ME",1) - trimmask
|
4831
5008
|
outdict['motion_corrected'] = corrmo['motion_corrected']
|
4832
|
-
outdict['brain_mask'] = bmask
|
4833
5009
|
outdict['nuisance'] = rsfNuisance
|
4834
5010
|
outdict['tsnr'] = mytsnr
|
4835
5011
|
outdict['ssnr'] = slice_snr( corrmo['motion_corrected'], csfAndWM, gmseg )
|
4836
5012
|
outdict['dvars'] = dvars( corrmo['motion_corrected'], gmseg )
|
4837
|
-
outdict['high_motion_count'] =
|
4838
|
-
outdict['high_motion_pct'] =
|
5013
|
+
outdict['high_motion_count'] = high_motion_count
|
5014
|
+
outdict['high_motion_pct'] = high_motion_pct
|
4839
5015
|
outdict['FD_max'] = rsfNuisance['FD'].max()
|
4840
5016
|
outdict['FD_mean'] = rsfNuisance['FD'].mean()
|
4841
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
|
4842
5020
|
return outdict
|
4843
5021
|
|
4844
5022
|
|
@@ -5010,8 +5188,9 @@ def bold_perfusion_minimal(
|
|
5010
5188
|
bmask = bmask * ants.iMath( tsnrmask, "FillHoles" )
|
5011
5189
|
fmrimotcorr=corrmo['motion_corrected']
|
5012
5190
|
und = fmri_template * bmask
|
5191
|
+
compcorquantile = 0.975
|
5013
5192
|
mycompcor = ants.compcor( fmrimotcorr,
|
5014
|
-
ncompcor=nc, quantile=
|
5193
|
+
ncompcor=nc, quantile=compcorquantile, mask = bmask,
|
5015
5194
|
filter_type='polynomial', degree=2 )
|
5016
5195
|
tr = ants.get_spacing( fmrimotcorr )[3]
|
5017
5196
|
simg = ants.smooth_image(fmrimotcorr, spa, sigma_in_physical_coordinates = True )
|
@@ -5342,8 +5521,9 @@ def bold_perfusion( fmri, t1head, t1, t1segmentation, t1dktcit,
|
|
5342
5521
|
t1reg['fwdtransforms'], interpolator = 'nearestNeighbor' ) * bmask
|
5343
5522
|
wmseg = ants.apply_transforms( und, wmseg,
|
5344
5523
|
t1reg['fwdtransforms'], interpolator = 'nearestNeighbor' ) * bmask
|
5524
|
+
compcorquantile = 0.975
|
5345
5525
|
mycompcor = ants.compcor( fmrimotcorr,
|
5346
|
-
ncompcor=nc, quantile=
|
5526
|
+
ncompcor=nc, quantile=compcorquantile, mask = csfAndWM,
|
5347
5527
|
filter_type='polynomial', degree=2 )
|
5348
5528
|
tr = ants.get_spacing( fmrimotcorr )[3]
|
5349
5529
|
simg = ants.smooth_image(fmrimotcorr, spa, sigma_in_physical_coordinates = True )
|
@@ -5472,7 +5652,7 @@ Where:
|
|
5472
5652
|
{'cbf' : df_cbf},
|
5473
5653
|
col_names = ['Mean'] )
|
5474
5654
|
df_cbf = df_cbf.add_prefix('cbf_')
|
5475
|
-
df_perf = pd.concat( [df_perf,df_cbf], axis=1 )
|
5655
|
+
df_perf = pd.concat( [df_perf,df_cbf], axis=1, ignore_index=False )
|
5476
5656
|
if verbose:
|
5477
5657
|
print("perfusion dataframe end")
|
5478
5658
|
|
@@ -5496,6 +5676,7 @@ Where:
|
|
5496
5676
|
outdict['bold_evr'] = antspyt1w.patch_eigenvalue_ratio( und, 512, [16,16,16], evdepth = 0.9, mask = bmask )
|
5497
5677
|
outdict['t1reg'] = t1reg
|
5498
5678
|
outdict['outlier_volumes']=hlinds
|
5679
|
+
outdict['n_outliers']=len(hlinds)
|
5499
5680
|
outdict['negative_voxels']=negative_voxels
|
5500
5681
|
return outdict
|
5501
5682
|
|
@@ -5739,8 +5920,10 @@ def mm(
|
|
5739
5920
|
# build a template then join the images
|
5740
5921
|
if verbose:
|
5741
5922
|
print("initial average for rsf")
|
5742
|
-
rsfavg1=
|
5743
|
-
|
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)
|
5744
5927
|
if verbose:
|
5745
5928
|
print("template average for rsf")
|
5746
5929
|
init_temp = ants.image_clone( rsfavg1 )
|
@@ -5760,17 +5943,14 @@ def mm(
|
|
5760
5943
|
rsf_image = rsf_image2
|
5761
5944
|
elif len( rsf_image ) == 1:
|
5762
5945
|
rsf_image = rsf_image[0]
|
5763
|
-
boldTemplate=
|
5946
|
+
boldTemplate, hlinds = loop_timeseries_censoring( rsf_image, 0.1 )
|
5947
|
+
boldTemplate = get_average_rsf(boldTemplate)
|
5764
5948
|
if rsf_image.shape[3] > 10: # FIXME - better heuristic?
|
5765
5949
|
output_dict['rsf'] = resting_state_fmri_networks(
|
5766
5950
|
rsf_image,
|
5767
5951
|
boldTemplate,
|
5768
5952
|
hier['brain_n4_dnz'],
|
5769
|
-
t1atropos,
|
5770
|
-
f=[0.03,0.08],
|
5771
|
-
spa = 1.0,
|
5772
|
-
spt = 0.5,
|
5773
|
-
nc = 6, verbose=verbose )
|
5953
|
+
t1atropos, verbose=verbose )
|
5774
5954
|
if nm_image_list is not None:
|
5775
5955
|
if verbose:
|
5776
5956
|
print('nm')
|
@@ -6036,7 +6216,7 @@ def write_mm( output_prefix, mm, mm_norm=None, t1wide=None, separator='_', verbo
|
|
6036
6216
|
fat1derk,
|
6037
6217
|
mdt1derk,
|
6038
6218
|
cnxderk
|
6039
|
-
], axis=1 )
|
6219
|
+
], axis=1, ignore_index=False )
|
6040
6220
|
mm_wide = mm_wide.copy()
|
6041
6221
|
if mm['NM'] is not None:
|
6042
6222
|
mm_wide['NM_avg_signaltonoise'] = mm['NM']['NM_avg_signaltonoise']
|
@@ -6065,7 +6245,7 @@ def write_mm( output_prefix, mm, mm_norm=None, t1wide=None, separator='_', verbo
|
|
6065
6245
|
mm_wide['flair_evr'] = mm['flair']['wmh_evr']
|
6066
6246
|
mm_wide['flair_SNR'] = mm['flair']['wmh_SNR']
|
6067
6247
|
if mm['rsf'] is not None:
|
6068
|
-
mynets = list([ 'meanBold', '
|
6248
|
+
mynets = list([ 'meanBold', 'brainmask', 'motion_corrected', 'alff', 'falff',
|
6069
6249
|
'CinguloopercularTaskControl', 'DefaultMode', 'MemoryRetrieval',
|
6070
6250
|
'VentralAttention', 'Visual', 'FrontoparietalTaskControl', 'Salience',
|
6071
6251
|
'Subcortical', 'DorsalAttention', 'tsnr'] )
|
@@ -6074,7 +6254,7 @@ def write_mm( output_prefix, mm, mm_norm=None, t1wide=None, separator='_', verbo
|
|
6074
6254
|
myop = output_prefix + separator + mykey + '.nii.gz'
|
6075
6255
|
image_write_with_thumbnail( rsfpro[mykey], myop, thumb=True )
|
6076
6256
|
rsfpro['corr_wide'].set_index( mm_wide.index, inplace=True )
|
6077
|
-
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 )
|
6078
6258
|
# falff and alff
|
6079
6259
|
search_key='alffPoint'
|
6080
6260
|
alffkeys = [key for key, val in rsfpro.items() if search_key in key]
|
@@ -6084,14 +6264,17 @@ def write_mm( output_prefix, mm, mm_norm=None, t1wide=None, separator='_', verbo
|
|
6084
6264
|
mm_wide['rsf_dvars_mean'] = rsfpro['dvars'].mean()
|
6085
6265
|
mm_wide['rsf_ssnr_mean'] = rsfpro['ssnr'].mean()
|
6086
6266
|
mm_wide['rsf_high_motion_count'] = rsfpro['high_motion_count']
|
6087
|
-
|
6267
|
+
mm_wide['rsf_high_motion_pct'] = rsfpro['high_motion_pct']
|
6088
6268
|
mm_wide['rsf_evr'] = rsfpro['bold_evr']
|
6269
|
+
mm_wide['rsf_n_outliers'] = rsfpro['n_outliers']
|
6089
6270
|
mm_wide['rsf_FD_mean'] = rsfpro['FD_mean']
|
6090
6271
|
mm_wide['rsf_FD_max'] = rsfpro['FD_max']
|
6091
6272
|
mm_wide['rsf_alff_mean'] = rsfpro['alff_mean']
|
6092
6273
|
mm_wide['rsf_alff_sd'] = rsfpro['alff_sd']
|
6093
6274
|
mm_wide['rsf_falff_mean'] = rsfpro['falff_mean']
|
6094
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']
|
6095
6278
|
ofn = output_prefix + separator + 'rsfcorr.csv'
|
6096
6279
|
rsfpro['corr'].to_csv( ofn )
|
6097
6280
|
# apply same principle to new correlation matrix, doesn't need to be incorporated with mm_wide
|
@@ -6125,11 +6308,12 @@ def write_mm( output_prefix, mm, mm_norm=None, t1wide=None, separator='_', verbo
|
|
6125
6308
|
mm_wide['ssnr_mean'] = perfpro['ssnr'].mean()
|
6126
6309
|
mm_wide['high_motion_count'] = perfpro['high_motion_count']
|
6127
6310
|
mm_wide['evr'] = perfpro['bold_evr']
|
6311
|
+
mm_wide['n_outliers'] = perfpro['n_outliers']
|
6128
6312
|
mm_wide['FD_mean'] = perfpro['FD_mean']
|
6129
6313
|
mm_wide['FD_max'] = perfpro['FD_max']
|
6130
6314
|
if 'perf_dataframe' in perfpro.keys():
|
6131
6315
|
pderk = perfpro['perf_dataframe'].iloc[: , 1:]
|
6132
|
-
mm_wide = pd.concat( [ mm_wide, pderk ], axis=1 )
|
6316
|
+
mm_wide = pd.concat( [ mm_wide, pderk ], axis=1, ignore_index=False )
|
6133
6317
|
else:
|
6134
6318
|
print("FIXME - perfusion dataframe")
|
6135
6319
|
for mykey in ['perfusion','cbf']:
|
@@ -7584,7 +7768,7 @@ def read_mm_csv( x, is_t1=False, colprefix=None, separator='-', verbose=False ):
|
|
7584
7768
|
return None
|
7585
7769
|
if colprefix is not None:
|
7586
7770
|
xdf.columns=colprefix + xdf.columns
|
7587
|
-
return pd.concat( [df,xdf], axis=1 )
|
7771
|
+
return pd.concat( [df,xdf], axis=1, ignore_index=False )
|
7588
7772
|
|
7589
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,
|
7590
7774
|
progress=False, verbose=False ):
|
@@ -7610,7 +7794,7 @@ progress=False, verbose=False ):
|
|
7610
7794
|
verbose : boolean
|
7611
7795
|
"""
|
7612
7796
|
from os.path import exists
|
7613
|
-
musthavecols = ['projectID', 'subjectID','date','imageID'
|
7797
|
+
musthavecols = ['projectID', 'subjectID','date','imageID']
|
7614
7798
|
for k in range(len(musthavecols)):
|
7615
7799
|
if not musthavecols[k] in sdf.keys():
|
7616
7800
|
raise ValueError('sdf is missing column ' +musthavecols[k] + ' in merge_wides_to_study_dataframe' )
|
@@ -7677,7 +7861,7 @@ progress=False, verbose=False ):
|
|
7677
7861
|
# mm.index=csvrow.index
|
7678
7862
|
uidname = mod_name + '_mmwide_filename'
|
7679
7863
|
mm[ uidname ] = rootid
|
7680
|
-
csvrow=pd.concat( [csvrow,mm], axis=1 )
|
7864
|
+
csvrow=pd.concat( [csvrow,mm], axis=1, ignore_index=False )
|
7681
7865
|
else:
|
7682
7866
|
if verbose and report_missing:
|
7683
7867
|
print( nrgwidefn + " absent")
|
@@ -7687,7 +7871,7 @@ progress=False, verbose=False ):
|
|
7687
7871
|
else:
|
7688
7872
|
csvrow=csvrow.loc[:,~csvrow.columns.duplicated()]
|
7689
7873
|
alldf = alldf.loc[:,~alldf.columns.duplicated()]
|
7690
|
-
alldf = pd.concat( [alldf, csvrow], axis=0, ignore_index=True)
|
7874
|
+
alldf = pd.concat( [alldf, csvrow], axis=0, ignore_index=True )
|
7691
7875
|
return alldf
|
7692
7876
|
|
7693
7877
|
def assemble_modality_specific_dataframes( mm_wide_csvs, hierdfin, nrg_modality, separator='-', progress=None, verbose=False ):
|
@@ -7707,7 +7891,7 @@ def assemble_modality_specific_dataframes( mm_wide_csvs, hierdfin, nrg_modality,
|
|
7707
7891
|
for y in fnsnm:
|
7708
7892
|
temp=read_mm_csv( y, colprefix=moddersub+'_', is_t1=False, separator=separator, verbose=verbose )
|
7709
7893
|
if temp is not None:
|
7710
|
-
nmdf=pd.concat( [nmdf, temp], axis=0)
|
7894
|
+
nmdf=pd.concat( [nmdf, temp], axis=0, ignore_index=False )
|
7711
7895
|
return nmdf
|
7712
7896
|
|
7713
7897
|
def bind_wide_mm_csvs( mm_wide_csvs, merge=True, separator='-', verbose = 0 ) :
|
@@ -7732,7 +7916,7 @@ def bind_wide_mm_csvs( mm_wide_csvs, merge=True, separator='-', verbose = 0 ) :
|
|
7732
7916
|
for y in mm_wide_csvs:
|
7733
7917
|
temp=read_mm_csv( y, colprefix='T1Hier_', separator=separator, is_t1=True )
|
7734
7918
|
if temp is not None:
|
7735
|
-
hierdf=pd.concat( [hierdf, temp], axis=0)
|
7919
|
+
hierdf=pd.concat( [hierdf, temp], axis=0, ignore_index=False )
|
7736
7920
|
if verbose > 0:
|
7737
7921
|
mypro=50
|
7738
7922
|
else:
|
@@ -7845,8 +8029,8 @@ def threaded_bind_wide_mm_csvs( mm_wide_csvs, n_workers ):
|
|
7845
8029
|
results = []
|
7846
8030
|
for future in futures.as_completed(to_do):
|
7847
8031
|
res0, res1 = future.result()
|
7848
|
-
alldf=pd.concat( [alldf, res0 ], axis=0 )
|
7849
|
-
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 )
|
7850
8034
|
return alldf, alldfavg
|
7851
8035
|
|
7852
8036
|
|
@@ -7857,6 +8041,9 @@ def get_names_from_data_frame(x, demogIn, exclusions=None):
|
|
7857
8041
|
antspymm.get_names_from_data_frame( ['a','e'], df )
|
7858
8042
|
antspymm.get_names_from_data_frame( ['e'], df, exclusions='N' )
|
7859
8043
|
"""
|
8044
|
+
# Check if x is a string and convert it to a list
|
8045
|
+
if isinstance(x, str):
|
8046
|
+
x = [x]
|
7860
8047
|
def get_unique( qq ):
|
7861
8048
|
unique = []
|
7862
8049
|
for number in qq:
|
@@ -7935,7 +8122,7 @@ def average_mm_df( jmm_in, diagnostic_n=25, corr_thresh=0.9, verbose=False ):
|
|
7935
8122
|
jmm.loc[k, dt0[1:]] = nanList * len(v1)
|
7936
8123
|
if verbose:
|
7937
8124
|
print( joinDiagnosticsLoc )
|
7938
|
-
joinDiagnostics = pd.concat( [joinDiagnostics, joinDiagnosticsLoc], axis=0)
|
8125
|
+
joinDiagnostics = pd.concat( [joinDiagnostics, joinDiagnosticsLoc], axis=0, ignore_index=False )
|
7939
8126
|
|
7940
8127
|
if verbose:
|
7941
8128
|
print("do DTI")
|
@@ -7989,7 +8176,7 @@ def average_mm_df( jmm_in, diagnostic_n=25, corr_thresh=0.9, verbose=False ):
|
|
7989
8176
|
jmm.loc[k, dt0[1:]] = nanList * len( dt0[1:] )
|
7990
8177
|
if verbose:
|
7991
8178
|
print( joinDiagnosticsLoc )
|
7992
|
-
joinDiagnostics = pd.concat( [joinDiagnostics, joinDiagnosticsLoc], axis=0)
|
8179
|
+
joinDiagnostics = pd.concat( [joinDiagnostics, joinDiagnosticsLoc], axis=0, ignore_index=False )
|
7993
8180
|
|
7994
8181
|
|
7995
8182
|
# first task - sort by u_hier_id
|
@@ -8048,7 +8235,8 @@ def average_mm_df( jmm_in, diagnostic_n=25, corr_thresh=0.9, verbose=False ):
|
|
8048
8235
|
jmmUniq.loc[u][fl_names[1:]] = temp.mean(axis=0)
|
8049
8236
|
else:
|
8050
8237
|
jmmUniq.loc[u][fl_names[1:]] = nanList * temp.shape[1]
|
8051
|
-
joinDiagnostics = pd.concat( [joinDiagnostics, joinDiagnosticsLoc],
|
8238
|
+
joinDiagnostics = pd.concat( [joinDiagnostics, joinDiagnosticsLoc],
|
8239
|
+
axis=0, ignore_index=False )
|
8052
8240
|
|
8053
8241
|
return jmmUniq, jmm, joinDiagnostics
|
8054
8242
|
|
@@ -8452,7 +8640,7 @@ def blind_image_assessment(
|
|
8452
8640
|
viz_filename_use = re.sub( ".png", "_slice"+str(jjj).zfill(4)+".png", viz_filename )
|
8453
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' )
|
8454
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' ])
|
8455
|
-
outdf = pd.concat( [outdf, df ], axis=0 )
|
8643
|
+
outdf = pd.concat( [outdf, df ], axis=0, ignore_index=False )
|
8456
8644
|
if verbose:
|
8457
8645
|
print( outdf )
|
8458
8646
|
if viz_filename is not None:
|
@@ -8620,6 +8808,46 @@ def wmh( flair, t1, t1seg,
|
|
8620
8808
|
'convexhull_mask': distmask }
|
8621
8809
|
|
8622
8810
|
|
8811
|
+
def replace_elements_in_numpy_array(original_array, indices_to_replace, new_value):
|
8812
|
+
"""
|
8813
|
+
Replace specified elements or rows in a numpy array with a new value.
|
8814
|
+
|
8815
|
+
Parameters:
|
8816
|
+
original_array (numpy.ndarray): A numpy array in which elements or rows are to be replaced.
|
8817
|
+
indices_to_replace (list or numpy.ndarray): Indices of elements or rows to be replaced.
|
8818
|
+
new_value: The new value to replace the specified elements or rows.
|
8819
|
+
|
8820
|
+
Returns:
|
8821
|
+
numpy.ndarray: A new numpy array with the specified elements or rows replaced. If the input array is None,
|
8822
|
+
the function returns None.
|
8823
|
+
"""
|
8824
|
+
|
8825
|
+
if original_array is None:
|
8826
|
+
return None
|
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
|
+
|
8838
|
+
if original_array.ndim == 1:
|
8839
|
+
# Replace elements in a 1D array
|
8840
|
+
original_array[valid_indices] = new_value
|
8841
|
+
elif original_array.ndim == 2:
|
8842
|
+
# Replace rows in a 2D array
|
8843
|
+
original_array[valid_indices, :] = new_value
|
8844
|
+
else:
|
8845
|
+
raise ValueError("original_array must be either 1D or 2D.")
|
8846
|
+
|
8847
|
+
return original_array
|
8848
|
+
|
8849
|
+
|
8850
|
+
|
8623
8851
|
def remove_elements_from_numpy_array(original_array, indices_to_remove):
|
8624
8852
|
"""
|
8625
8853
|
Remove specified elements or rows from a numpy array.
|
@@ -8668,13 +8896,14 @@ def remove_volumes_from_timeseries(time_series, volumes_to_remove):
|
|
8668
8896
|
return ants.copy_image_info( time_series, filtered_time_series )
|
8669
8897
|
|
8670
8898
|
|
8671
|
-
def impute_timeseries(time_series, volumes_to_impute, method='linear'):
|
8899
|
+
def impute_timeseries(time_series, volumes_to_impute, method='linear', verbose=False):
|
8672
8900
|
"""
|
8673
8901
|
Impute specified volumes from a time series with interpolated values.
|
8674
8902
|
|
8675
8903
|
:param time_series: ANTsImage representing the time series (4D image).
|
8676
8904
|
:param volumes_to_impute: List of volume indices to impute.
|
8677
8905
|
:param method: Interpolation method ('linear' or other methods if implemented).
|
8906
|
+
:param verbose: boolean
|
8678
8907
|
:return: ANTsImage with specified volumes imputed.
|
8679
8908
|
"""
|
8680
8909
|
if not isinstance(time_series, ants.ANTsImage):
|
@@ -8685,25 +8914,36 @@ def impute_timeseries(time_series, volumes_to_impute, method='linear'):
|
|
8685
8914
|
|
8686
8915
|
# Convert time_series to numpy for manipulation
|
8687
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)
|
8688
8925
|
|
8689
8926
|
for vol_idx in volumes_to_impute:
|
8690
8927
|
# Ensure the volume index is within the valid range
|
8691
|
-
if vol_idx < 0 or vol_idx >=
|
8928
|
+
if vol_idx < 0 or vol_idx >= total_volumes:
|
8692
8929
|
raise ValueError(f"Volume index {vol_idx} is out of bounds.")
|
8693
8930
|
|
8694
|
-
# Find
|
8695
|
-
|
8696
|
-
|
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}")
|
8697
8941
|
|
8698
8942
|
if method == 'linear':
|
8699
8943
|
# Linear interpolation between the two nearest volumes
|
8700
|
-
|
8701
|
-
|
8702
|
-
|
8703
|
-
else:
|
8704
|
-
lower_volume = time_series_np[..., lower_idx]
|
8705
|
-
upper_volume = time_series_np[..., upper_idx]
|
8706
|
-
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
|
8707
8947
|
else:
|
8708
8948
|
# Placeholder for other interpolation methods
|
8709
8949
|
raise NotImplementedError("Currently, only linear interpolation is implemented.")
|
@@ -8717,7 +8957,6 @@ def impute_timeseries(time_series, volumes_to_impute, method='linear'):
|
|
8717
8957
|
|
8718
8958
|
return imputed_time_series
|
8719
8959
|
|
8720
|
-
|
8721
8960
|
def impute_dwi( dwi, threshold = 0.20, verbose=False ):
|
8722
8961
|
"""
|
8723
8962
|
Identify bad volumes in a dwi and impute them fully automatically.
|
@@ -8746,6 +8985,36 @@ def impute_dwi( dwi, threshold = 0.20, verbose=False ):
|
|
8746
8985
|
return dwi
|
8747
8986
|
return impute_timeseries( dwi, complement )
|
8748
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
|
+
|
8749
9018
|
|
8750
9019
|
def flatten_time_series(time_series):
|
8751
9020
|
"""
|
@@ -9176,6 +9445,42 @@ def brainmap_figure(statistical_df, data_dictionary_path, output_prefix, brain_i
|
|
9176
9445
|
return addem
|
9177
9446
|
|
9178
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
|
+
|
9179
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 ):
|
9180
9485
|
"""
|
9181
9486
|
Aggregate ANTsPyMM results from the specified CSV file and save the aggregated results to a new CSV file.
|
@@ -9204,15 +9509,6 @@ def aggregate_antspymm_results(input_csv, subject_col='subjectID', date_col='dat
|
|
9204
9509
|
import numpy as np
|
9205
9510
|
from glob import glob
|
9206
9511
|
|
9207
|
-
def filter_df( indf, myprefix ):
|
9208
|
-
nums = [isinstance(indf[col].iloc[0], (int, float)) for col in indf.columns]
|
9209
|
-
indf = indf.loc[:, nums]
|
9210
|
-
indf=indf.loc[:, indf.dtypes != 'object' ]
|
9211
|
-
indf = indf.loc[:, ~indf.columns.str.contains('Unnamed*', na=False, regex=True)]
|
9212
|
-
indf = pd.DataFrame(indf.mean(axis=0, skipna=True)).T
|
9213
|
-
indf = indf.add_prefix( myprefix )
|
9214
|
-
return( indf )
|
9215
|
-
|
9216
9512
|
def myread_csv(x, cnms):
|
9217
9513
|
"""
|
9218
9514
|
Reads a CSV file and returns a DataFrame excluding specified columns.
|
@@ -9308,13 +9604,13 @@ def aggregate_antspymm_results(input_csv, subject_col='subjectID', date_col='dat
|
|
9308
9604
|
t1df = filter_df( t1df, mymod+'_')
|
9309
9605
|
dflist = dflist + [t1df]
|
9310
9606
|
|
9311
|
-
hdf = pd.concat( dflist, axis=1)
|
9607
|
+
hdf = pd.concat( dflist, axis=1, ignore_index=False )
|
9312
9608
|
if verbose:
|
9313
9609
|
print( df.loc[locind,'filename'] )
|
9314
9610
|
if myct == 1:
|
9315
9611
|
subdf = df.iloc[[x]]
|
9316
9612
|
hdf.index = subdf.index.copy()
|
9317
|
-
df = pd.concat( [df,hdf], axis=1)
|
9613
|
+
df = pd.concat( [df,hdf], axis=1, ignore_index=False )
|
9318
9614
|
else:
|
9319
9615
|
commcols = list(set(hdf.columns).intersection(df.columns))
|
9320
9616
|
df.loc[locind, commcols] = hdf.loc[0, commcols]
|
@@ -9369,14 +9665,18 @@ def aggregate_antspymm_results_sdf(
|
|
9369
9665
|
import numpy as np
|
9370
9666
|
from glob import glob
|
9371
9667
|
|
9372
|
-
def
|
9373
|
-
|
9374
|
-
|
9375
|
-
|
9376
|
-
|
9377
|
-
|
9378
|
-
|
9379
|
-
|
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()
|
9380
9680
|
|
9381
9681
|
def myread_csv(x, cnms):
|
9382
9682
|
"""
|
@@ -9420,8 +9720,8 @@ def aggregate_antspymm_results_sdf(
|
|
9420
9720
|
myfn = os.path.basename( df['filename'].iloc[x] )
|
9421
9721
|
temp = myfn.split( splitsep )
|
9422
9722
|
# Generalized search paths
|
9423
|
-
sid0 = temp[0]
|
9424
|
-
sid = str(df[subject_col].iloc[x])
|
9723
|
+
sid0 = str( temp[0] )
|
9724
|
+
sid = str( df[subject_col].iloc[x] )
|
9425
9725
|
if sid0 != sid:
|
9426
9726
|
warnings.warn("OUTER: the id derived from the filename " + sid + " does not match the id stored in the data frame " + sid )
|
9427
9727
|
warnings.warn( "filename is : " + myfn )
|
@@ -9449,18 +9749,20 @@ def aggregate_antspymm_results_sdf(
|
|
9449
9749
|
dfout = pd.DataFrame()
|
9450
9750
|
myct = 0
|
9451
9751
|
for x in range( df.shape[0]):
|
9452
|
-
print("\n\n-------------------------------------------------")
|
9453
9752
|
if verbose:
|
9753
|
+
print("\n\n-------------------------------------------------")
|
9454
9754
|
print(f"{x}...")
|
9755
|
+
else:
|
9756
|
+
progress_reporter(x, df.shape[0], width=500)
|
9455
9757
|
locind = df.index[x]
|
9456
9758
|
myfn = os.path.basename( df['filename'].iloc[x] )
|
9457
|
-
sid = df[subject_col].iloc[x]
|
9759
|
+
sid = str( df[subject_col].iloc[x] )
|
9458
9760
|
tempB = myfn.split( splitsep )
|
9459
|
-
sid0 = tempB[1]
|
9460
|
-
if sid0 != sid:
|
9461
|
-
warnings.warn("INNER: the id derived from the filename " + sid + " does not match the id stored in the data frame " + sid0 )
|
9462
|
-
warnings.warn( "filename is : " + myfn )
|
9463
|
-
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) )
|
9464
9766
|
warnings.warn( "x is : " + str(x) )
|
9465
9767
|
warnings.warn( "index is : " + str(locind) )
|
9466
9768
|
myproj = str(df[project_col].iloc[x])
|
@@ -9495,7 +9797,8 @@ def aggregate_antspymm_results_sdf(
|
|
9495
9797
|
dflist = [hdf]
|
9496
9798
|
|
9497
9799
|
for mymod in vmoddict.keys():
|
9498
|
-
|
9800
|
+
if verbose:
|
9801
|
+
print("\n\n************************* " + mymod + " *************************")
|
9499
9802
|
modalityclass = vmoddict[ mymod ]
|
9500
9803
|
if wild_card_modality_id:
|
9501
9804
|
mymodid = '*'
|
@@ -9508,7 +9811,8 @@ def aggregate_antspymm_results_sdf(
|
|
9508
9811
|
temp = mymodid.split( idsep )
|
9509
9812
|
mymodid = temp[ len( temp )-1 ]
|
9510
9813
|
else:
|
9511
|
-
|
9814
|
+
if verbose:
|
9815
|
+
print("missing")
|
9512
9816
|
continue
|
9513
9817
|
if verbose:
|
9514
9818
|
print( "modality id is " + mymodid + " for modality " + modalityclass + ' modality specific subj ' + sid + ' modality specific id is ' + myid + " its date " + mydate )
|
@@ -9521,7 +9825,10 @@ def aggregate_antspymm_results_sdf(
|
|
9521
9825
|
print( modsearch )
|
9522
9826
|
t1wfn = sorted( glob( modsearch ) )
|
9523
9827
|
if len( t1wfn ) > 1:
|
9524
|
-
|
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 )
|
9525
9832
|
if len( t1wfn ) == 1:
|
9526
9833
|
if verbose:
|
9527
9834
|
print(t1wfn)
|
@@ -9532,13 +9839,13 @@ def aggregate_antspymm_results_sdf(
|
|
9532
9839
|
if verbose:
|
9533
9840
|
print( " cannot find " + modsearch )
|
9534
9841
|
|
9535
|
-
hdf = pd.concat( dflist, axis=1)
|
9842
|
+
hdf = pd.concat( dflist, axis=1, ignore_index=False)
|
9536
9843
|
if verbose:
|
9537
9844
|
print( "count: " + str( myct ) )
|
9538
9845
|
subdf = df.iloc[[x]]
|
9539
9846
|
hdf.index = subdf.index.copy()
|
9540
|
-
subdf = pd.concat( [subdf,hdf], axis=1)
|
9541
|
-
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 )
|
9542
9849
|
badnames = get_names_from_data_frame( ['Unnamed'], dfout )
|
9543
9850
|
dfout=dfout.drop(badnames, axis=1)
|
9544
9851
|
return( dfout )
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: antspymm
|
3
|
-
Version: 1.1.
|
3
|
+
Version: 1.1.9
|
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
|
@@ -337,8 +337,8 @@ for each subject/timepoint, one would run:
|
|
337
337
|
studyfn="matched_mm_data2.csv"
|
338
338
|
df=pd.read_csv( studyfn )
|
339
339
|
index = 20 # 20th subject/timepoint
|
340
|
-
csvfns = df['
|
341
|
-
csvrow = df[ df['
|
340
|
+
csvfns = df['filename']
|
341
|
+
csvrow = df[ df['filename'] == csvfns[index] ]
|
342
342
|
csvrow['projectID']='MyStudy'
|
343
343
|
|
344
344
|
############################################################################################
|
@@ -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.7.dist-info/RECORD
DELETED
@@ -1,7 +0,0 @@
|
|
1
|
-
antspymm/__init__.py,sha256=DaLNk25DbKwtBnX_IKBnSK99tHCeU17M-OYUTfxR3pw,3656
|
2
|
-
antspymm/mm.py,sha256=hQIzKhltVHICtS9z9iYjE0rMjQO-zxXm0pHihLjkNV8,392560
|
3
|
-
antspymm-1.1.7.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
4
|
-
antspymm-1.1.7.dist-info/METADATA,sha256=uK0Aigxxr7MWmsgs58OCa2CH9ykZvrY0RosKdIE1u8c,14150
|
5
|
-
antspymm-1.1.7.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
|
6
|
-
antspymm-1.1.7.dist-info/top_level.txt,sha256=iyD1sRhCKzfwKRJLq5ZUeV9xsv1cGQl8Ejp6QwXM1Zg,9
|
7
|
-
antspymm-1.1.7.dist-info/RECORD,,
|
File without changes
|
File without changes
|