Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#181963356 ; fake data alerting #219

Merged
merged 3 commits into from
May 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 35 additions & 31 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
# 2.0.0-rc.2

- Better handling of the `fake_data` parameter to avoid erroneous recordings. Added a confirmation dialog when the `fake_data` parameter is set to `True` to alert users that they are in a system test mode.

# 2.0.0-rc.1

## Contributions

This version contains major refactoring efforts and features. We anticipate a few additional refactor efforts in the near term based on feature requests from the community and (CAMBI)[cambi.tech]. These will support multi-modality, data sharing, and more complex language modeling. We are utilizing a release candidate to make features and bugfixes available sooner despite the full second version being in-progress. Thank you for your understanding and continued support! All pull requests in Github from #123 until #217 represent the 2.0.0-rc.1 work.
This version contains major refactoring efforts and features. We anticipate a few additional refactor efforts in the near term based on feature requests from the community and (CAMBI)[cambi.tech]. These will support multi-modality, data sharing, and more complex language modeling. We are utilizing a release candidate to make features and bugfixes available sooner despite the full second version being in-progress. Thank you for your understanding and continued support! All pull requests in Github from #123 until #217 represent the 2.0.0-rc.1 work.

The highlights:
The highlights:

- `Acquisition Enhancements`: multi-modal support and better performance overall! #171, #174
- `Language Model Refactor`: deprecation of docker base models. Addition of `LanguageModel` base class, `UniformLanguageModel` and a hugggingface model `GPT2LanguageModel`. #207
Expand All @@ -26,8 +30,8 @@ The details (incomplete, our apologies!):
- `helpers/visualization.py`: moved plot_edf function from demo to this module #126
- `helpers/raw_data.py`: module for raw data format support in BciPy #160
- `helpers/load.py`: add `load_users` method for extracting user names from data save location #125 add extract_mode method for determining the mode #126
- `helpers/task/`: add `Reshaper`, refactor trial reshaper and add inquiry reshaper #147 add `get_key_press` method with custom stamp argument. #129
- `helpers/stimuli.StimuliOrder`: defined ordering of inquiry stimuli. The current approach is to randomize. This adds an alphabetical option. #153
- `helpers/task/`: add `Reshaper`, refactor trial reshaper and add inquiry reshaper #147 add `get_key_press` method with custom stamp argument. #129
- `helpers/stimuli.StimuliOrder`: defined ordering of inquiry stimuli. The current approach is to randomize. This adds an alphabetical option. #153
- `helpers/stimuli.alphabetize`: method for taking a list of strings and returning them in alphabetical order with characters last in the list. #153
- `helpers/validate`: `_validate_experiment_fields` and `validate_experiments`: validates experiments and fields in the correct format #156
- `bcipy/helpers/system_utils`: add report execution decorator #163
Expand All @@ -41,7 +45,7 @@ The details (incomplete, our apologies!):
- `LICENSE.md`: to used the Hippocratic license 2.1
- `CODE_OF_CONDUCT.md`: to latest version of the Contributor Covenant
- `README.md`: Add new glossary terms: mode, session and task #126 #127 and cleanup #129
- `bcipy/main.py`: formally, `bci_main.py`. To give a better console entry point and infrastructure for integration testing. In the terminal, you can now run `bcipy` instead of `python bci_main.py`
- `bcipy/main.py`: formally, `bci_main.py`. To give a better console entry point and infrastructure for integration testing. In the terminal, you can now run `bcipy` instead of `python bci_main.py`
- `parameters.json`: add stim_order #153 add max selections #175 remove max_inq_per_trial in favor of max_inq_per_series #176 add inquiry preview #177 with relevant stimuli units in help text, better starting stim_height, and inquiry preview keys #216
- `demo_stimuli_generation.py`: update imports and add a case showing the new ordering functionality. #153
- `copy_phrase_wrapper`: update logging and exception handling. add stim order. #153 BUGFIX: return transformed sampling rate #159
Expand All @@ -51,7 +55,7 @@ The details (incomplete, our apologies!):
- `FieldRegistry.py`: updated to use new alert types with timeout #156
- `gui/BCInterface.py`: use `load_users` method to populate user dropdown and remove internal BCInterface load method #125
- `gui/gui_main.py`: update to return a value in FormInput, set a value for IntegerInput only if provided #156
- `gui/viewer/data_viewer.py`: Replaced the original WxPython version of the signal data viewer with the new PyQt version #157. Use signal process filters instead of duplicating logic #147.
- `gui/viewer/data_viewer.py`: Replaced the original WxPython version of the signal data viewer with the new PyQt version #157. Use signal process filters instead of duplicating logic #147.
- `gui/viewer/file_viewer.py`: to use new raw data format #160
- `bcipy/acquisition`: refactored acquisition to support multi-modal acquisition and more performant real-time acquisition. These changes were significant and across multiple PRs. Support for new raw data format #160
- `ring_buffer_test.py` -> `test_ring_buffer.py`: to comply with naming conventions #156
Expand All @@ -78,7 +82,7 @@ The details (incomplete, our apologies!):
- `feedback/visual_feedback`: deprecate shape feedback type, line_color (in the administer method), and compare assertion as both were unused and added unneeded complexity. Set hard-coded values on the class instance for easier changing later. #128

