Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

moving eimask to execute in make_adaptive_mask #491

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file modified .all-contributorsrc
100644 → 100755
Empty file.
Empty file modified .circleci/config.yml
100644 → 100755
Empty file.
Empty file modified .codecov.yml
100644 → 100755
Empty file.
Empty file modified .dockerignore
100644 → 100755
Empty file.
Empty file modified .gitattributes
100644 → 100755
Empty file.
Empty file modified .github/ISSUE_TEMPLATE/issue_template.md
100644 → 100755
Empty file.
Empty file modified .github/pull_request_template.md
100644 → 100755
Empty file.
Empty file modified .github/release-drafter.yml
100644 → 100755
Empty file.
Empty file modified .github/stale.yml
100644 → 100755
Empty file.
Empty file modified .gitignore
100644 → 100755
Empty file.
Empty file modified .zenodo.json
100644 → 100755
Empty file.
Empty file modified CODE_OF_CONDUCT.md
100644 → 100755
Empty file.
Empty file modified CONTRIBUTING.md
100644 → 100755
Empty file.
Empty file modified Dockerfile_dev
100644 → 100755
Empty file.
Empty file modified LICENSE
100644 → 100755
Empty file.
Empty file modified MANIFEST.in
100644 → 100755
Empty file.
Empty file modified Makefile
100644 → 100755
Empty file.
Empty file modified README.md
100644 → 100755
Empty file.
Empty file modified dev_requirements.txt
100644 → 100755
Empty file.
Empty file modified dev_tools/run_tests.sh
100644 → 100755
Empty file.
Empty file modified docs/Makefile
100644 → 100755
Empty file.
Empty file modified docs/_static/a01_echo_timeseries.png
100644 → 100755
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified docs/_static/a02_echo_value_distributions.png
100644 → 100755
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified docs/_static/a03_adaptive_mask.png
100644 → 100755
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified docs/_static/a04_echo_log_value_distributions.png
100644 → 100755
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified docs/_static/a05_loglinear_regression.png
100644 → 100755
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified docs/_static/a06_monoexponential_decay_model.png
100644 → 100755
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified docs/_static/a07_monoexponential_decay_model_with_t2.png
100644 → 100755
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified docs/_static/a08_optimal_combination_echo_weights.png
100644 → 100755
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified docs/_static/a09_optimal_combination_value_distributions.png
100644 → 100755
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified docs/_static/a10_optimal_combination_timeseries.png
100644 → 100755
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified docs/_static/a11_pca_component_timeseries.png
100644 → 100755
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified docs/_static/a12_pca_reduced_data.png
100644 → 100755
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified docs/_static/a13_ica_component_timeseries.png
100644 → 100755
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified docs/_static/a14_te_dependence_models_component_0.png
100644 → 100755
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified docs/_static/a14_te_dependence_models_component_1.png
100644 → 100755
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified docs/_static/a14_te_dependence_models_component_2.png
100644 → 100755
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified docs/_static/a15_denoised_data_timeseries.png
100644 → 100755
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified docs/_static/a16_t1c_denoised_data_timeseries.png
100644 → 100755
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified docs/_static/b01_simulated_fluctuations.png
100644 → 100755
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified docs/_static/b02_model_fits.png
100644 → 100755
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified docs/_static/b03_component_timeseries.png
100644 → 100755
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified docs/_static/b04_component_model_fits.png
100644 → 100755
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified docs/_static/b04_echo_timeseries.png
100644 → 100755
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified docs/_static/b05_component_model_fits.png
100644 → 100755
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified docs/_static/example_Component_Overview.png
100644 → 100755
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified docs/_static/example_Kappa_vs_Rho_Scatter.png
100644 → 100755
Empty file modified docs/_static/example_bad_component.png
100644 → 100755
Empty file modified docs/_static/example_good_component.png
100644 → 100755
Empty file modified docs/_static/physics_kundu_2017_TE_dependence.jpg
100644 → 100755
Empty file modified docs/_static/physics_kundu_2017_multiple_echoes.jpg
100644 → 100755
Empty file modified docs/_static/tedana-ohbm2018-poster.png
100644 → 100755
Empty file modified docs/_static/tedana-ohbm2019-poster.png
100644 → 100755
Empty file modified docs/_static/tedana-workflow.png
100644 → 100755
Empty file modified docs/_static/tedana_favicon.png
100644 → 100755
Empty file modified docs/_static/theme_overrides.css
100644 → 100755
Empty file.
Empty file modified docs/_templates/function.rst
100644 → 100755
Empty file.
Empty file modified docs/_templates/module.rst
100644 → 100755
Empty file.
Empty file modified docs/api.rst
100644 → 100755
Empty file.
Empty file modified docs/approach.rst
100644 → 100755
Empty file.
Empty file modified docs/conf.py
100644 → 100755
Empty file.
Empty file modified docs/considerations.rst
100644 → 100755
Empty file.
Empty file modified docs/contributing.rst
100644 → 100755
Empty file.
Empty file modified docs/dependence_metrics.rst
100644 → 100755
Empty file.
Empty file modified docs/faq.rst
100644 → 100755
Empty file.
Empty file modified docs/index.rst
100644 → 100755
Empty file.
Empty file modified docs/installation.rst
100644 → 100755
Empty file.
Empty file modified docs/make.bat
100644 → 100755
Empty file.
Empty file modified docs/multi-echo.rst
100644 → 100755
Empty file.
Empty file modified docs/outputs.rst
100644 → 100755
Empty file.
Empty file modified docs/publications.rst
100644 → 100755
Empty file.
Empty file modified docs/roadmap.rst
100644 → 100755
Empty file.
Empty file modified docs/sphinxext/github_link.py
100644 → 100755
Empty file.
Empty file modified docs/support.rst
100644 → 100755
Empty file.
Empty file modified docs/usage.rst
100644 → 100755
Empty file.
Empty file modified examples/plot_approach_figures.ipynb
100644 → 100755
Empty file.
Empty file modified examples/plot_metric_simulations.ipynb
100644 → 100755
Empty file.
Empty file modified requirements.txt
100644 → 100755
Empty file.
Empty file modified setup.cfg
100644 → 100755
Empty file.
Empty file modified setup.py
100644 → 100755
Empty file.
Empty file modified tedana/__init__.py
100644 → 100755
Empty file.
Empty file modified tedana/_version.py
100644 → 100755
Empty file.
Empty file modified tedana/combine.py
100644 → 100755
Empty file.
Empty file modified tedana/decay.py
100644 → 100755
Empty file.
Empty file modified tedana/decomposition/__init__.py
100644 → 100755
Empty file.
47 changes: 0 additions & 47 deletions tedana/decomposition/_utils.py

