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

MelodicClassification, and MCPanel code updated to be case

insensitive. Unrelated bugfix to AtlasInfoPanel.
parent d3c1f9c2
No related branches found
No related tags found
No related merge requests found
...@@ -212,7 +212,9 @@ class MelodicClassification(props.HasProperties): ...@@ -212,7 +212,9 @@ class MelodicClassification(props.HasProperties):
clearComponents clearComponents
.. note:: All component labels are converted to lower case. .. note:: All component labels are internally stored as lower case;
their cased version (whatever is initially used) is accssible
via the :meth:`getDisplayLabel` method.
.. warning:: Do not modify the :attr:`labels` list directly - use the .. warning:: Do not modify the :attr:`labels` list directly - use the
...@@ -235,12 +237,18 @@ class MelodicClassification(props.HasProperties): ...@@ -235,12 +237,18 @@ class MelodicClassification(props.HasProperties):
"""Create a ``MelodicClassification`` instance. """Create a ``MelodicClassification`` instance.
""" """
self.__melimage = melimage self.__melimage = melimage
self.__ncomps = melimage.numComponents() self.__ncomps = melimage.numComponents()
self.__displayLabels = {}
self.clear() self.clear()
def getDisplayLabel(self, label):
"""Returns the display name for the given label. """
return self.__displayLabels.get(label.lower(), label)
def clear(self): def clear(self):
"""Removes all labels from all components. """ """Removes all labels from all components. """
...@@ -376,7 +384,13 @@ class MelodicClassification(props.HasProperties): ...@@ -376,7 +384,13 @@ class MelodicClassification(props.HasProperties):
noise = not (self.hasLabel(comp, 'signal') or noise = not (self.hasLabel(comp, 'signal') or
self.hasLabel(comp, 'unknown')) self.hasLabel(comp, 'unknown'))
tokens = [str(comp + 1)] + self.getLabels(comp) + [str(noise)]
# Make sure there are no
# commas in any label names
labels = [self.getDisplayLabel(l) for l in self.getLabels(comp)]
labels = [l.replace(',', '_') for l in labels]
tokens = [str(comp + 1)] + labels + [str(noise)]
lines.append(', '.join(tokens)) lines.append(', '.join(tokens))
...@@ -406,9 +420,10 @@ class MelodicClassification(props.HasProperties): ...@@ -406,9 +420,10 @@ class MelodicClassification(props.HasProperties):
def addLabel(self, component, label): def addLabel(self, component, label):
"""Adds the given label to the given component. """ """Adds the given label to the given component. """
label = label.lower() display = label
labels = list(self.labels[component]) label = label.lower()
comps = list(self.__components.get(label, [])) labels = list(self.labels[component])
comps = list(self.__components.get(label, []))
if label in labels: if label in labels:
return return
...@@ -416,6 +431,8 @@ class MelodicClassification(props.HasProperties): ...@@ -416,6 +431,8 @@ class MelodicClassification(props.HasProperties):
labels.append(label) labels.append(label)
comps .append(component) comps .append(component)
self.__displayLabels[label] = display
# Change __components first, so # Change __components first, so
# any listeners on labels are # any listeners on labels are
# not notified before our intenral # not notified before our intenral
......
...@@ -170,14 +170,19 @@ class AtlasInfoPanel(fslpanel.FSLEyesPanel): ...@@ -170,14 +170,19 @@ class AtlasInfoPanel(fslpanel.FSLEyesPanel):
text.SetPage(strings.messages['AtlasInfoPanel.chooseAnAtlas']) text.SetPage(strings.messages['AtlasInfoPanel.chooseAnAtlas'])
return return
opts = self._displayCtx.getOpts(overlay)
loc = self._displayCtx.location
loc = opts.transformCoords([loc], 'display', 'world')[0]
lines = [] lines = []
if topText is not None: if topText is not None:
lines.append(topText) lines.append(topText)
if overlay is None:
text.SetPage('<br>'.join(lines))
text.Refresh()
return
opts = self._displayCtx.getOpts(overlay)
loc = self._displayCtx.location
loc = opts.transformCoords([loc], 'display', 'world')[0]
# Three types of hyperlink: # Three types of hyperlink:
# - one for complete (summary) label atlases, # - one for complete (summary) label atlases,
......
...@@ -17,7 +17,6 @@ import pwidgets.widgetgrid as widgetgrid ...@@ -17,7 +17,6 @@ import pwidgets.widgetgrid as widgetgrid
import pwidgets.texttag as texttag import pwidgets.texttag as texttag
import fsl.fsleyes.panel as fslpanel import fsl.fsleyes.panel as fslpanel
import fsl.fsleyes.colourmaps as fslcm
import fsl.fsleyes.displaycontext as fsldisplay import fsl.fsleyes.displaycontext as fsldisplay
import fsl.data.melodicimage as fslmelimage import fsl.data.melodicimage as fslmelimage
import fsl.data.strings as strings import fsl.data.strings as strings
...@@ -169,7 +168,6 @@ class ComponentGrid(fslpanel.FSLEyesPanel): ...@@ -169,7 +168,6 @@ class ComponentGrid(fslpanel.FSLEyesPanel):
tags = texttag.TextTagPanel(self.__grid, tags = texttag.TextTagPanel(self.__grid,
style=(texttag.TTP_ALLOW_NEW_TAGS | style=(texttag.TTP_ALLOW_NEW_TAGS |
texttag.TTP_ADD_NEW_TAGS |
texttag.TTP_NO_DUPLICATES | texttag.TTP_NO_DUPLICATES |
texttag.TTP_KEYBOARD_NAV)) texttag.TTP_KEYBOARD_NAV))
...@@ -185,11 +183,32 @@ class ComponentGrid(fslpanel.FSLEyesPanel): ...@@ -185,11 +183,32 @@ class ComponentGrid(fslpanel.FSLEyesPanel):
tags.Bind(texttag.EVT_TTP_TAG_ADDED, self.__onTagAdded) tags.Bind(texttag.EVT_TTP_TAG_ADDED, self.__onTagAdded)
tags.Bind(texttag.EVT_TTP_TAG_REMOVED, self.__onTagRemoved) tags.Bind(texttag.EVT_TTP_TAG_REMOVED, self.__onTagRemoved)
self.__refreshTagOptions()
self.__refreshTags() self.__refreshTags()
self.Layout() self.Layout()
def __refreshTagOptions(self):
"""Updates the options available on each :class:`.TextTagPanel`, from
the entries in the melodic classification :class:`.LookupTable`.
"""
overlay = self.__overlay
numComps = overlay.numComponents()
lut = self.__lut
displayLabels = [l.displayName() for l in lut.labels]
colours = [l.colour() for l in lut.labels]
for i in range(len(colours)):
colours[i] = [int(round(c * 255)) for c in colours[i]]
for comp in range(numComps):
tags = self.__grid.GetWidget(comp, 1)
tags.SetOptions(displayLabels, colours)
def __refreshTags(self): def __refreshTags(self):
"""Re-generates the tags on every :class:`.TextTagPanel` in the grid. """Re-generates the tags on every :class:`.TextTagPanel` in the grid.
""" """
...@@ -197,33 +216,17 @@ class ComponentGrid(fslpanel.FSLEyesPanel): ...@@ -197,33 +216,17 @@ class ComponentGrid(fslpanel.FSLEyesPanel):
overlay = self.__overlay overlay = self.__overlay
melclass = overlay.getICClassification() melclass = overlay.getICClassification()
numComps = overlay.numComponents() numComps = overlay.numComponents()
lut = self.__lut
labels = [l.name() for l in lut.labels]
colours = [l.colour() for l in lut.labels]
# Compile lists of all the existing
# labels, and the colours for each one
for i in range(numComps):
for label in melclass.getLabels(i):
if label in labels:
continue
labels .append(label)
colours.append(fslcm.randomBrightColour())
for i in range(len(colours)):
colours[i] = [int(round(c * 255)) for c in colours[i]]
for row in range(numComps): for row in range(numComps):
tags = self.__grid.GetWidget(row, 1) tags = self.__grid.GetWidget(row, 1)
tags.ClearTags() tags.ClearTags()
tags.SetOptions(labels, colours)
for label in melclass.getLabels(row): for label in melclass.getLabels(row):
tags.AddTag(label) tags.AddTag(melclass.getDisplayLabel(label))
self.__grid.FitInside()
def __onTagAdded(self, ev): def __onTagAdded(self, ev):
...@@ -232,22 +235,26 @@ class ComponentGrid(fslpanel.FSLEyesPanel): ...@@ -232,22 +235,26 @@ class ComponentGrid(fslpanel.FSLEyesPanel):
:class:`.MelodicClassification` instance. :class:`.MelodicClassification` instance.
""" """
tags = ev.GetEventObject() tags = ev.GetEventObject()
label = ev.tag label = ev.tag
component = tags._melodicComponent comp = tags._melodicComponent
overlay = self.__overlay overlay = self.__overlay
lut = self.__lut lut = self.__lut
melclass = overlay.getICClassification() melclass = overlay.getICClassification()
log.debug('Label added to component {} ("{}")'.format(comp, label))
# Add the new label to the melodic component # Add the new label to the melodic component
melclass.disableListener('labels', self._name) melclass.disableListener('labels', self._name)
melclass.addLabel(component, label) melclass.addLabel(comp, label)
# If the tag panel previously just contained # If the tag panel previously just contained
# the 'Unknown' tag, remove that tag # the 'Unknown' tag, remove that tag
if tags.TagCount() == 2 and tags.HasTag('unknown'): if tags.TagCount() == 2 and \
melclass.removeLabel(component, 'unknown') tags.HasTag('Unknown') and \
tags.RemoveTag('unknown') label.lower() != 'unknown':
melclass.removeLabel(comp, 'Unknown')
tags.RemoveTag('Unknown')
melclass.enableListener('labels', self._name) melclass.enableListener('labels', self._name)
...@@ -257,10 +264,14 @@ class ComponentGrid(fslpanel.FSLEyesPanel): ...@@ -257,10 +264,14 @@ class ComponentGrid(fslpanel.FSLEyesPanel):
colour = tags.GetTagColour(label) colour = tags.GetTagColour(label)
colour = [c / 255.0 for c in colour] colour = [c / 255.0 for c in colour]
log.debug('Adding new lookup table '
'entry for label {}'.format(label))
lut.disableListener('labels', self._name) lut.disableListener('labels', self._name)
lut.new(name=label, colour=colour) lut.new(name=label, colour=colour)
lut.enableListener('labels', self._name) lut.enableListener('labels', self._name)
self.__refreshTagOptions()
self.__grid.FitInside() self.__grid.FitInside()
...@@ -270,16 +281,18 @@ class ComponentGrid(fslpanel.FSLEyesPanel): ...@@ -270,16 +281,18 @@ class ComponentGrid(fslpanel.FSLEyesPanel):
:class:`.MelodicClassification` instance. :class:`.MelodicClassification` instance.
""" """
tags = ev.GetEventObject() tags = ev.GetEventObject()
label = ev.tag label = ev.tag
component = tags._melodicComponent comp = tags._melodicComponent
overlay = self.__overlay overlay = self.__overlay
melclass = overlay.getICClassification() melclass = overlay.getICClassification()
log.debug('Label removed from component {} ("{}")'.format(comp, label))
# Remove the label from # Remove the label from
# the melodic component # the melodic component
melclass.disableListener('labels', self._name) melclass.disableListener('labels', self._name)
melclass.removeLabel(component, label) melclass.removeLabel(comp, label)
melclass.enableListener('labels', self._name) melclass.enableListener('labels', self._name)
# If the tag panel now has no tags, # If the tag panel now has no tags,
...@@ -299,6 +312,8 @@ class ComponentGrid(fslpanel.FSLEyesPanel): ...@@ -299,6 +312,8 @@ class ComponentGrid(fslpanel.FSLEyesPanel):
component = ev.row component = ev.row
opts = self._displayCtx.getOpts(self.__overlay) opts = self._displayCtx.getOpts(self.__overlay)
log.debug('Grid row selected (component {})'.format(component))
opts.disableListener('volume', self._name) opts.disableListener('volume', self._name)
opts.volume = component opts.volume = component
opts.enableListener('volume', self._name) opts.enableListener('volume', self._name)
...@@ -321,6 +336,8 @@ class ComponentGrid(fslpanel.FSLEyesPanel): ...@@ -321,6 +336,8 @@ class ComponentGrid(fslpanel.FSLEyesPanel):
grid = self.__grid grid = self.__grid
opts = self._displayCtx.getOpts(self.__overlay) opts = self._displayCtx.getOpts(self.__overlay)
tags = grid.GetWidget(opts.volume, 1) tags = grid.GetWidget(opts.volume, 1)
log.debug('Overlay volume changed ({})'.format(opts.volume))
grid.SetSelection(opts.volume, -1) grid.SetSelection(opts.volume, -1)
tags.FocusNewTagCtrl() tags.FocusNewTagCtrl()
...@@ -330,14 +347,18 @@ class ComponentGrid(fslpanel.FSLEyesPanel): ...@@ -330,14 +347,18 @@ class ComponentGrid(fslpanel.FSLEyesPanel):
"""Called when the :attr:`.MelodicClassification.labels` change. """Called when the :attr:`.MelodicClassification.labels` change.
Re-generates the tags shown on every :class:`.TextTagPanel`. Re-generates the tags shown on every :class:`.TextTagPanel`.
""" """
log.debug('Melodic classification changed - '
'refreshing component grid tags')
self.__refreshTags() self.__refreshTags()
def __lutChanged(self, *a): def __lutChanged(self, *a):
"""Called when the :attr:`.LookupTable.labels` change. """Called when the :attr:`.LookupTable.labels` change.
Re-generates the tags shown on every :class:`.TextTagPanel`. Updates the options on every :class:`.TextTagPanel`.
""" """
self.__refreshTags() log.debug('Lookup table changed - refreshing '
'component grid tag options')
self.__refreshTagOptions()
class LabelGrid(fslpanel.FSLEyesPanel): class LabelGrid(fslpanel.FSLEyesPanel):
...@@ -391,7 +412,7 @@ class LabelGrid(fslpanel.FSLEyesPanel): ...@@ -391,7 +412,7 @@ class LabelGrid(fslpanel.FSLEyesPanel):
self._name, self._name,
self.__selectedOverlayChanged) self.__selectedOverlayChanged)
self.__overlay = None self.__overlay = None
self.__recreateGrid() self.__recreateGrid()
self.__selectedOverlayChanged() self.__selectedOverlayChanged()
...@@ -474,7 +495,7 @@ class LabelGrid(fslpanel.FSLEyesPanel): ...@@ -474,7 +495,7 @@ class LabelGrid(fslpanel.FSLEyesPanel):
tags._label = label.name() tags._label = label.name()
self.__grid.SetText( i, 0, label.name()) self.__grid.SetText( i, 0, label.displayName())
self.__grid.SetWidget(i, 1, tags) self.__grid.SetWidget(i, 1, tags)
tags.Bind(texttag.EVT_TTP_TAG_ADDED, self.__onTagAdded) tags.Bind(texttag.EVT_TTP_TAG_ADDED, self.__onTagAdded)
...@@ -521,6 +542,9 @@ class LabelGrid(fslpanel.FSLEyesPanel): ...@@ -521,6 +542,9 @@ class LabelGrid(fslpanel.FSLEyesPanel):
overlay = self.__overlay overlay = self.__overlay
melclass = overlay.getICClassification() melclass = overlay.getICClassification()
comp = int(ev.tag) comp = int(ev.tag)
label = tags._label
log.debug('Component added to label {} ({})'.format(label, comp))
melclass.disableListener('labels', self._name) melclass.disableListener('labels', self._name)
...@@ -528,10 +552,11 @@ class LabelGrid(fslpanel.FSLEyesPanel): ...@@ -528,10 +552,11 @@ class LabelGrid(fslpanel.FSLEyesPanel):
# the other label is 'Unknown', remove the # the other label is 'Unknown', remove the
# 'Unknown' label. # 'Unknown' label.
if len(melclass.getLabels(comp)) == 1 and \ if len(melclass.getLabels(comp)) == 1 and \
melclass.hasLabel(comp, 'Unknown'): label != 'unknown' and \
melclass.removeLabel(comp, 'Unknown') melclass.hasLabel(comp, 'unknown'):
melclass.removeLabel(comp, 'unknown')
melclass.addComponent(tags._label, comp) melclass.addComponent(label, comp)
melclass.enableListener('labels', self._name) melclass.enableListener('labels', self._name)
self.__refreshTags() self.__refreshTags()
...@@ -547,10 +572,13 @@ class LabelGrid(fslpanel.FSLEyesPanel): ...@@ -547,10 +572,13 @@ class LabelGrid(fslpanel.FSLEyesPanel):
overlay = self.__overlay overlay = self.__overlay
melclass = overlay.getICClassification() melclass = overlay.getICClassification()
comp = int(ev.tag) comp = int(ev.tag)
label = tags._label
log.debug('Component removed from label {} ({})'.format(label, comp))
melclass.disableListener('labels', self._name) melclass.disableListener('labels', self._name)
melclass.removeComponent(tags._label, comp) melclass.removeComponent(label, comp)
# If the component has no more labels, # If the component has no more labels,
# give it an 'Unknown' label # give it an 'Unknown' label
...@@ -567,6 +595,9 @@ class LabelGrid(fslpanel.FSLEyesPanel): ...@@ -567,6 +595,9 @@ class LabelGrid(fslpanel.FSLEyesPanel):
""" """
tags = self.__grid.GetWidget(ev.row, 1) tags = self.__grid.GetWidget(ev.row, 1)
log.debug('Grid row selected (label "{}")'.format(tags._label))
tags.FocusNewTagCtrl() tags.FocusNewTagCtrl()
...@@ -575,10 +606,13 @@ class LabelGrid(fslpanel.FSLEyesPanel): ...@@ -575,10 +606,13 @@ class LabelGrid(fslpanel.FSLEyesPanel):
Changes the current :attr:`.ImageOpts.volume` to the component Changes the current :attr:`.ImageOpts.volume` to the component
corresponding to the selected tag. corresponding to the selected tag.
""" """
tag = int(ev.tag) tag = int(ev.tag)
overlay = self.__overlay overlay = self.__overlay
opts = self._displayCtx.getOpts(overlay) opts = self._displayCtx.getOpts(overlay)
log.debug('Tag selected on label grid: component {}'.format(tag))
opts.volume = tag opts.volume = tag
...@@ -595,5 +629,6 @@ class LabelGrid(fslpanel.FSLEyesPanel): ...@@ -595,5 +629,6 @@ class LabelGrid(fslpanel.FSLEyesPanel):
"""Called when the :attr:`.MelodicClassification.labels` change. """Called when the :attr:`.MelodicClassification.labels` change.
Re-populates the :class:`.WidgetGrid`. Re-populates the :class:`.WidgetGrid`.
""" """
log.debug('Melodic classification changed - refreshing tags') log.debug('Melodic classification changed - '
'refreshing label grid tags')
self.__refreshTags() self.__refreshTags()
...@@ -74,12 +74,11 @@ class MelodicClassificationPanel(fslpanel.FSLEyesPanel): ...@@ -74,12 +74,11 @@ class MelodicClassificationPanel(fslpanel.FSLEyesPanel):
self._displayCtx, self._displayCtx,
self.__lut) self.__lut)
# self.__labelGrid = melodicgrid.LabelGrid( self.__labelGrid = melodicgrid.LabelGrid(
# self.__notebook, self.__notebook,
# self._overlayList, self._overlayList,
# self._displayCtx, self._displayCtx,
# self.__lut) self.__lut)
self.__labelGrid = wx.Panel(self.__notebook)
self.__loadButton = wx.Button(self) self.__loadButton = wx.Button(self)
self.__saveButton = wx.Button(self) self.__saveButton = wx.Button(self)
...@@ -211,15 +210,14 @@ class MelodicClassificationPanel(fslpanel.FSLEyesPanel): ...@@ -211,15 +210,14 @@ class MelodicClassificationPanel(fslpanel.FSLEyesPanel):
# lookup table exists for all labels # lookup table exists for all labels
for comp, labels in enumerate(melclass.labels): for comp, labels in enumerate(melclass.labels):
for label in labels: for label in labels:
lutLabel = lut.getByName(label)
if lutLabel is not None:
print 'Label {} is already in lookup table'.format(label)
continue
print 'New melodic classification label: {}'.format(label) label = melclass.getDisplayLabel(label)
log.debug('New melodic classification label: {}'.format(label)) lutLabel = lut.getByName(label)
lut.new(label)
if lutLabel is None:
log.debug('New melodic classification '
'label: {}'.format(label))
lut.new(label)
melclass.enableNotification('labels') melclass.enableNotification('labels')
lut .enableNotification('labels') lut .enableNotification('labels')
...@@ -264,3 +262,11 @@ class MelodicClassificationPanel(fslpanel.FSLEyesPanel): ...@@ -264,3 +262,11 @@ class MelodicClassificationPanel(fslpanel.FSLEyesPanel):
melclass = overlay.getICClassification() melclass = overlay.getICClassification()
melclass.clear() melclass.clear()
melclass.disableNotification('labels')
for c in range(overlay.numComponents()):
melclass.addLabel(c, 'Unknown')
melclass.enableNotification('labels')
melclass.notify('labels')
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