From 085ca86e63260155db6f7a8d34290b789017fd17 Mon Sep 17 00:00:00 2001 From: Paul McCarthy <pauld.mccarthy@gmail.com> Date: Mon, 7 Sep 2015 13:52:43 +0100 Subject: [PATCH] 1. Documentation for all DisplayOpts modules. 2. Updated documentation references to __init__ methods, as sphinx doesn't resolve them. 3. Bug fix in featresults module when loading contrast matrix. --- fsl/data/featimage.py | 2 +- fsl/data/featresults.py | 2 +- fsl/data/image.py | 9 +- fsl/fsleyes/actions/__init__.py | 3 +- fsl/fsleyes/actions/copyoverlay.py | 2 +- fsl/fsleyes/actions/saveoverlay.py | 2 +- fsl/fsleyes/displaycontext/display.py | 2 +- fsl/fsleyes/displaycontext/displaycontext.py | 8 +- fsl/fsleyes/displaycontext/labelopts.py | 39 +++++- fsl/fsleyes/displaycontext/lightboxopts.py | 2 +- fsl/fsleyes/displaycontext/maskopts.py | 30 +++- fsl/fsleyes/displaycontext/modelopts.py | 99 ++++++++++++-- fsl/fsleyes/displaycontext/orthoopts.py | 2 +- fsl/fsleyes/displaycontext/vectoropts.py | 50 +++++-- fsl/fsleyes/displaycontext/volumeopts.py | 137 +++++++++++++------ fsl/fsleyes/frame.py | 2 +- 16 files changed, 298 insertions(+), 93 deletions(-) diff --git a/fsl/data/featimage.py b/fsl/data/featimage.py index 59d409158..6c536ba10 100644 --- a/fsl/data/featimage.py +++ b/fsl/data/featimage.py @@ -55,7 +55,7 @@ class FEATImage(fslimage.Image): :arg path: A FEAT analysis directory, or an image file contained within such a directory. - :arg kwargs: Passed to the :meth:`.Image.__init__` constructor. + :arg kwargs: Passed to the :class:`.Image` constructor. .. note:: If a FEAT directory is passed in for the ``path`` argument, this ``FEATImage`` instance will encapsulate diff --git a/fsl/data/featresults.py b/fsl/data/featresults.py index 1a65c2ce9..5148d99d5 100644 --- a/fsl/data/featresults.py +++ b/fsl/data/featresults.py @@ -170,7 +170,7 @@ def loadContrasts(featdir): elif line == '/Matrix': break - matrix = np.loadtxt(f) + matrix = np.loadtxt(f, ndmin=2) if matrix is None or \ numContrasts != matrix.shape[0]: diff --git a/fsl/data/image.py b/fsl/data/image.py index 2547614fd..31988dc6e 100644 --- a/fsl/data/image.py +++ b/fsl/data/image.py @@ -535,10 +535,11 @@ def loadImage(filename): """Given the name of an image file, loads it using nibabel. If the file is large, and is gzipped, it is decompressed to a temporary - location, so that it can be memory-mapped. A tuple is returned, - consisting of the nibabel image object, and the name of the file that it - was loaded from (either the passed-in file name, or the name of the - temporary decompressed file). + location, so that it can be memory-mapped. + + In any case, a tuple is returned, consisting of the nibabel image object, + and the name of the file that it was loaded from (either the passed-in + file name, or the name of the temporary decompressed file). """ # If we have a GUI, we can display a dialog diff --git a/fsl/fsleyes/actions/__init__.py b/fsl/fsleyes/actions/__init__.py index 8101d5ba5..f789ab0c5 100644 --- a/fsl/fsleyes/actions/__init__.py +++ b/fsl/fsleyes/actions/__init__.py @@ -241,7 +241,8 @@ class ActionProvider(props.SyncableHasProperties): mappings, where each function is an action that should be made available to the user. - :arg kwargs: Passed to :meth:`.SyncableHasProperties.__init__`. + :arg kwargs: Passed to the :class:`.SyncableHasProperties` + constructor. """ actions = kwargs.pop('actions', None) diff --git a/fsl/fsleyes/actions/copyoverlay.py b/fsl/fsleyes/actions/copyoverlay.py index e7205d35c..67fbd04ad 100644 --- a/fsl/fsleyes/actions/copyoverlay.py +++ b/fsl/fsleyes/actions/copyoverlay.py @@ -27,7 +27,7 @@ class CopyOverlayAction(actions.Action): def __init__(self, *args, **kwargs): """Create a ``CopyOverlayAction``. All arguments are passed through - to the :meth:`.Action.__init__` constructor. + to the :class:`.Action` constructor. """ actions.Action.__init__(self, *args, **kwargs) diff --git a/fsl/fsleyes/actions/saveoverlay.py b/fsl/fsleyes/actions/saveoverlay.py index ddbcb4508..56d95c38a 100644 --- a/fsl/fsleyes/actions/saveoverlay.py +++ b/fsl/fsleyes/actions/saveoverlay.py @@ -26,7 +26,7 @@ class SaveOverlayAction(actions.Action): def __init__(self, *args, **kwargs): """Create a ``SaveOverlayAction``. All arguments are passed through - to the :meth:`.Action.__init__` constructor. + to the :class:`.Action` constructor. """ actions.Action.__init__(self, *args, **kwargs) diff --git a/fsl/fsleyes/displaycontext/display.py b/fsl/fsleyes/displaycontext/display.py index 6fa4ce49a..43cdbe300 100644 --- a/fsl/fsleyes/displaycontext/display.py +++ b/fsl/fsleyes/displaycontext/display.py @@ -397,7 +397,7 @@ class DisplayOpts(actions.ActionProvider): how the overlays are to be displayed. :arg kwargs: Passed through to the - :meth:`.ActionProvider.__init__` constructor. + :class:`.ActionProvider` constructor. """ actions.ActionProvider.__init__( diff --git a/fsl/fsleyes/displaycontext/displaycontext.py b/fsl/fsleyes/displaycontext/displaycontext.py index 73c69bc96..53d6217f9 100644 --- a/fsl/fsleyes/displaycontext/displaycontext.py +++ b/fsl/fsleyes/displaycontext/displaycontext.py @@ -108,8 +108,8 @@ class DisplayContext(props.SyncableHasProperties): every overlay will be unsynchronised from the parent. .. note:: This property is accessed by the :class:`.Display` class, in its - :meth:`.Display.__init__` method, and when it creates new - :class:`.DisplayOpts` instances, to set initial sync states. + constructor, and when it creates new :class:`.DisplayOpts` + instances, to set initial sync states. """ @@ -120,7 +120,7 @@ class DisplayContext(props.SyncableHasProperties): :arg parent: Another ``DisplayContext`` instance to be used as the parent of this instance, passed to the - :meth:`.SyncableHasProperties.__init__` constructor. + :class:`.SyncableHasProperties` constructor. """ props.SyncableHasProperties.__init__( @@ -208,7 +208,7 @@ class DisplayContext(props.SyncableHasProperties): :arg overlayType: If a ``Display`` instance for the specified ``overlay`` does not exist, one is created - in this case, the specified ``overlayType`` is passed - to the :meth:`.Display.__init__` method. + to the :class:`.Display` constructor. """ if overlay is None: diff --git a/fsl/fsleyes/displaycontext/labelopts.py b/fsl/fsleyes/displaycontext/labelopts.py index 86dcbbcfc..1665e762d 100644 --- a/fsl/fsleyes/displaycontext/labelopts.py +++ b/fsl/fsleyes/displaycontext/labelopts.py @@ -1,9 +1,13 @@ #!/usr/bin/env python # -# labelopts.py - +# labelopts.py - The LabelOpts class. # # Author: Paul McCarthy <pauldmccarthy@gmail.com> # +"""This module provides the :class:`LabelOpts` class, which defines settings +for displaying :class:`.Image` overlays as label images., such as anatomical +atlas images, tissue segmentation images, and so on. +""" import props @@ -13,14 +17,39 @@ import fsl.fsleyes.colourmaps as fslcm class LabelOpts(volumeopts.ImageOpts): - - lut = props.Choice() - outline = props.Boolean(default=False) + """The ``LabelOpts`` class defines settings for displaying + :class:`.Image` overlays as label images., such as anatomical atlas + images, tissue segmentation images, and so on. + """ + + lut = props.Choice() + """The :class:`.LookupTable` used to colour each label. + """ + + outline = props.Boolean(default=False) + """If ``True`` only the outline of contiguous regions with the same label + value will be shown. If ``False``, contiguous regions will be filled. + """ + + outlineWidth = props.Real(minval=0, maxval=1, default=0.25, clamped=True) - showNames = props.Boolean(default=False) + """Width of labelled region outlines, if :attr:``outline` is ``True``. + This value is in terms of the image voxels - a value of 1 will result in + an outline that is one voxel wide. + """ + + + showNames = props.Boolean(default=False) + """If ``True``, region names (as defined by the current + :class:`.LookupTable`) will be shown alongside each labelled region. + """ def __init__(self, overlay, *args, **kwargs): + """Create a ``LabelOpts`` instance for the specified ``overlay``. + All arguments are passed through to the :class:`.ImageOpts` + constructor. + """ volumeopts.ImageOpts.__init__(self, overlay, *args, **kwargs) luts = fslcm.getLookupTables() diff --git a/fsl/fsleyes/displaycontext/lightboxopts.py b/fsl/fsleyes/displaycontext/lightboxopts.py index a1ed726d6..c8cb53c76 100644 --- a/fsl/fsleyes/displaycontext/lightboxopts.py +++ b/fsl/fsleyes/displaycontext/lightboxopts.py @@ -35,7 +35,7 @@ class LightBoxOpts(sceneopts.SceneOpts): def __init__(self, *args, **kwargs): """Create a ``LightBoxOpts`` instance. All arguments are passed - through to the :meth:`.SceneOpts.__init__` method. + through to the :class:`.SceneOpts` constructor. The :attr:`.SceneOpts.zoom` attribute is modified, as :class:`LightBoxPanel` uses it slightly differently to the diff --git a/fsl/fsleyes/displaycontext/maskopts.py b/fsl/fsleyes/displaycontext/maskopts.py index 6616f4752..972f1eb18 100644 --- a/fsl/fsleyes/displaycontext/maskopts.py +++ b/fsl/fsleyes/displaycontext/maskopts.py @@ -1,9 +1,12 @@ #!/usr/bin/env python # -# maskopts.py - +# maskopts.py - The MaskOpts class. # # Author: Paul McCarthy <pauldmccarthy@gmail.com> # +"""This module provides the :class:`MaskOpts` class, which defines settings +for displaying an :class:`.Image` overlay as a binary mask. +""" import numpy as np @@ -15,15 +18,32 @@ import volumeopts class MaskOpts(volumeopts.ImageOpts): + """The ``MaskOpts`` class defines settings for displaying an + :class:`.Image` overlay as a binary mask. + """ - colour = props.Colour() - invert = props.Boolean(default=False) - threshold = props.Bounds( + threshold = props.Bounds( ndims=1, labels=[strings.choices['VolumeOpts.displayRange.min'], - strings.choices['VolumeOpts.displayRange.max']]) + strings.choices['VolumeOpts.displayRange.max']]) + """The mask threshold range - values outside of this range are not + displayed. + """ + + invert = props.Boolean(default=False) + """If ``True``, the :attr:`threshold` range is inverted - values + inside the range are not shown, and values outside of the range are shown. + """ + + + colour = props.Colour() + """The mask colour.""" + def __init__(self, overlay, *args, **kwargs): + """Create a ``MaskOpts`` instance for the given overlay. All arguments + are passed through to the :class:`.ImageOpts` constructor. + """ if np.prod(overlay.shape) > 2 ** 30: sample = overlay.data[..., overlay.shape[-1] / 2] diff --git a/fsl/fsleyes/displaycontext/modelopts.py b/fsl/fsleyes/displaycontext/modelopts.py index 5491ba4bf..7f10ad46e 100644 --- a/fsl/fsleyes/displaycontext/modelopts.py +++ b/fsl/fsleyes/displaycontext/modelopts.py @@ -1,9 +1,13 @@ #!/usr/bin/env python # -# modelopts.py - +# modelopts.py - The ModelOpts class. # # Author: Paul McCarthy <pauldmccarthy@gmail.com> # +"""This module provides the :class:`ModelOpts` class, which defines settings +for displaying :class:`.Model` overlays. +""" + import copy @@ -21,17 +25,61 @@ import volumeopts class ModelOpts(fsldisplay.DisplayOpts): + """The ``ModelOpts`` class defines settings for displaying :class:`.Model` + overlays. + """ + + colour = props.Colour() + """The model colour. """ + + + outline = props.Boolean(default=False) + """If ``True``, an outline of the model is shown. Otherwise the model is + filled. + """ - colour = props.Colour() - outline = props.Boolean(default=False) + outlineWidth = props.Real(minval=0, maxval=1, default=0.25, clamped=True) - showName = props.Boolean(default=False) - refImage = props.Choice() - coordSpace = copy.copy(volumeopts.ImageOpts.transform) - transform = copy.copy(volumeopts.ImageOpts.transform) + """If :attr:`outline` is ``True``, this property defines the width of the + outline. + """ + + + showName = props.Boolean(default=False) + """If ``True``, the model name is shown alongside the model. """ + + + refImage = props.Choice() + """A reference :class:`.Image` instance which the model coordinates are + in terms of. + + For example, if this :class:`.Model` represents the segmentation of a + sub-cortical region from a T1 image, you would set the ``refImage`` to that + T1 image. + + Any :class:`.Image` instance in the :class:`.OverlayList` may be chosen + as the reference image. + """ + + + coordSpace = copy.copy(volumeopts.ImageOpts.transform) + """If :attr:`refImage` is not ``None``, this property defines the + reference image coordinate space in whihc the model coordinates are + defined (i.e. voxels, scaled voxels, or world coordinates). + """ + + + transform = copy.copy(volumeopts.ImageOpts.transform) + """If :attr:`refImage` is not ``None``, this property is bound to + the :attr:`~.ImageOpts.transform` property of the reference image + :class:`.ImageOpts` instance. + """ def __init__(self, *args, **kwargs): + """Create a ``ModelOpts`` instance. All arguments are passed through + to the :class:`.DisplayOpts` constructor. + """ # Create a random, highly # saturated colour @@ -73,6 +121,9 @@ class ModelOpts(fsldisplay.DisplayOpts): def destroy(self): + """Removes some property listeners, and calls the + :meth:`.DisplayOpts.destroy` method. + """ self.overlayList.removeListener('overlays', self.name) for overlay in self.overlayList: @@ -92,9 +143,14 @@ class ModelOpts(fsldisplay.DisplayOpts): def getCoordSpaceTransform(self): + """Returns a transformation matrix which can be used to transform + the :class:`.Model` vertex coordinates into the display coordinate + system. - if self.refImage is None or \ - self.coordSpace == self.transform: + If no :attr:`refImage` is selected, this method returns ``None``. + """ + + if self.refImage is None or self.coordSpace == self.transform: return None opts = self.displayCtx.getOpts(self.refImage) @@ -103,6 +159,11 @@ class ModelOpts(fsldisplay.DisplayOpts): def transformDisplayLocation(self, oldLoc): + """If the :attr:`refImage`, :attr:`coordSpace` or :attr:`transform` + properties have changed, this method will transform the specified + location from the old :class:`.Model` display coordinate system to + the new model display coordinate system. + """ newLoc = oldLoc propName = self.__lastPropChanged @@ -152,16 +213,32 @@ class ModelOpts(fsldisplay.DisplayOpts): def __transformChanged(self, *a): + """Called when the :attr:`transfrom` property changes. + Calls :meth:`__updateBounds`. + """ self.__lastPropChanged = 'transform' self.__updateBounds() def __coordSpaceChanged(self, *a): + """Called when the :attr:`coordSpace` property changes. + Calls :meth:`__updateBounds`. + """ self.__lastPropChanged = 'coordSpace' self.__updateBounds() def __refImageChanged(self, *a): + """Called when the :attr:`refImage` property changes. Configures the + :attr:`transform` property to track the :attr:`~.ImageOpts.transform` + property of the :class:`.ImageOpts` instance associated with the new + reference image, and calls :meth:`__updateBounds`. + """ + + # TODO You are not tracking changes to the + # refImage overlay type - if this changes, + # you will need to re-bind to the transform + # property of the new DisplayOpts instance self.__lastPropChanged = 'refImage' @@ -200,7 +277,7 @@ class ModelOpts(fsldisplay.DisplayOpts): def __overlayListChanged(self, *a): - """Called when the overlay list changes. Updates the ``refImage`` + """Called when the overlay list changes. Updates the :attr:`refImage` property so that it contains a list of overlays which can be associated with the model. """ @@ -219,7 +296,7 @@ class ModelOpts(fsldisplay.DisplayOpts): for overlay in overlays: - # The image must be an Image instance. + # The overlay must be an Image instance. if not isinstance(overlay, fslimage.Image): continue diff --git a/fsl/fsleyes/displaycontext/orthoopts.py b/fsl/fsleyes/displaycontext/orthoopts.py index 5fd075c7e..942b4a53e 100644 --- a/fsl/fsleyes/displaycontext/orthoopts.py +++ b/fsl/fsleyes/displaycontext/orthoopts.py @@ -66,7 +66,7 @@ class OrthoOpts(sceneopts.SceneOpts): def __init__(self, *args, **kwargs): """Create an ``OrthoOpts`` instance. All arguments are passed - through to the :meth:`.SceneOpts.__init__` constructor. + through to the :class:`.SceneOpts` constructor. This method sets up a binding from the :attr:`.SceneOpts.zoom` property to the :attr:`xzoom`, :attr:`yzoom`, and :attr:`zzoom` diff --git a/fsl/fsleyes/displaycontext/vectoropts.py b/fsl/fsleyes/displaycontext/vectoropts.py index 8bf19edf7..a9eace481 100644 --- a/fsl/fsleyes/displaycontext/vectoropts.py +++ b/fsl/fsleyes/displaycontext/vectoropts.py @@ -4,10 +4,12 @@ # # Author: Paul McCarthy <pauldmccarthy@gmail.com> # -"""This module defines the :class:`VectorOpts` class, which contains display -options for rendering :class:`.GLVector` instances. +"""This module provides the :class:`VectorOpts`, :class:`LineVectorOpts`, and +:class:`RGBVectorOpts` classes, which contain options for displaying NIFTI1 +vector images. """ + import copy import props @@ -17,6 +19,10 @@ import volumeopts class VectorOpts(volumeopts.ImageOpts): + """The ``VectorOpts`` class is the base class for :class:`LineVectorOpts` and + :class:`RGBVectorOpts`. It contains display settings which are common to + both. + """ xColour = props.Colour(default=(1.0, 0.0, 0.0)) @@ -44,20 +50,25 @@ class VectorOpts(volumeopts.ImageOpts): modulate = props.Choice() - """Modulate the vector colours by another image.""" + """Modulate the vector colours by another 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. + """ # TODO This is currently a percentage # of the modulation image data range. # It should be an absolute value modThreshold = props.Percentage(default=0.0) - """Hide voxels for which the modulation value is below this threshold.""" + """Hide voxels for which the modulation value is below this threshold, + as a percentage of the :attr:`modulate` image data range. + """ def __init__(self, *args, **kwargs): - """Create a ``VectorOpts`` instance for the given image. - - See the :class:`.ImageOpts` documentation for more details. + """Create a ``VectorOpts`` instance for the given image. All + arguments are passed through to the :class:`.ImageOpts` + constructor. """ volumeopts.ImageOpts.__init__(self, *args, **kwargs) @@ -70,6 +81,9 @@ class VectorOpts(volumeopts.ImageOpts): def destroy(self): + """Removes some property listeners, and calls the + :meth:`.ImageOpts.destroy` method. + """ self.overlayList.removeListener('overlays', self.name) for overlay in self.overlayList: @@ -80,7 +94,7 @@ class VectorOpts(volumeopts.ImageOpts): def __overlayListChanged(self, *a): - """Called when the overlay list changes. Updates the ``modulate`` + """Called when the overlay list changes. Updates the :attr:`modulate` property so that it contains a list of overlays which could be used to modulate the vector image. """ @@ -129,17 +143,25 @@ class VectorOpts(volumeopts.ImageOpts): class LineVectorOpts(VectorOpts): + """The ``LineVectorOpts`` class contains settings for displaying vector + images, using a line to represent the vector value at each voxel. + """ + lineWidth = props.Int(minval=1, maxval=10, default=1) - - directed = props.Boolean(default=False) + """Width of the line in pixels. """ - The directed property cannot be unbound across multiple LineVectorOpts - instances, as it affects the OpenGL representation + directed = props.Boolean(default=False) + """If ``True``, the vector data is interpreted as directed. Otherwise, + the vector data is assumed to be undirected. """ + def __init__(self, *args, **kwargs): + """Create a ``LineVectorOpts`` instance. All arguments are passed + through to the :class:`VectorOpts` constructor. + """ kwargs['nounbind'] = ['directed'] @@ -148,5 +170,9 @@ class LineVectorOpts(VectorOpts): class RGBVectorOpts(VectorOpts): + """The ``RGBVectorOpts`` class contains settings for displaying vector + images, using a combination of three colours to represent the vector value + at each voxel. + """ interpolation = copy.copy(volumeopts.VolumeOpts.interpolation) diff --git a/fsl/fsleyes/displaycontext/volumeopts.py b/fsl/fsleyes/displaycontext/volumeopts.py index 2635e1d01..19fd4331a 100644 --- a/fsl/fsleyes/displaycontext/volumeopts.py +++ b/fsl/fsleyes/displaycontext/volumeopts.py @@ -7,6 +7,8 @@ """This module defines the :class:`ImageOpts` and :class:`VolumeOpts` classes. +.. _volumeopts-coordinate-systems: + --------------------------------------- An important note on coordinate systems --------------------------------------- @@ -28,7 +30,7 @@ overlays can potentially be displayed in one of three coordinate systems: **world** space (a.k.a. ``affine``) The image data voxel coordinates are transformed by the ``qform``/``sform`` transformation matrix stored in the NIFTI1 header. - ==================== ==================================================== + ====================== ==================================================== The :attr:`Image.transform` property controls how the image data is @@ -108,38 +110,37 @@ class ImageOpts(fsldisplay.DisplayOpts): """The ``ImageOpts`` class describes how an :class:`.Image` overlay should be displayed. + ``ImageOpts`` is the base class for a number of :class:`.DisplayOpts` - sub-classes - it contains display options which are common to all. + sub-classes - it contains display options which are common to all overlay + types that represent a NIFTI1 image. """ volume = props.Int(minval=0, maxval=0, default=0, clamped=True) - """If the ``Image`` is 4D, the current volume to display.""" + """If the ``Image`` is 4D, the current volume to display.""" resolution = props.Real(maxval=10, default=1, clamped=True) """Data resolution in the image world coordinate system. The minimum - value is set in :meth:`__init__`. + value is configured in :meth:`__init__`. """ transform = props.Choice(('affine', 'pixdim', 'id'), default='pixdim') - """This property defines how the overlay should be transformd into the - display coordinate system. - - - ``affine``: Use the affine transformation matrix stored in the image - (the ``qform``/``sform`` fields in NIFTI1 headers). - - - ``pixdim``: Scale voxel sizes by the ``pixdim`` fields in the image - header. - - - ``id``: Perform no scaling or transformation - voxels will be - interpreted as :math:`1mm^3` isotropic, with the origin at voxel - (0,0,0). + """This property defines how the overlay should be transformd into + the display coordinate system. See the + :ref:`note on coordinate systems <volumeopts-coordinate-systems>` + for important information regarding this property. """ def __init__(self, *args, **kwargs): + """Create an ``ImageOpts`` instance. + + All arguments are passed through to the :class:`.DisplayOpts` + constructor. + """ # The transform property cannot be unsynced # across different displays, as it affects @@ -172,11 +173,14 @@ class ImageOpts(fsldisplay.DisplayOpts): def destroy(self): + """Calls the :meth:`.DisplayOpts.destroy` method. """ fsldisplay.DisplayOpts.destroy(self) def __transformChanged(self, *a): - """Calculates the min/max values of a 3D bounding box, in the display + """Called when the :attr:`transform` property changes. + + Calculates the min/max values of a 3D bounding box, in the display coordinate system, which is big enough to contain the image. Sets the :attr:`.DisplayOpts.bounds` property accordingly. """ @@ -234,20 +238,24 @@ class ImageOpts(fsldisplay.DisplayOpts): """Return a matrix which may be used to transform coordinates from ``from_`` to ``to``. Valid values for ``from_`` and ``to`` are: - - ``id``: Voxel coordinates + - - ``pixdim``: Voxel coordinates, scaled by voxel dimensions + =========== ====================================================== + ``id`` Voxel coordinates - - ``affine``: World coordinates, as defined by the NIFTI1 - ``qform``/``sform``. See - :attr:`~fsl.data.image.Image.voxToWorldMat`. + ``pixdim`` Voxel coordinates, scaled by voxel dimensions - - ``voxel``: Equivalent to ``id``. + ``affine`` World coordinates, as defined by the NIFTI1 + ``qform``/``sform``. See :attr:`.Image.voxToWorldMat`. - - ``display``: Equivalent to the current value of :attr:`transform`. + ``voxel`` Equivalent to ``id``. - - ``world``; Equivalent to ``affine``. + ``display`` Equivalent to the current value of :attr:`transform`. + + ``world`` Equivalent to ``affine``. + =========== ====================================================== + If the ``xform`` parameter is provided, and one of ``from_`` or ``to`` is ``display``, the value of ``xform`` is used instead of the current value of :attr:`transform`. @@ -268,9 +276,9 @@ class ImageOpts(fsldisplay.DisplayOpts): def getTransformOffsets(self, from_, to_): - """When an image is displayed in id/pixdim space, voxel coordinates - map to the voxel corner; i.e. a voxel at ``(0, 1, 2)`` occupies the - space ``(0 - 1, 1 - 2, 2 - 3)``. + """When an image is displayed in ``id``/``pixdim`` space, voxel + coordinates map to the voxel corner; i.e. a voxel at ``(0, 1, 2)`` + occupies the space ``(0 - 1, 1 - 2, 2 - 3)``. In contrast, when an image is displayed in affine space, voxel coordinates map to the voxel centre, so our voxel from above will @@ -289,6 +297,12 @@ class ImageOpts(fsldisplay.DisplayOpts): See also the :meth:`transformCoords` method, which will perform the transformation correctly for you, without you having to worry about these offsets. + + + .. note:: These offsets, and this method, will soon become obsolete - + see the note about **GedMode** in the + :ref:`note on coordinate systems + <volumeopts-coordinate-systems>`. """ displaySpace = self.transform pixdim = np.array(self.overlay.pixdim[:3]) @@ -354,9 +368,10 @@ class ImageOpts(fsldisplay.DisplayOpts): correcting for display space offsets (see :meth:`getTransformOffsets`). The ``from_`` and ``to_`` parameters must both be one of: - - ``display`` - - ``voxel`` - - ``world`` + + - ``display``: The display coordinate system + - ``voxel``: The image voxel coordinate system + - ``world``: The image world coordinate system """ xform = self.getTransform( from_, to_) @@ -369,6 +384,12 @@ class ImageOpts(fsldisplay.DisplayOpts): def transformDisplayLocation(self, oldLoc): + """Overrides :meth:`.DisplayOpts.transformDisplayLocation`. + + If the :attr:`transform` property has changed, returns the given + location, assumed to be in the old display coordinate system, + transformed into the new display coordinate system. + """ lastVal = self.getLastValue('transform') @@ -390,11 +411,31 @@ class ImageOpts(fsldisplay.DisplayOpts): class VolumeOpts(ImageOpts): - """A class which describes how an :class:`.Image` should be displayed. - - This class doesn't have much functionality - it is up to things which - actually display an :class:`.Image` to adhere to the properties stored in - the associated :class:`.Display` and :class:`VolumeOpts` object. + """The ``VolumeOpts`` class defines options for displaying :class:`.Image` + instances as regular 3D volumes. + + The ``VolumeOpts`` class links the :attr:`.Display.brightness` and + :attr:`.Display.contrast` properties to its own :attr:`displayRange` + property, so changes in either of the former will result in a change to + the latter, and vice versa. This relationship is defined by the + :func:`~.colourmaps.displayRangeToBricon` and + :func:`~.colourmaps.briconToDisplayRange` functions, in the + :mod:`.colourmaps` module. + + In addition to all of the display properties, ``VolumeOpts`` instances + have the following attributes: + + =========== =============================== + ``dataMin`` The minimum value in the image. + ``dataMax`` The maximum value in the image. + =========== =============================== + + For large images (where *large* is arbitrarily defined in + :meth:`__init__`), the ``dataMin`` and ``dataMax`` attributes will contain + range of a sample of the image data, rather their actual values. This is + purely to eliminate the need to calculate minimum/maximum values over very + large (and potentially memory-mapped) images, which can be a time + consuming operation. """ @@ -407,7 +448,7 @@ class VolumeOpts(ImageOpts): invertClipping = props.Boolean(default=False) - """If ``True``, the behaviour of ``clippingRange`` is inverted, i.e. + """If ``True``, the behaviour of :attr:`clippingRange` is inverted, i.e. values inside the clipping range are clipped, instead of those outside the clipping range. """ @@ -419,13 +460,15 @@ class VolumeOpts(ImageOpts): interpolation = props.Choice(('none', 'linear', 'spline')) """How the value shown at a real world location is derived from the - corresponding data value(s). 'No interpolation' is equivalent to nearest - neighbour interpolation. + corresponding data value(s). ``none`` is equivalent to nearest neighbour + interpolation. """ invert = props.Boolean(default=False) - """Invert the colour map.""" + """Use an inverted version of the current colour map (see the :attr:`cmap` + property). + """ def __init__(self, @@ -434,7 +477,12 @@ class VolumeOpts(ImageOpts): overlayList, displayCtx, **kwargs): - """Create a :class:`VolumeOpts` instance for the specified image.""" + """Create a :class:`VolumeOpts` instance for the specified ``overlay``, + assumed to be an :class:`.Image` instance. + + All arguments are passed through to the :class:`.DisplayOpts` + constructor. + """ # Attributes controlling image display. Only # determine the real min/max for small images - @@ -516,6 +564,9 @@ class VolumeOpts(ImageOpts): def destroy(self): + """Removes property listeners, and calls the :meth:`ImageOpts.destroy` + method. + """ if self.getParent() is not None: display = self.display @@ -535,7 +586,7 @@ class VolumeOpts(ImageOpts): def __toggleListeners(self, enable=True): """This method enables/disables the property listeners which are registered on the :attr:`displayRange` and - :attr:`.Display.brightness`/:attr:`.Display.contrast`/ properties. + :attr:`.Display.brightness`/:attr:`.Display.contrast`/properties. Because these properties are linked via the :meth:`__displayRangeChanged` and :meth:`__briconChanged` methods, @@ -596,7 +647,7 @@ class VolumeOpts(ImageOpts): def __displayRangeChanged(self, *a): - """Called when the `attr`:displayRange: property changes. + """Called when the `attr:`displayRange` property changes. Updates the :attr:`.Display.brightness` and :attr:`.Display.contrast` properties accordingly. diff --git a/fsl/fsleyes/frame.py b/fsl/fsleyes/frame.py index 143df255e..5c1f8d63a 100644 --- a/fsl/fsleyes/frame.py +++ b/fsl/fsleyes/frame.py @@ -405,7 +405,7 @@ class FSLEyesFrame(wx.Frame): def __restoreState(self, restore=True): - """Called on :meth:`__init__`. + """Called by :meth:`__init__`. If any frame size/layout properties have previously been saved via the :mod:`~fsl.utils.settings` module, they are read in, and applied to -- GitLab