# -*- coding: utf-8 -*-
"""Miscellaneous functions of various utility."""
import glob
import os
import subprocess
import nibabel as nib
import numpy as np
from scipy import ndimage
from sklearn.utils.validation import check_array
[docs]def add_constant(data):
"""
Add a constant (i.e., intercept) term to `data`.
Parameters
----------
data : (N, M) array_like
Samples by features data array
Returns
-------
data : (N, F) np.ndarray
Where `F` is `M + 1`
Examples
--------
>>> from netneurotools import utils
>>> A = np.zeros((5, 5))
>>> Ac = utils.add_constant(A)
>>> Ac
array([[0., 0., 0., 0., 0., 1.],
[0., 0., 0., 0., 0., 1.],
[0., 0., 0., 0., 0., 1.],
[0., 0., 0., 0., 0., 1.],
[0., 0., 0., 0., 0., 1.]])
"""
data = check_array(data, ensure_2d=False)
return np.column_stack([data, np.ones(len(data))])
[docs]def get_triu(data, k=1):
"""
Return vectorized version of upper triangle from `data`.
Parameters
----------
data : (N, N) array_like
Input data
k : int, optional
Which diagonal to select from (where primary diagonal is 0). Default: 1
Returns
-------
triu : (N * N-1 / 2) numpy.ndarray
Upper triangle of `data`
Examples
--------
>>> from netneurotools import utils
>>> X = np.array([[1, 0.5, 0.25], [0.5, 1, 0.33], [0.25, 0.33, 1]])
>>> tri = utils.get_triu(X)
>>> tri
array([0.5 , 0.25, 0.33])
"""
return data[np.triu_indices(len(data), k=k)].copy()
def globpath(*args):
"""
Join `args` with :py:func:`os.path.join` and returns sorted glob output.
Parameters
----------
args : str
Paths / `glob`-compatible regex strings
Returns
-------
files : list
Sorted list of files
"""
return sorted(glob.glob(os.path.join(*args)))
def rescale(data, low=0, high=1):
"""
Rescale `data` so it is within [`low`, `high`].
Parameters
----------
data : array_like
Input data array
low : float, optional
Lower bound for rescaling. Default: -1
high : float, optional
Upper bound for rescaling. Default: 1
Returns
-------
rescaled : np.ndarray
Rescaled data
"""
data = np.asarray(data)
rescaled = np.interp(data, (data.min(), data.max()), (low, high))
return rescaled
[docs]def run(cmd, env=None, return_proc=False, quiet=False):
"""
Run `cmd` via shell subprocess with provided environment `env`.
Parameters
----------
cmd : str
Command to be run as single string
env : dict, optional
If provided, dictionary of key-value pairs to be added to base
environment when running `cmd`. Default: None
return_proc : bool, optional
Whether to return CompletedProcess object. Default: false
quiet : bool, optional
Whether to suppress stdout/stderr from subprocess. Default: False
Returns
-------
proc : subprocess.CompletedProcess
Process output
Raises
------
subprocess.CalledProcessError
If subprocess does not exit cleanly
Examples
--------
>>> from netneurotools import utils
>>> p = utils.run('echo "hello world"', return_proc=True, quiet=True)
>>> p.returncode
0
>>> p.stdout # doctest: +SKIP
'hello world\\n'
""" # noqa: D301
merged_env = os.environ.copy()
if env is not None:
if not isinstance(env, dict):
raise TypeError('Provided `env` must be a dictionary, not {}'
.format(type(env)))
merged_env.update(env)
opts = {}
if quiet:
opts = dict(stdout=subprocess.PIPE, stderr=subprocess.PIPE)
proc = subprocess.run(cmd, env=merged_env, shell=True, check=True,
universal_newlines=True, **opts)
if return_proc:
return proc
def check_fs_subjid(subject_id, subjects_dir=None):
"""
Check that `subject_id` exists in provided FreeSurfer `subjects_dir`.
Parameters
----------
subject_id : str
FreeSurfer subject ID
subjects_dir : str, optional
Path to FreeSurfer subject directory. If not set, will inherit from
the environmental variable $SUBJECTS_DIR. Default: None
Returns
-------
subject_id : str
FreeSurfer subject ID, as provided
subjects_dir : str
Full filepath to `subjects_dir`
Raises
------
FileNotFoundError
"""
# check inputs for subjects_dir and subject_id
if subjects_dir is None or not os.path.isdir(subjects_dir):
try:
subjects_dir = os.environ['SUBJECTS_DIR']
except KeyError:
subjects_dir = os.getcwd()
else:
subjects_dir = os.path.abspath(subjects_dir)
subjdir = os.path.join(subjects_dir, subject_id)
if not os.path.isdir(subjdir):
raise FileNotFoundError('Cannot find specified subject id {} in '
'provided subject directory {}.'
.format(subject_id, subjects_dir))
return subject_id, subjects_dir
[docs]def get_centroids(img, labels=None, image_space=False):
"""
Find centroids of `labels` in `img`.
Parameters
----------
img : niimg-like object
3D image containing integer label at each point
labels : array_like, optional
List of labels for which to find centroids. If not specified all
labels present in `img` will be used. Zero will be ignored as it is
considered "background." Default: None
image_space : bool, optional
Whether to return xyz (image space) coordinates for centroids based
on transformation in `img.affine`. Default: False
Returns
-------
centroids : (N, 3) np.ndarray
Coordinates of centroids for ROIs in input data
"""
from nilearn._utils import check_niimg_3d
img = check_niimg_3d(img)
data = np.asarray(img.dataobj)
if labels is None:
labels = np.trim_zeros(np.unique(data))
centroids = np.vstack(ndimage.center_of_mass(data, labels=data,
index=labels))
if image_space:
centroids = nib.affines.apply_affine(img.affine, centroids)
return centroids