Skip to content
Snippets Groups Projects
Commit cce833cf authored by Paul McCarthy's avatar Paul McCarthy
Browse files

New module, displaydefaults, which attempts to configure sensible

default display settings for new overlays. Used by the addfile action,
the overlay list panel, and at startup via fsleyes_parseargs.
parent 0d97259c
No related branches found
No related tags found
No related merge requests found
...@@ -11,6 +11,8 @@ load overlay files into the :class:`.OverlayList`. ...@@ -11,6 +11,8 @@ load overlay files into the :class:`.OverlayList`.
import action import action
import fsl.fsleyes.displaydefaults as displaydefaults
class OpenFileAction(action.Action): class OpenFileAction(action.Action):
"""The ``OpenFileAction`` allows the user to add files to the """The ``OpenFileAction`` allows the user to add files to the
...@@ -34,7 +36,15 @@ class OpenFileAction(action.Action): ...@@ -34,7 +36,15 @@ class OpenFileAction(action.Action):
"""Calls :meth:`.OverlayList.addOverlays` method. If overlays were added, """Calls :meth:`.OverlayList.addOverlays` method. If overlays were added,
updates the :attr:`.DisplayContext.selectedOverlay` accordingly. updates the :attr:`.DisplayContext.selectedOverlay` accordingly.
""" """
overlays = self.__overlayList.addOverlays()
if len(overlays) == 0:
return
if self.__overlayList.addOverlays(): self.__displayCtx.selectedOverlay = self.__displayCtx.overlayOrder[-1]
self.__displayCtx.selectedOverlay = \
self.__displayCtx.overlayOrder[-1] for overlay in overlays:
displaydefaults.displayDefaults(overlay,
self.__overlayList,
self.__displayCtx)
...@@ -49,6 +49,8 @@ class OpenStandardAction(action.Action): ...@@ -49,6 +49,8 @@ class OpenStandardAction(action.Action):
added some overlays, updates the added some overlays, updates the
:attr:`.DisplayContext.selectedOverlay` accordingly. :attr:`.DisplayContext.selectedOverlay` accordingly.
""" """
if self.__overlayList.addOverlays(self.__stddir, addToEnd=False): added = self.__overlayList.addOverlays(self.__stddir, addToEnd=False)
if len(added) > 0:
self.__displayCtx.selectedOverlay = \ self.__displayCtx.selectedOverlay = \
self.__displayCtx.overlayOrder[0] self.__displayCtx.overlayOrder[0]
...@@ -15,11 +15,12 @@ import wx ...@@ -15,11 +15,12 @@ import wx
import props import props
import pwidgets.elistbox as elistbox import pwidgets.elistbox as elistbox
import fsl.fsleyes.panel as fslpanel import fsl.fsleyes.panel as fslpanel
import fsl.fsleyes.icons as icons import fsl.fsleyes.icons as icons
import fsl.data.image as fslimage import fsl.fsleyes.displaydefaults as displaydefaults
import fsl.data.image as fslimage
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
...@@ -207,8 +208,17 @@ class OverlayListPanel(fslpanel.FSLEyesPanel): ...@@ -207,8 +208,17 @@ class OverlayListPanel(fslpanel.FSLEyesPanel):
"""Called when the *add* button on the list box is pressed. """Called when the *add* button on the list box is pressed.
Calls the :meth:`.OverlayList.addOverlays` method. Calls the :meth:`.OverlayList.addOverlays` method.
""" """
if self._overlayList.addOverlays(): overlays = self._overlayList.addOverlays()
self._displayCtx.selectedOverlay = len(self._overlayList) - 1
if len(overlays) == 0:
return
self._displayCtx.selectedOverlay = len(self._overlayList) - 1
for overlay in overlays:
displaydefaults.displayDefaults(overlay,
self._overlayList,
self._displayCtx)
def __lbRemove(self, ev): def __lbRemove(self, ev):
......
...@@ -621,6 +621,15 @@ class VolumeOpts(ImageOpts): ...@@ -621,6 +621,15 @@ class VolumeOpts(ImageOpts):
display, display,
display.getSyncPropertyName('contrast')) display.getSyncPropertyName('contrast'))
# If centreRanges, linkLowRanges or linkHighRanges
# have been set to True (this will happen if they
# are true on the parent VolumeOpts instance), make
# sure the property / listener states are up to date.
if self.centreRanges: self.__centreRangesChanged()
else:
if self.linkLowRanges: self.__linkLowRangesChanged()
if self.linkHighRanges: self.__linkHighRangesChanged()
@actions.action @actions.action
def resetDisplayRange(self): def resetDisplayRange(self):
......
#!/usr/bin/env python
#
# displaydefaults.py - Routines for configuring default overlay display
# settings.
#
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#
"""This module provides the :func:`displayDefaults` function, which is used
for configuring default overlay display settings.
The :displayDefaults` function is called when *FSLeyes* is started, and when
new overlays are loaded.
"""
import re
import sys
import logging
import fsl.data.image as fslimage
log = logging.getLogger(__name__)
def displayDefaults(overlay, overlayList, displayCtx):
"""Configure default display settings for the given overlay.
:arg overlay: The overlay object (e.g. an :class:`.Image` instance).
:arg overlayList: The :class:`.OverlayList`.
:arg displayCtx: The :class:`.DisplayContext`.
"""
oType = type(overlay).__name__
func = getattr(sys.modules[__name__], '_{}Defaults'.format(oType), None)
if func is None:
log.warn('Unknown overlay type: {}'.format(oType))
return
log.debug('Applying default display arguments for {}'.format(overlay))
func(overlay, overlayList, displayCtx)
def _ImageDefaults(overlay, overlayList, displayCtx):
"""Configure default display settings for the given :class:`.Image`
overlay.
"""
if _isStatImage(overlay):
_statImageDefaults(overlay, overlayList, displayCtx)
def _isStatImage(overlay):
"""Returns ``True`` if the given :class:`.Image` overlay looks like a
statistic image, ``False`` otherwise.
"""
basename = fslimage.removeExt(overlay.dataSource)
tokens = ['zstat', 'tstat', 'fstat', 'zfstat']
pattern = '_({})\d+'.format('|'.join(tokens))
return re.search(pattern, basename) is not None
def _statImageDefaults(overlay, overlayList, displayCtx):
"""Configure default display settings for the given statistic
:class:`.Image` overlay.
"""
opts = displayCtx.getOpts(overlay)
basename = fslimage.removeExt(overlay.dataSource)
cmap = _statImageDefaults.cmaps[_statImageDefaults.currentCmap]
nameTokens = '_'.split(basename)
# Give each stat image
# a different colour map
_statImageDefaults.currentCmap += 1
_statImageDefaults.currentCmap %= len(_statImageDefaults.cmaps)
opts.cmap = cmap
pTokens = ['p', 'corrp']
statTokens = ['zstat', 'tstat', 'zfstat']
fStatTokens = ['fstat']
# The order of these tests is
# important, due to name overlap
# P-value image ?
if any([token in nameTokens for token in pTokens]):
opts.displayRange = [0.95, 1.0]
opts.clippingRange = [0.95, 1.0]
# T or Z stat image?
elif any([token in nameTokens for token in statTokens]):
opts.clippingRange = [-0.1, 0.1]
opts.displayRange = [-7.5, 7.5]
opts.centreRanges = True
opts.invertClipping = True
# F stat image?
elif any([token in nameTokens for token in fStatTokens]):
opts.displayRange = [0, 10]
# Colour maps used for statistic images
_statImageDefaults.cmaps = ['red-yellow',
'blue-lightblue',
'green',
'cool',
'hot',
'blue',
'red',
'yellow',
'pink',
'copper']
# Index into the cmaps list, pointing to the
# next colour map to use for statistic images.
_statImageDefaults.currentCmap = 0
def _FEATImageDefaults(overlay, overlayList, displayCtx):
"""Configure default display settings for the given :class:`.FEATImage`
overlay.
"""
pass
def _MelodicImageDefaults(overlay, overlayList, displayCtx):
"""Configure default display settings for the given :class:`.MelodicImage`
overlay.
"""
opts = displayCtx.getOpts(overlay)
opts.cmap = 'Render3'
opts.displayRange = [-5.0, 5.0]
opts.clippingRange = [-1.5, 1.5]
opts.centreRanges = True
opts.invertClipping = True
def _ModelDefaults(overlay, display, overlayList, displayCtx):
"""Configure default display settings for the given :class:`.Model`
overlay.
"""
# TODO some nice default colours
pass
...@@ -1122,8 +1122,18 @@ def applyOverlayArgs(args, overlayList, displayCtx, **kwargs): ...@@ -1122,8 +1122,18 @@ def applyOverlayArgs(args, overlayList, displayCtx, **kwargs):
for i, overlay in enumerate(overlayList): for i, overlay in enumerate(overlayList):
display = displayCtx.getDisplay(overlay) display = displayCtx.getDisplay(overlay)
_applyArgs(args.overlays[i], display) # Figure out how many arguments
# were passed in for this overlay
nArgs = len([v for k, v in vars(args.overlays[i]).items()
if k != 'overlay' and v is not None])
# If no arguments were passed,
# apply default display settings
if nArgs == 0 and args.defaultDisplay:
displaydefaults.displayDefaults(overlay, overlayList, displayCtx)
else:
_applyArgs(args.overlays[i], display)
# Retrieve the DisplayOpts instance # Retrieve the DisplayOpts instance
# after applying arguments to the # after applying arguments to the
......
...@@ -109,19 +109,17 @@ class OverlayList(props.HasProperties): ...@@ -109,19 +109,17 @@ class OverlayList(props.HasProperties):
"""Convenience method for interactively adding overlays to this """Convenience method for interactively adding overlays to this
:class:`OverlayList`. :class:`OverlayList`.
Returns: ``True`` if some overlays were added to the list, ``False`` Returns: A list containing the overlays that were added - the list
otherwise. will be empty if no overlays were added.
""" """
overlays = interactiveLoadOverlays(fromDir) overlays = interactiveLoadOverlays(fromDir)
if len(overlays) == 0: if len(overlays) > 0:
return False if addToEnd: self.extend( overlays)
else: self.insertAll(0, overlays)
if addToEnd: self.extend( overlays)
else: self.insertAll(0, overlays)
return True return overlays
def find(self, name): def find(self, name):
......
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