@@ -394,16 +394,22 @@ class CompCorInputSpec(BaseInterfaceInputSpec):
394
394
'components_file.txt',
395
395
usedefault=True,
396
396
desc='Filename to store physiological components')
397
- num_components = traits.Float(6, usedefault=True,
398
- desc='Number of components to return from the decomposition.'
399
- 'If `num_components` is a positive integer, then '
400
- '`num_components` components will be retained. If '
401
- '`num_components` is a fractional value between 0 and 1, then '
397
+ num_components = traits.Either('all', traits.Int,
398
+ xor=['variance_threshold'],
399
+ desc='Number of components to return from the decomposition. If '
400
+ '`num_components` is `all`, then all components will be '
401
+ 'retained.')
402
+ # 6 for BOLD, 4 for ASL
403
+ # automatically instantiated to 6 in CompCor below if neither
404
+ # `num_components` nor `variance_threshold` is defined (for
405
+ # backward compatibility)
406
+ variance_threshold = traits.Float(xor=['num_components'],
407
+ desc='Select the number of components to be returned automatically '
408
+ 'based on their ability to explain variance in the dataset. '
409
+ '`variance_threshold` is a fractional value between 0 and 1; '
402
410
'the number of components retained will be equal to the minimum '
403
411
'number of components necessary to explain the provided '
404
- 'fraction of variance in the masked time series. If '
405
- '`num_components` is -1, then all components will be retained.')
406
- # 6 for BOLD, 4 for ASL
412
+ 'fraction of variance in the masked time series.')
407
413
pre_filter = traits.Enum(
408
414
'polynomial',
409
415
'cosine',
@@ -564,8 +570,20 @@ def _run_interface(self, runtime):
564
570
'{} cannot detect repetition time from image - '
565
571
'Set the repetition_time input'.format(self._header))
566
572
573
+ if isdefined(self.inputs.variance_threshold):
574
+ components_criterion = self.inputs.variance_threshold
575
+ elif isdefined(self.inputs.num_components):
576
+ components_criterion = self.inputs.num_components
577
+ else:
578
+ components_criterion = 6
579
+ IFLOGGER.warning('`num_components` and `variance_threshold` are '
580
+ 'not defined. Setting number of components to 6 '
581
+ 'for backward compatibility. Please set either '
582
+ '`num_components` or `variance_threshold`, as '
583
+ 'this feature may be deprecated in the future.')
584
+
567
585
components, filter_basis, metadata = compute_noise_components(
568
- imgseries.get_data(), mask_images, self.inputs.num_components ,
586
+ imgseries.get_data(), mask_images, components_criterion ,
569
587
self.inputs.pre_filter, degree, self.inputs.high_pass_cutoff, TR,
570
588
self.inputs.failure_mode, self.inputs.mask_names)
571
589
@@ -1191,7 +1209,7 @@ def compute_noise_components(imgseries, mask_images, components_criterion=0.5,
1191
1209
Number of noise components to return. If this is a decimal value
1192
1210
between 0 and 1, then `create_noise_components` will instead return
1193
1211
the smallest number of components necessary to explain the indicated
1194
- fraction of variance. If `components_criterion` is -1 , then all
1212
+ fraction of variance. If `components_criterion` is `all` , then all
1195
1213
components will be returned.
1196
1214
filter_type: str
1197
1215
Type of filter to apply to time series before computing
@@ -1218,6 +1236,8 @@ def compute_noise_components(imgseries, mask_images, components_criterion=0.5,
1218
1236
"""
1219
1237
components = None
1220
1238
basis = np.array([])
1239
+ if components_criterion == 'all':
1240
+ components_criterion = -1
1221
1241
if not mask_names:
1222
1242
mask_names = range(len(mask_images))
1223
1243
for i, img in zip(mask_names, mask_images):
0 commit comments