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

New 'centreRanges' property on VolumeOpts - makes displayRange and

clippingRange symmetric about 0.
parent 98608763
No related branches found
No related tags found
No related merge requests found
...@@ -506,6 +506,7 @@ properties = TypeDict({ ...@@ -506,6 +506,7 @@ properties = TypeDict({
'VolumeOpts.displayRange' : 'Display range', 'VolumeOpts.displayRange' : 'Display range',
'VolumeOpts.clippingRange' : 'Clipping range', 'VolumeOpts.clippingRange' : 'Clipping range',
'VolumeOpts.centreRanges' : 'Centre display/clipping ranges at 0',
'VolumeOpts.cmap' : 'Colour map', 'VolumeOpts.cmap' : 'Colour map',
'VolumeOpts.invert' : 'Invert colour map', 'VolumeOpts.invert' : 'Invert colour map',
'VolumeOpts.invertClipping' : 'Invert clipping range', 'VolumeOpts.invertClipping' : 'Invert clipping range',
......
...@@ -288,6 +288,7 @@ _DISPLAY_PROPS = td.TypeDict({ ...@@ -288,6 +288,7 @@ _DISPLAY_PROPS = td.TypeDict({
props.Widget('cmap'), props.Widget('cmap'),
props.Widget('invert'), props.Widget('invert'),
props.Widget('invertClipping'), props.Widget('invertClipping'),
props.Widget('centreRanges'),
props.Widget('displayRange', props.Widget('displayRange',
showLimits=False, showLimits=False,
slider=True, slider=True,
......
...@@ -502,6 +502,13 @@ class VolumeOpts(ImageOpts): ...@@ -502,6 +502,13 @@ class VolumeOpts(ImageOpts):
""" """
centreRanges = props.Boolean(default=False)
"""If ``True``, the :attr:`displayRange` and :attr:`clippingRange` ranges
will be kept centred at zero. A change to the negative end of either range
will result in the positive end being changed, and vice versa.
"""
def __init__(self, def __init__(self,
overlay, overlay,
display, display,
...@@ -572,6 +579,9 @@ class VolumeOpts(ImageOpts): ...@@ -572,6 +579,9 @@ class VolumeOpts(ImageOpts):
self .addListener('displayRange', self .addListener('displayRange',
self.name, self.name,
self.__displayRangeChanged) self.__displayRangeChanged)
self .addListener('centreRanges',
self.name,
self.__centreRangesChanged)
# Because displayRange and bri/con are intrinsically # Because displayRange and bri/con are intrinsically
# linked, it makes no sense to let the user sync/unsync # linked, it makes no sense to let the user sync/unsync
...@@ -646,6 +656,11 @@ class VolumeOpts(ImageOpts): ...@@ -646,6 +656,11 @@ class VolumeOpts(ImageOpts):
for peer in peers: for peer in peers:
if not any((peer.display.isSyncedToParent('brightness'),
peer.display.isSyncedToParent('contrast'),
peer. isSyncedToParent('displayRange'))):
continue
if enable: if enable:
peer.display.enableListener('brightness', peer.name) peer.display.enableListener('brightness', peer.name)
peer.display.enableListener('contrast', peer.name) peer.display.enableListener('contrast', peer.name)
...@@ -684,6 +699,9 @@ class VolumeOpts(ImageOpts): ...@@ -684,6 +699,9 @@ class VolumeOpts(ImageOpts):
See :func:`.colourmaps.displayRangeToBricon`. See :func:`.colourmaps.displayRangeToBricon`.
""" """
if self.centreRanges:
return
brightness, contrast = fslcm.displayRangeToBricon( brightness, contrast = fslcm.displayRangeToBricon(
(self.dataMin, self.dataMax), (self.dataMin, self.dataMax),
self.displayRange.x) self.displayRange.x)
...@@ -695,3 +713,83 @@ class VolumeOpts(ImageOpts): ...@@ -695,3 +713,83 @@ class VolumeOpts(ImageOpts):
self.display.contrast = contrast * 100 self.display.contrast = contrast * 100
self.__toggleListeners(True) self.__toggleListeners(True)
def __centreRangesChanged(self, *a):
"""Called when the :attr:`centreRanges` property changes. Configures
property listeners on the :attr:`clippingRange` and
:attr:`displayRange` properties.
"""
if self.centreRanges:
self.display.disableProperty('brightness')
self.display.disableProperty('contrast')
else:
self.display.enableProperty('brightness')
self.display.enableProperty('contrast')
clipPVs = self.clippingRange.getPropertyValueList()
dispPVs = self.displayRange .getPropertyValueList()
if not self.centreRanges:
clipPVs[0].removeListener(self.name)
clipPVs[1].removeListener(self.name)
dispPVs[0].removeListener(self.name)
dispPVs[1].removeListener(self.name)
else:
clipPVs[0].addListener(self.name, self.__lowClippingChanged)
clipPVs[1].addListener(self.name, self.__highClippingChanged)
dispPVs[0].addListener(self.name, self.__lowDisplayChanged)
dispPVs[1].addListener(self.name, self.__highDisplayChanged)
self.__lowClippingChanged()
self.__lowDisplayChanged()
def __lowDisplayChanged(self, *a):
"""If :attr:`centreRanges` is ``True``, this method is called whenever
the low :attr:`displayRange` value changes. It synchronises the high
value.
"""
rangePVs = self.displayRange.getPropertyValueList()
rangePVs[1].disableListener(self.name)
rangePVs[1].set(-rangePVs[0].get())
rangePVs[1].enableListener(self.name)
def __highDisplayChanged(self, *a):
"""If :attr:`centreRanges` is ``True``, this method is called whenever
the high :attr:`displayRange` value changes. It synchronises the low
value.
"""
rangePVs = self.displayRange.getPropertyValueList()
rangePVs[0].disableListener(self.name)
rangePVs[0].set(-rangePVs[1].get())
rangePVs[0].enableListener(self.name)
def __lowClippingChanged(self, *a):
"""If :attr:`centreRanges` is ``True``, this method is called whenever
the low :attr:`clippingRange` value changes. It synchronises the high
value.
"""
clipPVs = self.clippingRange.getPropertyValueList()
clipPVs[1].disableListener(self.name)
clipPVs[1].set(-clipPVs[0].get())
clipPVs[1].enableListener(self.name)
def __highClippingChanged(self, *a):
"""If :attr:`centreRanges` is ``True``, this method is called whenever
the high :attr:`clippingRange` value changes. It synchronises the low
value.
"""
clipPVs = self.clippingRange.getPropertyValueList()
clipPVs[0].disableListener(self.name)
clipPVs[0].set(-clipPVs[1].get())
clipPVs[0].enableListener(self.name)
...@@ -67,6 +67,11 @@ properties = TypeDict({ ...@@ -67,6 +67,11 @@ properties = TypeDict({
'voxels outside of the range are displayed.' 'voxels outside of the range are displayed.'
'This option is useful for displaying ' 'This option is useful for displaying '
'statistic images.', 'statistic images.',
'VolumeOpts.centreRanges' : 'If checked, the low and high values '
'of both the clipping and display '
'ranges will be yoked together, so '
'that both ranges stay centered at '
'zero.' ,
'VolumeOpts.cmap' : 'The colour map to use.', 'VolumeOpts.cmap' : 'The colour map to use.',
'VolumeOpts.interpolation' : 'Interpolate the image data for display ' 'VolumeOpts.interpolation' : 'Interpolate the image data for display '
'purposes. You can choose no ' 'purposes. You can choose no '
......
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