diff --git a/doc/images/overlaydisplaypanel.png b/doc/images/overlaydisplaypanel.png
new file mode 100644
index 0000000000000000000000000000000000000000..a6d703147a9a4ef715f19124a11ba4abb82c2a77
Binary files /dev/null and b/doc/images/overlaydisplaypanel.png differ
diff --git a/doc/images/overlayinfopanel.png b/doc/images/overlayinfopanel.png
new file mode 100644
index 0000000000000000000000000000000000000000..8f8ce30d6951de94bd3750e3612b0fff52bd01c9
Binary files /dev/null and b/doc/images/overlayinfopanel.png differ
diff --git a/fsl/fsleyes/controls/overlaydisplaypanel.py b/fsl/fsleyes/controls/overlaydisplaypanel.py
index 210478f5affda6d2f223abb571e542da39f9475f..dee0feb071e040af9c003bcdc637cd5cbfd1f1c5 100644
--- a/fsl/fsleyes/controls/overlaydisplaypanel.py
+++ b/fsl/fsleyes/controls/overlaydisplaypanel.py
@@ -1,14 +1,14 @@
 #!/usr/bin/env python
 #
-# overlaydisplaypanel.py - A panel which shows display control options for the
-#                          currently selected overlay.
+# overlaydisplaypanel.py - The OverlayDisplayPanel.
 #
 # Author: Paul McCarthy <pauldmccarthy@gmail.com>
 
