diff --git a/fsl/data/strings.py b/fsl/data/strings.py
index d54391c7a208b3dc065b7f25ff7563fb81603897..b80b0962eea9109870a3f6b730983821077b14fb 100644
--- a/fsl/data/strings.py
+++ b/fsl/data/strings.py
@@ -553,6 +553,8 @@ properties = TypeDict({
     'VectorOpts.suppressX'     : 'Suppress X value',
     'VectorOpts.suppressY'     : 'Suppress Y value',
     'VectorOpts.suppressZ'     : 'Suppress Z value',
+    'VectorOpts.colourImage'   : 'Colour by',
+    'VectorOpts.cmap'          : 'Colour map',
     'VectorOpts.modulateImage' : 'Modulate by',
     'VectorOpts.clipImage'     : 'Clip by',
     'VectorOpts.clippingRange' : 'Clipping range',
diff --git a/fsl/fsleyes/colourmaps.py b/fsl/fsleyes/colourmaps.py
index f5b8b763b47e609e4009feec8ef4e89eb99d1bf7..0de096d153bc725bf73b03776a7f47e2afaa846a 100644
--- a/fsl/fsleyes/colourmaps.py
+++ b/fsl/fsleyes/colourmaps.py
@@ -265,29 +265,35 @@ def registerColourMap(cmapFile,
 
     _cmaps[key] = _Map(key, name, cmap, None, False)
 
-    # TODO Any new DisplayOpts sub-types which have a 
-    #      colour map will need to be patched here
-
-    log.debug('Patching VolumeOpts instances and class '
+    log.debug('Patching DisplayOpts instances and class '
               'to support new colour map {}'.format(key))
 
     import fsl.fsleyes.displaycontext as fsldisplay
     
-    # update the VolumeOpts colour map property
-    # for any existing VolumeOpts instances
-    cmapProp    = fsldisplay.VolumeOpts.getProp('cmap')
-    negCmapProp = fsldisplay.VolumeOpts.getProp('negativeCmap')
-    
+    # A list of all DisplayOpts colour map properties
+    # 
+    # TODO Any new DisplayOpts sub-types which have a 
+    #      colour map will need to be patched here
+    cmapProps = []
+    cmapProps.append((fsldisplay.VolumeOpts, 'cmap'))
+    cmapProps.append((fsldisplay.VolumeOpts, 'negativeCmap'))
+    cmapProps.append((fsldisplay.VectorOpts, 'cmap'))
+
+    # Update the colour map properties
+    # for any existing instances 
     for overlay in overlayList:
         opts = displayCtx.getOpts(overlay)
-        
-        if isinstance(opts, fsldisplay.VolumeOpts):
-            cmapProp   .addColourMap(key, opts)
-            negCmapProp.addColourMap(key, opts)
 
-    # and for all future volume overlays
-    cmapProp   .addColourMap(key)
-    negCmapProp.addColourMap(key)
+        for cls, propName in cmapProps:
+            if isinstance(opts, cls):
+                prop = opts.getProp(propName)
+                prop.addColourMap(key, opts)
+
+    # and for all future overlays
+    for cls, propName in cmapProps:
+        
+        prop = cls.getProp(propName)
+        prop.addColourMap(key)
                 
 
 def registerLookupTable(lut,
diff --git a/fsl/fsleyes/controls/overlaydisplaypanel.py b/fsl/fsleyes/controls/overlaydisplaypanel.py
index d30f90fcb22faa8ab20219fccdca7a7d36375368..1d4f8686313a1bd624abc7327a0ed1dab2b94773 100644
--- a/fsl/fsleyes/controls/overlaydisplaypanel.py
+++ b/fsl/fsleyes/controls/overlaydisplaypanel.py
@@ -10,6 +10,7 @@ control* panel which allows the user to change overlay display settings.
 
 
 import logging
+import functools
 
 import wx
 import props
@@ -206,7 +207,9 @@ class OverlayDisplayPanel(fslpanel.FSLEyesPanel):
 
         self.__widgets.ClearGroup(groupName)
 
-        dispProps = _DISPLAY_PROPS.get(target, [])
+        dispProps = _DISPLAY_PROPS.get(target, [], allhits=True)
+        dispProps = functools.reduce(lambda a, b: a + b, dispProps)
+ 
         labels    = [strings.properties.get((target, p.key), p.key)
                      for p in dispProps]
         tooltips  = [fsltooltips.properties.get((target, p.key), None)
@@ -214,6 +217,7 @@ class OverlayDisplayPanel(fslpanel.FSLEyesPanel):
 
         widgets = []
 
+
         for p in dispProps:
 
             widget = props.buildGUI(self.__widgets, target, p)
@@ -276,7 +280,8 @@ class OverlayDisplayPanel(fslpanel.FSLEyesPanel):
 
 def _imageName(img):
     """Used to generate choice labels for the :attr`.VectorOpts.modulateImage`,
-    :attr`.VectorOpts.clipImage` and :attr:`.ModelOpts.refImage` properties.
+    :attr`.VectorOpts.clipImage`, :attr`.VectorOpts.colourImage` and
+    :attr:`.ModelOpts.refImage` properties.
     """
     if img is None: return 'None'
     else:           return img.name
@@ -324,45 +329,46 @@ _DISPLAY_PROPS = td.TypeDict({
         props.Widget('invert'),
         props.Widget('threshold',  showLimits=False)],
 
-    'RGBVectorOpts' : [
-        props.Widget('resolution', showLimits=False),
-        props.Widget('interpolation',
-                     labels=strings.choices['VolumeOpts.interpolation']),
-        props.Widget('xColour'),
-        props.Widget('yColour'),
-        props.Widget('zColour'),
-        props.Widget('suppressX'),
-        props.Widget('suppressY'),
-        props.Widget('suppressZ'),
+    'VectorOpts' : [
+        props.Widget('colourImage',   labels=_imageName),
         props.Widget('modulateImage', labels=_imageName),
         props.Widget('clipImage',     labels=_imageName),
+        props.Widget('cmap',
+                     dependencies=['colourImage'],
+                     enabledWhen=lambda o, ci: ci is not None), 
         props.Widget('clippingRange',
                      showLimits=False,
                      slider=True,
                      labels=[strings.choices['VectorOpts.clippingRange.min'],
                              strings.choices['VectorOpts.clippingRange.max']],
                      dependencies=['clipImage'],
-                     enabledWhen=lambda o, ci: ci is not None)],
+                     enabledWhen=lambda o, ci: ci is not None),
+        props.Widget('xColour',
+                     dependencies=['colourImage'],
+                     enabledWhen=lambda o, ci: ci is None), 
+        props.Widget('yColour',
+                     dependencies=['colourImage'],
+                     enabledWhen=lambda o, ci: ci is None),
+        props.Widget('zColour',
+                     dependencies=['colourImage'],
+                     enabledWhen=lambda o, ci: ci is None),
+        props.Widget('suppressX',
+                     dependencies=['colourImage'],
+                     enabledWhen=lambda o, ci: ci is None),
+        props.Widget('suppressY',
+                     dependencies=['colourImage'],
+                     enabledWhen=lambda o, ci: ci is None),
+        props.Widget('suppressZ',
+                     dependencies=['colourImage'],
+                     enabledWhen=lambda o, ci: ci is None)],
 
-    'LineVectorOpts' : [
+    'RGBVectorOpts' : [
         props.Widget('resolution', showLimits=False),
-        props.Widget('xColour'),
-        props.Widget('yColour'),
-        props.Widget('zColour'),
-        props.Widget('suppressX'),
-        props.Widget('suppressY'),
-        props.Widget('suppressZ'),
-        props.Widget('directed'),
-        props.Widget('lineWidth', showLimits=False),
-        props.Widget('modulateImage', labels=_imageName),
-        props.Widget('clipImage',     labels=_imageName),
-        props.Widget('clippingRange',
-                     showLimits=False,
-                     slider=True,
-                     labels=[strings.choices['VectorOpts.clippingRange.min'],
-                             strings.choices['VectorOpts.clippingRange.max']],
-                     dependencies=['clipImage'],
-                     enabledWhen=lambda o, ci: ci is not None)],
+        props.Widget('interpolation',
+                     labels=strings.choices['VolumeOpts.interpolation'])],
+
+    'LineVectorOpts' : [
+        props.Widget('resolution', showLimits=False)],
 
     'ModelOpts' : [
         props.Widget('colour'),
@@ -382,22 +388,7 @@ _DISPLAY_PROPS = td.TypeDict({
             spin=False,
             labels=[strings.choices['TensorOpts.tensorResolution.min'],
                     strings.choices['TensorOpts.tensorResolution.max']]),
-        props.Widget('tensorScale', showLimits=False, spin=False),
-        props.Widget('xColour'),
-        props.Widget('yColour'),
-        props.Widget('zColour'),
-        props.Widget('suppressX'),
-        props.Widget('suppressY'),
-        props.Widget('suppressZ'),
-        props.Widget('modulateImage', labels=_imageName),
-        props.Widget('clipImage',     labels=_imageName),
-        props.Widget('clippingRange',
-                     showLimits=False,
-                     slider=True,
-                     labels=[strings.choices['VectorOpts.clippingRange.min'],
-                             strings.choices['VectorOpts.clippingRange.max']],
-                     dependencies=['clipImage'],
-                     enabledWhen=lambda o, ci: ci is not None)],
+        props.Widget('tensorScale', showLimits=False, spin=False)],
 
     'LabelOpts' : [
         props.Widget('lut', labels=lambda l: l.name),
diff --git a/fsl/fsleyes/displaycontext/vectoropts.py b/fsl/fsleyes/displaycontext/vectoropts.py
index cdc412d412f03bdb4a264b3d446f9dfc243dc354..53cb00b720e1e413147b41b98357451ba6720260 100644
--- a/fsl/fsleyes/displaycontext/vectoropts.py
+++ b/fsl/fsleyes/displaycontext/vectoropts.py
@@ -49,6 +49,22 @@ class VectorOpts(volumeopts.Nifti1Opts):
     """Do not use the Z vector magnitude to colour vectors."""
 
 
+    cmap = props.ColourMap()
+    """If an image is selected as the :attr:`colourImage`, this colour map
+    is used to colour the vector voxels.
+    """
+
+    
+    colourImage = props.Choice()
+    """Colour vector voxels by the values contained in this image. Any image which
+    is in the :class:`.OverlayList`, and which has the same voxel dimensions as
+    the vector image can be selected for modulation. If a ``colourImage`` is
+    selected, the :attr:`xColour`, :attr:`yColour`, :attr:`zColour`,
+    :attr:`suppressX`, :attr:`suppressY`, and :attr:`suppressZ` properties are
+    all ignored.
+    """
+
+
     modulateImage  = props.Choice()
     """Modulate the vector colour brightness by another image. Any image which
     is in the :class:`.OverlayList`, and which has the same voxel dimensions as
@@ -124,16 +140,19 @@ class VectorOpts(volumeopts.Nifti1Opts):
 
         
     def __overlayListChanged(self, *a):
-        """Called when the overlay list changes. Updates the :attr:`modulateImage`
-        and :attr:`clipImage` properties so that they contain a list of
-        overlays which could be used to modulate the vector image.
+        """Called when the overlay list changes. Updates the :attr:`modulateImage`,
+        :attr:`colourImage` and :attr:`clipImage` properties so that they
+        contain a list of overlays which could be used to modulate the vector
+        image.
         """
         
-        modProp  = self.getProp('modulateImage')
-        clipProp = self.getProp('clipImage')
-        modVal   = self.modulateImage
-        clipVal  = self.clipImage
-        overlays = self.displayCtx.getOrderedOverlays()
+        modProp    = self.getProp('modulateImage')
+        clipProp   = self.getProp('clipImage')
+        colourProp = self.getProp('colourImage')
+        modVal     = self.modulateImage
+        clipVal    = self.clipImage
+        colourVal  = self.clipImage
+        overlays   = self.displayCtx.getOrderedOverlays()
 
         # the image for this VectorOpts
         # instance has been removed
@@ -151,14 +170,14 @@ class VectorOpts(volumeopts.Nifti1Opts):
             if overlay is self.overlay:
                 continue
 
-            # The modulate/clip images
-            # must be images. 
+            # The modulate/clip/colour
+            # images must be images. 
             if not isinstance(overlay, fslimage.Image):
                 continue
 
             # an image can only be used to
-            # modulate/clip the vector image
-            # if it shares the same
+            # modulate/clip/colour the vector
+            # image if it shares the same
             # dimensions as said vector image.
             # 4D images are ok though.
             if overlay.shape[:3] != self.overlay.shape[:3]:
@@ -172,13 +191,16 @@ class VectorOpts(volumeopts.Nifti1Opts):
                                 self.__overlayListChanged,
                                 overwrite=True)
             
-        modProp .setChoices(options, instance=self)
-        clipProp.setChoices(options, instance=self)
-
-        if modVal  in overlays: self.modulateImage = modVal
-        else:                   self.modulateImage = None
-        if clipVal in overlays: self.clipImage     = clipVal
-        else:                   self.clipImage     = None 
+        modProp   .setChoices(options, instance=self)
+        clipProp  .setChoices(options, instance=self)
+        colourProp.setChoices(options, instance=self)
+
+        if modVal    in overlays: self.modulateImage = modVal
+        else:                     self.modulateImage = None
+        if clipVal   in overlays: self.clipImage     = clipVal
+        else:                     self.clipImage     = None
+        if colourVal in overlays: self.colourImage   = colourVal
+        else:                     self.colourImage   = None 
 
 
 class LineVectorOpts(VectorOpts):
diff --git a/fsl/fsleyes/tooltips.py b/fsl/fsleyes/tooltips.py
index a03f6757982a72fd6222211bcf36026022cc6418..50a2ba657855aa02bee234568423c1627491b1cf 100644
--- a/fsl/fsleyes/tooltips.py
+++ b/fsl/fsleyes/tooltips.py
@@ -120,28 +120,37 @@ properties = TypeDict({
     'VectorOpts.xColour'          : 'The colour corresponding to the X '
                                     'component of the vector - the brightness '
                                     'of the colour corresponds to the '
-                                    'magnitude of the X component',
+                                    'magnitude of the X component. This '
+                                    'option has no effect if a colour image '
+                                    'is selected.', 
     'VectorOpts.yColour'          : 'The colour corresponding to the Y '
                                     'component of the vector - the brightness '
                                     'of the colour corresponds to the '
-                                    'magnitude of the Y component.',
+                                    'magnitude of the Y component. This '
+                                    'option has no effect if a colour image '
+                                    'is selected.', 
     'VectorOpts.zColour'          : 'The colour corresponding to the Z '
                                     'component of the vector - the brightness '
                                     'of the colour corresponds to the '
-                                    'magnitude of the Z component.',
+                                    'magnitude of the Z component. This '
+                                    'option has no effect if a colour image '
+                                    'is selected.',
     'VectorOpts.suppressX'        : 'Ignore the X vector component when '
-                                    'colouring voxels.',
+                                    'colouring voxels. This option has no '
+                                    'effect if a colour image is selected.', 
     'VectorOpts.suppressY'        : 'Ignore the Y vector component when '
-                                    'colouring voxels.',
+                                    'colouring voxels. This option has no '
+                                    'effect if a colour image is selected.', 
     'VectorOpts.suppressZ'        : 'Ignore the Z vector component when '
-                                    'colouring voxels.',
+                                    'colouring voxels. This option has no '
+                                    'effect if a colour image is selected.', 
     'VectorOpts.modulateImage'    : 'Modulate the vector colour brightness by '
                                     'another image. The image selected here '
                                     'is normalised to lie in the range (0, '
-                                    '1), and the magnitude of each vector is '
-                                    'scaled by the corresponding modulation '
-                                    'value before it is coloured. The '
-                                    'modulation image must have the same '
+                                    '1), and the brightness of each vector '
+                                    'colour is scaled by the corresponding '
+                                    'modulation value before it is coloured. '
+                                    'The modulation image must have the same '
                                     'voxel dimensions as the vector image.',
     'VectorOpts.clipImage'        : 'Clip vector voxels according to the '
                                     'values in another image. Vector voxels '
@@ -150,10 +159,17 @@ properties = TypeDict({
                                     'than the current clipping threshold are '
                                     'not shown. The clipping image must have '
                                     'the same voxel dimensions as the vector '
-                                    'image. ', 
+                                    'image. ',
+    'VectorOpts.colourImage'      : 'Colour the vectors according to the '
+                                    'values in another image, and by the '
+                                    'selected colour map. The colour image '
+                                    'must have the same voxel dimensions as '
+                                    'the vector image. ',
     'VectorOpts.clippingRange'    : 'Vector values which have a corresponding '
                                     'clipping image value that is outside of '
                                     'this range are not displayed. ',
+    'VectorOpts.cmap'             : 'Colour map to use for colouring vector '
+                                    'voxels, if a colour image is selected.', 
     'LineVectorOpts.lineWidth'    : 'The width of each vector line, in '
                                     'display pixels.',
     'LineVectorOpts.directed'     : 'If unchecked, the vector data is assumed '