Skip to content
Snippets Groups Projects
Commit 2c3c4ced authored by Paul McCarthy's avatar Paul McCarthy
Browse files

No longer using any of the design.fsf settings to determine whether

clustering has been run or not, as design.fsf settings are very
fickle. Instead, I am using the existence of cluster_*txt to determine
whether or not they exist.

DisplayContext.getDisplay was potentially creating Display/Opts
instances for overlays that were not in overlay list. This has been
rectified.
parent 7770717a
No related branches found
No related tags found
No related merge requests found
......@@ -89,12 +89,6 @@ class FEATImage(fslimage.Image):
def clusterResults(self, contrast):
# If thresholdType is not 3, stats
# has not been run, or cluster
# thresholding has not been performed
if featresults.getThresholdType(self.__settings) != 3:
return None
return featresults.loadClusterResults(self.__featDir,
self.__settings,
contrast)
......
......@@ -10,11 +10,15 @@ contents of a FEAT analysis directory.
"""
import logging
import glob
import os.path as op
import numpy as np
log = logging.getLogger(__name__)
def isFEATDir(path):
"""Returns ``True`` if the given path looks like a FEAT directory, or
looks like the input data for a FEAT analysis, ``False`` otherwise.
......@@ -57,6 +61,8 @@ def loadDesign(featdir):
matrix = None
designmat = op.join(featdir, 'design.mat')
log.debug('Loading FEAT design matrix from {}'.format(designmat))
with open(designmat, 'rt') as f:
while True:
......@@ -85,6 +91,8 @@ def loadContrasts(featdir):
numContrasts = 0
names = {}
designcon = op.join(featdir, 'design.con')
log.debug('Loading FEAT contrasts from {}'.format(designcon))
with open(designcon, 'rt') as f:
......@@ -135,6 +143,8 @@ def loadSettings(featdir):
settings = {}
designfsf = op.join(featdir, 'design.fsf')
log.debug('Loading FEAT settings from {}'.format(designfsf))
with open(designfsf, 'rt') as f:
for line in f.readlines():
......@@ -150,53 +160,23 @@ def loadSettings(featdir):
if key.startswith('fmri(') and key.endswith(')'):
key = key[5:-1]
settings[key] = val
return settings
def getThresholdType(settings):
"""Returns the type of statistical thresholding used in the FEAT
analysis described in the given settings dict (see the
:func:`loadSettings` function).
Returns a number describing the thresholding approach:
-1 : Statistical analysis has not been performed
0 : No thresholding has been performed
1 : Uncorrected P-value thresholding
2 : Voxel-corrected thresholding
3 : Cluster-corrected thresholding
"""
poststats = int(settings['poststats_yn'])
threstype = int(settings['thresh'])
if poststats != 1:
return -1
return threstype
def loadClusterResults(featdir, settings, contrast):
"""If cluster thresholding was used in the FEAT analysis, this function
will load and return the cluster results for the specified contrast
(which is assumed to be 0-indexed).
If thresholding has not been performed, or cluster threhsolding was not
used, ``None`` is returned.
If there are no cluster results for the given contrast,
``None`` is returned.
An error will be raised if the cluster file cannot be parsed.
"""
# poststats_yn != 1 means that
# stats has not been performed
#
# thres=3 corresponds to
# cluster thresholding
if int(settings['poststats_yn']) != 1 or \
int(settings['thresh']) != 3:
return None
# This dict provides a mapping between
# Cluster object (see below) attribute
# names, and the corresponding column
......@@ -212,9 +192,10 @@ def loadClusterResults(featdir, settings, contrast):
'Z-MAX X (vox)' : ('zmaxx', int),
'Z-MAX Y (vox)' : ('zmaxy', int),
'Z-MAX Z (vox)' : ('zmaxz', int),
'Z-COG X (vox)' : ('zcogx', int),
'Z-COG Y (vox)' : ('zcogy', int),
'Z-COG Z (vox)' : ('zcogz', int),
'Z-COG X (vox)' : ('zcogx', float),
'Z-COG Y (vox)' : ('zcogy', float),
'Z-COG Z (vox)' : ('zcogz', float),
'COPE-MAX' : ('copemax', float),
'COPE-MAX X (vox)' : ('copemaxx', int),
'COPE-MAX Y (vox)' : ('copemaxy', int),
'COPE-MAX Z (vox)' : ('copemaxz', int),
......@@ -226,7 +207,7 @@ def loadClusterResults(featdir, settings, contrast):
# information about one cluster.
class Cluster(object):
def __init__(self, **kwargs):
for name, val in kwargs:
for name, val in kwargs.items():
attrName, atype = colmap[name]
if val is not None:
......@@ -236,6 +217,12 @@ def loadClusterResults(featdir, settings, contrast):
clusterFile = op.join(featdir, 'cluster_zstat{}.txt'.format(contrast + 1))
if not op.exists(clusterFile):
return None
log.debug('Loading cluster results for contrast {} from {}'.format(
contrast, clusterFile))
# An error will be raised if the
# cluster file does not exist (e.g.
# if the specified contrast index
......@@ -260,6 +247,10 @@ def loadClusterResults(featdir, settings, contrast):
colNames = colNames.split('\t')
clusterLines = [cl .split('\t') for cl in clusterLines]
# No clusters
if len(clusterLines) == 0:
return None
# Turn each cluster line into a
# Cluster instance. An error will
# be raised if the columm names
......@@ -309,6 +300,9 @@ def getCOPEFile(featdir, contrast):
def getEVNames(settings):
"""Returns the names of every EV in the FEAT analysis which has the given
``settings`` (see the :func:`loadSettings` function).
An error of some sort will be raised if the EV names cannot be determined
from the FEAT settings.
"""
numEVs = int(settings['evs_real'])
......
......@@ -107,6 +107,9 @@ class DisplayContext(props.SyncableHasProperties):
if overlay is None:
raise ValueError('No overlay specified')
if overlay not in self.__overlayList:
raise ValueError('Overlay is not in list')
if isinstance(overlay, int):
overlay = self.__overlayList[overlay]
......@@ -141,7 +144,10 @@ class DisplayContext(props.SyncableHasProperties):
"""
if overlay is None:
raise ValueError('No overlay specified')
raise ValueError('No overlay specified')
if overlay not in self.__overlayList:
raise ValueError('Overlay is not in list')
try:
return self.getDisplay(overlay, overlayType).getDisplayOpts()
......
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