-"""A :class:`wx.panel` which shows display control optionns for the currently
-selected overlay.
+"""This module provides the :class:`OverlayDisplayPanel` class, a *FSLeyes
+control* panel which allows the user to change overlay display settings.
 """
 
+
 import logging
 
 import wx
@@ -24,123 +24,44 @@ import fsl.fsleyes.actions.loadcolourmap as loadcmap
 import fsl.fsleyes.displaycontext        as displayctx
 
 
-
 log = logging.getLogger(__name__)
 
-
-def _imageName(img):
-    if img is None: return 'None'
-    else:           return img.name
-
-
-_DISPLAY_PROPS = td.TypeDict({
-    'Display' : [
-        props.Widget('name'),
-        props.Widget('overlayType',
-                     labels=strings.choices['Display.overlayType']),
-        props.Widget('enabled'),
-        props.Widget('alpha',      showLimits=False),
-        props.Widget('brightness', showLimits=False),
-        props.Widget('contrast',   showLimits=False)],
-
-    'VolumeOpts' : [
-        props.Widget('resolution',    showLimits=False),
-        props.Widget('transform',
-                     labels=strings.choices['ImageOpts.transform']),
-        props.Widget('volume',
-                     showLimits=False,
-                     enabledWhen=lambda o: o.overlay.is4DImage()),
-        props.Widget('interpolation',
-                     labels=strings.choices['VolumeOpts.interpolation']),
-        props.Widget('cmap'),
-        props.Widget('invert'),
-        props.Widget('invertClipping',
-                     enabledWhen=lambda o, sw: not sw,
-                     dependencies=[(lambda o: o.display, 'softwareMode')]),
-        props.Widget('displayRange',
-                     showLimits=False,
-                     slider=True,
-                     labels=[strings.choices['VolumeOpts.displayRange.min'],
-                             strings.choices['VolumeOpts.displayRange.max']]),
-        props.Widget('clippingRange',
-                     showLimits=False,
-                     slider=True,
-                     labels=[strings.choices['VolumeOpts.displayRange.min'],
-                             strings.choices['VolumeOpts.displayRange.max']])],
-
-    'MaskOpts' : [
-        props.Widget('resolution', showLimits=False),
-        props.Widget('transform',
-                     labels=strings.choices['ImageOpts.transform']),
-        props.Widget('volume',
-                     showLimits=False,
-                     enabledWhen=lambda o: o.overlay.is4DImage()),
-        props.Widget('colour'),
-        props.Widget('invert'),
-        props.Widget('threshold',  showLimits=False)],
-
-    'RGBVectorOpts' : [
-        props.Widget('resolution', showLimits=False),
-        props.Widget('transform',
-                     labels=strings.choices['ImageOpts.transform']),
-        props.Widget('interpolation'),
-        props.Widget('xColour'),
-        props.Widget('yColour'),
-        props.Widget('zColour'),
-        props.Widget('suppressX'),
-        props.Widget('suppressY'),
-        props.Widget('suppressZ'),
-        props.Widget('modulate', labels=_imageName),
-        props.Widget('modThreshold', showLimits=False, spin=False)],
-
-    'LineVectorOpts' : [
-        props.Widget('resolution',    showLimits=False),
-        props.Widget('transform',
-                     labels=strings.choices['ImageOpts.transform']),
-        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('modulate', labels=_imageName),
-        props.Widget('modThreshold', showLimits=False, spin=False)],
-
-    'ModelOpts' : [
-        props.Widget('colour'),
-        props.Widget('outline'),
-        props.Widget('outlineWidth', showLimits=False),
-        props.Widget('refImage', labels=_imageName),
-        # props.Widget('showName'),
-        props.Widget('coordSpace',
-                     enabledWhen=lambda o, ri: ri != 'none',
-                     dependencies=['refImage'])],
-
-    'LabelOpts' : [
-        props.Widget('lut', labels=lambda l: l.name),
-        props.Widget('outline',
-                     enabledWhen=lambda o, sw: not sw,
-                     dependencies=[(lambda o: o.display, 'softwareMode')]),
-        props.Widget('outlineWidth',
-                     showLimits=False,
-                     enabledWhen=lambda o, sw: not sw,
-                     dependencies=[(lambda o: o.display, 'softwareMode')]),
-        # props.Widget('showNames'),
-        props.Widget('resolution',   showLimits=False),
-        props.Widget('transform',
-                     labels=strings.choices['ImageOpts.transform']),
-        props.Widget('volume',
-                     showLimits=False,
-                     enabledWhen=lambda o: o.overlay.is4DImage())]
-})
-
     
 class OverlayDisplayPanel(fslpanel.FSLEyesPanel):
+    """The ``OverlayDisplayPanel`` is a :Class:`.FSLEyesPanel` which allows
+    the user to change the display settings of the currently selected
+    overlay (which is defined by the :attr:`.DisplayContext.selectedOverlay`
+    property). The display settings for an overlay are contained in the
+    :class:`.Display` and :class:`.DisplayOpts` instances associated with
+    that overlay. An ``OverlayDisplayPanel`` looks something like the
+    following:
+
+    .. image:: images/overlaydisplaypanel.png
+       :scale: 50%
+       :align: center
+
+    An ``OverlayDisplayPanel`` uses a :class:`.WidgetGrid` to organise the
+    settings into two main sections:
+
+      - Settings which are common across all overlays - these are defined
+        in the :class:`.Display` class.
+    
+      - Settings which are specific to the current
+        :attr:`.Display.overlayType` - these are defined in the
+        :class:`.DisplayOpts` sub-classes.
+
+    
+    The settings that are displayed on an ``OverlayDisplayPanel`` are
+    defined in the :attr:`_DISPLAY_PROPS` dictionary.
+    """
 
+    
     def __init__(self, parent, overlayList, displayCtx):
-        """
+        """Create an ``OverlayDisplayPanel``.
+
+        :arg parent:      The :mod:`wx` parent object.
+        :arg overlayList: The :class:`.OverlayList` instance.
+        :arg displayCtx:  The :class:`.DisplayContext` instance.
         """
 
         fslpanel.FSLEyesPanel.__init__(self, parent, overlayList, displayCtx)
@@ -169,6 +90,10 @@ class OverlayDisplayPanel(fslpanel.FSLEyesPanel):
 
         
     def destroy(self):
+        """Must be called when this ``OverlayDisplayPanel`` is no longer
+        needed. Removes property listeners, and calls the
+        :meth:`.FSLEyesPanel.destroy` method.
+        """
 
         self._displayCtx .removeListener('selectedOverlay', self._name)
         self._overlayList.removeListener('overlays',        self._name)
