Skip to content
Snippets Groups Projects
Commit 16496d1d authored by Paul McCarthy's avatar Paul McCarthy :mountain_bicyclist:
Browse files

Merge branch 'bf/voxelwise_ev' into 'master'

Bf/voxelwise ev

See merge request fsl/fslpy!83
parents 9c452125 ee42060d
No related branches found
No related tags found
No related merge requests found
......@@ -29,6 +29,17 @@ Removed
* Many deprecated items removed.
Fixed
^^^^^
* Added a missing ``image`` attribute in the :class:`.VoxelwiseConfoundEV`
class.
* Make sure that FEAT ``Cluster`` objects (created by the
:func:`.loadClusterResults` function) contain ``p`` and ``logp`` attributes,
even when cluster thresholding was not used.
1.13.0 (Thursday 22nd November 2018)
------------------------------------
......@@ -36,9 +47,9 @@ Removed
Added
^^^^^
* New wrapper functions for :func:`.fsl_anat`, :func:`.applytopup` (Matrin
* New wrapper functions for :func:`.fsl_anat`, :func:`.applytopup` (Martin
Craig).
* New :func:`.fileOrText` decorator for use in wrapper functions (Matrin
* New :func:`.fileOrText` decorator for use in wrapper functions (Martin
Craig).
......
......@@ -385,6 +385,12 @@ def loadClusterResults(featdir, settings, contrast):
setattr(self, attrName, val)
# if cluster thresholding was not used,
# the cluster table will not contain
# P valuse.
if not hasattr(self, 'p'): self.p = 1.0
if not hasattr(self, 'logp'): self.logp = 0.0
# This dict provides a mapping between
# Cluster object attribute names, and
# the corresponding column name in the
......
......@@ -219,6 +219,59 @@ class FEATFSFDesign(object):
return design
class VoxelwiseEVMixin(object):
"""Mixin class for voxelwise EVs.
``VoxelwiseEVMixin`` instances contain the following attributes:
============ ======================================================
``filename`` Path to the image file containing the data for this EV
``image`` Reference to the :class:`.Image` object
============ ======================================================
"""
def __init__(self, filename):
"""Create a ``VoxelwiseEVMixin``.
:arg filename: Path to the file containing the data for this
``VoxelwiseEV``.
"""
if op.exists(filename):
self.__filename = filename
else:
log.warning('Voxelwise EV file does not '
'exist: {}'.format(filename))
self.__filename = None
self.__image = None
def __del__(self):
"""Clears any reference to the voxelwise EV image. """
self.__image = None
@property
def filename(self):
"""Returns the path to the image file containing the data for this EV.
"""
return self.__filename
@property
def image(self):
"""Returns the :class:`.Image` containing the voxelwise EV data. """
if self.__filename is None:
return None
if self.__image is not None:
return self.__image
self.__image = fslimage.Image(self.__filename, mmap=False)
return self.__image
class EV(object):
"""Class representing an explanatory variable in a FEAT design matrix.
......@@ -276,7 +329,7 @@ class BasisFunctionEV(NormalEV):
pass
class VoxelwiseEV(NormalEV):
class VoxelwiseEV(NormalEV, VoxelwiseEVMixin):
"""Class representing an EV with different values for each voxel in the
analysis.
......@@ -308,34 +361,7 @@ class VoxelwiseEV(NormalEV):
``VoxelwiseEV``.
"""
NormalEV.__init__(self, realIdx, origIdx, title)
if op.exists(filename):
self.filename = filename
else:
log.warning('Voxelwise EV file does not '
'exist: {}'.format(filename))
self.filename = None
self.__image = None
def __del__(self):
"""Clears any reference to the voxelwise EV image. """
self.__image = None
@property
def image(self):
"""Returns the :class:`.Image` containing the voxelwise EV data. """
if self.filename is None:
return None
if self.__image is not None:
return self.__image
self.__image = fslimage.Image(self.filename, mmap=False)
return self.__image
VoxelwiseEVMixin.__init__(self, filename)
class ConfoundEV(EV):
......@@ -386,7 +412,7 @@ class MotionParameterEV(EV):
self.motionIndex = motionIndex
class VoxelwiseConfoundEV(EV):
class VoxelwiseConfoundEV(EV, VoxelwiseEVMixin):
"""Class representing a voxelwise confound EV.
``VoxelwiseConfoundEV`` instances contain the following attributes (in
......@@ -396,6 +422,7 @@ class VoxelwiseConfoundEV(EV):
``voxIndex`` Index of this ``VoxelwiseConfoundEV`` (starting from 0) in
relation to all other voxelwise confound EVs.
``filename`` Path to the image file containing the data for this EV
``image`` Reference to the :class:`.Image` object
============ ==========================================================
"""
def __init__(self, index, voxIndex, title, filename):
......@@ -407,17 +434,13 @@ class VoxelwiseConfoundEV(EV):
``VoxelwiseConfoundEV`` in relation to all other
voxelwise confound EVs.
:arg title: Name of this ``VoxelwiseConfoundEV``.
:arg filename: Path to the file containing the data for this
``VoxelwiseConfoundEV``.
"""
EV.__init__(self, index, title)
VoxelwiseEVMixin.__init__(self, filename)
self.voxIndex = voxIndex
if op.exists(filename):
self.filename = filename
else:
log.warning('Voxelwise confound EV file does '
'not exist: {}'.format(filename))
self.filename = None
def getFirstLevelEVs(featDir, settings, designMat):
"""Derives the EVs for the given first level FEAT analysis.
......
......@@ -109,8 +109,9 @@ import numpy as np
import pytest
import tests
import fsl.data.featdesign as featdesign
import fsl.data.featanalysis as featanalysis
from fsl.utils.tempdir import tempdir
import fsl.data.featdesign as featdesign
import fsl.data.featanalysis as featanalysis
datadir = op.join(op.dirname(__file__), 'testdata', 'test_feat')
......@@ -397,3 +398,17 @@ def test_loadDesignMat():
with pytest.raises(Exception):
featdesign.loadDesignMat(badfile)
def test_VoxelwiseEVs():
with tempdir():
img = tests.make_random_image('image.nii.gz', (10, 10, 10, 10))
ev1 = featdesign.VoxelwiseEV( 0, 0, 'ev1', 'image.nii.gz')
ev2 = featdesign.VoxelwiseConfoundEV(0, 0, 'ev2', 'image.nii.gz')
for xyz in tests.random_voxels((10, 10, 10), 10):
x, y, z = map(int, xyz)
exp = img.dataobj[x, y, z, :]
assert np.all(ev1.image[x, y, z, :] == exp)
assert np.all(ev2.image[x, y, z, :] == exp)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment