improvements
This commit is contained in:
83
main.py
83
main.py
@@ -23,10 +23,9 @@ from pathlib import Path, PurePosixPath
|
||||
from datetime import datetime
|
||||
from multiprocessing import Process, current_process, freeze_support, Manager
|
||||
|
||||
# External library imports
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
|
||||
# External library imports
|
||||
import psutil
|
||||
import requests
|
||||
|
||||
@@ -46,7 +45,7 @@ from PySide6.QtGui import QAction, QKeySequence, QIcon, QIntValidator, QDoubleVa
|
||||
from PySide6.QtSvgWidgets import QSvgWidget # needed to show svgs when app is not frozen
|
||||
|
||||
|
||||
CURRENT_VERSION = "1.0.0"
|
||||
CURRENT_VERSION = "1.2.0"
|
||||
|
||||
API_URL = "https://git.research.dezeeuw.ca/api/v1/repos/tyler/flares/releases"
|
||||
API_URL_SECONDARY = "https://git.research2.dezeeuw.ca/api/v1/repos/tyler/flares/releases"
|
||||
@@ -58,7 +57,6 @@ SECTIONS = [
|
||||
{
|
||||
"title": "Preprocessing",
|
||||
"params": [
|
||||
# {"name": "SECONDS_TO_STRIP", "default": 0, "type": int, "help": "Seconds to remove from beginning of all loaded snirf files. Setting this to 0 will remove nothing from the files."},
|
||||
{"name": "DOWNSAMPLE", "default": True, "type": bool, "help": "Should the snirf files be downsampled? If this is set to True, DOWNSAMPLE_FREQUENCY will be used as the target frequency to downsample to."},
|
||||
{"name": "DOWNSAMPLE_FREQUENCY", "default": 25, "type": int, "help": "Frequency (Hz) to downsample to. If this is set higher than the input data, new data will be interpolated. Only used if DOWNSAMPLE is set to True"},
|
||||
]
|
||||
@@ -74,12 +72,26 @@ SECTIONS = [
|
||||
"title": "Verify Optode Placement",
|
||||
"params": [
|
||||
{"name": "OPTODE_PLACEMENT", "default": True, "type": bool, "help": "Generate an image for each participant outlining their optode placement."},
|
||||
{"name": "SHOW_OPTODE_NAMES", "default": True, "type": bool, "help": "Should the optode names be written next to their location or not."},
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Short/Long Channels",
|
||||
"params": [
|
||||
{"name": "SHORT_CHANNEL", "default": True, "type": bool, "help": "This should be set to True if the data has a short channel present in the data."},
|
||||
{"name": "SHORT_CHANNEL_THRESH", "default": 0.015, "type": float, "help": "The maximum distance the short channel can be in metres."},
|
||||
{"name": "LONG_CHANNEL_THRESH", "default": 0.045, "type": float, "help": "The maximum distance the long channel can be in metres."},
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Heart Rate",
|
||||
"params": [
|
||||
{"name": "HEART_RATE", "default": True, "type": bool, "help": "Attempt to calculate the participants heart rate."},
|
||||
{"name": "SECONDS_TO_STRIP_HR", "default": 5, "type": int, "help": "Will remove this many seconds from the start and end of the file. Useful if recording before cap is firmly placed, or participant removes cap while still recording."},
|
||||
{"name": "MAX_LOW_HR", "default": 40, "type": int, "help": "Any heart rate windows that average below this value will be rounded up to this value."},
|
||||
{"name": "MAX_HIGH_HR", "default": 200, "type": int, "help": "Any heart rate windows that average above this value will be rounded down to this value."},
|
||||
{"name": "SMOOTHING_WINDOW_HR", "default": 100, "type": int, "help": "How many individual data points to smooth into a single window."},
|
||||
{"name": "HEART_RATE_WINDOW", "default": 25, "type": int, "help": "Used for visualization. Shows the range of the calculated heart rate +- this value."},
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -94,14 +106,12 @@ SECTIONS = [
|
||||
"title": "Signal to Noise Ratio",
|
||||
"params": [
|
||||
{"name": "SNR", "default": True, "type": bool, "help": "Calculate and mark channels bad based on their Signal to Noise Ratio. This metric calculates how much of the observed signal was noise versus how much of it was a useful signal."},
|
||||
# {"name": "SNR_TIME_WINDOW", "default": -1, "type": int, "help": "SNR time window."},
|
||||
{"name": "SNR_THRESHOLD", "default": 5.0, "type": float, "help": "SNR threshold (dB). A typical scale would be 0-25, but it is possible for values to be both above and below this range. Higher values correspond to a better signal. If SNR is True, any channels lower than this value will be marked as bad."},
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Peak Spectral Power",
|
||||
"params": [
|
||||
|
||||
{"name": "PSP", "default": True, "type": bool, "help": "Calculate and mark channels bad based on their Peak Spectral Power. This metric calculates the amplitude or strength of a frequency component that is most prominent in a particular frequency range or spectrum."},
|
||||
{"name": "PSP_TIME_WINDOW", "default": 3, "type": int, "help": "Independent PSP calculations will be perfomed in a time window for the duration of the value provided, until the end of the file is reached."},
|
||||
{"name": "PSP_THRESHOLD", "default": 0.1, "type": float, "help": "PSP threshold. A typical scale would be 0-0.5, but it is possible for values to be above this range. Higher values correspond to a better signal. If PSP is True, any channels lower than this value will be marked as bad."},
|
||||
@@ -110,15 +120,15 @@ SECTIONS = [
|
||||
{
|
||||
"title": "Bad Channels Handling",
|
||||
"params": [
|
||||
# {"name": "NOT_IMPLEMENTED", "default": True, "type": bool, "help": "Calculate Peak Spectral Power."},
|
||||
# {"name": "NOT_IMPLEMENTED", "default": 3, "type": int, "help": "PSP time window."},
|
||||
# {"name": "NOT_IMPLEMENTED", "default": 0.1, "type": float, "help": "PSP threshold."},
|
||||
{"name": "BAD_CHANNELS_HANDLING", "default": [], "type": list, "options": ["Interpolate", "Remove", "None"], "exclusive": True, "help": "How should we deal with the bad channels that occurred? Note: Some analysis options will only work when this is set to 'Interpolate'."},
|
||||
{"name": "MAX_DIST", "default": 0.03, "type": float, "help": "The maximum distance to look for neighbours when interpolating. Used only when BAD_CHANNELS_HANDLING is set to 'Interpolate'."},
|
||||
{"name": "MIN_NEIGHBORS", "default": 2, "type": int, "help": "The minimumn amount of neighbours needed within the MAX_DIST parameter. Used only when BAD_CHANNELS_HANDLING is set to 'Interpolate'."},
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Optical Density",
|
||||
"params": [
|
||||
# Intentionally empty (TODO)
|
||||
# NOTE: Intentionally empty
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -139,7 +149,7 @@ SECTIONS = [
|
||||
{
|
||||
"title": "Haemoglobin Concentration",
|
||||
"params": [
|
||||
# Intentionally empty (TODO)
|
||||
# NOTE: Intentionally empty
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -154,24 +164,18 @@ SECTIONS = [
|
||||
{"name": "FILTER", "default": True, "type": bool, "help": "Filter the data."},
|
||||
{"name": "L_FREQ", "default": 0.005, "type": float, "help": "Any frequencies lower than this value will be removed."},
|
||||
{"name": "H_FREQ", "default": 0.3, "type": float, "help": "Any frequencies higher than this value will be removed."},
|
||||
{"name": "L_TRANS_BANDWIDTH", "default": 0.002, "type": float, "help": "How wide the transitional period should be so the data doesn't just drop off on the lower bound."},
|
||||
{"name": "H_TRANS_BANDWIDTH", "default": 0.002, "type": float, "help": "How wide the transitional period should be so the data doesn't just drop off on the upper bound."},
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Short/Long Channels",
|
||||
"params": [
|
||||
{"name": "SHORT_CHANNEL", "default": True, "type": bool, "help": "This should be set to True if the data has a short channel present in the data."},
|
||||
{"name": "SHORT_CHANNEL_THRESH", "default": 0.015, "type": float, "help": "The maximum distance the short channel can be in metres."},
|
||||
{"name": "LONG_CHANNEL_THRESH", "default": 0.045, "type": float, "help": "The maximum distance the long channel can be in metres."},
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Extracting Events",
|
||||
"title": "Extracting Events*",
|
||||
"params": [
|
||||
#{"name": "EVENTS", "default": True, "type": bool, "help": "Calculate Peak Spectral Power."},
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Epoch Calculations",
|
||||
"title": "Epoch Calculations*",
|
||||
"params": [
|
||||
#{"name": "EVENTS", "default": True, "type": bool, "help": "Calculate Peak Spectral Power."},
|
||||
]
|
||||
@@ -179,18 +183,27 @@ SECTIONS = [
|
||||
{
|
||||
"title": "Design Matrix",
|
||||
"params": [
|
||||
{"name": "RESAMPLE", "default": True, "type": bool, "help": "The length of your stimulus."},
|
||||
{"name": "RESAMPLE_FREQ", "default": 1, "type": int, "help": "The length of your stimulus."},
|
||||
|
||||
{"name": "STIM_DUR", "default": 0.5, "type": float, "help": "The length of your stimulus."},
|
||||
{"name": "HRF_MODEL", "default": "fir", "type": str, "help": "Specifies the hemodynamic response function."},
|
||||
{"name": "DRIFT_MODEL", "default": "cosine", "type": str, "help": "Specifies the desired drift model."},
|
||||
{"name": "HIGH_PASS", "default": 0.01, "type": float, "help": "High-pass frequency in case of a cosine model (in Hz)."},
|
||||
{"name": "DRIFT_ORDER", "default": 1, "type": int, "help": "Order of the drift model (in case it is polynomial)"},
|
||||
{"name": "FIR_DELAYS", "default": "None", "type": range, "help": "In case of FIR design, yields the array of delays used in the FIR model (in scans)."},
|
||||
{"name": "MIN_ONSET", "default": -24, "type": int, "help": "Minimal onset relative to frame times (in seconds)"},
|
||||
{"name": "OVERSAMPLING", "default": 50, "type": int, "help": "Oversampling factor used in temporal convolutions."},
|
||||
{"name": "REMOVE_EVENTS", "default": "None", "type": list, "help": "Remove events matching the names provided before generating the Design Matrix"},
|
||||
{"name": "DRIFT_MODEL", "default": "cosine", "type": str, "help": "Drift model for GLM."},
|
||||
# {"name": "DURATION_BETWEEN_ACTIVITIES", "default": 35, "type": int, "help": "Time between activities (s)."},
|
||||
# {"name": "SHORT_CHANNEL_REGRESSION", "default": True, "type": bool, "help": "Use short channel regression."},
|
||||
{"name": "SHORT_CHANNEL_REGRESSION", "default": True, "type": bool, "help": "Whether to use short channel regression and regress out the short channels. Requires SHORT_CHANNELS to be True and at least one short channel to be found."},
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "General Linear Model",
|
||||
"params": [
|
||||
{"name": "TIME_WINDOW_START", "default": "0", "type": int, "help": "Where to start averaging the fir model bins. Only affects the significance and contrast images."},
|
||||
{"name": "TIME_WINDOW_END", "default": "15", "type": int, "help": "Where to end averaging the fir model bins. Only affects the significance and contrast images."},
|
||||
#{"name": "N_JOBS", "default": 1, "type": int, "help": "Number of jobs for GLM processing."},
|
||||
{"name": "NOISE_MODEL", "default": "ar1", "type": str, "help": "Number of jobs for GLM processing."},
|
||||
{"name": "BINS", "default": 0, "type": int, "help": "Number of jobs for GLM processing."},
|
||||
{"name": "N_JOBS", "default": 1, "type": int, "help": "Number of jobs for GLM processing."},
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -202,6 +215,8 @@ SECTIONS = [
|
||||
{
|
||||
"title": "Other",
|
||||
"params": [
|
||||
{"name": "TIME_WINDOW_START", "default": "0", "type": int, "help": "Where to start averaging the fir model bins. Only affects the significance and contrast images."},
|
||||
{"name": "TIME_WINDOW_END", "default": "15", "type": int, "help": "Where to end averaging the fir model bins. Only affects the significance and contrast images."},
|
||||
{"name": "MAX_WORKERS", "default": 4, "type": int, "help": "Number of files to be processed at once. Lowering this value may help on underpowered systems."},
|
||||
]
|
||||
},
|
||||
@@ -485,6 +500,7 @@ class UserGuideWindow(QWidget):
|
||||
label = QLabel("Progress Bar Stages:", self)
|
||||
label2 = QLabel("Stage 1: Load the snirf file\n"
|
||||
"Stage 2: Check the optode positions\n"
|
||||
"Stage 12: Get Short/Long Channels\n"
|
||||
"Stage 3: Scalp Coupling Index\n"
|
||||
"Stage 4: Signal to Noise Ratio\n"
|
||||
"Stage 5: Peak Spectral Power\n"
|
||||
@@ -494,7 +510,6 @@ class UserGuideWindow(QWidget):
|
||||
"Stage 9: Temporal Derivative Distribution Repair\n"
|
||||
"Stage 10: Beer Lambert Law\n"
|
||||
"Stage 11: Heart Rate Filtering\n"
|
||||
"Stage 12: Get Short/Long Channels\n"
|
||||
"Stage 13: Calculate Events from Annotations\n"
|
||||
"Stage 14: Epoch Calculations\n"
|
||||
"Stage 15: Design Matrix\n"
|
||||
@@ -1358,7 +1373,12 @@ class ParamSection(QWidget):
|
||||
widget.setValidator(QDoubleValidator())
|
||||
widget.setText(str(param["default"]))
|
||||
elif param["type"] == list:
|
||||
widget = self._create_multiselect_dropdown(None)
|
||||
if param.get("exclusive", True):
|
||||
widget = QComboBox()
|
||||
widget.addItems(param.get("options", []))
|
||||
widget.setCurrentText(str(param.get("default", "<None Selected>")))
|
||||
else:
|
||||
widget = self._create_multiselect_dropdown(None)
|
||||
else:
|
||||
widget = QLineEdit()
|
||||
widget.setText(str(param["default"]))
|
||||
@@ -1466,7 +1486,10 @@ class ParamSection(QWidget):
|
||||
if expected_type == bool:
|
||||
values[name] = widget.currentText() == "True"
|
||||
elif expected_type == list:
|
||||
values[name] = [x.strip() for x in widget.lineEdit().text().split(",") if x.strip()]
|
||||
if isinstance(widget, FullClickComboBox):
|
||||
values[name] = [x.strip() for x in widget.lineEdit().text().split(",") if x.strip()]
|
||||
elif isinstance(widget, QComboBox):
|
||||
values[name] = widget.currentText()
|
||||
else:
|
||||
raw_text = widget.text()
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user