@@ -190,6 +115,11 @@ class OverlayDisplayPanel(fslpanel.FSLEyesPanel):
 
 
     def __selectedOverlayChanged(self, *a):
+        """Called when the :class:`.OverlayList` or
+        :attr:`.DisplayContext.selectedOverlay` changes. Refreshes this
+        ``OverlayDisplayPanel`` so that the display settings for the newly
+        selected overlay are shown.
+        """
 
         overlay     = self._displayCtx.getSelectedOverlay()
         lastOverlay = self.__currentOverlay
@@ -249,6 +179,10 @@ class OverlayDisplayPanel(fslpanel.FSLEyesPanel):
 
         
     def __ovlNameChanged(self, *a):
+        """Called when the :attr:`.Display.name` of the current overlay
+        changes. Updates the text label at the top of this
+        ``OverlayDisplayPanel``.
+        """
         
         display = self._displayCtx.getDisplay(self.__currentOverlay)
         self.__overlayName.SetLabel(display.name)
@@ -256,6 +190,11 @@ class OverlayDisplayPanel(fslpanel.FSLEyesPanel):
         
 
     def __ovlTypeChanged(self, *a):
+        """Called when the :attr:`.Display.overlayType` of the current overlay
+        changes. Refreshes the :class:`.DisplayOpts` settings which are shown,
+        as a new :class:`.DisplayOpts` instance will have been created for the
+        overlay.
+        """
 
         opts = self._displayCtx.getOpts(self.__currentOverlay)
         self.__updateWidgets(opts, 'opts')
@@ -263,6 +202,18 @@ class OverlayDisplayPanel(fslpanel.FSLEyesPanel):
         
 
     def __updateWidgets(self, target, groupName):
+        """Called by the :meth:`__selectedOverlayChanged` and
+        :meth:`__ovlTypeChanged` methods. Re-creates the controls on this
+        ``OverlayDisplayPanel`` for the specified group.
+
+        :arg target:    A :class:`.Display` or :class:`.DisplayOpts` instance,
+                        which contains the properties that controls are to be
+                        created for.
+
+        :arg groupName: Either ``'display'`` or ``'opts'``, corresponding
+                        to :class:`.Display` or :class:`.DisplayOpts`
+                        properties.
+        """
 
         self.__widgets.ClearGroup(groupName)
 
@@ -325,6 +276,10 @@ class OverlayDisplayPanel(fslpanel.FSLEyesPanel):
 
 
     def __buildColourMapWidget(self, cmapWidget):
+        """Creates a control which allows the user to load a custom colour
+        map. This control is added to the settings for :class:`.Image`
+        overlays with a :attr:`.Display.overlayType`  of ``'volume'``.
+        """
 
         action = loadcmap.LoadColourMapAction(self._overlayList,
                                               self._displayCtx)
@@ -340,3 +295,118 @@ class OverlayDisplayPanel(fslpanel.FSLEyesPanel):
         sizer.Add(button,     flag=wx.EXPAND)
         
         return sizer