This file was deleted.

Empty file modified tedana/decomposition/ica.py
100644 → 100755
Empty file.
Empty file modified tedana/decomposition/ma_pca.py
100644 → 100755
Empty file.
16 changes: 4 additions & 12 deletions tedana/decomposition/pca.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from sklearn.decomposition import PCA

from tedana import metrics, utils, io
from tedana.decomposition import (ma_pca, _utils)
from tedana.decomposition import ma_pca
from tedana.stats import computefeats2
from tedana.selection import kundu_tedpca
from tedana.due import due, BibTeX
Expand Down Expand Up @@ -255,17 +255,15 @@ def tedpca(data_cat, data_oc, combmode, mask, t2s, t2sG,
LGR.info('Computing PCA of echo #{0}'.format(','.join([str(ee) for ee in source_tes])))
data = np.stack([data_cat[mask, ee, :] for ee in source_tes - 1], axis=1)

eim = np.squeeze(_utils.eimask(data))
data = np.squeeze(data[eim])
data = np.squeeze(data)

data_z = ((data.T - data.T.mean(axis=0)) / data.T.std(axis=0)).T # var normalize ts
data_z = (data_z - data_z.mean()) / data_z.std() # var normalize everything

if algorithm in ['mdl', 'aic', 'kic']:
data_img = io.new_nii_like(
ref_img, utils.unmask(utils.unmask(data, eim), mask))
mask_img = io.new_nii_like(ref_img,
utils.unmask(eim, mask).astype(int))
ref_img, utils.unmask(data, mask))
mask_img = io.new_nii_like(ref_img, mask.astype(int))
voxel_comp_weights, varex, varex_norm, comp_ts = ma_pca.ma_pca(
data_img, mask_img, algorithm)
elif algorithm == 'mle':
Expand All @@ -283,12 +281,6 @@ def tedpca(data_cat, data_oc, combmode, mask, t2s, t2sG,
varex_norm = varex / varex.sum()

# Compute Kappa and Rho for PCA comps
eimum = np.atleast_2d(eim)
eimum = np.transpose(eimum, np.argsort(eimum.shape)[::-1])
eimum = eimum.prod(axis=1)
o = np.zeros((mask.shape[0], *eimum.shape[1:]))
o[mask, ...] = eimum
eimum = np.squeeze(o).astype(bool)

# Normalize each component's time series
vTmixN = stats.zscore(comp_ts, axis=0)
Expand Down
Empty file modified tedana/due.py
100644 → 100755
Empty file.
Empty file modified tedana/gscontrol.py
100644 → 100755
Empty file.
Empty file modified tedana/info.py
100644 → 100755
Empty file.
Empty file modified tedana/io.py
100644 → 100755
Empty file.
Empty file modified tedana/metrics/__init__.py
100644 → 100755
Empty file.
1 change: 1 addition & 0 deletions tedana/metrics/kundu_fit.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ def dependence_metrics(catd, tsoc, mmix, t2s, tes, ref_img,
betas : :obj:`numpy.ndarray`
mmix_new : :obj:`numpy.ndarray`
"""

# Use t2s as mask
mask = t2s != 0
if not (catd.shape[0] == t2s.shape[0] == mask.shape[0] == tsoc.shape[0]):
Expand Down
Empty file modified tedana/selection/__init__.py
100644 → 100755
Empty file.
Empty file modified tedana/selection/_utils.py
100644 → 100755
Empty file.
Empty file modified tedana/selection/tedica.py
100644 → 100755
Empty file.
Empty file modified tedana/selection/tedpca.py
100644 → 100755
Empty file.
Empty file modified tedana/stats.py
100644 → 100755
Empty file.
Empty file modified tedana/tests/__init__.py
100644 → 100755
Empty file.
Empty file modified tedana/tests/conftest.py
100644 → 100755
Empty file.
Empty file modified tedana/tests/data/cornell_three_echo_outputs.txt
100644 → 100755
Empty file.
Empty file modified tedana/tests/data/echo1.nii.gz
100644 → 100755
Empty file.
Empty file modified tedana/tests/data/echo2.nii.gz
100644 → 100755
Empty file.
Empty file modified tedana/tests/data/echo3.nii.gz
100644 → 100755
Empty file.
Empty file modified tedana/tests/data/fdist.npy
100644 → 100755
Empty file.
Empty file modified tedana/tests/data/fiu_four_echo_outputs.txt
100644 → 100755
Empty file.
Empty file modified tedana/tests/data/mask.nii.gz
100644 → 100755
Empty file.
Empty file modified tedana/tests/data/nih_five_echo_outputs_verbose.txt
100644 → 100755
Empty file.
Empty file modified tedana/tests/test_combine.py
100644 → 100755
Empty file.
Empty file modified tedana/tests/test_decay.py
100644 → 100755
Empty file.
Empty file modified tedana/tests/test_gscontrol.py
100644 → 100755
Empty file.
Empty file modified tedana/tests/test_integration.py
100644 → 100755
Empty file.
Empty file modified tedana/tests/test_io.py
100644 → 100755
Empty file.
Empty file modified tedana/tests/test_mapca.py
100644 → 100755
Empty file.
Empty file modified tedana/tests/test_model_fit_dependence_metrics.py
100644 → 100755
Empty file.
Empty file modified tedana/tests/test_model_kundu_metrics.py
100644 → 100755
Empty file.
Empty file modified tedana/tests/test_selection.py
100644 → 100755
Empty file.
Empty file modified tedana/tests/test_stats.py
100644 → 100755
Empty file.
Empty file modified tedana/tests/test_t2smap.py
100644 → 100755
Empty file.
Empty file modified tedana/tests/test_utils.py
100644 → 100755
Empty file.
Empty file modified tedana/tests/test_viz.py
100644 → 100755
Empty file.
Empty file modified tedana/tests/utils.py
100644 → 100755
Empty file.
59 changes: 55 additions & 4 deletions tedana/utils.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import numpy as np
import nibabel as nib
from scipy import ndimage
from scipy import ndimage, stats
from nilearn._utils import check_niimg
from sklearn.utils import check_array

Expand Down Expand Up @@ -41,6 +41,45 @@ def load_image(data):
return fdata


def extreme_percentile_mask(dd, ees=None):
"""
Returns mask for data between [0.001, 5] * 98th percentile of dd

Parameters
----------
dd : (S x E x T) array_like
Input data, where `S` is samples, `E` is echos, and `T` is time
ees : (N,) :obj:`list`
Indices of echos to assess from `dd` in calculating output

Returns
-------
imask : (S x N) :obj:`numpy.ndarray`
0 1 int array denoting
"""

if ees is None:
ees = range(dd.shape[1])
imask = np.zeros((dd.shape[0], len(ees)), dtype=bool)
for ee in ees:
if len(ees) == 1:
LGR.debug('Creating eimask for optimal combination')
else:
LGR.debug('Creating eimask for echo {}'.format(ee))
perc98 = stats.scoreatpercentile(dd[:, ee, :].flatten(), 98,
interpolation_method='lower')
lthr, hthr = 0.001 * perc98, 5 * perc98
LGR.debug('Eimask threshold boundaries: '
'{:.03f} {:.03f}'.format(lthr, hthr))
m = dd[:, ee, :].mean(axis=1)
imask[np.logical_and(m > lthr, m < hthr), ee] = True

# if any echo has an outlier set the mask for that voxel to False

mask = imask.all(axis=1).astype(int)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code says "all" but the comment says "any". I noticed in the conversation that you were leaning toward any. Is that still accurate?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Permissions should now be changed. FWIW, this is still a work in progress. My hope is to get #358 merged and then get this working on that code.

return mask


def make_adaptive_mask(data, mask=None, getsum=False):
"""
Makes map of `data` specifying longest echo a voxel can be sampled with
Expand Down Expand Up @@ -68,6 +107,10 @@ def make_adaptive_mask(data, mask=None, getsum=False):
RepLGR.info("An adaptive mask was then generated, in which each voxel's "
"value reflects the number of echoes with 'good' data.")

# TODO: This function is a combination of several arbtirary thresholds
# It would be nice to modularize each threshold so that this is slightly
# easier to tweak the arbirary levels.

# take temporal mean of echos and extract non-zero values in first echo
echo_means = data.mean(axis=-1) # temporal mean of echos
first_echo = echo_means[echo_means[:, 0] != 0, 0]
Expand All @@ -87,21 +130,29 @@ def make_adaptive_mask(data, mask=None, getsum=False):

# determine samples where absolute value is greater than echo-specific thresholds
# and count # of echos that pass criterion
masksum = (np.abs(echo_means) > lthrs).sum(axis=-1)
masksum1 = ((np.abs(echo_means) > lthrs).sum(axis=-1))

masksum2 = extreme_percentile_mask(data)

masksum = masksum1 * masksum2

if mask is None:
# make it a boolean mask to (where we have at least 1 echo with good signal)
mask = masksum.astype(bool)
else:
# if the user has supplied a binary mask
# Note: The way this function is currently called in tedana.py means either
# a user-provided mask or a mask defined by compute_epi_mask is the input
# The warning message below was changed to account for both of these scenarios
mask = load_image(mask).astype(bool)
masksum = masksum * mask
# reduce mask based on masksum
# TODO: Use visual report to make checking the reduced mask easier
if np.any(masksum[mask] == 0):
n_bad_voxels = np.sum(masksum[mask] == 0)
LGR.warning('{0} voxels in user-defined mask do not have good '
'signal. Removing voxels from mask.'.format(n_bad_voxels))
LGR.warning(('make_adaptive_mask removed an additional {} voxels from the {} voxels '
'in the inputted mask.').format(
n_bad_voxels, mask.sum()))
mask = masksum.astype(bool)

if getsum:
Expand Down
Empty file modified tedana/viz.py
100644 → 100755
Empty file.
Empty file modified tedana/workflows/__init__.py
100644 → 100755
Empty file.
Empty file modified tedana/workflows/parser_utils.py
100644 → 100755
Empty file.
Empty file modified tedana/workflows/t2smap.py
100644 → 100755
Empty file.
2 changes: 1 addition & 1 deletion tedana/workflows/tedana.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,7 @@ def tedana_workflow(data, tes, mask=None, mixm=None, ctab=None, manacc=None,
# TODO: add affine check
LGR.info('Using user-defined mask')
RepLGR.info("A user-defined mask was applied to the data.")

LGR.info('Checking for additional outlier voxels to mask')
mask, masksum = utils.make_adaptive_mask(catd, mask=mask, getsum=True)
LGR.debug('Retaining {}/{} samples'.format(mask.sum(), n_samp))
io.filewrite(masksum, op.join(out_dir, 'adaptive_mask.nii'), ref_img)
Expand Down
Empty file modified update_changes.sh
100644 → 100755
Empty file.
Empty file modified versioneer.py
100644 → 100755
Empty file.