fsleyes.views.plotpanel

This module provides the PlotPanel and OverlayPlotPanel classes. The PlotPanel class is the base class for all FSLeyes views which display some sort of data plot. The OverlayPlotPanel is a PlotPanel which contains some extra logic for displaying plots related to the currently selected overlay.

class fsleyes.views.plotpanel.PlotPanel(parent, overlayList, displayCtx, frame)[source]

Bases: fsleyes.views.viewpanel.ViewPanel

The PlotPanel class is the base class for all FSLeyes views which display some sort of 2D data plot, such as the TimeSeriesPanel, and the HistogramPanel. See also the OverlayPlotPanel, which contains extra logic for displaying plots related to the currently selected overlay.

PlotPanel uses matplotlib for its plotting. The matplotlib Figure, Axis, and Canvas instances can be accessed via the getFigure(), getAxis(), and getCanvas() methods, if they are needed. Various display settings can be configured through PlotPanel properties, including legend, smooth, etc.

Sub-class requirements

Sub-class implementations of PlotPanel must do the following:

  1. Call the PlotPanel constructor.

  2. Define a DataSeries sub-class.

  3. Override the draw() method, so it calls the drawDataSeries() method.

  4. If necessary, override the prepareDataSeries() method to perform any preprocessing on extraSeries passed to the drawDataSeries() method (but not applied to DataSeries that have been added to the dataSeries list).

  5. If necessary, override the destroy() method, but make sure that the base-class implementation is called.

Data series

A PlotPanel instance plots data contained in one or more DataSeries instances; all DataSeries classes are defined in the plotting sub-package. Therefore, PlotPanel sub-classes also need to define a sub-class of the DataSeries base class.

DataSeries objects can be plotted by passing them to the drawDataSeries() method.

Or, if you want one or more DataSeries to be held, i.e. plotted every time, you can add them to the dataSeries list. The DataSeries in the dataSeries list will be plotted on every call to drawDataSeries() (in addition to any DataSeries passed directly to drawDataSeries()) until they are removed from the dataSeries list.

The draw queue

The PlotPanel uses a async.TaskThread to asynchronously extract and prepare data for plotting, This is because data preparation may take a long time for large Image overlays, and the main application thread should not be blocked while this is occurring. The TaskThread instance is accessible through the getDrawQueue() method, in case anything needs to be scheduled on it.

Plot panel actions

A number of actions are also provided by the PlotPanel class:

screenshot

Prompts the user to select a file name, then saves a screenshot of the current plot.

importDataSeries

Imports data series from a text file.

exportDataSeries

Exports displayed data series to a text file.

dataSeries = <MagicMock name='mock.List()' id='139656530353984'>

This list contains DataSeries instances which are plotted on every call to drawDataSeries(). DataSeries instances can be added/removed directly to/from this list.

artists = <MagicMock name='mock.List()' id='139656530353984'>

This list contains any matplotlib.Artist instances which are plotted every call to drawArtists().

legend = <MagicMock name='mock.Boolean()' id='139656535298112'>

If True, a legend is added to the plot, with an entry for every DataSeries instance in the dataSeries list.

xAutoScale = <MagicMock name='mock.Boolean()' id='139656535298112'>

If True, the plot limits for the X axis are automatically updated to fit all plotted data.

yAutoScale = <MagicMock name='mock.Boolean()' id='139656535298112'>

If True, the plot limits for the Y axis are automatically updated to fit all plotted data.

xLogScale = <MagicMock name='mock.Boolean()' id='139656535298112'>

Toggle a \(log_{10}\) x axis scale.

yLogScale = <MagicMock name='mock.Boolean()' id='139656535298112'>

Toggle a \(log_{10}\) y axis scale.

invertX = <MagicMock name='mock.Boolean()' id='139656535298112'>

Invert the plot along the X axis.

invertY = <MagicMock name='mock.Boolean()' id='139656535298112'>

Invert the plot along the Y axis.

xScale = <MagicMock name='mock.Real()' id='139656530885120'>

Scale to apply to the X axis data.

yScale = <MagicMock name='mock.Real()' id='139656530885120'>

Scale to apply to the Y axis data.

xOffset = <MagicMock name='mock.Real()' id='139656530885120'>

Offset to apply to the X axis data.

yOffset = <MagicMock name='mock.Real()' id='139656530885120'>

Offset to apply to the Y axis data.

ticks = <MagicMock name='mock.Boolean()' id='139656535298112'>

Toggle axis ticks and tick labels on/off.

grid = <MagicMock name='mock.Boolean()' id='139656535298112'>