+
+
+def _imageName(img):
+    """Used to generate choice labels for the :attr`.VectorOpts.modulate` and
+    :attr:`.ModelOpts.refImage` properties.
+    """
+    if img is None: return 'None'
+    else:           return img.name
+
+
+_DISPLAY_PROPS = td.TypeDict({
+    'Display' : [
+        props.Widget('name'),
+        props.Widget('overlayType',
+                     labels=strings.choices['Display.overlayType']),
+        props.Widget('enabled'),
+        props.Widget('alpha',      showLimits=False),
+        props.Widget('brightness', showLimits=False),
+        props.Widget('contrast',   showLimits=False)],
+
+    'VolumeOpts' : [
+        props.Widget('resolution',    showLimits=False),
+        props.Widget('transform',
+                     labels=strings.choices['ImageOpts.transform']),
+        props.Widget('volume',
+                     showLimits=False,
+                     enabledWhen=lambda o: o.overlay.is4DImage()),
+        props.Widget('interpolation',
+                     labels=strings.choices['VolumeOpts.interpolation']),
+        props.Widget('cmap'),
+        props.Widget('invert'),
+        props.Widget('invertClipping',
+                     enabledWhen=lambda o, sw: not sw,
+                     dependencies=[(lambda o: o.display, 'softwareMode')]),
+        props.Widget('displayRange',
+                     showLimits=False,
+                     slider=True,
+                     labels=[strings.choices['VolumeOpts.displayRange.min'],
+                             strings.choices['VolumeOpts.displayRange.max']]),
+        props.Widget('clippingRange',
+                     showLimits=False,
+                     slider=True,
+                     labels=[strings.choices['VolumeOpts.displayRange.min'],
+                             strings.choices['VolumeOpts.displayRange.max']])],
+
+    'MaskOpts' : [
+        props.Widget('resolution', showLimits=False),
+        props.Widget('transform',
+                     labels=strings.choices['ImageOpts.transform']),
+        props.Widget('volume',
+                     showLimits=False,
+                     enabledWhen=lambda o: o.overlay.is4DImage()),
+        props.Widget('colour'),
+        props.Widget('invert'),
+        props.Widget('threshold',  showLimits=False)],
+
+    'RGBVectorOpts' : [
+        props.Widget('resolution', showLimits=False),
+        props.Widget('transform',
+                     labels=strings.choices['ImageOpts.transform']),
+        props.Widget('interpolation'),
+        props.Widget('xColour'),
+        props.Widget('yColour'),
+        props.Widget('zColour'),
+        props.Widget('suppressX'),
+        props.Widget('suppressY'),
+        props.Widget('suppressZ'),
+        props.Widget('modulate', labels=_imageName),
+        props.Widget('modThreshold', showLimits=False, spin=False)],
+
+    'LineVectorOpts' : [
+        props.Widget('resolution',    showLimits=False),
+        props.Widget('transform',
+                     labels=strings.choices['ImageOpts.transform']),
+        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('modulate', labels=_imageName),
+        props.Widget('modThreshold', showLimits=False, spin=False)],
+
+    'ModelOpts' : [
+        props.Widget('colour'),
+        props.Widget('outline'),
+        props.Widget('outlineWidth', showLimits=False),
+        props.Widget('refImage', labels=_imageName),
+        # props.Widget('showName'),
+        props.Widget('coordSpace',
+                     enabledWhen=lambda o, ri: ri != 'none',
+                     dependencies=['refImage'])],
+
+    'LabelOpts' : [
+        props.Widget('lut', labels=lambda l: l.name),
+        props.Widget('outline',
+                     enabledWhen=lambda o, sw: not sw,
+                     dependencies=[(lambda o: o.display, 'softwareMode')]),
+        props.Widget('outlineWidth',
+                     showLimits=False,
+                     enabledWhen=lambda o, sw: not sw,
+                     dependencies=[(lambda o: o.display, 'softwareMode')]),
+        # props.Widget('showNames'),
+        props.Widget('resolution',   showLimits=False),
+        props.Widget('transform',
+                     labels=strings.choices['ImageOpts.transform']),
+        props.Widget('volume',
+                     showLimits=False,
+                     enabledWhen=lambda o: o.overlay.is4DImage())]
+})
+"""This dictionary contains specifications for all controls that are shown on
+an ``OverlayDisplayPanel``.
+"""
diff --git a/fsl/fsleyes/controls/overlayinfopanel.py b/fsl/fsleyes/controls/overlayinfopanel.py
index 245025693ba9d85bd468f0b96ddfb5ea23338672..8f15f85342208b794a0aca449b20e9df794764a2 100644
--- a/fsl/fsleyes/controls/overlayinfopanel.py
+++ b/fsl/fsleyes/controls/overlayinfopanel.py
@@ -1,9 +1,13 @@
 #!/usr/bin/env python
 #
-# overlayinfopanel.py -
+# overlayinfopanel.py - The OverlayInfoPanel class.
 #
 # Author: Paul McCarthy <pauldmccarthy@gmail.com>
 #
