accusleepy 0.3.1__tar.gz → 0.4.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {accusleepy-0.3.1 → accusleepy-0.4.3}/PKG-INFO +13 -1
- {accusleepy-0.3.1 → accusleepy-0.4.3}/README.md +11 -0
- accusleepy-0.4.3/accusleepy/gui/images/primary_window.png +0 -0
- accusleepy-0.4.3/accusleepy/gui/images/viewer_window.png +0 -0
- accusleepy-0.4.3/accusleepy/gui/images/viewer_window_annotated.png +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.3}/accusleepy/gui/main.py +39 -12
- {accusleepy-0.3.1 → accusleepy-0.4.3}/accusleepy/gui/manual_scoring.py +12 -15
- {accusleepy-0.3.1 → accusleepy-0.4.3}/accusleepy/gui/primary_window.py +81 -20
- {accusleepy-0.3.1 → accusleepy-0.4.3}/accusleepy/gui/primary_window.ui +162 -118
- {accusleepy-0.3.1 → accusleepy-0.4.3}/accusleepy/gui/text/config_guide.txt +2 -1
- accusleepy-0.3.1/accusleepy/gui/text/main_guide_text.py → accusleepy-0.4.3/accusleepy/gui/text/main_guide.md +81 -68
- accusleepy-0.4.3/accusleepy/gui/text/manual_scoring_guide.md +23 -0
- {accusleepy-0.3.1 → accusleepy-0.4.3}/pyproject.toml +2 -1
- accusleepy-0.3.1/accusleepy/gui/text/manual_scoring_guide.txt +0 -28
- {accusleepy-0.3.1 → accusleepy-0.4.3}/accusleepy/__init__.py +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.3}/accusleepy/__main__.py +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.3}/accusleepy/brain_state_set.py +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.3}/accusleepy/classification.py +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.3}/accusleepy/config.json +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.3}/accusleepy/constants.py +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.3}/accusleepy/fileio.py +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.3}/accusleepy/gui/__init__.py +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.3}/accusleepy/gui/icons/brightness_down.png +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.3}/accusleepy/gui/icons/brightness_up.png +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.3}/accusleepy/gui/icons/double_down_arrow.png +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.3}/accusleepy/gui/icons/double_up_arrow.png +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.3}/accusleepy/gui/icons/down_arrow.png +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.3}/accusleepy/gui/icons/home.png +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.3}/accusleepy/gui/icons/question.png +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.3}/accusleepy/gui/icons/save.png +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.3}/accusleepy/gui/icons/up_arrow.png +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.3}/accusleepy/gui/icons/zoom_in.png +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.3}/accusleepy/gui/icons/zoom_out.png +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.3}/accusleepy/gui/mplwidget.py +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.3}/accusleepy/gui/resources.qrc +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.3}/accusleepy/gui/resources_rc.py +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.3}/accusleepy/gui/viewer_window.py +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.3}/accusleepy/gui/viewer_window.ui +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.3}/accusleepy/models.py +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.3}/accusleepy/multitaper.py +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.3}/accusleepy/signal_processing.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: accusleepy
|
|
3
|
-
Version: 0.3
|
|
3
|
+
Version: 0.4.3
|
|
4
4
|
Summary: Python implementation of AccuSleep
|
|
5
5
|
License: GPL-3.0-only
|
|
6
6
|
Author: Zeke Barger
|
|
@@ -20,6 +20,7 @@ Requires-Dist: pillow (>=11.1.0,<12.0.0)
|
|
|
20
20
|
Requires-Dist: pre-commit (>=4.2.0,<5.0.0)
|
|
21
21
|
Requires-Dist: pyside6 (>=6.7.1,<6.8.0)
|
|
22
22
|
Requires-Dist: scipy (>=1.15.2,<2.0.0)
|
|
23
|
+
Requires-Dist: toml (>=0.10.2,<0.11.0)
|
|
23
24
|
Requires-Dist: torch (>=2.6.0,<3.0.0)
|
|
24
25
|
Requires-Dist: torchvision (>=0.21.0,<0.22.0)
|
|
25
26
|
Requires-Dist: tqdm (>=4.67.1,<5.0.0)
|
|
@@ -56,6 +57,17 @@ etc.) using python >=3.10,<3.13
|
|
|
56
57
|
|
|
57
58
|
`python -m accusleepy` will open the primary interface.
|
|
58
59
|
|
|
60
|
+
[Guide to the primary interface](accusleepy/gui/text/main_guide.md)
|
|
61
|
+
|
|
62
|
+
[Guide to the manual scoring interface](accusleepy/gui/text/manual_scoring_guide.md)
|
|
63
|
+
|
|
64
|
+
## Screenshots
|
|
65
|
+
Primary interface
|
|
66
|
+

|
|
67
|
+
|
|
68
|
+
Manual scoring interface
|
|
69
|
+

|
|
70
|
+
|
|
59
71
|
## Acknowledgements
|
|
60
72
|
|
|
61
73
|
We would like to thank [Franz Weber](https://www.med.upenn.edu/weberlab/) for creating an
|
|
@@ -29,6 +29,17 @@ etc.) using python >=3.10,<3.13
|
|
|
29
29
|
|
|
30
30
|
`python -m accusleepy` will open the primary interface.
|
|
31
31
|
|
|
32
|
+
[Guide to the primary interface](accusleepy/gui/text/main_guide.md)
|
|
33
|
+
|
|
34
|
+
[Guide to the manual scoring interface](accusleepy/gui/text/manual_scoring_guide.md)
|
|
35
|
+
|
|
36
|
+
## Screenshots
|
|
37
|
+
Primary interface
|
|
38
|
+

|
|
39
|
+
|
|
40
|
+
Manual scoring interface
|
|
41
|
+