Toggle an axis grid on/off.

gridColour = <MagicMock name='mock.Colour()' id='139656530836304'>

Grid colour (if grid is True).

bgColour = <MagicMock name='mock.Colour()' id='139656530836304'>

Plot background colour.

smooth = <MagicMock name='mock.Boolean()' id='139656535298112'>

If True all plotted data is up-sampled, and smoothed using spline interpolation.

xlabel = <MagicMock name='mock.String()' id='139656530779296'>

A label to show on the x axis.

ylabel = <MagicMock name='mock.String()' id='139656530779296'>

A label to show on the y axis.

limits = <MagicMock name='mock.Bounds()' id='139656530358912'>

The x/y axis limits. If xAutoScale and yAutoScale are True, these limit values are automatically updated on every call to drawDataSeries().

__init__(parent, overlayList, displayCtx, frame)[source]

Create a PlotPanel.

Parameters
getFigure()[source]

Returns the matplotlib Figure instance.

getAxis()[source]

Returns the matplotlib Axis instance.

getCanvas()[source]

Returns the matplotlib Canvas instance.

getDrawQueue()[source]

Returns the :class`.idle.TaskThread` instance used for data preparation.

draw(*a)[source]

This method must be overridden by PlotPanel sub-classes.

It is called whenever a DataSeries is added to the dataSeries list, or when any plot display properties change.

Sub-class implementations should call the drawDataSeries() and meth:drawArtists methods.

asyncDraw(*a)[source]

Schedules draw() to be run asynchronously. This method should be used in preference to calling draw() directly in most cases, particularly where the call occurs within a property callback function.

destroy()[source]

Removes some property listeners, and then calls ViewPanel.destroy().

screenshot(*a)[source]

Prompts the user to select a file name, then saves a screenshot of the current plot.

See the ScreenshotAction.

importDataSeries(*a)[source]

Imports data series from a text file.

See the ImportDataSeriesAction.

exportDataSeries(*args, **kwargs)[source]

Exports displayed data series to a text file.

See the ExportDataSeriesAction.

message(msg, clear=True, border=False)[source]

Displays the given message in the centre of the figure.

This is a convenience method provided for use by subclasses.

getArtist(ds)[source]

Returns the matplotlib.Artist (typically a Line2D instance) associated with the given DataSeries instance. A KeyError is raised if there is no such artist.

getDrawnDataSeries()[source]

Returns a list of tuples, each tuple containing the (DataSeries, x, y) data for one DataSeries instance as it is shown on the plot.

prepareDataSeries(ds)[source]

Prepares the data from the given DataSeries so it is ready to be plotted. Called by the __drawOneDataSeries() method for any extraSeries passed to the drawDataSeries() method (but not applied to DataSeries that have been added to the dataSeries list).

This implementation just returns DataSeries.getData - override it to perform any custom preprocessing.

drawArtists(refresh=True, immediate=False)[source]

Draw all matplotlib.Artist instances in the artists list, then refresh the canvas.

Parameters

refresh – If True (default), the canvas is refreshed.

drawDataSeries(extraSeries=None, refresh=False, **plotArgs)[source]

Queues a request to plot all of the DataSeries instances in the dataSeries list.

This method does not do the actual plotting - it is performed asynchronously, to avoid locking up the GUI:

  1. The data for each DataSeries instance is prepared on separate threads (using idle.run()).

  2. A call to idle.wait() is enqueued on a TaskThread.

  3. This wait function waits until all of the data preparation threads have completed, and then passes all of the data to the __drawDataSeries() method.

Parameters
  • extraSeries – A sequence of additional DataSeries to be plotted. These series are passed through the prepareDataSeries() method before being plotted.

  • refresh – If True, the canvas is refreshed. Otherwise, you must call getCanvas().draw() manually. Defaults to False - the drawArtists() method will refresh the canvas, so if you call drawArtists() immediately after calling this method (which you should), then you don’t need to manually refresh the canvas.

  • plotArgs – Passed through to the __drawDataSeries() method.

Note

This method must only be called from the main application thread (the wx event loop).

__drawDataSeries(dataSeries, allXdata, allYdata, oldxlim, oldylim, refresh, xlabel=None, ylabel=None, **plotArgs)

Called by __drawDataSeries(). Plots all of the data associated with the given dataSeries.