### Removed

- `target_rsvp_inquiry_generator`: #153 unused
- `rsvp_copy_phrase_inq_generator`: #153 unused
- `tasks/rsvp/icon_to_icon.py`: #129 unused
Expand All @@ -94,31 +98,31 @@ The details (incomplete, our apologies!):

## Contributions

This version contains major refactoring and tooling improvements across the codebase. In addition, it introduces the concept of BciPy Experiments and Fields. Below we describe the major changes along with a PR# in github where applicable.
This version contains major refactoring and tooling improvements across the codebase. In addition, it introduces the concept of BciPy Experiments and Fields. Below we describe the major changes along with a PR# in github where applicable.

### Added
- Language model histogram #91
- BciPy official glossary (Sequence -> Inquiry & Epoch -> Series) #121
- System information to `system_utils` (cpu, platform, etc) #98
- Language model histogram #91
- BciPy official glossary (Sequence -> Inquiry & Epoch -> Series) #121
- System information to `system_utils` (cpu, platform, etc) #98
- BciPy Experiments and Fields: See PRs #113 #111, #114 for more information on the additions!
- `.bcipy` system directory to support experiment and fields #100
- `.bcipy` system directory to support experiment and fields #100
- support for python 3.7
- `rsvp/query_mechanisms`: to model the way we build inquiries #108
- `rsvp/query_mechanisms`: to model the way we build inquiries #108
- `Makefile`: contains useful install and development commands
- `convert`: a module for data conversions that will be useful for data sharing. Implemented a conversion function to the EDF format. #104
- `convert`: a module for data conversions that will be useful for data sharing. Implemented a conversion function to the EDF format. #104
- `exceptions`: a module for BciPy core exceptions

### Updated
- `acquisition`: refactored the acquisition module to separate the concept of a device (ex. DSI-24 headset) and a connection method to that device (TCP or LSL). #122
- `setup.py`: with new repo location and CAMBI official support email
- `offline_analysis`: to pull parameters from session file #90
- `requirements.txt`: to the latest available #99 #107
- `Parameters` (added help text, removed redundant parameters). Refactored to make them immutable. #101
- `gui_main `: to use PyQt5. We will refactor all GUI code to use this in the future. After this PR, the signal viewer (WxPython) and a couple of loading functions will remain (Tk). #102
- `BCInterface` : updated to use new gui_main methods. Added user if validations. #102 #120
- `params_form`: moved into a parameters modules within GUI and updated to use PyQt5. #109
- `dev_requirements`: used to be called test_requirements. It contains more than that, so we updated the name! #99
- `README`: with relevant updates and contributors
- `acquisition`: refactored the acquisition module to separate the concept of a device (ex. DSI-24 headset) and a connection method to that device (TCP or LSL). #122
- `setup.py`: with new repo location and CAMBI official support email
- `offline_analysis`: to pull parameters from session file #90
- `requirements.txt`: to the latest available #99 #107
- `Parameters` (added help text, removed redundant parameters). Refactored to make them immutable. #101
- `gui_main `: to use PyQt5. We will refactor all GUI code to use this in the future. After this PR, the signal viewer (WxPython) and a couple of loading functions will remain (Tk). #102
- `BCInterface` : updated to use new gui_main methods. Added user if validations. #102 #120
- `params_form`: moved into a parameters modules within GUI and updated to use PyQt5. #109
- `dev_requirements`: used to be called test_requirements. It contains more than that, so we updated the name! #99
- `README`: with relevant updates and contributors

### Removed
- `RSVPKeyboard.py`
Expand All @@ -145,8 +149,8 @@ This version contains major refactoring and tooling improvements across the code
### Updated