|
|
42
|
+
|
|
32
43
|
## Acknowledgements
|
|
33
44
|
|
|
34
45
|
We would like to thank [Franz Weber](https://www.med.upenn.edu/weberlab/) for creating an
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -5,6 +5,7 @@ import datetime
|
|
|
5
5
|
import os
|
|
6
6
|
import shutil
|
|
7
7
|
import sys
|
|
8
|
+
import toml
|
|
8
9
|
from dataclasses import dataclass
|
|
9
10
|
from functools import partial
|
|
10
11
|
|
|
@@ -40,7 +41,6 @@ from accusleepy.fileio import (
|
|
|
40
41
|
save_model,
|
|
41
42
|
save_recording_list,
|
|
42
43
|
)
|
|
43
|
-
from accusleepy.gui.text.main_guide_text import MAIN_GUIDE_TEXT
|
|
44
44
|
from accusleepy.gui.manual_scoring import ManualScoringWindow
|
|
45
45
|
from accusleepy.gui.primary_window import Ui_PrimaryWindow
|
|
46
46
|
from accusleepy.signal_processing import (
|
|
@@ -54,7 +54,8 @@ from accusleepy.signal_processing import (
|
|
|
54
54
|
MESSAGE_BOX_MAX_DEPTH = 50
|
|
55
55
|
LABEL_LENGTH_ERROR = "label file length does not match recording length"
|
|
56
56
|
# relative path to config guide txt file
|
|
57
|
-
CONFIG_GUIDE_FILE = "text/config_guide.txt"
|
|
57
|
+
CONFIG_GUIDE_FILE = os.path.normpath(r"text/config_guide.txt")
|
|
58
|
+
MAIN_GUIDE_FILE = os.path.normpath(r"text/main_guide.md")
|
|
58
59
|
|
|
59
60
|
|
|
60
61
|
@dataclass
|
|
@@ -116,6 +117,20 @@ class AccuSleepWindow(QtWidgets.QMainWindow):
|
|
|
116
117
|
# messages to display
|
|
117
118
|
self.messages = []
|
|
118
119
|
|
|
120
|
+
# display current version
|
|
121
|
+
version = ""
|
|
122
|
+
toml_file = os.path.join(
|
|
123
|
+
os.path.dirname(
|
|
124
|
+
os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
125
|
+
),
|
|
126
|
+
"pyproject.toml",
|
|
127
|
+
)
|
|
128
|
+
if os.path.isfile(toml_file):
|
|
129
|
+
toml_data = toml.load(toml_file)
|
|
130
|
+
if "project" in toml_data and "version" in toml_data["project"]:
|
|
131
|
+
version = toml_data["project"]["version"]
|
|
132
|
+
self.ui.version_label.setText(f"v{version}")
|
|
133
|
+
|
|
119
134
|
# user input: keyboard shortcuts
|
|
120
135
|
keypress_quit = QtGui.QShortcut(
|
|
121
136
|
QtGui.QKeySequence(
|
|
@@ -179,6 +194,7 @@ class AccuSleepWindow(QtWidgets.QMainWindow):
|
|
|
179
194
|
)
|
|
180
195
|
if not filename:
|
|
181
196
|
return
|
|
197
|
+
filename = os.path.normpath(filename)
|
|
182
198
|
save_recording_list(filename=filename, recordings=self.recordings)
|
|
183
199
|
self.show_message(f"Saved list of recordings to {filename}")
|
|
184
200
|
|
|
@@ -193,6 +209,7 @@ class AccuSleepWindow(QtWidgets.QMainWindow):
|
|
|
193
209
|
if file_dialog.exec():
|
|
194
210
|
selected_files = file_dialog.selectedFiles()
|
|
195
211
|
filename = selected_files[0]
|
|
212
|
+
filename = os.path.normpath(filename)
|
|
196
213
|
else:
|
|
197
214
|
return
|
|
198
215
|
|
|
@@ -229,7 +246,7 @@ class AccuSleepWindow(QtWidgets.QMainWindow):
|
|
|
229
246
|
if event.type() == QtCore.QEvent.Drop:
|
|
230
247
|
urls = event.mimeData().urls()
|
|
231
248
|
if len(urls) == 1:
|
|
232
|
-
filename = urls[0].toLocalFile()
|
|
249
|
+
filename = os.path.normpath(urls[0].toLocalFile())
|
|
233
250
|
|
|
234
251
|
if filename is None:
|
|
235
252
|
return super().eventFilter(obj, event)
|
|
@@ -289,6 +306,8 @@ class AccuSleepWindow(QtWidgets.QMainWindow):
|
|
|
289
306
|
)
|
|
290
307
|
if not model_filename:
|
|
291
308
|
self.show_message("Model training canceled, no filename given")
|
|
309
|
+
return
|
|
310
|
+
model_filename = os.path.normpath(model_filename)
|
|
292
311
|
|
|
293
312
|
# create (probably temporary) image folder
|
|
294
313
|
temp_image_dir = os.path.join(
|
|
@@ -363,6 +382,7 @@ class AccuSleepWindow(QtWidgets.QMainWindow):
|
|
|
363
382
|
self, "Select directory for training images"
|
|
364
383
|
)
|
|
365
384
|
if training_folder_parent:
|
|
385
|
+
training_folder_parent = os.path.normpath(training_folder_parent)
|
|
366
386
|
self.training_image_dir = training_folder_parent
|
|
367
387
|
self.ui.image_folder_label.setText(training_folder_parent)
|
|
368
388
|
|
|
@@ -560,6 +580,7 @@ class AccuSleepWindow(QtWidgets.QMainWindow):
|
|
|
560
580
|
if file_dialog.exec():
|
|
561
581
|
selected_files = file_dialog.selectedFiles()
|
|
562
582
|
filename = selected_files[0]
|
|
583
|
+
filename = os.path.normpath(filename)
|
|
563
584
|
else:
|
|
564
585
|
return
|
|
565
586
|
|
|
@@ -707,6 +728,7 @@ class AccuSleepWindow(QtWidgets.QMainWindow):
|
|
|
707
728
|
)
|
|
708
729
|
if not filename:
|
|
709
730
|
return
|
|
731
|
+
filename = os.path.normpath(filename)
|
|
710
732
|
|
|
711
733
|
create_calibration_file(
|
|
712
734
|
filename=filename,
|
|
@@ -871,6 +893,7 @@ class AccuSleepWindow(QtWidgets.QMainWindow):
|
|
|
871
893
|
filter="*" + LABEL_FILE_TYPE,
|
|
872
894
|
)
|
|
873
895
|
if filename:
|
|
896
|
+
filename = os.path.normpath(filename)
|
|
874
897
|
self.recordings[self.recording_index].label_file = filename
|
|
875
898
|
self.ui.label_file_label.setText(filename)
|
|
876
899
|
|
|
@@ -885,6 +908,7 @@ class AccuSleepWindow(QtWidgets.QMainWindow):
|
|
|
885
908
|
if file_dialog.exec():
|
|
886
909
|
selected_files = file_dialog.selectedFiles()
|
|
887
910
|
filename = selected_files[0]
|
|
911
|
+
filename = os.path.normpath(filename)
|
|
888
912
|
self.recordings[self.recording_index].label_file = filename
|
|
889
913
|
self.ui.label_file_label.setText(filename)
|
|
890
914
|
|
|
@@ -899,6 +923,7 @@ class AccuSleepWindow(QtWidgets.QMainWindow):
|
|
|
899
923
|
if file_dialog.exec():
|
|
900
924
|
selected_files = file_dialog.selectedFiles()
|
|
901
925
|
filename = selected_files[0]
|
|
926
|
+
filename = os.path.normpath(filename)
|
|
902
927
|
self.recordings[self.recording_index].calibration_file = filename
|
|
903
928
|
self.ui.calibration_file_label.setText(filename)
|
|
904
929
|
|
|
@@ -913,6 +938,7 @@ class AccuSleepWindow(QtWidgets.QMainWindow):
|
|
|
913
938
|
if file_dialog.exec():
|
|
914
939
|
selected_files = file_dialog.selectedFiles()
|
|
915
940
|
filename = selected_files[0]
|
|
941
|
+
filename = os.path.normpath(filename)
|
|
916
942
|
self.recordings[self.recording_index].recording_file = filename
|
|
917
943
|
self.ui.recording_file_label.setText(filename)
|
|
918
944
|
|
|
@@ -1005,15 +1031,15 @@ class AccuSleepWindow(QtWidgets.QMainWindow):
|
|
|
1005
1031
|
|
|
1006
1032
|
def show_user_manual(self) -> None:
|
|
1007
1033
|
"""Show a popup window with the user manual"""
|
|
1008
|
-
label_widget = QtWidgets.QLabel()
|
|
1009
|
-
label_widget.setText(MAIN_GUIDE_TEXT)
|
|
1010
|
-
scroll_area = QtWidgets.QScrollArea()
|
|
1011
|
-
scroll_area.setStyleSheet("background-color: white;")
|
|
1012
|
-
scroll_area.setWidget(label_widget)
|
|
1013
|
-
grid = QtWidgets.QGridLayout()
|
|
1014
|
-
grid.addWidget(scroll_area)
|
|
1015
1034
|
self.popup = QtWidgets.QWidget()
|
|
1016
|
-
self.
|
|
1035
|
+
self.popup_vlayout = QtWidgets.QVBoxLayout(self.popup)
|
|
1036
|
+
self.guide_textbox = QtWidgets.QTextBrowser(self.popup)
|
|
1037
|
+
self.popup_vlayout.addWidget(self.guide_textbox)
|
|
1038
|
+
|
|
1039
|
+
url = QtCore.QUrl.fromLocalFile(MAIN_GUIDE_FILE)
|
|
1040
|
+
self.guide_textbox.setSource(url)
|
|
1041
|
+
self.guide_textbox.setOpenLinks(False)
|
|
1042
|
+
|
|
1017
1043
|
self.popup.setGeometry(QtCore.QRect(100, 100, 600, 600))
|
|
1018
1044
|
self.popup.show()
|
|
1019
1045
|
|
|
@@ -1252,7 +1278,7 @@ def check_label_validity(
|
|
|
1252
1278
|
sampling_rate: int | float,
|
|
1253
1279
|
epoch_length: int | float,
|
|
1254
1280
|
brain_state_set: BrainStateSet,
|
|
1255
|
-
) -> str:
|
|
1281
|
+
) -> str | None:
|
|
1256
1282
|
"""Check whether a set of brain state labels is valid
|
|
1257
1283
|
|
|
1258
1284
|
This returns an error message if a problem is found with the
|
|
@@ -1352,6 +1378,7 @@ def check_config_consistency(
|
|
|
1352
1378
|
output.append(
|
|
1353
1379
|
(
|
|
1354
1380
|
"Warning: the epoch length used when training this model "
|
|
1381
|
+
f"({model_epoch_length} seconds) "
|
|
1355
1382
|
"does not match the current epoch length setting."
|
|
1356
1383
|
)
|
|
1357
1384
|
)
|
|
@@ -27,7 +27,7 @@ LABEL_CMAP = np.concatenate(
|
|
|
27
27
|
[np.array([[0, 0, 0, 0]]), plt.colormaps["tab10"](range(10))], axis=0
|
|
28
28
|
)
|
|
29
29
|
# relative path to user manual text file
|
|
30
|
-
USER_MANUAL_FILE = "text/manual_scoring_guide.
|
|
30
|
+
USER_MANUAL_FILE = os.path.normpath(r"text/manual_scoring_guide.md")
|
|
31
31
|
|
|
32
32
|
# constants used by callback functions
|
|
33
33
|
# label formats
|
|
@@ -61,7 +61,7 @@ UNDEFINED_STATE = "undefined"
|
|
|
61
61
|
# before starting to scroll again - must be in (0, 0.5)
|
|
62
62
|
SCROLL_BOUNDARY = 0.35
|
|
63
63
|
# max number of sequential undo actions allowed
|
|
64
|
-
UNDO_LIMIT =
|
|
64
|
+
UNDO_LIMIT = 1000
|
|
65
65
|
|
|
66
66
|
|
|
67
67
|
@dataclass
|
|
@@ -501,21 +501,18 @@ class ManualScoringWindow(QtWidgets.QDialog):
|
|
|
501
501
|
|
|
502
502
|
def show_user_manual(self) -> None:
|
|
503
503
|
"""Show a popup window with the user manual"""
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
504
|
+
self.popup = QtWidgets.QWidget()
|
|
505
|
+
self.popup_vlayout = QtWidgets.QVBoxLayout(self.popup)
|
|
506
|
+
self.guide_textbox = QtWidgets.QTextBrowser(self.popup)
|
|
507
|
+
self.popup_vlayout.addWidget(self.guide_textbox)
|
|
508
|
+
|
|
509
|
+
url = QtCore.QUrl.fromLocalFile(
|
|
510
|
+
os.path.join(os.path.dirname(os.path.abspath(__file__)), USER_MANUAL_FILE)
|
|
507
511
|
)
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
label_widget = QtWidgets.QLabel()
|
|
511
|
-
label_widget.setText(user_manual_text)
|
|
512
|
-
label_widget.setStyleSheet("background-color: white;")
|
|
512
|
+
self.guide_textbox.setSource(url)
|
|
513
|
+
self.guide_textbox.setOpenLinks(False)
|
|
513
514
|
|
|
514
|
-
self.popup
|
|
515
|
-
grid = QtWidgets.QGridLayout()
|
|
516
|
-
grid.addWidget(label_widget)
|
|
517
|
-
self.popup.setLayout(grid)
|
|
518
|
-
self.popup.setGeometry(QtCore.QRect(50, 100, 350, 400))
|
|
515
|
+
self.popup.setGeometry(QtCore.QRect(100, 100, 830, 600))
|
|
519
516
|
self.popup.show()
|
|
520
517
|
|
|
521
518
|
def jump_to_next_state(self, direction: str, target: str) -> None:
|
|
@@ -8,20 +8,8 @@
|
|
|
8
8
|
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
|
9
9
|
################################################################################
|
|
10
10
|
|
|
11
|
-
from PySide6.QtCore import
|
|
12
|
-
|
|
13
|
-
QMetaObject,
|
|
14
|
-
QRect,
|
|
15
|
-
QSize,
|
|
16
|
-
Qt,
|
|
17
|
-
)
|
|
18
|
-
from PySide6.QtGui import (
|
|
19
|
-
QBrush,
|
|
20
|
-
QColor,
|
|
21
|
-
QFont,
|
|
22
|
-
QIcon,
|
|
23
|
-
QPalette,
|
|
24
|
-
)
|
|
11
|
+
from PySide6.QtCore import QCoreApplication, QMetaObject, QRect, QSize, Qt
|
|
12
|
+
from PySide6.QtGui import QBrush, QColor, QFont, QIcon, QPalette
|
|
25
13
|
from PySide6.QtWidgets import (
|
|
26
14
|
QCheckBox,
|
|
27
15
|
QDoubleSpinBox,
|
|
@@ -202,6 +190,8 @@ class Ui_PrimaryWindow(object):
|
|
|
202
190
|
|
|
203
191
|
self.left_scoring_vlayout.addWidget(self.recordinglistgroupbox)
|
|
204
192
|
|
|
193
|
+
self.logo_and_version_layout = QVBoxLayout()
|
|
194
|
+
self.logo_and_version_layout.setObjectName("logo_and_version_layout")
|
|
205
195
|
self.logo_layout = QVBoxLayout()
|
|
206
196
|
self.logo_layout.setObjectName("logo_layout")
|
|
207
197
|
self.frame = QFrame(self.scoring_tab)
|
|
@@ -252,7 +242,24 @@ class Ui_PrimaryWindow(object):
|
|
|
252
242
|
|
|
253
243
|
self.logo_layout.addWidget(self.frame)
|
|
254
244
|
|
|
255
|
-
self.
|
|
245
|
+
self.logo_and_version_layout.addLayout(self.logo_layout)
|
|
246
|
+
|
|
247
|
+
self.version_label = QLabel(self.scoring_tab)
|
|
248
|
+
self.version_label.setObjectName("version_label")
|
|
249
|
+
sizePolicy3 = QSizePolicy(
|
|
250
|
+
QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Fixed
|
|
251
|
+
)
|
|
252
|
+
sizePolicy3.setHorizontalStretch(0)
|
|
253
|
+
sizePolicy3.setVerticalStretch(0)
|
|
254
|
+
sizePolicy3.setHeightForWidth(
|
|
255
|
+
self.version_label.sizePolicy().hasHeightForWidth()
|
|
256
|
+
)
|
|
257
|
+
self.version_label.setSizePolicy(sizePolicy3)
|
|
258
|
+
self.version_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
|
259
|
+
|
|
260
|
+
self.logo_and_version_layout.addWidget(self.version_label)
|
|
261
|
+
|
|
262
|
+
self.left_scoring_vlayout.addLayout(self.logo_and_version_layout)
|
|
256
263
|
|
|
257
264
|
self.user_manual_layout = QHBoxLayout()
|
|
258
265
|
self.user_manual_layout.setObjectName("user_manual_layout")
|
|
@@ -340,11 +347,6 @@ class Ui_PrimaryWindow(object):
|
|
|
340
347
|
self.horizontalLayout.setObjectName("horizontalLayout")
|
|
341
348
|
self.recording_file_button = QPushButton(self.selected_recording_groupbox)
|
|
342
349
|
self.recording_file_button.setObjectName("recording_file_button")
|
|
343
|
-
sizePolicy3 = QSizePolicy(
|
|
344
|
-
QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Fixed
|
|
345
|
-
)
|
|
346
|
-
sizePolicy3.setHorizontalStretch(0)
|
|
347
|
-
sizePolicy3.setVerticalStretch(0)
|
|
348
350
|
sizePolicy3.setHeightForWidth(
|
|
349
351
|
self.recording_file_button.sizePolicy().hasHeightForWidth()
|
|
350
352
|
)
|
|
@@ -2217,9 +2219,23 @@ class Ui_PrimaryWindow(object):
|
|
|
2217
2219
|
self.remove_button.setText(
|
|
2218
2220
|
QCoreApplication.translate("PrimaryWindow", "remove", None)
|
|
2219
2221
|
)
|
|
2222
|
+
# if QT_CONFIG(tooltip)
|
|
2223
|
+
self.export_button.setToolTip(
|
|
2224
|
+
QCoreApplication.translate(
|
|
2225
|
+
"PrimaryWindow", "Export recording list to file", None
|
|
2226
|
+
)
|
|
2227
|
+
)
|
|
2228
|
+
# endif // QT_CONFIG(tooltip)
|
|
2220
2229
|
self.export_button.setText(
|
|
2221
2230
|
QCoreApplication.translate("PrimaryWindow", "export", None)
|
|
2222
2231
|
)
|
|
2232
|
+
# if QT_CONFIG(tooltip)
|
|
2233
|
+
self.import_button.setToolTip(
|
|
2234
|
+
QCoreApplication.translate(
|
|
2235
|
+
"PrimaryWindow", "Import recording list from file", None
|
|
2236
|
+
)
|
|
2237
|
+
)
|
|
2238
|
+
# endif // QT_CONFIG(tooltip)
|
|
2223
2239
|
self.import_button.setText(
|
|
2224
2240
|
QCoreApplication.translate("PrimaryWindow", "import", None)
|
|
2225
2241
|
)
|
|
@@ -2232,6 +2248,9 @@ class Ui_PrimaryWindow(object):
|
|
|
2232
2248
|
self.accusleepy1.setText(
|
|
2233
2249
|
QCoreApplication.translate("PrimaryWindow", "AccuSleePy", None)
|
|
2234
2250
|
)
|
|
2251
|
+
self.version_label.setText(
|
|
2252
|
+
QCoreApplication.translate("PrimaryWindow", "TextLabel", None)
|
|
2253
|
+
)
|
|
2235
2254
|
# if QT_CONFIG(tooltip)
|
|
2236
2255
|
self.user_manual_button.setToolTip(
|
|
2237
2256
|
QCoreApplication.translate("PrimaryWindow", "User manual", None)
|
|
@@ -2246,6 +2265,13 @@ class Ui_PrimaryWindow(object):
|
|
|
2246
2265
|
self.samplingratelabel.setText(
|
|
2247
2266
|
QCoreApplication.translate("PrimaryWindow", "Sampling rate (Hz):", None)
|
|
2248
2267
|
)
|
|
2268
|
+
# if QT_CONFIG(tooltip)
|
|
2269
|
+
self.recording_file_button.setToolTip(
|
|
2270
|
+
QCoreApplication.translate(
|
|
2271
|
+
"PrimaryWindow", "Select EEG+EMG recording", None
|
|
2272
|
+
)
|
|
2273
|
+
)
|
|
2274
|
+
# endif // QT_CONFIG(tooltip)
|
|
2249
2275
|
self.recording_file_button.setText(
|
|
2250
2276
|
QCoreApplication.translate("PrimaryWindow", "Select recording file", None)
|
|
2251
2277
|
)
|
|
@@ -2288,10 +2314,24 @@ class Ui_PrimaryWindow(object):
|
|
|
2288
2314
|
QCoreApplication.translate("PrimaryWindow", "Score manually", None)
|
|
2289
2315
|
)
|
|
2290
2316
|
self.manual_scoring_status.setText("")
|
|
2317
|
+
# if QT_CONFIG(tooltip)
|
|
2318
|
+
self.create_calibration_button.setToolTip(
|
|
2319
|
+
QCoreApplication.translate(
|
|
2320
|
+
"PrimaryWindow", "Create calibration file for this subject", None
|
|
2321
|
+
)
|
|
2322
|
+
)
|
|
2323
|
+
# endif // QT_CONFIG(tooltip)
|
|
2291
2324
|
self.create_calibration_button.setText(
|
|
2292
2325
|
QCoreApplication.translate("PrimaryWindow", "Create calibration file", None)
|
|
2293
2326
|
)
|
|
2294
2327
|
self.calibration_status.setText("")
|
|
2328
|
+
# if QT_CONFIG(tooltip)
|
|
2329
|
+
self.select_calibration_button.setToolTip(
|
|
2330
|
+
QCoreApplication.translate(
|
|
2331
|
+
"PrimaryWindow", "Load calibration file for this recording", None
|
|
2332
|
+
)
|
|
2333
|
+
)
|
|
2334
|
+
# endif // QT_CONFIG(tooltip)
|
|
2295
2335
|
self.select_calibration_button.setText(
|
|
2296
2336
|
QCoreApplication.translate("PrimaryWindow", "Select calibration file", None)
|
|
2297
2337
|
)
|
|
@@ -2319,6 +2359,13 @@ class Ui_PrimaryWindow(object):
|
|
|
2319
2359
|
"PrimaryWindow", "Minimum bout length (sec):", None
|
|
2320
2360
|
)
|
|
2321
2361
|
)
|
|
2362
|
+
# if QT_CONFIG(tooltip)
|
|
2363
|
+
self.load_model_button.setToolTip(
|
|
2364
|
+
QCoreApplication.translate(
|
|
2365
|
+
"PrimaryWindow", "Load a trained sleep scoring classifier", None
|
|
2366
|
+
)
|
|
2367
|
+
)
|
|
2368
|
+
# endif // QT_CONFIG(tooltip)
|
|
2322
2369
|
self.load_model_button.setText(
|
|
2323
2370
|
QCoreApplication.translate(
|
|
2324
2371
|
"PrimaryWindow", "Load classification model", None
|
|
@@ -2346,6 +2393,13 @@ class Ui_PrimaryWindow(object):
|
|
|
2346
2393
|
self.real_time_button.setText(
|
|
2347
2394
|
QCoreApplication.translate("PrimaryWindow", "Real-time", None)
|
|
2348
2395
|
)
|
|
2396
|
+
# if QT_CONFIG(tooltip)
|
|
2397
|
+
self.train_model_button.setToolTip(
|
|
2398
|
+
QCoreApplication.translate(
|
|
2399
|
+
"PrimaryWindow", "Begin training the classification model", None
|
|
2400
|
+
)
|
|
2401
|
+
)
|
|
2402
|
+
# endif // QT_CONFIG(tooltip)
|
|
2349
2403
|
self.train_model_button.setText(
|
|
2350
2404
|
QCoreApplication.translate(
|
|
2351
2405
|
"PrimaryWindow", "Train classification model", None
|
|
@@ -2422,6 +2476,13 @@ class Ui_PrimaryWindow(object):
|
|
|
2422
2476
|
self.label_17.setText(
|
|
2423
2477
|
QCoreApplication.translate("PrimaryWindow", "Default epoch length:", None)
|
|
2424
2478
|
)
|
|
2479
|
+
# if QT_CONFIG(tooltip)
|
|
2480
|
+
self.save_config_button.setToolTip(
|
|
2481
|
+
QCoreApplication.translate(
|
|
2482
|
+
"PrimaryWindow", "Save current configuration", None
|
|
2483
|
+
)
|
|
2484
|
+
)
|
|
2485
|
+
# endif // QT_CONFIG(tooltip)
|
|
2425
2486
|
self.save_config_button.setText(
|
|
2426
2487
|
QCoreApplication.translate("PrimaryWindow", "Save", None)
|
|
2427
2488
|
)
|
|
@@ -263,6 +263,9 @@
|
|
|
263
263
|
<verstretch>0</verstretch>
|
|
264
264
|
</sizepolicy>
|
|
265
265
|
</property>
|
|
266
|
+
<property name="toolTip">
|
|
267
|
+
<string>Export recording list to file</string>
|
|
268
|
+
</property>
|
|
266
269
|
<property name="text">
|
|
267
270
|
<string>export</string>
|
|
268
271
|
</property>
|
|
@@ -276,6 +279,9 @@
|
|
|
276
279
|
<verstretch>0</verstretch>
|
|
277
280
|
</sizepolicy>
|
|
278
281
|
</property>
|
|
282
|
+
<property name="toolTip">
|
|
283
|
+
<string>Import recording list from file</string>
|
|
284
|
+
</property>
|
|
279
285
|
<property name="text">
|
|
280
286
|
<string>import</string>
|
|
281
287
|
</property>
|
|
@@ -287,132 +293,152 @@
|
|
|
287
293
|
</widget>
|
|
288
294
|
</item>
|
|
289
295
|
<item>
|
|
290
|
-
<layout class="QVBoxLayout" name="
|
|
296
|
+
<layout class="QVBoxLayout" name="logo_and_version_layout">
|
|
297
|
+
<item>
|
|
298
|
+
<layout class="QVBoxLayout" name="logo_layout">
|
|
299
|
+
<item>
|
|
300
|
+
<widget class="QFrame" name="frame">
|
|
301
|
+
<property name="sizePolicy">
|
|
302
|
+
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
|
303
|
+
<horstretch>0</horstretch>
|
|
304
|
+
<verstretch>0</verstretch>
|
|
305
|
+
</sizepolicy>
|
|
306
|
+
</property>
|
|
307
|
+
<property name="minimumSize">
|
|
308
|
+
<size>
|
|
309
|
+
<width>180</width>
|
|
310
|
+
<height>80</height>
|
|
311
|
+
</size>
|
|
312
|
+
</property>
|
|
313
|
+
<property name="styleSheet">
|
|
314
|
+
<string notr="true">background-color: transparent;</string>
|
|
315
|
+
</property>
|
|
316
|
+
<property name="frameShape">
|
|
317
|
+
<enum>QFrame::Shape::NoFrame</enum>
|
|
318
|
+
</property>
|
|
319
|
+
<property name="frameShadow">
|
|
320
|
+
<enum>QFrame::Shadow::Raised</enum>
|
|
321
|
+
</property>
|
|
322
|
+
<widget class="QLabel" name="accusleepy2">
|
|
323
|
+
<property name="geometry">
|
|
324
|
+
<rect>
|
|
325
|
+
<x>11</x>
|
|
326
|
+
<y>15</y>
|
|
327
|
+
<width>160</width>
|
|
328
|
+
<height>50</height>
|
|
329
|
+
</rect>
|
|
330
|
+
</property>
|
|
331
|
+
<property name="sizePolicy">
|
|
332
|
+
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
|
333
|
+
<horstretch>0</horstretch>
|
|
334
|
+
<verstretch>0</verstretch>
|
|
335
|
+
</sizepolicy>
|
|
336
|
+
</property>
|
|
337
|
+
<property name="font">
|
|
338
|
+
<font>
|
|
339
|
+
<pointsize>21</pointsize>
|
|
340
|
+
<italic>true</italic>
|
|
341
|
+
<bold>true</bold>
|
|
342
|
+
</font>
|
|
343
|
+
</property>
|
|
344
|
+
<property name="styleSheet">
|
|
345
|
+
<string notr="true">background-color: transparent;
|
|
346
|
+
color: rgb(130, 169, 68);</string>
|
|
347
|
+
</property>
|
|
348
|
+
<property name="text">
|
|
349
|
+
<string>AccuSleePy</string>
|
|
350
|
+
</property>
|
|
351
|
+
<property name="alignment">
|
|
352
|
+
<set>Qt::AlignmentFlag::AlignCenter</set>
|
|
353
|
+
</property>
|
|
354
|
+
</widget>
|
|
355
|
+
<widget class="QLabel" name="accusleepy3">
|
|
356
|
+
<property name="geometry">
|
|
357
|
+
<rect>
|
|
358
|
+
<x>13</x>
|
|
359
|
+
<y>17</y>
|
|
360
|
+
<width>160</width>
|
|
361
|
+
<height>50</height>
|
|
362
|
+
</rect>
|
|
363
|
+
</property>
|
|
364
|
+
<property name="sizePolicy">
|
|
365
|
+
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
|
366
|
+
<horstretch>0</horstretch>
|
|
367
|
+
<verstretch>0</verstretch>
|
|
368
|
+
</sizepolicy>
|
|
369
|
+
</property>
|
|
370
|
+
<property name="font">
|
|
371
|
+
<font>
|
|
372
|
+
<pointsize>21</pointsize>
|
|
373
|
+
<italic>true</italic>
|
|
374
|
+
<bold>true</bold>
|
|
375
|
+
</font>
|
|
376
|
+
</property>
|
|
377
|
+
<property name="styleSheet">
|
|
378
|
+
<string notr="true">background-color: transparent;
|
|
379
|
+
color: rgb(46, 63, 150);</string>
|
|
380
|
+
</property>
|
|
381
|
+
<property name="text">
|
|
382
|
+
<string>AccuSleePy</string>
|
|
383
|
+
</property>
|
|
384
|
+
<property name="alignment">
|
|
385
|
+
<set>Qt::AlignmentFlag::AlignCenter</set>
|
|
386
|
+
</property>
|
|
387
|
+
</widget>
|
|
388
|
+
<widget class="QLabel" name="accusleepy1">
|
|
389
|
+
<property name="geometry">
|
|
390
|
+
<rect>
|
|
391
|
+
<x>9</x>
|
|
392
|
+
<y>13</y>
|
|
393
|
+
<width>160</width>
|
|
394
|
+
<height>50</height>
|
|
395
|
+
</rect>
|
|
396
|
+
</property>
|
|
397
|
+
<property name="sizePolicy">
|
|
398
|
+
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
|
399
|
+
<horstretch>0</horstretch>
|
|
400
|
+
<verstretch>0</verstretch>
|
|
401
|
+
</sizepolicy>
|
|
402
|
+
</property>
|
|
403
|
+
<property name="font">
|
|
404
|
+
<font>
|
|
405
|
+
<pointsize>21</pointsize>
|
|
406
|
+
<italic>true</italic>
|
|
407
|
+
<bold>true</bold>
|
|
408
|
+
</font>
|
|
409
|
+
</property>
|
|
410
|
+
<property name="styleSheet">
|
|
411
|
+
<string notr="true">background-color: transparent;
|
|
412
|
+
color: rgb(244, 195, 68);</string>
|
|
413
|
+
</property>
|
|
414
|
+
<property name="text">
|
|
415
|
+
<string>AccuSleePy</string>
|
|
416
|
+
</property>
|
|
417
|
+
<property name="alignment">
|
|
418
|
+
<set>Qt::AlignmentFlag::AlignCenter</set>
|
|
419
|
+
</property>
|
|
420
|
+
</widget>
|
|
421
|
+
<zorder>accusleepy1</zorder>
|
|
422
|
+
<zorder>accusleepy2</zorder>
|
|
423
|
+
<zorder>accusleepy3</zorder>
|
|
424
|
+
</widget>
|
|
425
|
+
</item>
|
|
426
|
+
</layout>
|
|
427
|
+
</item>
|
|
291
428
|
<item>
|
|
292
|
-
<widget class="
|
|
429
|
+
<widget class="QLabel" name="version_label">
|
|
293
430
|
<property name="sizePolicy">
|
|
294
|
-
<sizepolicy hsizetype="
|
|
431
|
+
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
|
295
432
|
<horstretch>0</horstretch>
|
|
296
433
|
<verstretch>0</verstretch>
|
|
297
434
|
</sizepolicy>
|
|
298
435
|
</property>
|
|
299
|
-
<property name="
|
|
300
|
-
<
|
|
301
|
-
<width>180</width>
|
|
302
|
-
<height>80</height>
|
|
303
|
-
</size>
|
|
304
|
-
</property>
|
|
305
|
-
<property name="styleSheet">
|
|
306
|
-
<string notr="true">background-color: transparent;</string>
|
|
307
|
-
</property>
|
|
308
|
-
<property name="frameShape">
|
|
309
|
-
<enum>QFrame::Shape::NoFrame</enum>
|
|
436
|
+
<property name="text">
|
|
437
|
+
<string>TextLabel</string>
|
|
310
438
|
</property>
|
|
311
|
-
<property name="
|
|
312
|
-
<
|
|
439
|
+
<property name="alignment">
|
|
440
|
+
<set>Qt::AlignmentFlag::AlignCenter</set>
|
|
313
441
|
</property>
|
|
314
|
-
<widget class="QLabel" name="accusleepy2">
|
|
315
|
-
<property name="geometry">
|
|
316
|
-
<rect>
|
|
317
|
-
<x>11</x>
|
|
318
|
-
<y>15</y>
|
|
319
|
-
<width>160</width>
|
|
320
|
-
<height>50</height>
|
|
321
|
-
</rect>
|
|
322
|
-
</property>
|
|
323
|
-
<property name="sizePolicy">
|
|
324
|
-
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
|
325
|
-
<horstretch>0</horstretch>
|
|
326
|
-
<verstretch>0</verstretch>
|
|
327
|
-
</sizepolicy>
|
|
328
|
-
</property>
|
|
329
|
-
<property name="font">
|
|
330
|
-
<font>
|
|
331
|
-
<pointsize>21</pointsize>
|
|
332
|
-
<italic>true</italic>
|
|
333
|
-
<bold>true</bold>
|
|
334
|
-
</font>
|
|
335
|
-
</property>
|
|
336
|
-
<property name="styleSheet">
|
|
337
|
-
<string notr="true">background-color: transparent;
|
|
338
|
-
color: rgb(130, 169, 68);</string>
|
|
339
|
-
</property>
|
|
340
|
-
<property name="text">
|
|
341
|
-
<string>AccuSleePy</string>
|
|
342
|
-
</property>
|
|
343
|
-
<property name="alignment">
|
|
344
|
-
<set>Qt::AlignmentFlag::AlignCenter</set>
|
|
345
|
-
</property>
|
|
346
|
-
</widget>
|
|
347
|
-
<widget class="QLabel" name="accusleepy3">
|
|
348
|
-
<property name="geometry">
|
|
349
|
-
<rect>
|
|
350
|
-
<x>13</x>
|
|
351
|
-
<y>17</y>
|
|
352
|
-
<width>160</width>
|
|
353
|
-
<height>50</height>
|
|
354
|
-
</rect>
|
|
355
|
-
</property>
|
|
356
|
-
<property name="sizePolicy">
|
|
357
|
-
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
|
358
|
-
<horstretch>0</horstretch>
|
|
359
|
-
<verstretch>0</verstretch>
|
|
360
|
-
</sizepolicy>
|
|
361
|
-
</property>
|
|
362
|
-
<property name="font">
|
|
363
|
-
<font>
|
|
364
|
-
<pointsize>21</pointsize>
|
|
365
|
-
<italic>true</italic>
|
|
366
|
-
<bold>true</bold>
|
|
367
|
-
</font>
|
|
368
|
-
</property>
|
|
369
|
-
<property name="styleSheet">
|
|
370
|
-
<string notr="true">background-color: transparent;
|
|
371
|
-
color: rgb(46, 63, 150);</string>
|
|
372
|
-
</property>
|
|
373
|
-
<property name="text">
|
|
374
|
-
<string>AccuSleePy</string>
|
|
375
|
-
</property>
|
|
376
|
-
<property name="alignment">
|
|
377
|
-
<set>Qt::AlignmentFlag::AlignCenter</set>
|
|
378
|
-
</property>
|
|
379
|
-
</widget>
|
|
380
|
-
<widget class="QLabel" name="accusleepy1">
|
|
381
|
-
<property name="geometry">
|
|
382
|
-
<rect>
|
|
383
|
-
<x>9</x>
|
|
384
|
-
<y>13</y>
|
|
385
|
-
<width>160</width>
|
|
386
|
-
<height>50</height>
|
|
387
|
-
</rect>
|
|
388
|
-
</property>
|
|
389
|
-
<property name="sizePolicy">
|
|
390
|
-
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
|
391
|
-
<horstretch>0</horstretch>
|
|
392
|
-
<verstretch>0</verstretch>
|
|
393
|
-
</sizepolicy>
|
|
394
|
-
</property>
|
|
395
|
-
<property name="font">
|
|
396
|
-
<font>
|
|
397
|
-
<pointsize>21</pointsize>
|
|
398
|
-
<italic>true</italic>
|
|
399
|
-
<bold>true</bold>
|
|
400
|
-
</font>
|
|
401
|
-
</property>
|
|
402
|
-
<property name="styleSheet">
|
|
403
|
-
<string notr="true">background-color: transparent;
|
|
404
|
-
color: rgb(244, 195, 68);</string>
|
|
405
|
-
</property>
|
|
406
|
-
<property name="text">
|
|
407
|
-
<string>AccuSleePy</string>
|
|
408
|
-
</property>
|
|
409
|
-
<property name="alignment">
|
|
410
|
-
<set>Qt::AlignmentFlag::AlignCenter</set>
|
|
411
|
-
</property>
|
|
412
|
-
</widget>
|
|
413
|
-
<zorder>accusleepy1</zorder>
|
|
414
|
-
<zorder>accusleepy2</zorder>
|
|
415
|
-
<zorder>accusleepy3</zorder>
|
|
416
442
|
</widget>
|
|
417
443
|
</item>
|
|
418
444
|
</layout>
|
|
@@ -562,6 +588,9 @@ color: rgb(244, 195, 68);</string>
|
|
|
562
588
|
<verstretch>0</verstretch>
|
|
563
589
|
</sizepolicy>
|
|
564
590
|
</property>
|
|
591
|
+
<property name="toolTip">
|
|
592
|
+
<string>Select EEG+EMG recording</string>
|
|
593
|
+
</property>
|
|
565
594
|
<property name="text">
|
|
566
595
|
<string>Select recording file</string>
|
|
567
596
|
</property>
|
|
@@ -753,6 +782,9 @@ color: rgb(244, 195, 68);</string>
|
|
|
753
782
|
<verstretch>0</verstretch>
|
|
754
783
|
</sizepolicy>
|
|
755
784
|
</property>
|
|
785
|
+
<property name="toolTip">
|
|
786
|
+
<string>Create calibration file for this subject</string>
|
|
787
|
+
</property>
|
|
756
788
|
<property name="text">
|
|
757
789
|
<string>Create calibration file</string>
|
|
758
790
|
</property>
|
|
@@ -813,6 +845,9 @@ color: rgb(244, 195, 68);</string>
|
|
|
813
845
|
<verstretch>0</verstretch>
|
|
814
846
|
</sizepolicy>
|
|
815
847
|
</property>
|
|
848
|
+
<property name="toolTip">
|
|
849
|
+
<string>Load calibration file for this recording</string>
|
|
850
|
+
</property>
|
|
816
851
|
<property name="text">
|
|
817
852
|
<string>Select calibration file</string>
|
|
818
853
|
</property>
|
|
@@ -1042,6 +1077,9 @@ color: rgb(244, 195, 68);</string>
|
|
|
1042
1077
|
<verstretch>0</verstretch>
|
|
1043
1078
|
</sizepolicy>
|
|
1044
1079
|
</property>
|
|
1080
|
+
<property name="toolTip">
|
|
1081
|
+
<string>Load a trained sleep scoring classifier</string>
|
|
1082
|
+
</property>
|
|
1045
1083
|
<property name="text">
|
|
1046
1084
|
<string>Load classification model</string>
|
|
1047
1085
|
</property>
|
|
@@ -1296,6 +1334,9 @@ color: rgb(244, 195, 68);</string>
|
|
|
1296
1334
|
<verstretch>0</verstretch>
|
|
1297
1335
|
</sizepolicy>
|
|
1298
1336
|
</property>
|
|
1337
|
+
<property name="toolTip">
|
|
1338
|
+
<string>Begin training the classification model</string>
|
|
1339
|
+
</property>
|
|
1299
1340
|
<property name="text">
|
|
1300
1341
|
<string>Train classification model</string>
|
|
1301
1342
|
</property>
|
|
@@ -3553,6 +3594,9 @@ color: rgb(244, 195, 68);</string>
|
|
|
3553
3594
|
<verstretch>0</verstretch>
|
|
3554
3595
|
</sizepolicy>
|
|
3555
3596
|
</property>
|
|
3597
|
+
<property name="toolTip">
|
|
3598
|
+
<string>Save current configuration</string>
|
|
3599
|
+
</property>
|
|
3556
3600
|
<property name="text">
|
|
3557
3601
|
<string>Save</string>
|
|
3558
3602
|
</property>
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
This is the current brain state configuration.
|
|
2
|
-
You can also choose the default epoch length.
|
|
3
2
|
If you make changes, click 'Save' to store them.
|
|
4
3
|
|
|
5
4
|
Each brain state has several attributes:
|
|
@@ -26,3 +25,5 @@ Important notes:
|
|
|
26
25
|
- Changing these settings can invalidate existing label files,
|
|
27
26
|
calibration files, and trained models!
|
|
28
27
|
- Reinstalling AccuSleePy will overwrite this configuration.
|
|
28
|
+
- You can also choose the default epoch length that is shown
|
|
29
|
+
when the primary interface starts up.
|
|
@@ -1,28 +1,31 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
2.
|
|
18
|
-
|
|
19
|
-
|
|
1
|
+
# Definitions
|
|
2
|
+
- Recording: a table containing one channel of electroencephalogram (EEG)
|
|
3
|
+
data and one channel of electromyogram (EMG) data collected at a
|
|
4
|
+
constant sampling rate.
|
|
5
|
+
- Epoch: the temporal resolution of brain state scoring. If, for example,
|
|
6
|
+
the epoch length is 5 seconds, then a brain state label will be
|
|
7
|
+
assigned to each 5-second segment of a recording.
|
|
8
|
+
- Bout: a contiguous set of epochs with the same brain state.
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# 1. Overview of the primary interface
|
|
12
|
+
|
|
13
|
+
The workflow for sleep scoring is as follows:
|
|
14
|
+
1. Set the epoch length
|
|
15
|
+
2. For each of your recordings:
|
|
16
|
+
1. create a new entry in the list of recordings
|
|
17
|
+
2. enter the sampling rate
|
|
18
|
+
3. select the recording file containing the EEG and EMG data
|
|
19
|
+
4. choose a filename for saving the brain state labels,
|
|
20
|
+
or select an existing label file
|
|
21
|
+
|
|
20
22
|
At this point, you can score the recordings manually.
|
|
23
|
+
|
|
21
24
|
3. For each recording, create a calibration file using a small amount
|
|
22
25
|
of labeled data, or choose a calibration file created using
|
|
23
26
|
another recording from the same subject and under the same recording
|
|
24
|
-
conditions
|
|
25
|
-
4.
|
|
27
|
+
conditions
|
|
28
|
+
4. Select a trained classification model file with the correct epoch length
|
|
26
29
|
5. Score all recordings automatically using the classifier
|
|
27
30
|
|
|
28
31
|
By default, there are three brain state options: REM, wake, and NREM.
|
|
@@ -33,49 +36,46 @@ classification model.
|
|
|
33
36
|
|
|
34
37
|
Use the "import" and "export" buttons to load or save a list of
|
|
35
38
|
recordings. This can be useful if you need to re-score a set of
|
|
36
|
-
recordings with a
|
|
37
|
-
the recordings that were used when training
|
|
39
|
+
recordings with a new model, or if you want to keep a record of
|
|
40
|
+
the recordings that were used when training a model.
|
|
38
41
|
|
|
39
|
-
|
|
40
|
-
Section 2: AccuSleePy file types
|
|
41
|
-
-----------------------------------------------------------------------
|
|
42
|
+
# 2. AccuSleePy file types
|
|
42
43
|
There are four types of files associated with AccuSleePy.
|
|
43
44
|
To select a file in the primary interface, you can either use the
|
|
44
45
|
associated button, or drag/drop the file into the empty box adjacent
|
|
45
46
|
to the button.
|
|
46
|
-
Recording file: a .
|
|
47
|
-
data and one column of EMG data.
|
|
48
|
-
|
|
49
|
-
Label file: a .csv file with one column titled
|
|
50
|
-
with entries that are either the undefined brain state,
|
|
47
|
+
- Recording file: a .parquet or .csv file containing one
|
|
48
|
+
column of EEG data and one column of EMG data.
|
|
49
|
+
The column names must be eeg and emg.
|
|
50
|
+
- Label file: a .csv file with one column titled brain_state
|
|
51
|
+
with entries that are either the undefined brain state (by default, this is -1)
|
|
51
52
|
or one of the digits in your brain state configuration.
|
|
52
53
|
By default, these are 1-3 where REM = 1, wake = 2, NREM = 3.
|
|
53
|
-
Calibration data file: required for
|
|
54
|
+
- Calibration data file: required for automated scoring. See Section 4
|
|
54
55
|
for details. These have .csv format.
|
|
55
|
-
Trained classification model: required for
|
|
56
|
+
- Trained classification model: required for automated scoring. See
|
|
56
57
|
Section 4 for details. These have .pth format.
|
|
57
58
|
|
|
58
|
-
|
|
59
|
-
Section 3: Manually assigning brain state labels
|
|
60
|
-
-----------------------------------------------------------------------
|
|
59
|
+
# 3. Manually assigning brain state labels
|
|
61
60
|
1. Select the recording you wish to modify from the recording list, or
|
|
62
61
|
add a new one.
|
|
63
|
-
2. Click the
|
|
62
|
+
2. Click the "Select recording file" button to set the location of the
|
|
64
63
|
EEG/EMG data, or drag/drop the recording file into the box next
|
|
65
64
|
to the button.
|
|
66
|
-
3. Click the
|
|
67
|
-
existing label file, or click the
|
|
65
|
+
3. Click the "Select" label file button (or drag/drop) to choose an
|
|
66
|
+
existing label file, or click the "create" label file button to
|
|
68
67
|
enter the filename for a new label file.
|
|
69
|
-
4. Click
|
|
70
|
-
brain state
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
68
|
+
4. Click "Score manually" to launch an interactive window for manual
|
|
69
|
+
brain state scoring. When you are finished, save your changes and
|
|
70
|
+
close the window.
|
|
71
|
+
|
|
72
|
+
The manual scoring interface has many useful keyboard shortcuts,
|
|
73
|
+
so please consult its user manual by clicking the question mark icon.
|
|
74
|
+
|
|
75
|
+
# 4. Automatically scoring recordings with a classification model
|
|
77
76
|
Automatic brain state scoring requires the inputs described in
|
|
78
|
-
Section 3, as well as calibration data files and a trained
|
|
77
|
+
Section 3, as well as calibration data files and a trained classification
|
|
78
|
+
model.
|
|
79
79
|
If you already have all of these files, proceed to Section 4C.
|
|
80
80
|
Models trained on the AccuSleep dataset are provided at
|
|
81
81
|
https://osf.io/py5eb under /python_format/models/ for epoch lengths of
|
|
@@ -84,14 +84,18 @@ they use several epochs of data before and after any given epoch when
|
|
|
84
84
|
scoring that epoch. (The other model type, called "real-time", only
|
|
85
85
|
uses data from the current epoch and several preceding epochs.)
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
## 4A. Creating calibration data files
|
|
88
|
+
|
|
89
|
+
In order to perform automated sleep scoring,
|
|
90
|
+
each recording must have a calibration file assigned to it.
|
|
89
91
|
This file lets AccuSleep transform features of the EEG and EMG data so
|
|
90
92
|
that they are in the same range as the classifier's training data.
|
|
91
93
|
You can use the same calibration file for multiple recordings, as long
|
|
92
94
|
as they come from the same subject and were collected under the same
|
|
93
95
|
recording conditions (i.e., the same recording equipment was used).
|
|
96
|
+
|
|
94
97
|
To create a calibration data file:
|
|
98
|
+
|
|
95
99
|
1. Ensure you have a file containing brain state labels. You can create
|
|
96
100
|
this file by following the steps in Section 3, or select an
|
|
97
101
|
existing label file.
|
|
@@ -99,16 +103,23 @@ To create a calibration data file:
|
|
|
99
103
|
stage (e.g., REM, wakefulness, and NREM). It is recommended to
|
|
100
104
|
label at least several minutes of each stage, and more labels can
|
|
101
105
|
improve classification accuracy.
|
|
102
|
-
3. Click
|
|
106
|
+
3. Click "Create calibration file".
|
|
103
107
|
4. Enter a filename for the calibration data file.
|
|
104
108
|
5. The calibration file will automatically be assigned to the currently
|
|
105
109
|
selected recording.
|
|
106
110
|
|
|
107
|
-
|
|
111
|
+
Note that epoch length can affect the calibration process. If you make
|
|
112
|
+
a calibration file for a subject using one epoch length, but want to
|
|
113
|
+
score another recording from the same subject with a different epoch
|
|
114
|
+
length, it's best to create a new calibration file.
|
|
115
|
+
|
|
116
|
+
## 4B. Training your own classification model
|
|
117
|
+
|
|
108
118
|
To train a new model on your own data:
|
|
119
|
+
|
|
109
120
|
1. Add your scored recordings to the recording list. Make sure the
|
|
110
121
|
sampling rate, recording file, and label file are set for each
|
|
111
|
-
recording.
|
|
122
|
+
recording. Calibration files are not required.
|
|
112
123
|
2. Click the "Model training" tab
|
|
113
124
|
3. Choose the number of epochs to consider when scoring each epoch.
|
|
114
125
|
This will be the "width" of the training images. For "default"
|
|
@@ -118,32 +129,34 @@ To train a new model on your own data:
|
|
|
118
129
|
deleted once training is complete. (It's generally best to
|
|
119
130
|
leave this box checked.)
|
|
120
131
|
5. Choose whether to create a "default" or "real-time"-type model.
|
|
121
|
-
Note that scoring recordings in the
|
|
122
|
-
model.
|
|
123
|
-
6.
|
|
132
|
+
Note that scoring recordings in the primary interface requires
|
|
133
|
+
a default-type model.
|
|
134
|
+
6. Click "Set training image directory" to select the location
|
|
135
|
+
where the images used to train the model will be saved. A
|
|
124
136
|
new directory with an automatically generated name will be
|
|
125
137
|
created inside the directory you choose.
|
|
126
|
-
7. Click
|
|
138
|
+
7. Click "Train classification model" and enter a
|
|
127
139
|
filename for the trained model. Training can take some time.
|
|
140
|
+
The console will display progress updates.
|
|
141
|
+
|
|
142
|
+
## 4C. Automatic scoring
|
|
143
|
+
|
|
144
|
+
Instructions for automatic scoring using this interface are below.
|
|
128
145
|
|
|
129
|
-
--- Section 4C: Automatic labeling ---
|
|
130
|
-
Instructions for automatic labeling using this GUI are below.
|
|
131
146
|
1. Set the epoch length for all recordings.
|
|
132
147
|
2. Select the recording file, label file, and calibration file to use
|
|
133
148
|
for each recording. See section 4A for instructions on creating
|
|
134
149
|
calibration files.
|
|
135
|
-
3. Click
|
|
150
|
+
3. Click "Load classification model" to load the trained classification
|
|
136
151
|
model. It's important that the epoch length used when training this
|
|
137
152
|
model is the same as the current epoch length.
|
|
138
153
|
4. If you wish to preserve any existing labels in the label file, and
|
|
139
154
|
only overwrite undefined epochs, check the box labeled
|
|
140
|
-
|
|
155
|
+
"Only overwrite undefined epochs".
|
|
141
156
|
5. Set the minimum bout length, in seconds. A typical value could be 5.
|
|
142
157
|
Following automatic labeling, any brain state bout shorter than this
|
|
143
|
-
duration will be reassigned to the surrounding
|
|
144
|
-
on either side of the bout
|
|
145
|
-
6. Click
|
|
146
|
-
recording list.
|
|
147
|
-
the
|
|
148
|
-
click 'Score manually' to visualize the results.
|
|
149
|
-
"""
|
|
158
|
+
duration will be reassigned to the surrounding state (if the states
|
|
159
|
+
on either side of the bout are the same).
|
|
160
|
+
6. Click "Score all automatically" to score all recordings in the
|
|
161
|
+
recording list. To inspect the results, select a recording
|
|
162
|
+
in the list and click "Score manually".
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Manual scoring interface
|
|
2
|
+
|
|
3
|
+
Keyboard shortcuts:
|
|
4
|
+
- Mouse click on the upper 3 plots: jump to epoch
|
|
5
|
+
- Ctrl + S: save labels to file
|
|
6
|
+
- Right / left arrow: move one epoch forward / backward in time
|
|
7
|
+
- Numbers 0-9: set current epoch to this brain state
|
|
8
|
+
- Backspace: set current epoch to the undefined state
|
|
9
|
+
- Ctrl + Z: undo last change to brain state labels
|
|
10
|
+
- Ctrl + Y: redo last change to brain state labels
|
|
11
|
+
- Shift + (number 0-9, or backspace):
|
|
12
|
+
After pressing this combination, click and drag on the upper plot of brain
|
|
13
|
+
state labels to set the selected epochs
|
|
14
|
+
to this brain state. Press Escape to cancel.
|
|
15
|
+
- Plus (+): zoom in (upper panel x-axis)
|
|
16
|
+
- Minus (-): zoom out (upper panel x-axis)
|
|
17
|
+
- Shift + right / left arrow: jump to the next / previous epoch with a different brain state
|
|
18
|
+
than the current epoch
|
|
19
|
+
- Spacebar: equivalent to shift + right arrow
|
|
20
|
+
- Ctrl + right / left arrow: jump to the next / preceding undefined epoch
|
|
21
|
+
- Ctrl + W: quit
|
|
22
|
+
|
|
23
|
+

|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "accusleepy"
|
|
3
|
-
version = "0.3
|
|
3
|
+
version = "0.4.3"
|
|
4
4
|
description = "Python implementation of AccuSleep"
|
|
5
5
|
authors = [
|
|
6
6
|
{name = "Zeke Barger",email = "zekebarger@gmail.com"}
|
|
@@ -21,6 +21,7 @@ dependencies = [
|
|
|
21
21
|
"fastparquet (>=2024.11.0,<2025.0.0)",
|
|
22
22
|
"pre-commit (>=4.2.0,<5.0.0)",
|
|
23
23
|
"tqdm (>=4.67.1,<5.0.0)",
|
|
24
|
+
"toml (>=0.10.2,<0.11.0)",
|
|
24
25
|
]
|
|
25
26
|
|
|
26
27
|
[tool.poetry.group.dev.dependencies]
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
The lower panel shows a zoomed-in subset of the epochs shown in the upper panel.
|
|
2
|
-
The red diamond in the upper panel and the red lines in the lower panel
|
|
3
|
-
mark the currently selected epoch.
|
|
4
|
-
The red horizontal line in the upper panel indicates the epochs shown in the lower panel.
|
|
5
|
-
Click a location on the upper panel to jump to that epoch.
|
|
6
|
-
The buttons next to the spectrogram control the zoom level and intensity.
|
|
7
|
-
The buttons next to the EEG and EMG plots control the zoom level and y-axis offset.
|
|
8
|
-
If "auto-scroll" is enabled, modifying the brain state of the current epoch
|
|
9
|
-
will automatically select the next epoch.
|
|
10
|
-
|
|
11
|
-
Keyboard shortcuts:
|
|
12
|
-
Ctrl + S: save labels to file
|
|
13
|
-
Right arrow: move one epoch forward in time
|
|
14
|
-
Left arrow: move one epoch backward in time
|
|
15
|
-
Numbers 0-9: set current epoch to this brain state
|
|
16
|
-
Backspace: set current epoch to undefined
|
|
17
|
-
Ctrl + Z: undo last change to brain state labels
|
|
18
|
-
Ctrl + Y: redo last change to brain state labels
|
|
19
|
-
Shift + (number 0-9, or backspace):
|
|
20
|
-
Click and drag on the upper plot of brain state labels to set the selected epochs
|
|
21
|
-
to the desired brain state. Press Esc to cancel.
|
|
22
|
-
+: zoom in (upper panel x-axis)
|
|
23
|
-
-: zoom out (upper panel x-axis)
|
|
24
|
-
Shift + right arrow, or space: jump to the next epoch of a different state
|
|
25
|
-
than the current epoch
|
|
26
|
-
Shift + left arrow: jump to the preceding epoch of a different state than the current epoch
|
|
27
|
-
Ctrl + right/left arrow: jump to the next/preceding undefined epoch
|
|
28
|
-
Ctrl + W: quit
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|