fix for xlsx and upgrade dependencies
This commit is contained in:
@@ -4,6 +4,8 @@
|
||||
- The BLAZES option will assign events that are exported directly from the software [BLAZES](https://git.research.dezeeuw.ca/tyler/blazes)
|
||||
- Moved the updating logic to a seperate file for better reusability and generalization
|
||||
- Fixed 'Toggle Status Bar' having no effect on the visibility of the status bar
|
||||
- Fixed a bug when updating optode positions that would prevent .txt files from being selected. Fixes [Issue 54](https://git.research.dezeeuw.ca/tyler/flares/issues/54)
|
||||
- Fixed a missing dependency in the standalone application when attempting to use an .xlsx file to update optode positions
|
||||
|
||||
|
||||
# Version 1.2.1
|
||||
|
||||
72
main.py
72
main.py
@@ -190,8 +190,7 @@ SECTIONS = [
|
||||
{"name": "DRIFT_MODEL", "default": ["cosine"], "type": list, "options": ["cosine", "polynomial"], "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, "depends_on": "HRF_MODEL", "depends_value": "fir", "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": "FIR_DELAYS", "default": 15, "type": range, "depends_on": "HRF_MODEL", "depends_value": "fir", "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": "SHORT_CHANNEL_REGRESSION", "default": True, "type": bool, "depends_on": "SHORT_CHANNEL", "help": "Should short channel regression be used to create the design matrix? This will use the 'signal' from the short channel and regress it out of all other channels."},
|
||||
@@ -543,7 +542,7 @@ class UpdateOptodesWindow(QWidget):
|
||||
self.line_edit_file_a.setText(file_path)
|
||||
|
||||
def browse_file_b(self):
|
||||
file_path, _ = QFileDialog.getOpenFileName(self, "Select File", "", "Text Files (*.txt), Excel Files (*.xlsx)")
|
||||
file_path, _ = QFileDialog.getOpenFileName(self, "Select File", "", "Text Files (*.txt);;Excel Files (*.xlsx)")
|
||||
if file_path:
|
||||
self.line_edit_file_b.setText(file_path)
|
||||
|
||||
@@ -1730,26 +1729,31 @@ class ParamSection(QWidget):
|
||||
h_layout.addWidget(label)
|
||||
h_layout.setStretch(1, 3) # Set the stretch factor for label (40%)
|
||||
|
||||
default_val = param["default"]
|
||||
|
||||
# Create input widget based on type
|
||||
if param["type"] == bool:
|
||||
widget = QComboBox()
|
||||
widget.addItems(["True", "False"])
|
||||
widget.setCurrentText(str(param["default"]))
|
||||
widget.setCurrentText(str(default_val))
|
||||
widget.currentTextChanged.connect(lambda val, p=param["name"]: self.check_if_changed(p, val))
|
||||
widget.currentTextChanged.connect(self.notify_global_update)
|
||||
elif param["type"] == int:
|
||||
widget = QLineEdit()
|
||||
widget.setValidator(QIntValidator())
|
||||
widget.setText(str(param["default"]))
|
||||
widget.setText(str(default_val))
|
||||
widget.textChanged.connect(lambda val, p=param["name"]: self.check_if_changed(p, val))
|
||||
elif param["type"] == float:
|
||||
widget = QLineEdit()
|
||||
widget.setValidator(QDoubleValidator())
|
||||
widget.setText(str(param["default"]))
|
||||
widget.setText(str(default_val))
|
||||
widget.textChanged.connect(lambda val, p=param["name"]: self.check_if_changed(p, val))
|
||||
elif param["type"] == list:
|
||||
if param.get("exclusive", True):
|
||||
widget = QComboBox()
|
||||
widget.addItems(param.get("options", []))
|
||||
widget.setCurrentText(str(param.get("default", "<None Selected>")))
|
||||
widget.setCurrentText(str(default_val))
|
||||
widget.currentTextChanged.connect(lambda val, p=param["name"]: self.check_if_changed(p, val))
|
||||
widget.currentTextChanged.connect(self.notify_global_update)
|
||||
else:
|
||||
widget = self._create_multiselect_dropdown(None)
|
||||
@@ -1757,16 +1761,16 @@ class ParamSection(QWidget):
|
||||
widget = QSpinBox()
|
||||
widget.setRange(0, 999) # Set a sensible maximum
|
||||
# If default is "None" or range(15), handle it gracefully:
|
||||
default_val = param["default"]
|
||||
if isinstance(default_val, range):
|
||||
widget.setValue(default_val.stop)
|
||||
elif str(default_val).isdigit():
|
||||
widget.setValue(int(default_val))
|
||||
else:
|
||||
widget.setValue(15) # Default fallback
|
||||
widget.valueChanged.connect(lambda val, p=param["name"]: self.check_if_changed(p, val))
|
||||
else:
|
||||
widget = QLineEdit()
|
||||
widget.setText(str(param["default"]))
|
||||
widget.setText(str(default_val))
|
||||
|
||||
if "depends_on" in param:
|
||||
self.dependencies.append({
|
||||
@@ -1783,12 +1787,62 @@ class ParamSection(QWidget):
|
||||
layout.addLayout(h_layout)
|
||||
self.widgets[param["name"]] = {
|
||||
"widget": widget,
|
||||
"label": label,
|
||||
"default": default_val,
|
||||
"type": param["type"],
|
||||
"h_layout": h_layout
|
||||
}
|
||||
|
||||
self.update_dependencies()
|
||||
|
||||
def check_if_changed(self, param_name, current_value):
|
||||
"""Toggles bold font on the label if the value differs from default."""
|
||||
info = self.widgets.get(param_name)
|
||||
if not info:
|
||||
return
|
||||
|
||||
label = info["label"]
|
||||
default = info["default"]
|
||||
|
||||
is_changed = False
|
||||
|
||||
if info["type"] == list:
|
||||
# If it's an exclusive ComboBox, current_value is a string.
|
||||
# We wrap it in a list to compare it to the default list.
|
||||
if isinstance(current_value, str):
|
||||
normalized_current = [current_value]
|
||||
else:
|
||||
normalized_current = current_value # Already a list from multi-select
|
||||
|
||||
# Ensure default is a list for comparison
|
||||
normalized_default = default if isinstance(default, list) else [default]
|
||||
|
||||
# Use sorted to ensure order doesn't matter
|
||||
is_changed = sorted(normalized_current) != sorted(normalized_default)
|
||||
|
||||
# 2. Handle Range (SpinBox)
|
||||
elif info["type"] == range:
|
||||
ref = default.stop if isinstance(default, range) else default
|
||||
try:
|
||||
is_changed = int(current_value) != int(ref)
|
||||
except (ValueError, TypeError):
|
||||
is_changed = True
|
||||
|
||||
# 3. Standard Comparison (bool, int, float, str)
|
||||
else:
|
||||
is_changed = str(current_value) != str(default)
|
||||
|
||||
# Update Font
|
||||
font = label.font()
|
||||
font.setBold(is_changed)
|
||||
label.setFont(font)
|
||||
|
||||
# Optional: Change color to make it even more obvious
|
||||
if is_changed:
|
||||
label.setStyleSheet("color: #3498db; font-weight: bold;") # Nice Blue
|
||||
else:
|
||||
label.setStyleSheet("color: none; font-weight: normal;")
|
||||
|
||||
def notify_global_update(self):
|
||||
"""
|
||||
Since dependencies can cross sections, we need to tell
|
||||
|
||||
BIN
requirements.txt
BIN
requirements.txt
Binary file not shown.
Reference in New Issue
Block a user