Parameters
  • dataSeries – The list of DataSeries instances to plot.

  • allXdata – A list of arrays containing X axis data, one for each DataSeries.

  • allYdata – A list of arrays containing Y axis data, one for each DataSeries.

  • oldxlim – X plot limits from the previous draw. If xAutoScale is disabled, this limit is preserved.

  • oldylim – Y plot limits from the previous draw. If yAutoScale is disabled, this limit is preserved.

  • refresh – Refresh the canvas - see drawDataSeries().

  • xlabel – If provided, overrides the value of the xlabel property.

  • ylabel – If provided, overrides the value of the ylabel property.

  • plotArgs – Remaining arguments passed to the __drawOneDataSeries() method.

__drawOneDataSeries(ds, xdata, ydata, **plotArgs)

Plots a single DataSeries instance. This method is called by the drawDataSeries() method.

Parameters
  • ds – The DataSeries instance.

  • xdata – X axis data.

  • ydata – Y axis data.

  • plotArgs – May be used to customise the plot - these arguments are all passed through to the Axis.plot function.

__dataSeriesChanged(*a)

Called when the dataSeries list changes. Adds listeners to any new DataSeries instances, and then calls asyncDraw().

__artistsChanged(*a)

Called when the artists list changes. Calls asyncDraw().

__limitsChanged(*a)

Called when the limits change. Updates the axis limits accordingly.

__calcLimits(dataxlims, dataylims, axisxlims, axisylims, axWidth, axHeight)

Calculates and returns suitable axis limits for the current plot. Also updates the limits property. This method is called by the drawDataSeries() method.

If xAutoScale or yAutoScale are enabled, the limits are calculated from the data range, using the canvas width and height to maintain consistent padding around the plotted data, irrespective of the canvas size.

. Otherwise, the existing axis limits are retained.

Parameters
  • dataxlims – A tuple containing the (min, max) x data range.

  • dataylims – A tuple containing the (min, max) y data range.

  • axisxlims – A tuple containing the current (min, max) x axis limits.

  • axisylims – A tuple containing the current (min, max) y axis limits.

  • axWidth – Canvas width in pixels

  • axHeight – Canvas height in pixels

__module__ = 'fsleyes.views.plotpanel'
class fsleyes.views.plotpanel.OverlayPlotPanel(*args, **kwargs)[source]

Bases: fsleyes.views.plotpanel.PlotPanel

The OverlayPlotPanel is a PlotPanel which contains some extra logic for creating, storing, and drawing DataSeries instances for each overlay in the OverlayList.

Subclass requirements

Sub-classes must:

  1. Implement the createDataSeries() method, so it creates a DataSeries instance for a specified overlay.

  2. Implement the PlotPanel.draw() method so it calls the PlotPanel.drawDataSeries(), passing DataSeries instances for all overlays where Display.enabled is True.

  3. Optionally implement the prepareDataSeries() method to perform any custom preprocessing.

The internal data series store

The OverlayPlotPanel maintains a store of DataSeries instances, one for each compatible overlay in the OverlayList. The OverlayPlotPanel manages the property listeners that must be registered with each of these DataSeries to refresh the plot. These instances are created by the createDataSeries() method, which is implemented by sub-classes. The following methods are available to sub-classes, for managing the internal store of DataSeries instances:

getDataSeries

Returns the DataSeries instance associated with the specified overlay, or None if there is no DataSeries instance.

getDataSeriesToPlot

Convenience method which returns a list of overlays which have DataSeries that should be plotted.

clearDataSeries

Destroys the internally cached DataSeries for the given overlay.

updateDataSeries

Makes sure that a DataSeries instance has been created for every compatible overlay, and that property listeners are correctly registered, so the plot can be refreshed when needed.

addDataSeries

Every DataSeries which is currently plotted, and has not been added to the PlotPanel.dataSeries list, is added to said list.

removeDataSeries

Removes the most recently added DataSeries from this OverlayPlotPanel.

Proxy images

The OverlayPlotPanel will replace all ProxyImage instances with their base images. This functionality was originally added to support the HistogramSeries.showOverlay functionality - it adds a mask image to the OverlayList to display the histogram range. Sub-classes may wish to adhere to the same logic (replacing ProxyImage instances with their bases)

Control panels

The PlotControlPanel, PlotListPanel, and OverlayListPanel are FSLeyes control panels which work with the OverlayPlotPanel. The PlotControlPanel is not intended to be used directly - plot-specific sub-classes are used instead. The following actions can be used to toggle control panels on an OverlayPlotPanel:

toggleOverlayList

Shows/hides an OverlayListPanel.

togglePlotList

Shows/hides a PlotListPanel.

Sub-classes

The OverlayPlotPanel is the base class for:

TimeSeriesPanel

The TimeSeriesPanel is an OverlayPlotPanel which plots time series data from overlays.

HistogramPanel