- DAQ file writing. Instead of writing to `raw_data.csv` during task executions, optionally write `raw_data.csv` on call to `stop_acquisition`, and only write to SQLite database during task.
- `get_data` queries in `buffer_server` to increase speed on Windows machines.
- RSVP sequence stimuli presentation. Reduces reported timing slips on Windows and Linux machines.
- `get_data` queries in `buffer_server` to increase speed on Windows machines.
- RSVP sequence stimuli presentation. Reduces reported timing slips on Windows and Linux machines.
- List of stimuli to be presented is now generated before each sequence is presented, rather than generating stimuli during the sequence.
- The screen is now only drawn once per stimulus, rather than redrawing the screen every frame.
- Signal viewer to shut down when data is no longer streaming
Expand All @@ -165,18 +169,18 @@ Patch for gui.viewer module. Missing init file.

# 1.4.0

This release focused on bug fixes, exposing parameters, and refactoring. Further dual screen configuration and testing was done to allow for simultaneous signal viewing and task operation.
This release focused on bug fixes, exposing parameters, and refactoring. Further dual screen configuration and testing was done to allow for simultaneous signal viewing and task operation.

## Added

- Dual screen configuration / updated support
- Parameters:
- Copy phrase decision thresholds
- Inter-sequence Feedback level thresholds


## Updated
- RSVP Display: refactor
- RSVP Display: refactor
- Decision Maker / Evidence Fusion: refactor
- Signal Viewer: more distinct channel names
- bci_main: shutdown handling and bug fix
Expand All @@ -189,7 +193,7 @@ This release focused on bug fixes, exposing parameters, and refactoring. Further

# 1.3.0

This release focused on the addition of a Signal Viewer, Inter-sequence Feedback Task, Signal Processing / Decomposition Methods, and miscellaneous cleanup.
This release focused on the addition of a Signal Viewer, Inter-sequence Feedback Task, Signal Processing / Decomposition Methods, and miscellaneous cleanup.

## Added

Expand All @@ -201,7 +205,7 @@ This release focused on the addition of a Signal Viewer, Inter-sequence Feedback
- Backspace frequency parameterization and implementation
- Bandpass and Notch Filter implementation
- Custom Exceptions


## Updated
- Refactor RSVP Task: Icon-to-Icon (WIP)
Expand Down
26 changes: 26 additions & 0 deletions bcipy/gui/alert.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
"""GUI alert messages"""
# pylint: disable=no-name-in-module
import sys
from PyQt5.QtWidgets import QApplication
from bcipy.gui.main import alert_message, AlertMessageType, AlertResponse, AlertMessageResponse


def confirm(message: str) -> bool:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some duplicate functionality and enums exist in gui_main

It may be useful to use the enums or factor this out of BCIGui to be used elsewhere.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good callout. I factored out the code for constructing a MessageBox into its own function in GUI/main that's now used in both BCIGui and here. They each call the resulting message box in slightly different ways and have separate use cases, so I think it still makes sense for them to be distinct, but now this module uses functionality provided by the main module.

"""Confirmation dialog which allows the user to select between a true and false.

Parameters
----------
message - alert to display
Returns
-------
users selection : True for selecting Ok, False for Cancel.
"""
app = QApplication(sys.argv)
dialog = alert_message(message,
message_type=AlertMessageType.INFO,
message_response=AlertMessageResponse.OCE)
button = dialog.exec()

result = bool(button == AlertResponse.OK.value)
app.quit()
return result
49 changes: 37 additions & 12 deletions bcipy/gui/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,38 @@ class AlertMessageResponse(Enum):
OCE = "Okay or Cancel Exit"


def alert_message(
message: str,
title: str = None,
message_type: AlertMessageType = AlertMessageType.INFO,
message_response: AlertMessageResponse = AlertMessageResponse.OTE,
message_timeout: float = 0) -> MessageBox:
"""Constructs an Alert Message.

Parameters
----------
message - text to display
title - optional title of the GUI window
message_type - type of icon that is displayed
message_response - response buttons available to the user
message_time - optional timeout for displaying the alert
"""

msg = MessageBox()
if title:
msg.setWindowTitle(title)
msg.setText(message)
msg.setIcon(message_type.value)
msg.setTimeout(message_timeout)

if message_response is AlertMessageResponse.OTE:
msg.setStandardButtons(AlertResponse.OK.value)
elif message_response is AlertMessageResponse.OCE:
msg.setStandardButtons(AlertResponse.OK.value |
AlertResponse.CANCEL.value)
return msg


