Skip to content
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
80 changes: 65 additions & 15 deletions ulc_mm_package/QtGUI/form_gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

import sys


from PyQt5.QtWidgets import (
QApplication,
QDialog,
Expand All @@ -19,10 +18,11 @@
QDesktopWidget,
)
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtCore import pyqtSignal, QDate, QTime

from ulc_mm_package.scope_constants import EXPERIMENT_METADATA_KEYS
from ulc_mm_package.image_processing.processing_constants import TARGET_FLOWRATE
from PyQt5.QtWidgets import QDateEdit, QTimeEdit
from ulc_mm_package.QtGUI.gui_constants import (
ICON_PATH,
SITE_LIST,
Expand All @@ -48,6 +48,15 @@ def closeEvent(self, event):
else:
event.accept()

def _validate_temperature(self):
text = self.sample_storage_temp.text()
if not text.endswith(("C", "F", "c", "f")) or not text[:-1].isdigit():
self.sample_storage_temp.setStyleSheet("border: 1px solid red;")
self.start_btn.setEnabled(False)
else:
self.sample_storage_temp.setStyleSheet("")
self.start_btn.setEnabled(True)

def _load_ui(self):
self.setWindowTitle("Experiment form")

Expand Down Expand Up @@ -78,15 +87,35 @@ def _load_ui(self):
# Labels
self.operator_lbl = QLabel("Operator ID")
self.participant_lbl = QLabel("Non-identifying participant ID")
self.sample_collection_date_lbl = QLabel("Sample collection date")
self.sample_collection_time_lbl = QLabel("Sample collection time")
self.sample_storage_temp_lbl = QLabel("Sample storage temperature (°C or °F)")
self.flowcell_lbl = QLabel("Flowcell ID")
self.notes_lbl = QLabel("Other notes")
self.site_lbl = QLabel("Site")
self.sample_lbl = QLabel("Sample type")
self.msg_lbl = QLabel("Please fill out experiment data.")

# Text boxes
self.operator_val = QLineEdit()
self.participant_val = QLineEdit()

# Sample collection date
self.sample_collection_date = QDateEdit(QDate.currentDate())
self.sample_collection_date.setCalendarPopup(True)
self.sample_collection_date.setDisplayFormat("yyyy-MMM-dd")

# Sample collection time
self.sample_collection_time = QTimeEdit(QTime.currentTime())
self.sample_collection_time.setDisplayFormat("hh:mm AP")
self.sample_collection_time.setCalendarPopup(True)

# Sample storage temperature
self.sample_storage_temp = QLineEdit()
self.sample_storage_temp.setPlaceholderText(
"Enter temperature (e.g. 25C or 77F)"
)
self.sample_storage_temp.textChanged.connect(self._validate_temperature)

self.flowcell_val = QLineEdit()
self.notes_val = QPlainTextEdit()

Expand All @@ -107,31 +136,51 @@ def _load_ui(self):
# Place widgets
self.main_layout.addWidget(self.operator_lbl, 0, 0)
self.main_layout.addWidget(self.participant_lbl, 1, 0)
self.main_layout.addWidget(self.flowcell_lbl, 2, 0)
self.main_layout.addWidget(self.site_lbl, 4, 0)
self.main_layout.addWidget(self.sample_lbl, 5, 0)
self.main_layout.addWidget(self.notes_lbl, 6, 0)
self.main_layout.addWidget(self.exit_btn, 8, 0)
self.main_layout.addWidget(self.sample_collection_date_lbl, 2, 0)
self.main_layout.addWidget(self.sample_collection_time_lbl, 3, 0)
self.main_layout.addWidget(self.sample_storage_temp_lbl, 4, 0)
self.main_layout.addWidget(self.flowcell_lbl, 5, 0)
self.main_layout.addWidget(self.site_lbl, 6, 0)
self.main_layout.addWidget(self.sample_lbl, 7, 0)
self.main_layout.addWidget(self.notes_lbl, 8, 0)
self.main_layout.addWidget(self.exit_btn, 9, 0)

self.main_layout.addWidget(self.operator_val, 0, 1)
self.main_layout.addWidget(self.participant_val, 1, 1)
self.main_layout.addWidget(self.flowcell_val, 2, 1)
self.main_layout.addWidget(self.site_val, 4, 1)
self.main_layout.addWidget(self.sample_val, 5, 1)
self.main_layout.addWidget(self.notes_val, 6, 1)
self.main_layout.addWidget(self.start_btn, 8, 1)

self.main_layout.addWidget(self.msg_lbl, 7, 0, 1, 2)
self.main_layout.addWidget(self.sample_collection_date, 2, 1)
self.main_layout.addWidget(self.sample_collection_time, 3, 1)
self.main_layout.addWidget(self.sample_storage_temp, 4, 1)
self.main_layout.addWidget(self.flowcell_val, 5, 1)
self.main_layout.addWidget(self.site_val, 6, 1)
self.main_layout.addWidget(self.sample_val, 7, 1)
self.main_layout.addWidget(self.notes_val, 8, 1)
self.main_layout.addWidget(self.start_btn, 9, 1)

# Set the focus order
self.operator_val.setFocus()
self.start_btn.setDefault(True)

def get_form_input(self) -> dict:
# Determine the sample age from the current time and the sample collection time
current_date = QDate.currentDate()
current_time = QTime.currentTime()

sample_date = self.sample_collection_date.date()
sample_time = self.sample_collection_time.time()

date_diff_in_hours = sample_date.daysTo(current_date) * 24
time_diff_in_hours = sample_time.secsTo(current_time) / 3600

sample_age_hours = round(date_diff_in_hours + time_diff_in_hours, 2)

form_metadata = {
"operator_id": self.operator_val.text(),
"participant_id": self.participant_val.text(),
"flowcell_id": self.flowcell_val.text(),
"sample_collection_date": self.sample_collection_date.text(),
"sample_collection_time": self.sample_collection_time.text(),
"sample_age_hours": sample_age_hours,
"sample_storage_temp": self.sample_storage_temp.text(),
"target_flowrate": (
TARGET_FLOWRATE.name.capitalize(),
TARGET_FLOWRATE.value,
Expand All @@ -156,6 +205,7 @@ def reset_parameters(self) -> None:
if __name__ == "__main__":
app = QApplication(sys.argv)
gui = FormGUI()
gui.exit_btn.clicked.connect(gui.close)

print(gui.get_form_input())

Expand Down
50 changes: 34 additions & 16 deletions ulc_mm_package/QtGUI/scope_op.py
Original file line number Diff line number Diff line change
Expand Up @@ -869,7 +869,7 @@ def run_experiment(self, img, timestamp) -> None:
return

# Record timestamp before running routines
self.img_metadata["timestamp"] = timestamp
self.img_metadata["timestamp"] = round(timestamp, 2)
self.img_metadata["im_counter"] = f"{self.frame_count:0{self.digits}d}"

t0 = perf_counter()
Expand Down Expand Up @@ -1002,33 +1002,51 @@ def run_experiment(self, img, timestamp) -> None:
self.img_metadata["motor_pos"] = self.mscope.motor.getCurrentPosition()
try:
pressure, status = self.mscope.pneumatic_module.getPressure()
(
self.img_metadata["pressure_hpa"],
self.img_metadata["pressure_status_flag"],
) = (pressure, status)
self.img_metadata["pressure_hpa"] = (
round(pressure, 2) if pressure is not None else pressure
)
except PressureSensorStaleValue as e:
## TODO???
self.logger.error(f"Stale pressure sensor value - {e}")

self.img_metadata["led_pwm_val"] = self.mscope.led.pwm_duty_cycle
self.img_metadata[
"syringe_pos"
] = self.mscope.pneumatic_module.getCurrentDutyCycle()
self.img_metadata["flowrate"] = self.flowrate
self.img_metadata["focus_error"] = raw_focus_err
self.img_metadata["filtered_focus_error"] = filtered_focus_err
self.img_metadata["led_pwm_val"] = round(self.mscope.led.pwm_duty_cycle, 4)
self.img_metadata["syringe_pos"] = round(
self.mscope.pneumatic_module.getCurrentDutyCycle(), 4
)
self.img_metadata["flowrate"] = (
round(self.flowrate, 4) if self.flowrate is not None else self.flowrate
)
self.img_metadata["focus_error"] = (
round(raw_focus_err, 4) if raw_focus_err is not None else raw_focus_err
)
self.img_metadata["filtered_focus_error"] = (
round(filtered_focus_err, 4)
if filtered_focus_err is not None
else filtered_focus_err
)
self.img_metadata["focus_adjustment"] = focus_adjustment
self.img_metadata["classic_sharpness_ratio"] = sharpness_ratio_rel_peak
self.img_metadata["mean_pixel_val"] = curr_mean_pixel_val
self.img_metadata["classic_sharpness_ratio"] = (
round(sharpness_ratio_rel_peak, 4)
if sharpness_ratio_rel_peak is not None
else sharpness_ratio_rel_peak
)
self.img_metadata["mean_pixel_val"] = (
round(curr_mean_pixel_val, 4)
if curr_mean_pixel_val is not None
else curr_mean_pixel_val
)

if self.frame_count % TH_PERIOD_NUM == 0:
try:
(
temperature,
humidity,
) = self.mscope.ht_sensor.get_temp_and_humidity()
self.img_metadata["humidity"] = humidity
self.img_metadata["temperature"] = temperature
self.img_metadata["humidity"] = round(humidity, 4)
self.img_metadata["temperature"] = round(temperature, 2)
self.img_metadata["camera_temperature"] = round(
self.mscope.camera._getTemperature(), 2
)
except Exception as e:
# some error has occurred, but the TH sensor isn't critical, so just warn
# and move on
Expand Down
5 changes: 4 additions & 1 deletion ulc_mm_package/scope_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,10 @@ def IMG_HEIGHT(self) -> int:
EXPERIMENT_METADATA_KEYS = [
"operator_id",
"participant_id",
"sample_collection_date",
"sample_collection_time",
"sample_age_hours",
"sample_storage_temp",
"flowcell_id",
"target_flowrate",
"site",
Expand All @@ -166,7 +170,6 @@ def IMG_HEIGHT(self) -> int:
"timestamp",
"motor_pos",
"pressure_hpa",
"pressure_status_flag",
"led_pwm_val",
"syringe_pos",
"flowrate",
Expand Down