+"""This module provides the ``OverlayInfoPanel`` class, a *FSLeyes control*
+panel which displays information about the currently selected overlay.
+"""
+
 
 import collections
 
@@ -15,33 +19,35 @@ import fsl.data.constants as constants
 import fsl.fsleyes.panel  as fslpanel
 
 
-class OverlayInfo(object):
-    """A little class which encapsulates human-readable information about
-    one overlay. ``OverlayInfo`` objects are created and returned by the
-    ``OverlayInfoPanel.__get*Info`` methods.
-    """
-
-    def __init__(self, title):
-        
-        self.title    = title
-        self.info     = []
-        self.sections = collections.OrderedDict()
-
-        
-    def addSection(self, section):
-        self.sections[section] = []
-
-        
-    def addInfo(self, name, info, section=None):
-        if section is None: self.info             .append((name, info))
-        else:               self.sections[section].append((name, info))
-        
-
-
 class OverlayInfoPanel(fslpanel.FSLEyesPanel):
+    """An ``OverlayInfoPanel`` is a :class:`.FSLEyesPanel` which displays
+    information about the currently selected overlay in a
+    ``wx.html.HtmlWindow``. The currently selected overlay is defined by the
+    :attr:`.DisplayContext.selectedOverlay` property. An ``OverlayInfoPanel``
+    looks something like the following:
+
+    .. image:: images/overlayinfopanel.png
+       :scale: 50%
+       :align: center
+
+    Slightly different informtion is shown depending on the overlay type,
+    and is generated by the following methods:
+
+    =================== ==========================
+    :class:`.Image`     :meth:`__getImageInfo`
+    :class:`.FEATImage` :meth:`__getFEATImageInfo`
+    :class:`.Model`     :meth:`__getModelInfo`
+    =================== ==========================
+    """
 
 
     def __init__(self, parent, overlayList, displayCtx):
+        """Create an ``OverlayInfoPanel``.
+
+        :arg parent:      The :mod:`wx` parent object.
+        :arg overlayList: The :class:`.OverlayList` instance.
+        :arg displayCtx:  The :class:`.DisplayContext` instance.
+        """
 
         fslpanel.FSLEyesPanel.__init__(self, parent, overlayList, displayCtx)
 
@@ -69,6 +75,11 @@ class OverlayInfoPanel(fslpanel.FSLEyesPanel):
 
         
     def destroy(self):
+        """Must be called when this ``OverlayInfoPanel`` is no longer
+        needed. Removes some property listeners, and calls the
+        :meth:`.FSLEyesPanel.destroy` method.
+        """
+        
         self._displayCtx .removeListener('selectedOverlay', self._name)
         self._overlayList.removeListener('overlays',        self._name)
 
@@ -82,6 +93,10 @@ class OverlayInfoPanel(fslpanel.FSLEyesPanel):
 
 
     def __selectedOverlayChanged(self, *a):
+        """Called when the :class:`.OverlayList` or
+        :attr:`.DisplayContext.selectedOverlay` changes. Refreshes the
+        information shown on this ``OverlayInfoPanel``.
+        """
 
         overlay = self._displayCtx.getSelectedOverlay()
 
@@ -114,10 +129,17 @@ class OverlayInfoPanel(fslpanel.FSLEyesPanel):
 
         
     def __overlayNameChanged(self, *a):
+        """Called when the :attr:`.Display.name` for the current overlay
+        changes. Updates the information display.
+        """
         self.__updateInformation()
 
 
     def __updateInformation(self):
+        """Refreshes the information shown on this ``OverlayInfoPanel``.
+        Called by the :meth:`__selectedOverlayChanged` and
+        :meth:`__overlayNameChanged` methods.
+        """
 
         overlay   = self.__currentOverlay
         display   = self.__currentDisplay
@@ -125,6 +147,8 @@ class OverlayInfoPanel(fslpanel.FSLEyesPanel):
                                             type(overlay).__name__)
         infoFunc  = getattr(self, infoFunc, None)
 
