mne_rt.viz.NFPlot#

class mne_rt.viz.NFPlot(modalities: list[str], scales_dict: dict[str, float], sfreq: float, time_window: float = 30.0, display_smoothing: float = 0.3, verbose=None)[source]#

Bases: _MockQMainWindow

Scrolling real-time neurofeedback signal monitor.

Displays one colour-coded trace per active NF modality in a dark-themed pyqtgraph.PlotWidget. Designed to be driven by record_main() via push().

Parameters:
modalitieslist of str

Names of the active NF modalities. One scrolling trace is shown per entry. Names must match entries in _LABELS for a human-readable legend, or the raw string is used as a fallback.

scales_dictdict[str, float]

Mapping from modality name to its physical display scale. The raw NF value is divided by this scale before plotting so that all traces occupy a similar vertical range.

sfreqfloat

Nominal update rate in Hz. Used to size the ring buffer.

time_windowfloat, default 30.0

Visible time range in seconds at startup (can be changed at runtime from the control panel).

verbosebool | str | None, default None

Verbosity level. See set_log_level().

See also

mne_rt.viz.BrainPlot

3D brain activation display.

mne_rt.viz.RawPlot

Scrolling raw M/EEG channel viewer.

mne_rt.RTStream.record_main

Drives both plots from the NF loop.

Notes

The control panel (right sidebar) provides:

  • Playback — pause/resume, clear buffer, screenshot.

  • Display — time-window selector, grid toggle, threshold-line toggle, reward-zone toggle, auto-range.

  • Channel Scales — per-modality amplitude scaling with + / buttons and a live ×N readout.

Each subplot can show a dashed horizontal threshold line marking the reward boundary of the protocol driving that modality (fixed or adaptive), passed per-update via the thresholds argument of push(). A modality with no associated protocol, or one whose protocol has no single-level threshold (e.g. LinearTrendProtocol), simply shows no line.

Each subplot can also show a translucent green reward span behind the trace, scrolling in lock-step with it, marking windows where the driving protocol currently rewards the subject — passed per-update via the rewards argument of push(). A modality with no driving protocol simply shows no span.

Status bar shows the latest value — and, when available, the current threshold — for every active modality, prefixed with 🟢 during reward.

Examples

Minimal offline usage:

>>> app = QApplication([])
>>> plot = NFPlot(["sensor_power"], {"sensor_power": 1e-12}, sfreq=100)
>>> plot.show()
>>> plot.push([3.2e-13], thresholds=[2.0e-13], rewards=[True])
>>> app.exec()

Added in version 1.0.0.

__init__(modalities: list[str], scales_dict: dict[str, float], sfreq: float, time_window: float = 30.0, display_smoothing: float = 0.3, verbose=None) None[source]#

Methods

__init__(modalities, scales_dict, sfreq[, ...])

closeEvent(event)

push(new_vals[, thresholds, rewards])

Append one new sample per modality and refresh all traces.

Attributes

closed

Emitted when the window is closed, before Qt tears down the widget.

closed = <MagicMock name='mock.Signal()' id='140412836434064'>#

Emitted when the window is closed, before Qt tears down the widget. record_main() connects this to stop pumping new data into a closed window while other plot windows stay open.

push(new_vals: list[float], thresholds: list[float | None] | None = None, rewards: list[bool | None] | None = None) None[source]#

Append one new sample per modality and refresh all traces.

This is the main update entry point, called at ~30 fps by the Qt pump timer inside record_main().

Parameters:
new_valslist of float

Latest NF value for each active modality, in the same order as the modalities list passed to __init__().

thresholdslist of (float or None), optional

Current reward-threshold value for each modality, in the same raw units as new_vals (i.e. not pre-normalised). Omit entirely to leave threshold lines untouched; use None or nan for an individual entry to hide that modality’s line (e.g. a modality with no protocol, or a protocol with no single-level threshold such as LinearTrendProtocol). Typically sourced from a protocol’s current_threshold property — see record_main().

rewardslist of (bool or None), optional

Whether the driving protocol is currently rewarding the subject for each modality, i.e. the crossed half of that protocol’s evaluate() return value. Rendered as a translucent green span behind the trace, scrolling in lock-step with it. Omit entirely to leave reward spans untouched; use None for an individual entry when the modality has no driving protocol.

Notes

The call is a no-op when the plot is paused (⏸ button pressed). Each value is normalised by its entry in scales_dict before being written into the ring buffer, so all traces share a common vertical scale. Threshold values are normalised the same way so the dashed threshold line stays aligned with its trace, including after per-channel + / scale adjustments.

closeEvent(event) None[source]#