Source code for fsleyes.profiles.timeseriesprofile

#
# timeseriesprofile.py - The TimeSeriesProfile class.
#
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#
"""This module provides the :class:`.TimeSeriesProfile` class, an interaction
profile for the :class:`.TimeSeriesPanel`.
"""


import fsl.utils.idle        as idle
import fsl.data.image        as fslimage
import fsl.data.melodicimage as fslmelimage
from . import                   plotprofile


[docs]class TimeSeriesProfile(plotprofile.PlotProfile): """The ``TimeSeriesProfile`` is a :class:`.PlotProfile` for use with the :class:`.TimeSeriesPanel`. In addition to the ``panzoom`` mode provided by the :class:`.PlotProfile` class, the ``TimeSeriesProfile`` class implements a ``volume`` mode, in which the user is able to click/drag on a plot to change the :attr:`.VolumeOpts.volume` for the currently selected overlay. """
[docs] def __init__(self, viewPanel, overlayList, displayCtx): """Create a ``TimeSeriesProfile``. :arg viewPanel: A :class:`.TimeSeriesPanel` instance. :arg overlayList: The :class:`.OverlayList` instance. :arg displayCtx: The :class:`.DisplayContext` instance. """ plotprofile.PlotProfile.__init__(self, viewPanel, overlayList, displayCtx, ['volume']) self.__volumeLine = None
def __volumeModeCompatible(self): """Returns ``True`` if a volume line can currently be shown, ``False`` otherwise. """ tsPanel = self.viewPanel overlay = self.displayCtx.getSelectedOverlay() display = self.displayCtx.getDisplay(overlay) if not isinstance(overlay, fslimage.Image): return False if display.overlayType not in ('volume', 'label', 'mask'): return False if isinstance(overlay, fslmelimage.MelodicImage) and \ tsPanel.plotMelodicICs: return False if len(overlay.shape) < 4 or overlay.shape[3] == 1: return False return True def __updateVolume(self, volumeLine, xvalue): """Called by the ``volume`` event handlers. Updates the given ``volumeLine`` artist (assumed to be a ``matplotlib.Line2D`` instance) so that it is located at the given ``xvalue``. Also updates the :attr:`.VolumeOpts.volume` property of the currently selected overlay accordingly. """ tsPanel = self.viewPanel canvas = tsPanel.getCanvas() overlay = self.displayCtx.getSelectedOverlay() opts = self.displayCtx.getOpts(overlay) if xvalue is None: return if tsPanel.usePixdim: volume = round(xvalue / overlay.pixdim[3]) else: volume = round(xvalue) if volume < 0: volume = 0 if volume >= overlay.shape[3]: volume = overlay.shape[3] - 1 if tsPanel.usePixdim: xvalue = volume * overlay.pixdim[3] else: xvalue = volume volumeLine.set_xdata(xvalue) canvas.draw() # Update the volume asynchronously, # and drop any previously enqueued # updates. def update(): opts.volume = volume idle.idle( update, name='{}_{}_volume'.format(self.name, id(overlay)), dropIfQueued=True)
[docs] def _volumeModeLeftMouseDown(self, ev, canvas, mousePos, canvasPos): """Adds a vertical line to the plot at the current volume. """ if self.__volumeLine is not None: self.__volumeLine.remove() self.__volumeLine = None if not self.__volumeModeCompatible(): return if canvasPos is None: xvalue = None else: xvalue = canvasPos[0] tsPanel = self.viewPanel axis = tsPanel.getAxis() self.__volumeLine = axis.axvline(0, c='#000080', lw=3) self.__updateVolume(self.__volumeLine, xvalue)
[docs] def _volumeModeLeftMouseDrag(self, ev, canvas, mousePos, canvasPos): """Updates the position of the vertical volume line. """ if self.__volumeLine is None: return if canvasPos is None: xvalue = None else: xvalue = canvasPos[0] self.__updateVolume(self.__volumeLine, xvalue)
[docs] def _volumeModeLeftMouseUp(self, ev, canvas, mousePos, canvasPos): """Removes the vertical volume line. """ if self.__volumeLine is None: return self.__volumeLine.remove() self.__volumeLine = None self.viewPanel.getCanvas().draw()