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

Functional histogram list, allows add/remove histogram plots. Histograms

are not recalculated if they've already been calculated.
parent 012016c3
No related branches found
No related tags found
No related merge requests found
...@@ -112,12 +112,12 @@ titles = TypeDict({ ...@@ -112,12 +112,12 @@ titles = TypeDict({
'OrthoSettingsPanel' : 'Ortho view settings', 'OrthoSettingsPanel' : 'Ortho view settings',
'LightBoxToolBar' : 'Lightbox view toolbar', 'LightBoxToolBar' : 'Lightbox view toolbar',
'LightBoxSettingsPanel' : 'Lightbox view settings', 'LightBoxSettingsPanel' : 'Lightbox view settings',
'HistogramToolBar' : 'Histogram settings',
'LookupTablePanel' : 'Lookup tables', 'LookupTablePanel' : 'Lookup tables',
'LutLabelDialog' : 'New LUT label', 'LutLabelDialog' : 'New LUT label',
'NewLutDialog' : 'New LUT', 'NewLutDialog' : 'New LUT',
'TimeSeriesListPanel' : 'Time series list', 'TimeSeriesListPanel' : 'Time series list',
'TimeSeriesControlPanel' : 'Time series control', 'TimeSeriesControlPanel' : 'Time series control',
'HistogramListPanel' : 'Histogram list',
'LookupTablePanel.loadLut' : 'Select a lookup table file', 'LookupTablePanel.loadLut' : 'Select a lookup table file',
'LookupTablePanel.labelExists' : 'Label already exists', 'LookupTablePanel.labelExists' : 'Label already exists',
...@@ -149,13 +149,10 @@ actions = TypeDict({ ...@@ -149,13 +149,10 @@ actions = TypeDict({
'LightBoxPanel.toggleLightBoxToolBar' : 'View properties', 'LightBoxPanel.toggleLightBoxToolBar' : 'View properties',
'PlotPanel.screenshot' : 'Take screenshot', 'PlotPanel.screenshot' : 'Take screenshot',
'TimeSeriesPanel.toggleTimeSeriesList' : 'Time series list', 'TimeSeriesPanel.toggleTimeSeriesList' : 'Time series list',
'TimeSeriesPanel.toggleTimeSeriesControl' : 'Time series control', 'TimeSeriesPanel.toggleTimeSeriesControl' : 'Time series control',
'HistogramPanel.toggleToolbar' : 'Histogram controls', 'HistogramPanel.toggleHistogramList' : 'Histogram list',
'OrthoViewProfile.centreCursor' : 'Centre cursor', 'OrthoViewProfile.centreCursor' : 'Centre cursor',
'OrthoViewProfile.resetZoom' : 'Reset zoom', 'OrthoViewProfile.resetZoom' : 'Reset zoom',
......
...@@ -15,6 +15,7 @@ from orthosettingspanel import OrthoSettingsPanel ...@@ -15,6 +15,7 @@ from orthosettingspanel import OrthoSettingsPanel
from lookuptablepanel import LookupTablePanel from lookuptablepanel import LookupTablePanel
from timeserieslistpanel import TimeSeriesListPanel from timeserieslistpanel import TimeSeriesListPanel
from timeseriescontrolpanel import TimeSeriesControlPanel from timeseriescontrolpanel import TimeSeriesControlPanel
from histogramlistpanel import HistogramListPanel
from orthotoolbar import OrthoToolBar from orthotoolbar import OrthoToolBar
from orthoprofiletoolbar import OrthoProfileToolBar from orthoprofiletoolbar import OrthoProfileToolBar
......
#!/usr/bin/env python
#
# histogramlistpanel.py -
#
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#
import wx
import pwidgets.elistbox as elistbox
import fsl.fslview.panel as fslpanel
import fsl.fslview.colourmaps as fslcm
import timeserieslistpanel
class HistogramListPanel(fslpanel.FSLViewPanel):
def __init__(self, parent, overlayList, displayCtx, histPanel):
fslpanel.FSLViewPanel.__init__(self, parent, overlayList, displayCtx)
self.__hsPanel = histPanel
self.__hsList = elistbox.EditableListBox(
self, style=(elistbox.ELB_NO_MOVE |
elistbox.ELB_EDITABLE))
self.__sizer = wx.BoxSizer(wx.VERTICAL)
self.SetSizer(self.__sizer)
self.__sizer.Add(self.__hsList, flag=wx.EXPAND, proportion=1)
self.__hsList.Bind(elistbox.EVT_ELB_ADD_EVENT, self.__onListAdd)
self.__hsList.Bind(elistbox.EVT_ELB_REMOVE_EVENT, self.__onListRemove)
self.__hsList.Bind(elistbox.EVT_ELB_EDIT_EVENT, self.__onListEdit)
self.__hsList.Bind(elistbox.EVT_ELB_SELECT_EVENT, self.__onListSelect)
self.__hsPanel.addListener('dataSeries',
self._name,
self.__histSeriesChanged)
self.__histSeriesChanged()
self.Layout()
def destroy(self):
fslpanel.FSLViewPanel.destroy(self)
self.__hsPanel.removeListener('dataSeries', self._name)
def __histSeriesChanged(self, *a):
self.__hsList.Clear()
for hs in self.__hsPanel.dataSeries:
widg = timeserieslistpanel.TimeSeriesWidget(self, hs)
self.__hsList.Append(hs.overlay.name,
clientData=hs,
extraWidget=widg)
def __onListAdd(self, ev):
hs = self.__hsPanel.getCurrent()
if hs is None:
return
hs.alpha = 1
hs.lineWidth = 2
hs.lineStyle = '-'
hs.colour = fslcm.randomColour()
hs.label = hs.overlay.name
self.__hsPanel.dataSeries.append(hs)
def __onListEdit(self, ev):
ev.data.label = ev.label
def __onListSelect(self, ev):
overlay = ev.data.overlay
self._displayCtx.selectedOverlay = self._overlayList.index(overlay)
def __onListRemove(self, ev):
self.__hsPanel.dataSeries.remove(ev.data)
...@@ -15,7 +15,7 @@ import props ...@@ -15,7 +15,7 @@ import props
import fsl.data.image as fslimage import fsl.data.image as fslimage
import fsl.data.strings as strings import fsl.data.strings as strings
import fsl.fslview.colourmaps as fslcm import fsl.fslview.controls as fslcontrols
import plotpanel import plotpanel
...@@ -50,26 +50,6 @@ def autoBin(data, dataRange): ...@@ -50,26 +50,6 @@ def autoBin(data, dataRange):
return nbins return nbins
#
# Ideas:
#
# - Plot histogram for multiple images (how to select them?)
#
# - Ability to apply a label mask image, and plot separate
# histograms for each label
#
# - Ability to put an overlay on the display, showing the
# voxels that are within the histogram range
#
# - For 4D images, add an option to plot the histogram for
# the current volume only, or for all volumes
#
# - For different image types (e.g. vector), add anoption
# to plot the histogram of calculated values, e.g.
# magnitude, or separate histogram lines for xyz
# components?
#
class HistogramSeries(plotpanel.DataSeries): class HistogramSeries(plotpanel.DataSeries):
nbins = props.Int(minval=10, maxval=500, default=100, clamped=True) nbins = props.Int(minval=10, maxval=500, default=100, clamped=True)
...@@ -92,13 +72,13 @@ class HistogramSeries(plotpanel.DataSeries): ...@@ -92,13 +72,13 @@ class HistogramSeries(plotpanel.DataSeries):
if overlay.is4DImage(): if overlay.is4DImage():
self.setConstraint('volume', 'maxval', overlay.shape[3] - 1) self.setConstraint('volume', 'maxval', overlay.shape[3] - 1)
self.__calcInitDataRange()
self.histPropsChanged()
hsPanel.addListener('autoBin', self.name, self.histPropsChanged) hsPanel.addListener('autoBin', self.name, self.histPropsChanged)
self .addListener('nbins', self.name, self.histPropsChanged) self .addListener('nbins', self.name, self.histPropsChanged)
self .addListener('dataRange', self.name, self.histPropsChanged) self .addListener('dataRange', self.name, self.histPropsChanged)
self.__calcInitDataRange()
self.histPropsChanged()
def __del__(self): def __del__(self):
self.hsPanel.removeListener('autoBin', self.name) self.hsPanel.removeListener('autoBin', self.name)
...@@ -133,7 +113,13 @@ class HistogramSeries(plotpanel.DataSeries): ...@@ -133,7 +113,13 @@ class HistogramSeries(plotpanel.DataSeries):
if self.ignoreZeros: if self.ignoreZeros:
data = data[data != 0] data = data[data != 0]
nvals = data.size
dataRange = self.dataRange.x dataRange = self.dataRange.x
log.debug('Calculating histogram for overlay '
'{} (number of values {})'.format(
self.overlay.name,
nvals))
if self.hsPanel.autoBin: nbins = autoBin(data, dataRange) if self.hsPanel.autoBin: nbins = autoBin(data, dataRange)
else: nbins = self.nbins else: nbins = self.nbins
...@@ -153,10 +139,18 @@ class HistogramSeries(plotpanel.DataSeries): ...@@ -153,10 +139,18 @@ class HistogramSeries(plotpanel.DataSeries):
self.xdata = np.array(histX, dtype=np.float32) self.xdata = np.array(histX, dtype=np.float32)
self.ydata = np.array(histY, dtype=np.float32) self.ydata = np.array(histY, dtype=np.float32)
self.nvals = nvals
def getData(self): def getData(self):
return self.xdata, self.ydata
xdata = self.xdata
ydata = self.ydata
nvals = self.nvals
histType = self.hsPanel.histType
if histType == 'count': return xdata, ydata
elif histType == 'probability': return xdata, ydata / nvals
class HistogramPanel(plotpanel.PlotPanel): class HistogramPanel(plotpanel.PlotPanel):
...@@ -164,13 +158,15 @@ class HistogramPanel(plotpanel.PlotPanel): ...@@ -164,13 +158,15 @@ class HistogramPanel(plotpanel.PlotPanel):
autoBin = props.Boolean(default=True) autoBin = props.Boolean(default=True)
showCurrent = props.Boolean(default=True) showCurrent = props.Boolean(default=True)
enableOverlay = props.Boolean(default=False) enableOverlay = props.Boolean(default=False)
histType = props.Choice(('probability', 'count'))
def __init__(self, parent, overlayList, displayCtx): def __init__(self, parent, overlayList, displayCtx):
actionz = {} actionz = {'toggleHistogramList' : lambda *a: self.togglePanel(
fslcontrols.HistogramListPanel, False, self)
}
plotpanel.PlotPanel.__init__( plotpanel.PlotPanel.__init__(
self, parent, overlayList, displayCtx, actionz) self, parent, overlayList, displayCtx, actionz)
...@@ -185,13 +181,14 @@ class HistogramPanel(plotpanel.PlotPanel): ...@@ -185,13 +181,14 @@ class HistogramPanel(plotpanel.PlotPanel):
self._overlayList.addListener( self._overlayList.addListener(
'overlays', 'overlays',
self._name, self._name,
self.__selectedOverlayChanged) self.__updateCurrent)
self._displayCtx.addListener( self._displayCtx.addListener(
'selectedOverlay', 'selectedOverlay',
self._name, self._name,
self.__selectedOverlayChanged) self.__updateCurrent)
self.addGlobalListener(self._name, self.__updateCurrent)
self.__selectedOverlayChanged() self.__updateCurrent()
self.Layout() self.Layout()
...@@ -204,7 +201,8 @@ class HistogramPanel(plotpanel.PlotPanel): ...@@ -204,7 +201,8 @@ class HistogramPanel(plotpanel.PlotPanel):
self._displayCtx .removeListener('selectedOverlay', self._name) self._displayCtx .removeListener('selectedOverlay', self._name)
def __calcCurrent(self): def __updateCurrent(self, *a):
self.__current = None self.__current = None
if self._overlayList == 0: if self._overlayList == 0:
...@@ -215,6 +213,9 @@ class HistogramPanel(plotpanel.PlotPanel): ...@@ -215,6 +213,9 @@ class HistogramPanel(plotpanel.PlotPanel):
if not isinstance(overlay, fslimage.Image): if not isinstance(overlay, fslimage.Image):
return return
if overlay in [hs.overlay for hs in self.dataSeries]:
return
hs = HistogramSeries(self, overlay) hs = HistogramSeries(self, overlay)
hs.colour = [0.2, 0.2, 0.2] hs.colour = [0.2, 0.2, 0.2]
hs.alpha = 1 hs.alpha = 1
...@@ -228,19 +229,9 @@ class HistogramPanel(plotpanel.PlotPanel): ...@@ -228,19 +229,9 @@ class HistogramPanel(plotpanel.PlotPanel):
def getCurrent(self): def getCurrent(self):
return self.__current return self.__current
def __selectedOverlayChanged(self, *a):
if len(self._overlayList) == 0:
return
self.draw()
def draw(self, *a): def draw(self, *a):
self.__calcCurrent()
current = self.getCurrent() current = self.getCurrent()
if current is not None: self.drawDataSeries([current]) if current is not None: self.drawDataSeries([current])
......
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