class FormInput(QWidget):
"""A form element with a label, help tip, and input control. The default control is a text
input. This object may be subclassed to specialize the input control or the arrangement of
Expand Down Expand Up @@ -748,18 +780,11 @@ def throw_alert_message(self,
message_response: AlertMessageResponse = AlertMessageResponse.OTE,
message_timeout: float = 0) -> MessageBox:
"""Throw Alert Message."""

msg = MessageBox()
msg.setWindowTitle(title)
msg.setText(message)
msg.setIcon(message_type.value)
msg.setTimeout(message_timeout)

if message_response is AlertMessageResponse.OTE:
msg.setStandardButtons(AlertResponse.OK.value)
elif message_response is AlertMessageResponse.OCE:
msg.setStandardButtons(AlertResponse.OK.value | AlertResponse.CANCEL.value)

msg = alert_message(message,
title=title,
message_type=message_type,
message_response=message_response,
message_timeout=message_timeout)
return msg.exec_()

def get_filename_dialog(self,
Expand Down
7 changes: 6 additions & 1 deletion bcipy/helpers/acquisition.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Helper functions for working with the acquisition module"""
import logging
import subprocess
import time
from pathlib import Path
Expand All @@ -14,6 +15,8 @@
from bcipy.acquisition.devices import DeviceSpec, preconfigured_device
from bcipy.acquisition.protocols.lsl.lsl_client import LslAcquisitionClient

log = logging.getLogger(__name__)


def init_eeg_acquisition(parameters: dict,
save_folder: str,
Expand Down Expand Up @@ -44,15 +47,17 @@ def init_eeg_acquisition(parameters: dict,
-------
(client, server) tuple
"""

# TODO: parameter for loading devices; path to devices.json?
# devices.load(devices_path)
device_spec = preconfigured_device(parameters['acq_device'])

dataserver = False
if server:
log.info(f"fake data is on. Generating mock device data for {device_spec.name}")
dataserver = LslDataServer(device_spec=device_spec)
await_start(dataserver)
else:
log.info(f"fake data is off. Connecting to {device_spec.name}...")

client = init_lsl_client(parameters, device_spec, save_folder)
client.start_acquisition()
Expand Down
19 changes: 12 additions & 7 deletions bcipy/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,21 @@
import multiprocessing

from bcipy.display import init_display_window
from bcipy.gui.alert import confirm
from bcipy.helpers.acquisition import init_eeg_acquisition
from bcipy.helpers.task import print_message
from bcipy.helpers.session import collect_experiment_field_data
from bcipy.helpers.system_utils import get_system_info, configure_logger, DEFAULT_EXPERIMENT_ID
from bcipy.helpers.language_model import init_language_model
from bcipy.helpers.load import load_json_parameters, load_experiments, load_signal_model
from bcipy.helpers.validate import validate_experiment
from bcipy.helpers.load import (load_experiments, load_json_parameters,
load_signal_model)
from bcipy.helpers.parameters import DEFAULT_PARAMETERS_PATH
from bcipy.helpers.save import init_save_data_structure
from bcipy.helpers.session import collect_experiment_field_data
from bcipy.helpers.system_utils import (DEFAULT_EXPERIMENT_ID,
configure_logger, get_system_info)
from bcipy.helpers.task import print_message
from bcipy.helpers.validate import validate_experiment
from bcipy.signal.model import PcaRdaKdeModel
from bcipy.task import TaskType
from bcipy.task.start_task import start_task
from bcipy.signal.model import PcaRdaKdeModel


log = logging.getLogger(__name__)

Expand Down Expand Up @@ -45,6 +47,9 @@ def bci_main(parameter_location: str, user: str, task: TaskType, experiment: str
# Load parameters
parameters = load_json_parameters(parameter_location, value_cast=True)

if parameters['fake_data'] and not confirm("Fake data is on. Do you want to continue?"):
return False

# Update property to reflect the parameter source
parameters['parameter_location'] = parameter_location
if parameter_location != DEFAULT_PARAMETERS_PATH:
Expand Down
2 changes: 1 addition & 1 deletion bcipy/parameters/parameters.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"fake_data": {
"value": "true",
"value": "false",
"section": "bci_config",
"readableName": "Fake EEG Data On/Off",
"helpTip": "If ‘true’, fake EEG data will be used instead of real EEG data. Useful for testing by software development team.",
Expand Down
3 changes: 2 additions & 1 deletion bcipy/tests/test_bci_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ class TestBciMain(unittest.TestCase):
save_location = '/'
parameters = {
'data_save_loc': data_save_location,
'log_name': 'test_log'
'log_name': 'test_log',
'fake_data': False
}
system_info = {
'bcipy_version': 'test_version'
Expand Down