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