accusleepy 0.10.1__py3-none-any.whl → 0.11.0__py3-none-any.whl
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/constants.py +3 -2
- accusleepy/fileio.py +24 -9
- accusleepy/gui/images/primary_window.png +0 -0
- accusleepy/gui/main.py +13 -22
- accusleepy/gui/manual_scoring.py +3 -5
- accusleepy/gui/mplwidget.py +3 -5
- accusleepy/gui/primary_window.py +3 -5
- accusleepy/gui/primary_window.ui +0 -1
- accusleepy/gui/settings_widget.py +1 -1
- accusleepy/gui/viewer_window.py +2 -4
- accusleepy/multitaper.py +10 -6
- accusleepy/services.py +4 -4
- accusleepy/signal_processing.py +7 -4
- accusleepy/temperature_scaling.py +3 -3
- accusleepy/validation.py +17 -19
- {accusleepy-0.10.1.dist-info → accusleepy-0.11.0.dist-info}/METADATA +6 -3
- {accusleepy-0.10.1.dist-info → accusleepy-0.11.0.dist-info}/RECORD +19 -19
- /accusleepy/{config.json → default_config.json} +0 -0
- {accusleepy-0.10.1.dist-info → accusleepy-0.11.0.dist-info}/WHEEL +0 -0
accusleepy/constants.py
CHANGED
|
@@ -26,8 +26,9 @@ MIN_EPOCHS_PER_STATE = 3
|
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
# very unlikely you will want to change values from here onwards
|
|
29
|
-
# config file
|
|
30
|
-
|
|
29
|
+
# config file names
|
|
30
|
+
DEFAULT_CONFIG_FILE = "default_config.json"
|
|
31
|
+
USER_CONFIG_FILE = "config.json"
|
|
31
32
|
# number of times to include the EMG power in a training image
|
|
32
33
|
EMG_COPIES = 9
|
|
33
34
|
# minimum spectrogram window length, in seconds
|
accusleepy/fileio.py
CHANGED
|
@@ -2,14 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
4
|
import os
|
|
5
|
+
import shutil
|
|
5
6
|
from dataclasses import dataclass
|
|
6
|
-
from importlib.metadata import
|
|
7
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
8
|
+
from importlib.resources import files
|
|
7
9
|
|
|
8
10
|
import numpy as np
|
|
9
11
|
import pandas as pd
|
|
12
|
+
from platformdirs import user_config_dir
|
|
10
13
|
|
|
11
|
-
from accusleepy.brain_state_set import BRAIN_STATES_KEY, BrainState, BrainStateSet
|
|
12
14
|
import accusleepy.constants as c
|
|
15
|
+
from accusleepy.brain_state_set import BRAIN_STATES_KEY, BrainState, BrainStateSet
|
|
13
16
|
|
|
14
17
|
|
|
15
18
|
@dataclass
|
|
@@ -128,6 +131,16 @@ def save_labels(
|
|
|
128
131
|
pd.DataFrame({c.BRAIN_STATE_COL: labels}).to_csv(filename, index=False)
|
|
129
132
|
|
|
130
133
|
|
|
134
|
+
def _get_user_config_path() -> str:
|
|
135
|
+
"""Return the path to the user's config file in the platform config directory."""
|
|
136
|
+
return os.path.join(user_config_dir("accusleepy"), c.USER_CONFIG_FILE)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def _get_default_config_path() -> str:
|
|
140
|
+
"""Return the path to the bundled default config file."""
|
|
141
|
+
return str(files("accusleepy").joinpath(c.DEFAULT_CONFIG_FILE))
|
|
142
|
+
|
|
143
|
+
|
|
131
144
|
def load_config() -> AccuSleePyConfig:
|
|
132
145
|
"""Load configuration file with brain state options
|
|
133
146
|
|
|
@@ -143,9 +156,11 @@ def load_config() -> AccuSleePyConfig:
|
|
|
143
156
|
default autoscroll state for manual scoring,
|
|
144
157
|
setting to delete training images automatically
|
|
145
158
|
"""
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
159
|
+
user_config = _get_user_config_path()
|
|
160
|
+
if not os.path.exists(user_config):
|
|
161
|
+
os.makedirs(os.path.dirname(user_config), exist_ok=True)
|
|
162
|
+
shutil.copy2(_get_default_config_path(), user_config)
|
|
163
|
+
with open(user_config) as f:
|
|
149
164
|
data = json.load(f)
|
|
150
165
|
|
|
151
166
|
return AccuSleePyConfig(
|
|
@@ -229,9 +244,9 @@ def save_config(
|
|
|
229
244
|
output_dict.update({c.EPOCHS_TO_SHOW_KEY: epochs_to_show})
|
|
230
245
|
output_dict.update({c.AUTOSCROLL_KEY: autoscroll_state})
|
|
231
246
|
output_dict.update({c.DELETE_TRAINING_IMAGES_KEY: delete_training_images})
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
) as f:
|
|
247
|
+
user_config = _get_user_config_path()
|
|
248
|
+
os.makedirs(os.path.dirname(user_config), exist_ok=True)
|
|
249
|
+
with open(user_config, "w") as f:
|
|
235
250
|
json.dump(output_dict, f, indent=4)
|
|
236
251
|
f.write("\n")
|
|
237
252
|
|
|
@@ -242,7 +257,7 @@ def load_recording_list(filename: str) -> list[Recording]:
|
|
|
242
257
|
:param filename: filename of list of recordings
|
|
243
258
|
:return: list of recordings
|
|
244
259
|
"""
|
|
245
|
-
with open(filename
|
|
260
|
+
with open(filename) as f:
|
|
246
261
|
data = json.load(f)
|
|
247
262
|
recording_list = [Recording(**r) for r in data[c.RECORDING_LIST_NAME]]
|
|
248
263
|
for i, r in enumerate(recording_list):
|
|
Binary file
|
accusleepy/gui/main.py
CHANGED
|
@@ -41,10 +41,10 @@ from accusleepy.constants import (
|
|
|
41
41
|
UNDEFINED_LABEL,
|
|
42
42
|
)
|
|
43
43
|
from accusleepy.fileio import (
|
|
44
|
+
get_version,
|
|
44
45
|
load_config,
|
|
45
46
|
load_labels,
|
|
46
47
|
load_recording,
|
|
47
|
-
get_version,
|
|
48
48
|
)
|
|
49
49
|
from accusleepy.gui.dialogs import select_existing_file, select_save_location
|
|
50
50
|
from accusleepy.gui.manual_scoring import ManualScoringWindow
|
|
@@ -58,9 +58,8 @@ from accusleepy.services import (
|
|
|
58
58
|
create_calibration,
|
|
59
59
|
score_recording_list,
|
|
60
60
|
)
|
|
61
|
-
from accusleepy.validation import validate_and_correct_labels
|
|
62
61
|
from accusleepy.signal_processing import resample_and_standardize
|
|
63
|
-
from accusleepy.validation import check_config_consistency
|
|
62
|
+
from accusleepy.validation import check_config_consistency, validate_and_correct_labels
|
|
64
63
|
|
|
65
64
|
logger = logging.getLogger(__name__)
|
|
66
65
|
|
|
@@ -95,7 +94,7 @@ class AccuSleepWindow(QMainWindow):
|
|
|
95
94
|
"""AccuSleePy primary window"""
|
|
96
95
|
|
|
97
96
|
def __init__(self):
|
|
98
|
-
super(
|
|
97
|
+
super().__init__()
|
|
99
98
|
|
|
100
99
|
# initialize the UI
|
|
101
100
|
self.ui = Ui_PrimaryWindow()
|
|
@@ -363,22 +362,18 @@ class AccuSleepWindow(QMainWindow):
|
|
|
363
362
|
except Exception:
|
|
364
363
|
logger.exception("Failed to load %s", filename)
|
|
365
364
|
self.show_message(
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
"user manual for instructions on creating this file."
|
|
369
|
-
)
|
|
365
|
+
"ERROR: could not load classification model. Check "
|
|
366
|
+
"user manual for instructions on creating this file."
|
|
370
367
|
)
|
|
371
368
|
return
|
|
372
369
|
|
|
373
370
|
# make sure only "default" model type is loaded
|
|
374
371
|
if model_type != DEFAULT_MODEL_TYPE:
|
|
375
372
|
self.show_message(
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
"for an example of how to classify brain states in real time."
|
|
381
|
-
)
|
|
373
|
+
"ERROR: only 'default'-style models can be used. "
|
|
374
|
+
"'Real-time' models are not supported. "
|
|
375
|
+
"See classification.example_real_time_scoring_function.py "
|
|
376
|
+
"for an example of how to classify brain states in real time."
|
|
382
377
|
)
|
|
383
378
|
return
|
|
384
379
|
|
|
@@ -433,10 +428,8 @@ class AccuSleepWindow(QMainWindow):
|
|
|
433
428
|
)
|
|
434
429
|
status_widget.setText("could not load recording")
|
|
435
430
|
self.show_message(
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
"Check user manual for formatting instructions."
|
|
439
|
-
)
|
|
431
|
+
"ERROR: could not load recording. "
|
|
432
|
+
"Check user manual for formatting instructions."
|
|
440
433
|
)
|
|
441
434
|
return None, None, None, False
|
|
442
435
|
|
|
@@ -506,10 +499,8 @@ class AccuSleepWindow(QMainWindow):
|
|
|
506
499
|
logger.exception("Failed to load %s", label_file)
|
|
507
500
|
self.ui.manual_scoring_status.setText("could not load labels")
|
|
508
501
|
self.show_message(
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
"Check user manual for formatting instructions."
|
|
512
|
-
)
|
|
502
|
+
"ERROR: could not load labels. "
|
|
503
|
+
"Check user manual for formatting instructions."
|
|
513
504
|
)
|
|
514
505
|
return
|
|
515
506
|
else:
|
accusleepy/gui/manual_scoring.py
CHANGED
|
@@ -34,7 +34,7 @@ from PySide6.QtWidgets import (
|
|
|
34
34
|
)
|
|
35
35
|
|
|
36
36
|
from accusleepy.constants import UNDEFINED_LABEL
|
|
37
|
-
from accusleepy.fileio import load_config, save_labels
|
|
37
|
+
from accusleepy.fileio import EMGFilter, load_config, save_labels
|
|
38
38
|
from accusleepy.gui.mplwidget import resample_x_ticks
|
|
39
39
|
from accusleepy.gui.viewer_window import Ui_ViewerWindow
|
|
40
40
|
from accusleepy.signal_processing import create_spectrogram, get_emg_power
|
|
@@ -124,7 +124,7 @@ class ManualScoringWindow(QDialog):
|
|
|
124
124
|
:param epoch_length: epoch length, in seconds
|
|
125
125
|
:param emg_filter: EMG filter parameters
|
|
126
126
|
"""
|
|
127
|
-
super(
|
|
127
|
+
super().__init__()
|
|
128
128
|
|
|
129
129
|
self.label_file = label_file
|
|
130
130
|
self.eeg = eeg
|
|
@@ -915,9 +915,7 @@ class ManualScoringWindow(QDialog):
|
|
|
915
915
|
)
|
|
916
916
|
self.ui.lowerfigure.canvas.axes[1].set_xticklabels(
|
|
917
917
|
[
|
|
918
|
-
"{:02d}:{:02d}:{:05.2f}"
|
|
919
|
-
int(x // 3600), int(x // 60) % 60, (x % 60)
|
|
920
|
-
)
|
|
918
|
+
f"{int(x // 3600):02d}:{int(x // 60) % 60:02d}:{x % 60:05.2f}"
|
|
921
919
|
for x in x_ticks * self.epoch_length
|
|
922
920
|
]
|
|
923
921
|
)
|
accusleepy/gui/mplwidget.py
CHANGED
|
@@ -294,7 +294,7 @@ class MplWidget(QtWidgets.QWidget):
|
|
|
294
294
|
[1 - marker_dy, 1],
|
|
295
295
|
]
|
|
296
296
|
)
|
|
297
|
-
for x, y in zip(marker_x, marker_y):
|
|
297
|
+
for x, y in zip(marker_x, marker_y, strict=True):
|
|
298
298
|
self.top_marker.append(axes[0].plot(x, y - marker_y_offset_top, "r")[0])
|
|
299
299
|
|
|
300
300
|
# EMG subplot
|
|
@@ -318,7 +318,7 @@ class MplWidget(QtWidgets.QWidget):
|
|
|
318
318
|
linewidth=0.5,
|
|
319
319
|
)[0]
|
|
320
320
|
|
|
321
|
-
for x, y in zip(marker_x, marker_y):
|
|
321
|
+
for x, y in zip(marker_x, marker_y, strict=True):
|
|
322
322
|
self.bottom_marker.append(
|
|
323
323
|
axes[1].plot(x, -1 * (y - marker_y_offset_bottom), "r")[0]
|
|
324
324
|
)
|
|
@@ -356,9 +356,7 @@ class MplWidget(QtWidgets.QWidget):
|
|
|
356
356
|
|
|
357
357
|
def time_formatter(self, x, pos):
|
|
358
358
|
x = x * self.epoch_length
|
|
359
|
-
return "{:02d}:{:02d}:{:05.2f}"
|
|
360
|
-
int(x // 3600), int(x // 60) % 60, (x % 60)
|
|
361
|
-
)
|
|
359
|
+
return f"{int(x // 3600):02d}:{int(x // 60) % 60:02d}:{x % 60:05.2f}"
|
|
362
360
|
|
|
363
361
|
|
|
364
362
|
def resample_x_ticks(x_ticks: np.array) -> np.array:
|
accusleepy/gui/primary_window.py
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
|
|
3
1
|
################################################################################
|
|
4
2
|
## Form generated from reading UI file 'primary_window.ui'
|
|
5
3
|
##
|
|
6
|
-
## Created by: Qt User Interface Compiler version 6.
|
|
4
|
+
## Created by: Qt User Interface Compiler version 6.10.2
|
|
7
5
|
##
|
|
8
6
|
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
|
9
7
|
################################################################################
|
|
@@ -32,10 +30,11 @@ from PySide6.QtWidgets import (
|
|
|
32
30
|
QVBoxLayout,
|
|
33
31
|
QWidget,
|
|
34
32
|
)
|
|
33
|
+
|
|
35
34
|
import accusleepy.gui.resources_rc # noqa F401
|
|
36
35
|
|
|
37
36
|
|
|
38
|
-
class Ui_PrimaryWindow
|
|
37
|
+
class Ui_PrimaryWindow:
|
|
39
38
|
def setupUi(self, PrimaryWindow):
|
|
40
39
|
if not PrimaryWindow.objectName():
|
|
41
40
|
PrimaryWindow.setObjectName("PrimaryWindow")
|
|
@@ -3148,7 +3147,6 @@ class Ui_PrimaryWindow(object):
|
|
|
3148
3147
|
"This is the current set of brain states. Important notes:\n"
|
|
3149
3148
|
"- You must click 'Save settings' for changes to take effect.\n"
|
|
3150
3149
|
"- Changing these settings can prevent existing label files, calibration files, and trained models from working properly.\n"
|
|
3151
|
-
"- Reinstalling AccuSleePy will overwrite this configuration.\n"
|
|
3152
3150
|
"\n"
|
|
3153
3151
|
"Each brain state has several attributes:\n"
|
|
3154
3152
|
"- Digit: the indicator for this state in label files, and the keyboard shortcut for this state in manual scoring.\n"
|
accusleepy/gui/primary_window.ui
CHANGED
|
@@ -3701,7 +3701,6 @@ color: rgb(244, 195, 68);</string>
|
|
|
3701
3701
|
<string>This is the current set of brain states. Important notes:
|
|
3702
3702
|
- You must click 'Save settings' for changes to take effect.
|
|
3703
3703
|
- Changing these settings can prevent existing label files, calibration files, and trained models from working properly.
|
|
3704
|
-
- Reinstalling AccuSleePy will overwrite this configuration.
|
|
3705
3704
|
|
|
3706
3705
|
Each brain state has several attributes:
|
|
3707
3706
|
- Digit: the indicator for this state in label files, and the keyboard shortcut for this state in manual scoring.
|
|
@@ -197,7 +197,7 @@ class SettingsWidget(QObject):
|
|
|
197
197
|
# Brain states
|
|
198
198
|
states = {b.digit: b for b in self._brain_state_set.brain_states}
|
|
199
199
|
for digit in range(10):
|
|
200
|
-
if digit in states
|
|
200
|
+
if digit in states:
|
|
201
201
|
self._settings_widgets[digit].enabled_widget.setChecked(True)
|
|
202
202
|
self._settings_widgets[digit].name_widget.setText(states[digit].name)
|
|
203
203
|
self._settings_widgets[digit].is_scored_widget.setChecked(
|
accusleepy/gui/viewer_window.py
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
|
|
3
1
|
################################################################################
|
|
4
2
|
## Form generated from reading UI file 'viewer_window.ui'
|
|
5
3
|
##
|
|
@@ -23,11 +21,11 @@ from PySide6.QtWidgets import (
|
|
|
23
21
|
QVBoxLayout,
|
|
24
22
|
)
|
|
25
23
|
|
|
26
|
-
from accusleepy.gui.mplwidget import MplWidget
|
|
27
24
|
import accusleepy.gui.resources_rc # noqa F401
|
|
25
|
+
from accusleepy.gui.mplwidget import MplWidget
|
|
28
26
|
|
|
29
27
|
|
|
30
|
-
class Ui_ViewerWindow
|
|
28
|
+
class Ui_ViewerWindow:
|
|
31
29
|
def setupUi(self, ViewerWindow):
|
|
32
30
|
if not ViewerWindow.objectName():
|
|
33
31
|
ViewerWindow.setObjectName("ViewerWindow")
|
accusleepy/multitaper.py
CHANGED
|
@@ -331,7 +331,8 @@ def process_input(
|
|
|
331
331
|
+ str(frequency_range[0])
|
|
332
332
|
+ ", "
|
|
333
333
|
+ str(frequency_range[1])
|
|
334
|
-
+ "]"
|
|
334
|
+
+ "]",
|
|
335
|
+
stacklevel=2,
|
|
335
336
|
)
|
|
336
337
|
|
|
337
338
|
# Set number of tapers if none provided
|
|
@@ -342,7 +343,8 @@ def process_input(
|
|
|
342
343
|
if num_tapers != math.floor(2 * time_bandwidth) - 1:
|
|
343
344
|
warnings.warn(
|
|
344
345
|
"Number of tapers is optimal at floor(2*TW) - 1. consider using "
|
|
345
|
-
+ str(math.floor(2 * time_bandwidth) - 1)
|
|
346
|
+
+ str(math.floor(2 * time_bandwidth) - 1),
|
|
347
|
+
stacklevel=2,
|
|
346
348
|
)
|
|
347
349
|
|
|
348
350
|
# If no window params provided, set to defaults
|
|
@@ -355,7 +357,8 @@ def process_input(
|
|
|
355
357
|
warnings.warn(
|
|
356
358
|
"Window size is not divisible by sampling frequency. Adjusting window size to "
|
|
357
359
|
+ str(winsize_samples / fs)
|
|
358
|
-
+ " seconds"
|
|
360
|
+
+ " seconds",
|
|
361
|
+
stacklevel=2,
|
|
359
362
|
)
|
|
360
363
|
else:
|
|
361
364
|
winsize_samples = window_params[0] * fs
|
|
@@ -366,7 +369,8 @@ def process_input(
|
|
|
366
369
|
warnings.warn(
|
|
367
370
|
"Window step size is not divisible by sampling frequency. Adjusting window step size to "
|
|
368
371
|
+ str(winstep_samples / fs)
|
|
369
|
-
+ " seconds"
|
|
372
|
+
+ " seconds",
|
|
373
|
+
stacklevel=2,
|
|
370
374
|
)
|
|
371
375
|
else:
|
|
372
376
|
winstep_samples = window_params[1] * fs
|
|
@@ -508,7 +512,7 @@ def nanpow2db(y):
|
|
|
508
512
|
ydB (float or np array): inputs converted to dB with 0s and negatives resulting in nans
|
|
509
513
|
"""
|
|
510
514
|
|
|
511
|
-
if isinstance(y, int
|
|
515
|
+
if isinstance(y, int | float):
|
|
512
516
|
if y == 0:
|
|
513
517
|
return np.nan
|
|
514
518
|
else:
|
|
@@ -581,7 +585,7 @@ def calc_mts_segment(
|
|
|
581
585
|
spower_iter = np.mean(spower[:, 0:2], 1)
|
|
582
586
|
spower_iter = spower_iter[:, np.newaxis]
|
|
583
587
|
a = (1 - dpss_eigen) * tpower
|
|
584
|
-
for
|
|
588
|
+
for _i in range(3): # 3 iterations only
|
|
585
589
|
# Calc the MSE weights
|
|
586
590
|
b = np.dot(spower_iter, np.ones((1, num_tapers))) / (
|
|
587
591
|
(np.dot(spower_iter, np.transpose(dpss_eigen)))
|
accusleepy/services.py
CHANGED
|
@@ -8,8 +8,8 @@ import datetime
|
|
|
8
8
|
import logging
|
|
9
9
|
import os
|
|
10
10
|
import shutil
|
|
11
|
+
from collections.abc import Callable
|
|
11
12
|
from dataclasses import dataclass, field
|
|
12
|
-
from typing import Callable
|
|
13
13
|
|
|
14
14
|
import numpy as np
|
|
15
15
|
import pandas as pd
|
|
@@ -21,9 +21,9 @@ from accusleepy.constants import (
|
|
|
21
21
|
CALIBRATION_ANNOTATION_FILENAME,
|
|
22
22
|
DEFAULT_MODEL_TYPE,
|
|
23
23
|
MIN_EPOCHS_PER_STATE,
|
|
24
|
-
UNDEFINED_LABEL,
|
|
25
24
|
MIXTURE_MEAN_COL,
|
|
26
25
|
MIXTURE_SD_COL,
|
|
26
|
+
UNDEFINED_LABEL,
|
|
27
27
|
)
|
|
28
28
|
from accusleepy.fileio import (
|
|
29
29
|
EMGFilter,
|
|
@@ -36,10 +36,10 @@ from accusleepy.fileio import (
|
|
|
36
36
|
)
|
|
37
37
|
from accusleepy.models import SSANN
|
|
38
38
|
from accusleepy.signal_processing import (
|
|
39
|
-
create_training_images,
|
|
40
|
-
resample_and_standardize,
|
|
41
39
|
create_eeg_emg_image,
|
|
40
|
+
create_training_images,
|
|
42
41
|
get_mixture_values,
|
|
42
|
+
resample_and_standardize,
|
|
43
43
|
)
|
|
44
44
|
from accusleepy.validation import check_label_validity
|
|
45
45
|
|
accusleepy/signal_processing.py
CHANGED
|
@@ -21,10 +21,10 @@ from accusleepy.constants import (
|
|
|
21
21
|
LABEL_COL,
|
|
22
22
|
MIN_EPOCHS_PER_STATE,
|
|
23
23
|
MIN_WINDOW_LEN,
|
|
24
|
-
UPPER_FREQ,
|
|
25
24
|
SPECTROGRAM_UPPER_FREQ,
|
|
25
|
+
UPPER_FREQ,
|
|
26
26
|
)
|
|
27
|
-
from accusleepy.fileio import Recording, load_labels, load_recording
|
|
27
|
+
from accusleepy.fileio import EMGFilter, Recording, load_labels, load_recording
|
|
28
28
|
from accusleepy.multitaper import spectrogram
|
|
29
29
|
|
|
30
30
|
# note: scipy is lazily imported
|
|
@@ -151,7 +151,7 @@ def create_spectrogram(
|
|
|
151
151
|
# pad the EEG signal so that the first spectrogram window is centered
|
|
152
152
|
# on the first epoch
|
|
153
153
|
# it's possible there's some jank here, if this isn't close to an integer
|
|
154
|
-
pad_length = round(
|
|
154
|
+
pad_length = round(sampling_rate * (window_length_sec - epoch_length) / 2)
|
|
155
155
|
padded_eeg = np.concatenate(
|
|
156
156
|
[eeg[:pad_length][::-1], eeg, eeg[(len(eeg) - pad_length) :][::-1]]
|
|
157
157
|
)
|
|
@@ -328,7 +328,10 @@ def mixture_z_score_img(
|
|
|
328
328
|
if labels is None and (mixture_means is None or mixture_sds is None):
|
|
329
329
|
raise ValueError("must provide either labels or mixture means+SDs")
|
|
330
330
|
if labels is not None and ((mixture_means is not None) ^ (mixture_sds is not None)):
|
|
331
|
-
warnings.warn(
|
|
331
|
+
warnings.warn(
|
|
332
|
+
"labels were given, mixture means / SDs will be ignored",
|
|
333
|
+
stacklevel=2,
|
|
334
|
+
)
|
|
332
335
|
|
|
333
336
|
if labels is not None:
|
|
334
337
|
mixture_means, mixture_sds = get_mixture_values(
|
|
@@ -20,7 +20,7 @@ class ModelWithTemperature(nn.Module):
|
|
|
20
20
|
"""
|
|
21
21
|
|
|
22
22
|
def __init__(self, model):
|
|
23
|
-
super(
|
|
23
|
+
super().__init__()
|
|
24
24
|
self.model = model
|
|
25
25
|
# https://github.com/gpleiss/temperature_scaling/issues/20
|
|
26
26
|
# for another approach, see https://github.com/gpleiss/temperature_scaling/issues/36
|
|
@@ -142,7 +142,7 @@ class _ECELoss(nn.Module):
|
|
|
142
142
|
"""
|
|
143
143
|
n_bins (int): number of confidence interval bins
|
|
144
144
|
"""
|
|
145
|
-
super(
|
|
145
|
+
super().__init__()
|
|
146
146
|
bin_boundaries = torch.linspace(0, 1, n_bins + 1)
|
|
147
147
|
self.bin_lowers = bin_boundaries[:-1]
|
|
148
148
|
self.bin_uppers = bin_boundaries[1:]
|
|
@@ -153,7 +153,7 @@ class _ECELoss(nn.Module):
|
|
|
153
153
|
accuracies = predictions.eq(labels)
|
|
154
154
|
|
|
155
155
|
ece = torch.zeros(1, device=logits.device)
|
|
156
|
-
for bin_lower, bin_upper in zip(self.bin_lowers, self.bin_uppers):
|
|
156
|
+
for bin_lower, bin_upper in zip(self.bin_lowers, self.bin_uppers, strict=True):
|
|
157
157
|
# Calculated |confidence - accuracy| in each bin
|
|
158
158
|
in_bin = confidences.gt(bin_lower.item()) * confidences.le(bin_upper.item())
|
|
159
159
|
prop_in_bin = in_bin.float().mean()
|
accusleepy/validation.py
CHANGED
|
@@ -41,9 +41,10 @@ def check_label_validity(
|
|
|
41
41
|
):
|
|
42
42
|
return "label file contains invalid entries"
|
|
43
43
|
|
|
44
|
-
if confidence_scores is not None
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
if confidence_scores is not None and (
|
|
45
|
+
np.min(confidence_scores) < 0 or np.max(confidence_scores) > 1
|
|
46
|
+
):
|
|
47
|
+
return "label file contains invalid confidence scores"
|
|
47
48
|
|
|
48
49
|
return None
|
|
49
50
|
|
|
@@ -143,7 +144,9 @@ def check_config_consistency(
|
|
|
143
144
|
# generate message comparing the brain state configs
|
|
144
145
|
config_comparisons = list()
|
|
145
146
|
for config, config_name in zip(
|
|
146
|
-
[current_scored_states, model_scored_states],
|
|
147
|
+
[current_scored_states, model_scored_states],
|
|
148
|
+
["current", "model's"],
|
|
149
|
+
strict=True,
|
|
147
150
|
):
|
|
148
151
|
config_comparisons.append(
|
|
149
152
|
f"Scored brain states in {config_name} configuration: "
|
|
@@ -154,6 +157,7 @@ def check_config_consistency(
|
|
|
154
157
|
for x, y in zip(
|
|
155
158
|
config["digit"],
|
|
156
159
|
config["name"],
|
|
160
|
+
strict=True,
|
|
157
161
|
)
|
|
158
162
|
]
|
|
159
163
|
)
|
|
@@ -164,32 +168,26 @@ def check_config_consistency(
|
|
|
164
168
|
len_diff = len(current_scored_states["name"]) - len(model_scored_states["name"])
|
|
165
169
|
if len_diff != 0:
|
|
166
170
|
output.append(
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
"scored brain states than the model's configuration."
|
|
171
|
-
)
|
|
171
|
+
"WARNING: current brain state configuration has "
|
|
172
|
+
f"{'fewer' if len_diff < 0 else 'more'} "
|
|
173
|
+
"scored brain states than the model's configuration."
|
|
172
174
|
)
|
|
173
175
|
output = output + config_comparisons
|
|
174
176
|
else:
|
|
175
177
|
# the length is the same, but names might be different
|
|
176
178
|
if current_scored_states["name"] != model_scored_states["name"]:
|
|
177
179
|
output.append(
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
"the model's configuration."
|
|
182
|
-
)
|
|
180
|
+
"WARNING: current brain state configuration appears "
|
|
181
|
+
"to contain different brain states than "
|
|
182
|
+
"the model's configuration."
|
|
183
183
|
)
|
|
184
184
|
output = output + config_comparisons
|
|
185
185
|
|
|
186
186
|
if current_epoch_length != model_epoch_length:
|
|
187
187
|
output.append(
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
"does not match the current epoch length setting."
|
|
192
|
-
)
|
|
188
|
+
"Warning: the epoch length used when training this model "
|
|
189
|
+
f"({model_epoch_length} seconds) "
|
|
190
|
+
"does not match the current epoch length setting."
|
|
193
191
|
)
|
|
194
192
|
|
|
195
193
|
return output
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: accusleepy
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.11.0
|
|
4
4
|
Summary: Python implementation of AccuSleep
|
|
5
5
|
License: GPL-3.0-only
|
|
6
6
|
Author: Zeke Barger
|
|
@@ -15,6 +15,7 @@ Requires-Dist: matplotlib (>=3.10.1,<4.0.0)
|
|
|
15
15
|
Requires-Dist: numpy (>=2.2.4,<3.0.0)
|
|
16
16
|
Requires-Dist: pandas (>=2.2.3,<3.0.0)
|
|
17
17
|
Requires-Dist: pillow (>=11.1.0,<12.0.0)
|
|
18
|
+
Requires-Dist: platformdirs (>=4.0.0,<5.0.0)
|
|
18
19
|
Requires-Dist: pyarrow (>=23.0.0,<24.0.0)
|
|
19
20
|
Requires-Dist: pyside6 (>=6.10.1,<7.0.0)
|
|
20
21
|
Requires-Dist: scipy (>=1.15.2,<2.0.0)
|
|
@@ -60,13 +61,14 @@ etc.) with python >=3.11,<3.14
|
|
|
60
61
|
- `pip install accusleepy`
|
|
61
62
|
- (optional) download a classification model from https://osf.io/py5eb/ under /python_format/models/
|
|
62
63
|
|
|
63
|
-
Note that upgrading or reinstalling the package will overwrite any changes
|
|
64
|
-
to the [config file](accusleepy/config.json).
|
|
65
64
|
|
|
66
65
|
## Usage
|
|
67
66
|
|
|
68
67
|
`python -m accusleepy` will open the primary interface.
|
|
69
68
|
|
|
69
|
+
Your settings are saved to a platform-specific location
|
|
70
|
+
(e.g., `~/Library/Application Support/accusleepy/config.json` on macOS)
|
|
71
|
+
|
|
70
72
|
[Guide to the primary interface](accusleepy/gui/text/main_guide.md)
|
|
71
73
|
|
|
72
74
|
[Guide to the manual scoring interface](accusleepy/gui/text/manual_scoring_guide.md)
|
|
@@ -77,6 +79,7 @@ please consult the [developer guide](accusleepy/gui/text/dev_guide.md).
|
|
|
77
79
|
|
|
78
80
|
## Changelog
|
|
79
81
|
|
|
82
|
+
- 0.11.0: Store config file in a user directory
|
|
80
83
|
- 0.10.0-0.10.1: Improved zoom behavior, updated dependencies
|
|
81
84
|
- 0.7.1-0.9.3: Bugfixes, code cleanup, additional config settings
|
|
82
85
|
- 0.7.0: More settings can be configured in the UI
|
|
@@ -3,9 +3,9 @@ accusleepy/__main__.py,sha256=yRSJnSLFjt9BqzmdemfMzejp1TPS0VGIAvyYcd-yg3w,182
|
|
|
3
3
|
accusleepy/bouts.py,sha256=s77xtimYWFJ9CjTzqMUu98A2odoT8waoyuE6FVmj1dA,6089
|
|
4
4
|
accusleepy/brain_state_set.py,sha256=la7CjgwMByXEIE__Yzv-G9mbuNYFIB6G41rDPP2T21k,3314
|
|
5
5
|
accusleepy/classification.py,sha256=Zh-iMjvttRWf-Oarr1urgT-FkjcCbzYgndooAdeZbTA,8726
|
|
6
|
-
accusleepy/
|
|
7
|
-
accusleepy/
|
|
8
|
-
accusleepy/fileio.py,sha256=
|
|
6
|
+
accusleepy/constants.py,sha256=i7fl1d54leGkL8YoSPK5ZXZo9FKe9k8Ka-gEIy4m9PM,3327
|
|
7
|
+
accusleepy/default_config.json,sha256=vtzWKXSwZRNlYQhyaIl-TvOPrOxgRC7Pt3fUcWChVeo,911
|
|
8
|
+
accusleepy/fileio.py,sha256=Z95oaZrSfcc7GQnFlsmEP-Q3V1UMLCRdJUs-lVbZhP0,9900
|
|
9
9
|
accusleepy/gui/__init__.py,sha256=bv2FO3aQKzcBifoEfzg3ZeZHQaHUY_SuEceIE5mzZ7k,58
|
|
10
10
|
accusleepy/gui/dialogs.py,sha256=DqkarJKgRovTuDDJhqPaw_o8ZfopuR7R6M8C49QWZu0,1230
|
|
11
11
|
accusleepy/gui/icons/brightness_down.png,sha256=PLT1fb83RHIhSRuU7MMMx0G7oJAY7o9wUcnqM8veZfM,12432
|
|
@@ -19,29 +19,29 @@ accusleepy/gui/icons/save.png,sha256=J3EA8iU1BqLYRSsrq_OdoZlqrv2yfL7oV54DklTy_DI
|
|
|
19
19
|
accusleepy/gui/icons/up_arrow.png,sha256=V9yF9t1WgjPaUu-mF1YGe_DfaRHg2dUpR_sUVVcvVvY,3329
|
|
20
20
|
accusleepy/gui/icons/zoom_in.png,sha256=MFWnKZp7Rvh4bLPq4Cqo4sB_jQYedUUtT8-ZO8tNYyc,13589
|
|
21
21
|
accusleepy/gui/icons/zoom_out.png,sha256=IB8Jecb3i0U4qjWRR46ridjLpvLCSe7PozBaLqQqYSw,13055
|
|
22
|
-
accusleepy/gui/images/primary_window.png,sha256=
|
|
22
|
+
accusleepy/gui/images/primary_window.png,sha256=lLk-VxOt9U3igta5MBalwbItANn_hyG7zsMyTltxqdI,567825
|
|
23
23
|
accusleepy/gui/images/viewer_window.png,sha256=b_B7m9WSLMAOzNjctq76SyekO1WfC6qYZVNnYfhjPe8,977197
|
|
24
24
|
accusleepy/gui/images/viewer_window_annotated.png,sha256=uMNUmsZIdzDlQpyoiS3lJGoWlg_T325Oj5hDZhM3Y14,146817
|
|
25
|
-
accusleepy/gui/main.py,sha256=
|
|
26
|
-
accusleepy/gui/manual_scoring.py,sha256=
|
|
27
|
-
accusleepy/gui/mplwidget.py,sha256=
|
|
28
|
-
accusleepy/gui/primary_window.py,sha256=
|
|
29
|
-
accusleepy/gui/primary_window.ui,sha256=
|
|
25
|
+
accusleepy/gui/main.py,sha256=eTj7u83vWXCd1Suts7D9OX_chisqE3yVU9uVZvd4vEk,24693
|
|
26
|
+
accusleepy/gui/manual_scoring.py,sha256=S8aonPdrb4tUwaFzXX4N4oXjv5CvREGYMnQm30b0AbY,43288
|
|
27
|
+
accusleepy/gui/mplwidget.py,sha256=yZTd4lQi9LG5gtM43RYgr3BSf4DFf96HnwEKGq0CNgI,13481
|
|
28
|
+
accusleepy/gui/primary_window.py,sha256=2KPIrVPygxpgefZkHDeseKJZAo9KreC_XfRZdV89Kvo,141748
|
|
29
|
+
accusleepy/gui/primary_window.ui,sha256=a8Xzvq_U08Os-ES2BB_vs7D8JVsUj2kdLt6s3VztRhw,207886
|
|
30
30
|
accusleepy/gui/recording_manager.py,sha256=CqgP8Q2lI7Vir-zAOhVlZbIVBxRAbgC6ydmvzlMLYz4,4207
|
|
31
31
|
accusleepy/gui/resources.qrc,sha256=wqPendnTLAuKfVI6v2lKHiRqAWM0oaz2ZuF5cucJdS4,803
|
|
32
32
|
accusleepy/gui/resources_rc.py,sha256=Z2e34h30U4snJjnYdZVV9B6yjATKxxfvgTRt5uXtQdo,329727
|
|
33
|
-
accusleepy/gui/settings_widget.py,sha256=
|
|
33
|
+
accusleepy/gui/settings_widget.py,sha256=G5tpH8bDkbRGAH1sGn0wAOFN2KhtDgpWkZcgS7viAHE,17482
|
|
34
34
|
accusleepy/gui/text/dev_guide.md,sha256=PgOXfGvN17fCtnsfGvPhrhK4FUWFGP_TsHA6t9skP3U,2060
|
|
35
35
|
accusleepy/gui/text/main_guide.md,sha256=XDJU2anRsA72zXOSkhstSy66uEIA4jitD4uCHIxDP_w,8456
|
|
36
36
|
accusleepy/gui/text/manual_scoring_guide.md,sha256=mzIqYJ5IOkzIpAWNZUh82ve_lI9SHjVvbQzn5kDWP_k,1065
|
|
37
|
-
accusleepy/gui/viewer_window.py,sha256=
|
|
37
|
+
accusleepy/gui/viewer_window.py,sha256=KnaNjknF_Lf3vMKtDGOgcsUj3kzhaa6OUtrgFeLUi7I,24446
|
|
38
38
|
accusleepy/gui/viewer_window.ui,sha256=a89iVLk1sJg9N6ZvWAV6YNPStb2Tm4-rs-W7TmIDkb4,31658
|
|
39
39
|
accusleepy/models.py,sha256=Kmbt6a8kIbPD8fIPVHIo60oywQNNH86_lj1dSsjPkFE,3588
|
|
40
|
-
accusleepy/multitaper.py,sha256=
|
|
41
|
-
accusleepy/services.py,sha256=
|
|
42
|
-
accusleepy/signal_processing.py,sha256
|
|
43
|
-
accusleepy/temperature_scaling.py,sha256=
|
|
44
|
-
accusleepy/validation.py,sha256=
|
|
45
|
-
accusleepy-0.
|
|
46
|
-
accusleepy-0.
|
|
47
|
-
accusleepy-0.
|
|
40
|
+
accusleepy/multitaper.py,sha256=faBADd0C9ZVSi5u3kleE6DcztW-9orUzMzT5dvTQet0,23716
|
|
41
|
+
accusleepy/services.py,sha256=cLy60v_Rh5d84wXb_NivwVBSnCtVu8Ny9FHGRu-ff90,20237
|
|
42
|
+
accusleepy/signal_processing.py,sha256=npxok73jfW2Er0OU1x6Nh6VdO7WdV-hRX7iwZaKaFxI,20104
|
|
43
|
+
accusleepy/temperature_scaling.py,sha256=P9iKyay73fPqLa-nTYi-IaH_pIsER4RS2SH5WPTvNQ0,5882
|
|
44
|
+
accusleepy/validation.py,sha256=SKPiW0xPo2wXUif1xSvC7GL5Ooam7BgtYvvc48xIbEA,6947
|
|
45
|
+
accusleepy-0.11.0.dist-info/METADATA,sha256=OD-oUROHExjI6A5mv66uQa3ghVvWWBEGLtkEjUmMZOM,4683
|
|
46
|
+
accusleepy-0.11.0.dist-info/WHEEL,sha256=kJCRJT_g0adfAJzTx2GUMmS80rTJIVHRCfG0DQgLq3o,88
|
|
47
|
+
accusleepy-0.11.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|