diff --git a/fsl/data/featimage.py b/fsl/data/featimage.py
index 27a10f28fb2634e1f9663ba9869888d72b792b49..12d2b3af97010d0d5261889a14eef7b7bd6a2e9c 100644
--- a/fsl/data/featimage.py
+++ b/fsl/data/featimage.py
@@ -332,7 +332,9 @@ class FEATImage(fslimage.Image):
         # We also take the absolute value
         # of the values in the contrast
         # vector, as the parameter estimates
-        # should be appropriately signed.
+        # should be appropriately signed,
+        # so we don't negative contrast
+        # vector values to invert them.
         contrast = np.array(contrast)
         nonzero  = sum(~np.isclose(contrast, 0))
         contrast = contrast / np.sqrt((contrast ** 2).sum())
diff --git a/fsl/data/gifti.py b/fsl/data/gifti.py
index 3302a974f3f9b750eb17d4247667e339ae4b4246..97227b4f6003331b5737cc26778917eef2cfeb08 100644
--- a/fsl/data/gifti.py
+++ b/fsl/data/gifti.py
@@ -68,7 +68,9 @@ class GiftiSurface(mesh.TriangleMesh):
 
 
     def loadVertexData(self, dataSource):
-        """Attempts to load data associated with each vertex of this
+        """Overrides the :meth:`.TriangleMesh.loadVertexData` method.
+
+        Attempts to load data associated with each vertex of this
         ``GiftiSurface`` from the given ``dataSource``.
 
         Currently, only the first ``DataArray`` contained in the
@@ -80,15 +82,17 @@ class GiftiSurface(mesh.TriangleMesh):
          - ``*.time.gii``
         """
 
-        # TODO support 4D 
-        # TODO make this more robust
-        vdata = nib.load(dataSource)
-        vdata = vdata.darrays[0].data
+        if dataSource.endswith('.gii'):
 
-        if vdata.size != self.vertices.shape[0]:
-            raise ValueError('Incompatible size: {}'.format(dataSource))
+            # TODO support 4D 
+            # TODO make this more robust
+            vdata = nib.load(dataSource)
+            vdata = vdata.darrays[0].data
+            
+        else:
+            vdata = None
 
-        return vdata
+        return mesh.TriangleMesh.loadVertexData(self, dataSource, vdata)
 
 
 ALLOWED_EXTENSIONS = ['.surf.gii', '.gii']
@@ -161,7 +165,6 @@ def relatedFiles(fname):
     """Given a GIFTI file, returns a list of other GIFTI files in the same
     directory which appear to be related with the given one.  Files which
     share the same prefix are assumed to be related to the given file.
-
     """
 
     try:
diff --git a/fsl/data/mesh.py b/fsl/data/mesh.py
index d9afd3cf252bcb02c4432d57759626f978938136..ee3e0dea53626aec123d8e61464c023b7e6c0a48 100644
--- a/fsl/data/mesh.py
+++ b/fsl/data/mesh.py
@@ -63,6 +63,8 @@ class TriangleMesh(object):
 
        getBounds
        loadVertexData
+       getVertexData
+       clearVertexData
     """
 
     
@@ -95,11 +97,12 @@ class TriangleMesh(object):
         if indices is None:
             indices = np.arange(data.shape[0])
 
-        self.vertices = np.array(data)
-        self.indices  = np.array(indices).reshape((-1, 3))
-
-        self.__loBounds = self.vertices.min(axis=0)
-        self.__hiBounds = self.vertices.max(axis=0)
+        self.vertices     = np.array(data)
+        self.indices      = np.array(indices).reshape((-1, 3))
+        
+        self.__vertexData = {}
+        self.__loBounds   = self.vertices.min(axis=0)
+        self.__hiBounds   = self.vertices.max(axis=0)
 
 
     def __repr__(self):
@@ -125,13 +128,51 @@ class TriangleMesh(object):
         return (self.__loBounds, self.__hiBounds)
 
 
-    def loadVertexData(self, dataSource):
+    def loadVertexData(self, dataSource, vertexData=None):
         """Attempts to load scalar data associated with each vertex of this
-        ``TriangleMesh`` from the given ``dataSource``.
+        ``TriangleMesh`` from the given ``dataSource``. The data is returned,
+        and also stored in an internal cache so it can be retrieved later
+        via the :meth:`getVertexData` method.
 
         This method may be overridden by sub-classes.
+
+        :arg dataSource: Path to the vertex data to load
+        :arg vertexData: The vertex data itself, if it has already been
+                         loaded.
         """
-        raise NotImplementedError('Not implemented yet')
+
+        nvertices = self.vertices.shape[0]
+
+        # Currently only white-space delimited
+        # text files are supported
+        if vertexData is None:
+            vertexData = np.loadtxt(dataSource)
+            vertexData.reshape(nvertices, -1)
+
+        if vertexData.shape[0] != nvertices:
+            raise ValueError('Incompatible size: {}'.format(dataSource))
+
+        self.__vertexData[dataSource] = vertexData
+
+        return vertexData
+
+
+    def getVertexData(self, dataSource):
+        """Returns the vertex data for the given ``dataSource`` from the
+        internal vertex data cache. If the given ``dataSource`` is not
+        in the cache, it is loaded via :meth:`loadVertexData`.
+        """
+
+        try:             return self.__vertexData[dataSource]
+        except KeyError: return self.loadVertexData(dataSource)
+
+    
+    def clearVertexData(self):
+        """Clears the internal vertex data cache - see the
+        :meth:`loadVertexData` and :meth:`getVertexData`  methods.
+        """
+
+        self.__vertexData = {}
 
 
 ALLOWED_EXTENSIONS     = ['.vtk']