#
# timeseriescontrolpanel.py - The TimeSeriesControlPanel class.
#
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#
"""This module provides the :class:`TimeSeriesControlPanel` a *FSLeyes
control* which allows the user to configure a :class:`.TimeSeriesPanel`.
"""
import wx
import fsleyes_props as props
import fsl.data.image as fslimage
import fsl.data.featimage as fslfeatimage
import fsleyes.tooltips as fsltooltips
import fsleyes.plotting.timeseries as timeseries
import fsleyes.strings as strings
import fsleyes.views.timeseriespanel as timeseriespanel
from . import plotcontrolpanel as plotctrl
[docs]class TimeSeriesControlPanel(plotctrl.PlotControlPanel):
"""The ``TimeSeriesControlPanel`` is a :class:`.PlotContrlPanel` which
allows the user to configure a :class:`.TimeSeriesPanel`. It contains
controls which are linked to the properties of the ``TimeSeriesPanel``,
(which include properties defined on the :class:`.PlotPanel` base class),
and the :class:`.DataSeries` class.
A ``TimeSeriesControlPanel`` looks something like this:
.. image:: images/timeseriescontrolpanel.png
:scale: 50%
:align: center
The settings shown on a ``TimeSeriesControlPanel`` are organised into three
or four sections:
- The *Time series plot settings* section has controls which are linked to
properties of the :class:`.PlotCanvas` class.
- The *General plot settings* section has controls which are linked to
properties of the :class:`.PlotPanel` base class.
- The *Settings for the current time course* section has controls which
are linked to properties of the :class:`.DataSeries` class. These
properties define how the *current* time course is displayed (see the
:class:`.TimeSeriesPanel` class documentation).
- The *FEAT plot settings* is only shown if the currently selected overlay
is a :class:`.FEATImage`. It has controls which are linked to properties
of the :class:`.FEATTimeSeries` class.
"""
[docs] @staticmethod
def supportedViews():
"""Overrides :meth:`.ControlMixin.supportedViews`. The
``TimeSeriesControlPanel`` is only intended to be added to
:class:`.TimeSeriesPanel` views.
"""
return [timeseriespanel.TimeSeriesPanel]
[docs] @staticmethod
def defaultLayout():
"""Returns a dictionary containing layout settings to be passed to
:class:`.ViewPanel.togglePanel`.
"""
return {'location' : wx.RIGHT}
[docs] def __init__(self, *args, **kwargs):
"""Create a ``TimeSeriesControlPanel``. All arguments are passed
through to the :meth:`.PlotControlPanel.__init__` method.
"""
plotctrl.PlotControlPanel.__init__(self, *args, **kwargs)
self.plotPanel.addListener('plotMelodicICs',
self.name,
self.__plotMelodicICsChanged)
[docs] def destroy(self):
"""Must be called when this ``TimeSeriesControlPanel`` is no longer
needed. Removes some property listeners, and calls
:meth:`.PlotControlPanel.destroy`.
"""
psPanel = self.plotPanel
psPanel.removeListener('plotMelodicICs', self.name)
plotctrl.PlotControlPanel.destroy(self)
def __generateFeatWidgets(self, ts, groupName):
"""Called by :meth:`generateCustomDataSeriesWidgets`. Generates
widgets for :class:`.FEATTimeSeries` options, and adds them
to the widget list.
"""
overlay = ts.overlay
widgetList = self.getWidgetList()
allWidgets = []
full = props.makeWidget( widgetList, ts, 'plotFullModelFit')
res = props.makeWidget( widgetList, ts, 'plotResiduals')
evs = props.makeListWidgets(widgetList, ts, 'plotEVs')
pes = props.makeListWidgets(widgetList, ts, 'plotPEFits')
copes = props.makeListWidgets(widgetList, ts, 'plotCOPEFits')
partial = props.makeWidget( widgetList, ts, 'plotPartial')
data = props.makeWidget( widgetList, ts, 'plotData')
allWidgets.append(full)
allWidgets.append(res)
allWidgets.extend(evs)
allWidgets.extend(pes)
allWidgets.extend(copes)
allWidgets.append(partial)
allWidgets.append(data)
widgetList.AddWidget(
data,
displayName=strings.properties[ts, 'plotData'],
tooltip=fsltooltips.properties[ts, 'plotData'],
groupName=groupName)
widgetList.AddWidget(
full,
displayName=strings.properties[ts, 'plotFullModelFit'],
tooltip=fsltooltips.properties[ts, 'plotFullModelFit'],
groupName=groupName)
widgetList.AddWidget(
res,
displayName=strings.properties[ts, 'plotResiduals'],
tooltip=fsltooltips.properties[ts, 'plotResiduals'],
groupName=groupName)
widgetList.AddWidget(
partial,
displayName=strings.properties[ts, 'plotPartial'],
tooltip=fsltooltips.properties[ts, 'plotPartial'],
groupName=groupName)
widgetList.AddSpace(groupName=groupName)
for i, ev in enumerate(evs):
evName = overlay.evNames()[i]
widgetList.AddWidget(
ev,
displayName=strings.properties[ts, 'plotEVs'].format(
i + 1, evName),
tooltip=fsltooltips.properties[ts, 'plotEVs'],
groupName=groupName)
widgetList.AddSpace(groupName=groupName)
for i, pe in enumerate(pes):
evName = overlay.evNames()[i]
widgetList.AddWidget(
pe,
displayName=strings.properties[ts, 'plotPEFits'].format(
i + 1, evName),
tooltip=fsltooltips.properties[ts, 'plotPEFits'],
groupName=groupName)
widgetList.AddSpace(groupName=groupName)
copeNames = overlay.contrastNames()
for i, (cope, name) in enumerate(zip(copes, copeNames)):
widgetList.AddWidget(
cope,
displayName=strings.properties[ts, 'plotCOPEFits'].format(
i + 1, name),
tooltip=fsltooltips.properties[ts, 'plotCOPEFits'],
groupName=groupName)
return allWidgets
def __generateComplexWidgets(self, ts, groupName):
"""Called by :meth:`generateCustomDataSeriesWidgets`. Generates
widgets for :class:`.ComplexTimeSeries` options, and adds them
to the widget list.
"""
widgetList = self.getWidgetList()
allWidgets = []
if isinstance(ts, timeseries.ComplexTimeSeries):
for propName in ['plotReal', 'plotImaginary',
'plotMagnitude', 'plotPhase']:
widg = props.makeWidget(widgetList, ts, propName)
widgetList.AddWidget(
widg,
displayName=strings.properties[ts, propName],
tooltip=fsltooltips.properties[ts, propName],
groupName=groupName)
allWidgets.append(widg)
return allWidgets
def __plotMelodicICsChanged(self, *a):
"""Called when the :attr:`.TimeSeriesPanel.plotMelodicICs` property
changes. If the current overlay is a :class:`.MelodicImage`,
re-generates the widgets in the *current time course* section, as
the :class:`.DataSeries` instance associated with the overlay may
have been re-created.
"""
self.refreshDataSeriesWidgets()