An OverlayPlotPanel which plots histograms from Image overlay data.

PowerSpectrumPanel

The PowerSpectrumPanel class is an OverlayPlotPanel which plots power spectra of overlay data.

plotColours = {}

This dictionary is used to store a collection of {overlay : colour} mappings. It is shared across all OverlayPlotPanel instances, so that the same (initial) colour is used for the same overlay, across multiple plots.

See also plotStyles.

Sub-classes should use the getOverlayPlotColour() and :meth:`getOverlayPlotStyle`methods to retrieve the initial colour and linestyle to use for a given overlay.

__module__ = 'fsleyes.views.plotpanel'
plotStyles = {}

This dictionary is used to store a collection of {overlay : colour} mappings - it is used in conjunction with plotColours.

__init__(*args, **kwargs)[source]

Create an OverlayPlotPanel.

Parameters

initialState – Must be passed as a keyword argument. Allows you to specify the initial enabled/disabled state for each overlay. See updateDataSeries(). If not provided, only the data series for the currently selected overlay is shown (if possible).

All other argumenst are passed through to PlotPanel.__init__().

destroy()[source]

Must be called when this OverlayPlotPanel is no longer needed. Removes some property listeners, and calls PlotPanel.destroy().

getDataSeriesToPlot()[source]

Convenience method which returns a list of overlays which have DataSeries that should be plotted.

getDataSeries(overlay)[source]

Returns the DataSeries instance associated with the specified overlay, or None if there is no DataSeries instance.

getOverlayPlotColour(overlay)[source]

Returns an initial colour to use for plots associated with the given overlay. If a colour is present in the plotColours dictionary, it is returned. Otherwise a random colour is generated, added to plotColours, and returned.

getOverlayPlotStyle(overlay)[source]

Returns an initial line style to use for plots associated with the given overlay. If a colour is present in the plotStyles dictionary, it is returned. Otherwise a line style is generated, added to plotStyles, and returned.

The format of the returned line style is suitable for use with the linestyle argument of the matplotlib ``plot``functions.

addDataSeries()[source]

Every DataSeries which is currently plotted, and has not been added to the PlotPanel.dataSeries list, is added to said list.

removeDataSeries(*a)[source]

Removes the most recently added DataSeries from this OverlayPlotPanel.

createDataSeries(overlay)[source]

This method must be implemented by sub-classes. It must create and return a DataSeries instance for the specified overlay.

Note

Sub-class implementations should set the DataSeries.colour property to that returned by the getOverlayPlotColour() method, and the DataSeries.lineStyle property to that returned by the getOverlayPlotStyle() method

Different DataSeries types need to be re-drawn when different properties change. For example, a VoxelTimeSeries` instance needs to be redrawn when the DisplayContext.location property changes, whereas a MelodicTimeSeries instance needs to be redrawn when the VolumeOpts.volume property changes.

Therefore, in addition to creating and returning a DataSeries instance for the given overlay, sub-class implementations must also specify the properties which affect the state of the DataSeries instance. These must be specified as two lists:

  • the targets list, a list of objects which own the dependant properties (e.g. the DisplayContext or VolumeOpts instance).

  • The properties list, a list of names, each specifying the property on the corresponding target.

This method must therefore return a tuple containing:

  • A DataSeries instance, or None if the overlay is incompatible.

  • A list of target instances.

  • A list of property names.

The target and property name lists must have the same length.

clearDataSeries(overlay)[source]

Destroys the internally cached DataSeries for the given overlay.

updateDataSeries(initialState=None)[source]

Makes sure that a DataSeries instance has been created for every compatible overlay, and that property listeners are correctly registered, so the plot can be refreshed when needed.

Parameters

initialState – If provided, must be a dict of { overlay : bool } mappings, specifying the initial value of the DataSeries.enabled property for newly created instances. If not provided, only the data series for the currently selected overlay (if it has been newly added) is initially enabled.

toggleOverlayList()[source]

Shows/hides an OverlayListPanel. See ViewPanel.togglePanel().

togglePlotList(floatPane=False)[source]

Shows/hides a PlotListPanel. See ViewPanel.togglePanel().

__dataSeriesChanged(*a)

Called when the dataSeries list changes. Enables/disables the removeDataSeries() action accordingly.

__overlayListChanged(*a, **kwa)

Called when the OverlayList changes. Makes sure that there are no DataSeries instances in the PlotPanel.dataSeries list, or in the internal cache, which refer to overlays that no longer exist.

Parameters

initialState – Must be passed as a keyword argument. If provided, passed through to the updateDataSeries() method.