+        # Try and preserve the
+        # current scroll position 
         scrollPos = self.__info.GetViewStart()
 
         # Overlay is none, or the overlay 
@@ -143,6 +167,13 @@ class OverlayInfoPanel(fslpanel.FSLEyesPanel):
 
 
     def __getImageInfo(self, overlay, display):
+        """Creates and returns an :class:`OverlayInfo` object containing
+        information about the given :class:`.Image` overlay.
+
+        :arg overlay: A :class:`.Image` instance.
+        :arg display: The :class:`.Display` instance assocated with the
+                      ``Image``.
+        """
         
         info = OverlayInfo('{} - {}'.format(
             display.name, strings.labels[self, overlay]))
@@ -238,6 +269,13 @@ class OverlayInfoPanel(fslpanel.FSLEyesPanel):
 
 
     def __getFEATImageInfo(self, overlay, display):
+        """Creates and returns an :class:`OverlayInfo` object containing
+        information about the given :class:`.FEATImage` overlay.
+
+        :arg overlay: A :class:`.FEATImage` instance.
+        :arg display: The :class:`.Display` instance assocated with the
+                      ``FEATImage``.
+        """ 
         info = self.__getImageInfo(overlay, display)
 
         featInfo = collections.OrderedDict([
@@ -257,6 +295,13 @@ class OverlayInfoPanel(fslpanel.FSLEyesPanel):
 
     
     def __getModelInfo(self, overlay, display):
+        """Creates and returns an :class:`OverlayInfo` object containing
+        information about the given :class:`.Model` overlay.
+
+        :arg overlay: A :class:`.Model` instance.
+        :arg display: The :class:`.Display` instance assocated with the
+                      ``Model``.
+        """ 
         info = OverlayInfo('{} - {}'.format(
             display.name,
             strings.labels[self, overlay]))
@@ -273,6 +318,9 @@ class OverlayInfoPanel(fslpanel.FSLEyesPanel):
 
 
     def __formatArray(self, array):
+        """Creates and returns a string containing a HTML table which
+        formats the data in the given ``numpy.array``.
+        """
 
         lines = []
 
@@ -290,6 +338,9 @@ class OverlayInfoPanel(fslpanel.FSLEyesPanel):
 
 
     def __formatOverlayInfo(self, info):
+        """Creates and returns a string containing some HTML which formats
+        the information in the given ``OverlayInfo`` instance.
+        """
         lines = []
 
         lines.append('<h3>{}</h3>'.format(info.title))
@@ -322,3 +373,45 @@ class OverlayInfoPanel(fslpanel.FSLEyesPanel):
             lines.append('</table>')
 
         return '\n'.join(lines)
+
+
+class OverlayInfo(object):
+    """A little class which encapsulates human-readable information about
+    one overlay. ``OverlayInfo`` objects are created and returned by the
+    ``OverlayInfoPanel.__get*Info`` methods.
+
+    The information stored in an ``OverlayInfo`` instance is organised into
+    *sections*. Within each section, information is organised into key-value
+    pairs. The order in which both ``OverlayInfo`` sections, and information,
+    is ultimately output, is the order in which the sections/information are
+    added, via the :meth:`addSection` and :meth:`addInfo` methods.
+    """
+
+    def __init__(self, title):
+        """Create an ``OverlayInfo`` instance.
+
+        :arg title: The ``OverlaytInfo`` title.
+        """
+        
+        self.title    = title
+        self.info     = []
+        self.sections = collections.OrderedDict()
+
+        
+    def addSection(self, section):
+        """Add a section to this ``OverlayInfo`` instance.
+
+        :arg section: The section name.
+        """
+        self.sections[section] = []
+
+        
+    def addInfo(self, name, info, section=None):
+        """Add some information to this ``OverlayInfo`` instance.
+
+        :arg name:    The information name.
+        :arg info:    The information value.
+        :arg section: Section to place the information in.
+        """ 
+        if section is None: self.info             .append((name, info))
+        else:               self.sections[section].append((name, info))