accusleepy 0.9.3__py3-none-any.whl → 0.10.1__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.
@@ -1239,14 +1239,14 @@ color: rgb(244, 195, 68);</string>
1239
1239
  <number>10</number>
1240
1240
  </property>
1241
1241
  <item row="0" column="0">
1242
- <layout class="QHBoxLayout" name="top_training_layout" stretch="2,1,2,1,3,1">
1242
+ <layout class="QHBoxLayout" name="top_training_layout" stretch="5,1,3,4,1,5">
1243
1243
  <property name="spacing">
1244
1244
  <number>10</number>
1245
1245
  </property>
1246
1246
  <item>
1247
1247
  <layout class="QHBoxLayout" name="horizontalLayout_5">
1248
1248
  <property name="spacing">
1249
- <number>5</number>
1249
+ <number>3</number>
1250
1250
  </property>
1251
1251
  <item>
1252
1252
  <widget class="QLabel" name="label">
@@ -1299,7 +1299,7 @@ color: rgb(244, 195, 68);</string>
1299
1299
  </spacer>
1300
1300
  </item>
1301
1301
  <item>
1302
- <widget class="QCheckBox" name="delete_image_box">
1302
+ <widget class="QCheckBox" name="calibrate_checkbox">
1303
1303
  <property name="sizePolicy">
1304
1304
  <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
1305
1305
  <horstretch>0</horstretch>
@@ -1307,7 +1307,7 @@ color: rgb(244, 195, 68);</string>
1307
1307
  </sizepolicy>
1308
1308
  </property>
1309
1309
  <property name="text">
1310
- <string>Delete images after training</string>
1310
+ <string>Calibrate model</string>
1311
1311
  </property>
1312
1312
  <property name="checked">
1313
1313
  <bool>true</bool>
@@ -1315,7 +1315,55 @@ color: rgb(244, 195, 68);</string>
1315
1315
  </widget>
1316
1316
  </item>
1317
1317
  <item>
1318
- <spacer name="horizontalSpacer_6">
1318
+ <layout class="QHBoxLayout" name="horizontalLayout_84">
1319
+ <property name="spacing">
1320
+ <number>3</number>
1321
+ </property>
1322
+ <property name="leftMargin">
1323
+ <number>10</number>
1324
+ </property>
1325
+ <item>
1326
+ <widget class="QLabel" name="calibrate_label">
1327
+ <property name="sizePolicy">
1328
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
1329
+ <horstretch>0</horstretch>
1330
+ <verstretch>0</verstretch>
1331
+ </sizepolicy>
1332
+ </property>
1333
+ <property name="text">
1334
+ <string>Calibration set size:</string>
1335
+ </property>
1336
+ </widget>
1337
+ </item>
1338
+ <item>
1339
+ <widget class="QSpinBox" name="calibration_spinbox">
1340
+ <property name="sizePolicy">
1341
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
1342
+ <horstretch>0</horstretch>
1343
+ <verstretch>0</verstretch>
1344
+ </sizepolicy>
1345
+ </property>
1346
+ <property name="suffix">
1347
+ <string>%</string>
1348
+ </property>
1349
+ <property name="prefix">
1350
+ <string/>
1351
+ </property>
1352
+ <property name="minimum">
1353
+ <number>10</number>
1354
+ </property>
1355
+ <property name="maximum">
1356
+ <number>50</number>
1357
+ </property>
1358
+ <property name="value">
1359
+ <number>15</number>
1360
+ </property>
1361
+ </widget>
1362
+ </item>
1363
+ </layout>
1364
+ </item>
1365
+ <item>
1366
+ <spacer name="horizontalSpacer_3">
1319
1367
  <property name="orientation">
1320
1368
  <enum>Qt::Orientation::Horizontal</enum>
1321
1369
  </property>
@@ -1376,30 +1424,14 @@ color: rgb(244, 195, 68);</string>
1376
1424
  </item>
1377
1425
  </layout>
1378
1426
  </item>
1379
- <item>
1380
- <spacer name="horizontalSpacer_3">
1381
- <property name="orientation">
1382
- <enum>Qt::Orientation::Horizontal</enum>
1383
- </property>
1384
- <property name="sizeType">
1385
- <enum>QSizePolicy::Policy::Preferred</enum>
1386
- </property>
1387
- <property name="sizeHint" stdset="0">
1388
- <size>
1389
- <width>10</width>
1390
- <height>5</height>
1391
- </size>
1392
- </property>
1393
- </spacer>
1394
- </item>
1395
1427
  </layout>
1396
1428
  </item>
1397
1429
  <item row="1" column="0">
1398
- <layout class="QHBoxLayout" name="bottom_training_layout" stretch="6,5,3,1,3,1,1">
1430
+ <layout class="QHBoxLayout" name="bottom_training_layout" stretch="5,5">
1399
1431
  <item>
1400
1432
  <widget class="QPushButton" name="train_model_button">
1401
1433
  <property name="sizePolicy">
1402
- <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
1434
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
1403
1435
  <horstretch>0</horstretch>
1404
1436
  <verstretch>0</verstretch>
1405
1437
  </sizepolicy>
@@ -1428,89 +1460,6 @@ color: rgb(244, 195, 68);</string>
1428
1460
  </property>
1429
1461
  </spacer>
1430
1462
  </item>
1431
- <item>
1432
- <widget class="QCheckBox" name="calibrate_checkbox">
1433
- <property name="sizePolicy">
1434
- <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
1435
- <horstretch>0</horstretch>
1436
- <verstretch>0</verstretch>
1437
- </sizepolicy>
1438
- </property>
1439
- <property name="text">
1440
- <string>Calibrate model</string>
1441
- </property>
1442
- <property name="checked">
1443
- <bool>true</bool>
1444
- </property>
1445
- </widget>
1446
- </item>
1447
- <item>
1448
- <spacer name="horizontalSpacer_7">
1449
- <property name="orientation">
1450
- <enum>Qt::Orientation::Horizontal</enum>
1451
- </property>
1452
- <property name="sizeType">
1453
- <enum>QSizePolicy::Policy::Preferred</enum>
1454
- </property>
1455
- <property name="sizeHint" stdset="0">
1456
- <size>
1457
- <width>10</width>
1458
- <height>10</height>
1459
- </size>
1460
- </property>
1461
- </spacer>
1462
- </item>
1463
- <item>
1464
- <widget class="QLabel" name="calibrate_label">
1465
- <property name="sizePolicy">
1466
- <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
1467
- <horstretch>0</horstretch>
1468
- <verstretch>0</verstretch>
1469
- </sizepolicy>
1470
- </property>
1471
- <property name="text">
1472
- <string>Calibration set size:</string>
1473
- </property>
1474
- </widget>
1475
- </item>
1476
- <item>
1477
- <widget class="QSpinBox" name="calibration_spinbox">
1478
- <property name="sizePolicy">
1479
- <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
1480
- <horstretch>0</horstretch>
1481
- <verstretch>0</verstretch>
1482
- </sizepolicy>
1483
- </property>
1484
- <property name="suffix">
1485
- <string>%</string>
1486
- </property>
1487
- <property name="minimum">
1488
- <number>10</number>
1489
- </property>
1490
- <property name="maximum">
1491
- <number>50</number>
1492
- </property>
1493
- <property name="value">
1494
- <number>15</number>
1495
- </property>
1496
- </widget>
1497
- </item>
1498
- <item>
1499
- <spacer name="horizontalSpacer_78">
1500
- <property name="orientation">
1501
- <enum>Qt::Orientation::Horizontal</enum>
1502
- </property>
1503
- <property name="sizeType">
1504
- <enum>QSizePolicy::Policy::Preferred</enum>
1505
- </property>
1506
- <property name="sizeHint" stdset="0">
1507
- <size>
1508
- <width>10</width>
1509
- <height>10</height>
1510
- </size>
1511
- </property>
1512
- </spacer>
1513
- </item>
1514
1463
  </layout>
1515
1464
  </item>
1516
1465
  </layout>
@@ -4612,6 +4561,43 @@ Each brain state has several attributes:
4612
4561
  </item>
4613
4562
  </layout>
4614
4563
  </item>
4564
+ <item>
4565
+ <layout class="QHBoxLayout" name="horizontalLayout_79">
4566
+ <item>
4567
+ <layout class="QHBoxLayout" name="horizontalLayout_85">
4568
+ <item>
4569
+ <widget class="QCheckBox" name="delete_image_box">
4570
+ <property name="sizePolicy">
4571
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
4572
+ <horstretch>0</horstretch>
4573
+ <verstretch>0</verstretch>
4574
+ </sizepolicy>
4575
+ </property>
4576
+ <property name="text">
4577
+ <string>Delete images after training</string>
4578
+ </property>
4579
+ <property name="checked">
4580
+ <bool>true</bool>
4581
+ </property>
4582
+ </widget>
4583
+ </item>
4584
+ </layout>
4585
+ </item>
4586
+ <item>
4587
+ <spacer name="horizontalSpacer_93">
4588
+ <property name="orientation">
4589
+ <enum>Qt::Orientation::Horizontal</enum>
4590
+ </property>
4591
+ <property name="sizeHint" stdset="0">
4592
+ <size>
4593
+ <width>40</width>
4594
+ <height>20</height>
4595
+ </size>
4596
+ </property>
4597
+ </spacer>
4598
+ </item>
4599
+ </layout>
4600
+ </item>
4615
4601
  <item>
4616
4602
  <layout class="QHBoxLayout" name="horizontalLayout_74">
4617
4603
  <item>
@@ -4682,7 +4668,9 @@ Each brain state has several attributes:
4682
4668
  - Batch size: number of examples in each training iteration
4683
4669
  - Learning rate: step size for adjusting model weights
4684
4670
  - Momentum: amount of past gradients to use in the current update. Typically between 0.6 and 0.99
4685
- - Epochs: number of passes over the training data</string>
4671
+ - Epochs: number of passes over the training data
4672
+
4673
+ You can also choose whether to delete images created by the training process once it's finished. This is recommended unless you are debugging the training code.</string>
4686
4674
  </property>
4687
4675
  <property name="textFormat">
4688
4676
  <enum>Qt::TextFormat::MarkdownText</enum>
@@ -1,11 +1,20 @@
1
1
  """Recording list manager"""
2
2
 
3
+ from dataclasses import dataclass
4
+
3
5
  from PySide6.QtCore import QObject
4
6
  from PySide6.QtWidgets import QListWidget, QListWidgetItem
5
7
 
6
8
  from accusleepy.fileio import Recording, load_recording_list, save_recording_list
7
9
 
8
10
 
11
+ @dataclass
12
+ class RecordingListItem(Recording):
13
+ """A Recording with an associated QListWidget item for the GUI"""
14
+
15
+ widget: QListWidgetItem = None
16
+
17
+
9
18
  class RecordingListManager(QObject):
10
19
  """Manages the list of recordings and the associated QListWidget"""
11
20
 
@@ -14,19 +23,19 @@ class RecordingListManager(QObject):
14
23
  self._widget = list_widget
15
24
 
16
25
  # Create initial empty recording (there is always at least one)
17
- first_recording = Recording(
26
+ first_recording = RecordingListItem(
18
27
  widget=QListWidgetItem("Recording 1", self._widget),
19
28
  )
20
- self._recordings: list[Recording] = [first_recording]
29
+ self._recordings: list[RecordingListItem] = [first_recording]
21
30
  self._widget.addItem(first_recording.widget)
22
31
  self._widget.setCurrentRow(0)
23
32
 
24
33
  @property
25
- def current(self) -> Recording:
34
+ def current(self) -> RecordingListItem:
26
35
  """The currently selected recording"""
27
36
  return self._recordings[self._widget.currentRow()]
28
37
 
29
- def add(self, sampling_rate: int | float) -> Recording:
38
+ def add(self, sampling_rate: int | float) -> RecordingListItem:
30
39
  """Add a new recording to the list
31
40
 
32
41
  :param sampling_rate: sampling rate for the new recording
@@ -35,7 +44,7 @@ class RecordingListManager(QObject):
35
44
  new_name = max(r.name for r in self._recordings) + 1
36
45
 
37
46
  # Create recording with widget
38
- recording = Recording(
47
+ recording = RecordingListItem(
39
48
  name=new_name,
40
49
  sampling_rate=sampling_rate,
41
50
  widget=QListWidgetItem(f"Recording {new_name}", self._widget),
@@ -63,7 +72,7 @@ class RecordingListManager(QObject):
63
72
  else:
64
73
  # Reset the single recording to defaults
65
74
  recording_name = self._recordings[0].name
66
- self._recordings[0] = Recording(widget=self._recordings[0].widget)
75
+ self._recordings[0] = RecordingListItem(widget=self._recordings[0].widget)
67
76
  self._recordings[0].widget.setText(f"Recording {self._recordings[0].name}")
68
77
  return f"cleared Recording {recording_name}"
69
78
 
@@ -85,14 +94,15 @@ class RecordingListManager(QObject):
85
94
  try:
86
95
  self._widget.clear()
87
96
 
88
- # Load recordings
89
- self._recordings = load_recording_list(filename)
90
-
91
- # Create widgets for each recording
92
- for recording in self._recordings:
93
- recording.widget = QListWidgetItem(
94
- f"Recording {recording.name}", self._widget
97
+ # Load recordings and create widgets
98
+ self._recordings = [
99
+ RecordingListItem(
100
+ **r.__dict__,
101
+ widget=QListWidgetItem(f"Recording {r.name}", self._widget),
95
102
  )
103
+ for r in load_recording_list(filename)
104
+ ]
105
+ for recording in self._recordings:
96
106
  self._widget.addItem(recording.widget)
97
107
  finally:
98
108
  self._widget.blockSignals(False)
@@ -106,5 +116,5 @@ class RecordingListManager(QObject):
106
116
  def __len__(self):
107
117
  return len(self._recordings)
108
118
 
109
- def __getitem__(self, index: int) -> Recording:
119
+ def __getitem__(self, index: int) -> RecordingListItem:
110
120
  return self._recordings[index]
@@ -9,6 +9,7 @@ from PySide6.QtWidgets import QCheckBox, QDoubleSpinBox, QLineEdit
9
9
  from accusleepy.brain_state_set import BrainState, BrainStateSet
10
10
  from accusleepy.constants import (
11
11
  DEFAULT_BATCH_SIZE,
12
+ DEFAULT_DELETE_TRAINING_IMAGES_STATE,
12
13
  DEFAULT_EMG_BP_LOWER,
13
14
  DEFAULT_EMG_BP_UPPER,
14
15
  DEFAULT_EMG_FILTER_ORDER,
@@ -55,6 +56,7 @@ class SettingsWidget(QObject):
55
56
  self._hyperparameters = config.hyperparameters
56
57
  self._default_epochs_to_show = config.epochs_to_show
57
58
  self._default_autoscroll_state = config.autoscroll_state
59
+ self._delete_training_images = config.delete_training_images
58
60
 
59
61
  # Store default values for main tab settings (used to populate Settings tab UI)
60
62
  self._default_epoch_length = config.default_epoch_length
@@ -81,6 +83,11 @@ class SettingsWidget(QObject):
81
83
  """Model training hyperparameters"""
82
84
  return self._hyperparameters
83
85
 
86
+ @property
87
+ def delete_training_images(self) -> bool:
88
+ """Whether to delete images after training"""
89
+ return self._delete_training_images
90
+
84
91
  @property
85
92
  def default_epochs_to_show(self) -> int:
86
93
  """Default number of epochs to show in manual scoring"""
@@ -186,6 +193,7 @@ class SettingsWidget(QObject):
186
193
  self._ui.learning_rate_spinbox.setValue(self._hyperparameters.learning_rate)
187
194
  self._ui.momentum_spinbox.setValue(self._hyperparameters.momentum)
188
195
  self._ui.training_epochs_spinbox.setValue(self._hyperparameters.training_epochs)
196
+ self._ui.delete_image_box.setChecked(self._delete_training_images)
189
197
  # Brain states
190
198
  states = {b.digit: b for b in self._brain_state_set.brain_states}
191
199
  for digit in range(10):
@@ -233,6 +241,7 @@ class SettingsWidget(QObject):
233
241
  self._ui.training_epochs_spinbox.valueChanged.connect(
234
242
  self._hyperparameters_changed
235
243
  )
244
+ self._ui.delete_image_box.stateChanged.connect(self._hyperparameters_changed)
236
245
  for digit in range(10):
237
246
  state = self._settings_widgets[digit]
238
247
  state.enabled_widget.stateChanged.connect(
@@ -302,6 +311,7 @@ class SettingsWidget(QObject):
302
311
  momentum=self._ui.momentum_spinbox.value(),
303
312
  training_epochs=self._ui.training_epochs_spinbox.value(),
304
313
  )
314
+ self._delete_training_images = self._ui.delete_image_box.isChecked()
305
315
  self._ui.save_config_status.setText("")
306
316
 
307
317
  def reset_status_message(self, _new_value=None) -> None:
@@ -392,6 +402,7 @@ class SettingsWidget(QObject):
392
402
  hyperparameters=self._hyperparameters,
393
403
  epochs_to_show=self._ui.epochs_to_show_spinbox.value(),
394
404
  autoscroll_state=self._ui.autoscroll_checkbox.isChecked(),
405
+ delete_training_images=self._ui.delete_image_box.isChecked(),
395
406
  )
396
407
  self._ui.save_config_status.setText("configuration saved")
397
408
 
@@ -407,3 +418,4 @@ class SettingsWidget(QObject):
407
418
  self._ui.learning_rate_spinbox.setValue(DEFAULT_LEARNING_RATE)
408
419
  self._ui.momentum_spinbox.setValue(DEFAULT_MOMENTUM)
409
420
  self._ui.training_epochs_spinbox.setValue(DEFAULT_TRAINING_EPOCHS)
421
+ self._ui.delete_image_box.setChecked(DEFAULT_DELETE_TRAINING_IMAGES_STATE)
@@ -125,25 +125,28 @@ To train a new model on your own data:
125
125
  recording. Calibration files are not required.
126
126
  2. Click the "Model training" tab
127
127
  3. Choose the number of epochs to consider when scoring each epoch.
128
- This will be the "width" of the training images. For "default"
129
- type models, this must be an odd number. In general, about 30
130
- seconds worth of data is enough.
131
- 4. Choose whether the images used to train the model should be
132
- deleted once training is complete. It's generally best to
133
- leave this box checked. A (temporary) folder for these files
134
- will be created in the same location as the trained model.
135
- 5. Choose whether to create a "default" or "real-time"-type model.
136
- Note that scoring recordings in the primary interface requires
137
- a default-type model.
138
- 6. Choose whether to calibrate the model. This process uses part
128
+ This will be the width, in pixels, of the training images.
129
+ For "default" type models, this must be an odd number. Generally,
130
+ about 30 seconds worth of data is enough.
131
+ 4. Choose whether to create a "default" or "real-time"-type model.
132
+ Scoring recordings in the AccuSleePy interface requires a
133
+ default-type model. Only select real-time if you plan to create
134
+ your own scoring function. An example real-time scoring function
135
+ can be found in `classification.py`.
136
+ 5. Choose whether to calibrate the model. This process uses part
139
137
  of the training data to make the model's confidence scores
140
138
  more accurately reflect the probability that the output
141
139
  labels are accurate. If using calibration, choose what percent
142
140
  of the training data to set aside for calibration.
143
- 7. Click "Train classification model" and enter a
141
+ 6. Click "Train classification model" and enter a
144
142
  filename for the trained model. Training can take some time.
145
143
  The terminal will display progress updates.
146
144
 
145
+ As part of the training process, a temporary folder of images will
146
+ be created in the location where the model will be saved. This folder
147
+ is deleted by default, but if you want to keep it for debugging
148
+ purposes, you can change this behavior in the "Settings" tab.
149
+
147
150
  ## 4C. Automatic scoring
148
151
 
149
152
  Instructions for automatic scoring using this interface are below.
@@ -2,6 +2,7 @@
2
2
 
3
3
  Keyboard shortcuts:
4
4
  - Mouse click on the upper 3 plots: jump to epoch
5
+ - Mouse scroll on the upper 3 plots: zoom in/out along the x-axis
5
6
  - Ctrl + S: save labels to file
6
7
  - Right / left arrow: move one epoch forward / backward in time
7
8
  - Numbers 0-9: set current epoch to this brain state
accusleepy/models.py CHANGED
@@ -1,3 +1,5 @@
1
+ """Neural network model definitions for sleep stage classification."""
2
+
1
3
  from torch import device, flatten, nn
2
4
  from torch import load as torch_load
3
5
  from torch import save as torch_save
accusleepy/multitaper.py CHANGED
@@ -14,10 +14,6 @@ import timeit
14
14
  import warnings
15
15
 
16
16
  import numpy as np
17
- from joblib import Parallel, cpu_count, delayed
18
-
19
- # from scipy.signal import detrend # unused by AccuSleePy
20
- # from scipy.signal.windows import dpss # lazily loaded later
21
17
 
22
18
 
23
19
  # MULTITAPER SPECTROGRAM #
@@ -206,19 +202,9 @@ def spectrogram(
206
202
  wt,
207
203
  )
208
204
 
209
- if multiprocess: # use multiprocessing
210
- n_jobs = max(cpu_count() - 1, 1) if n_jobs is None else n_jobs
211
- mt_spectrogram = np.vstack(
212
- Parallel(n_jobs=n_jobs)(
213
- delayed(calc_mts_segment)(data_segments[num_window, :], *mts_params)
214
- for num_window in range(num_windows)
215
- )
216
- )
217
-
218
- else: # if no multiprocessing, compute normally
219
- mt_spectrogram = np.apply_along_axis(
220
- calc_mts_segment, 1, data_segments, *mts_params
221
- )
205
+ mt_spectrogram = np.apply_along_axis(
206
+ calc_mts_segment, 1, data_segments, *mts_params
207
+ )
222
208
 
223
209
  # Compute one-sided PSD spectrum
224
210
  mt_spectrogram = mt_spectrogram.T
@@ -251,37 +237,6 @@ def spectrogram(
251
237
  if np.all(mt_spectrogram.flatten() == 0):
252
238
  print("\n Data was all zeros, no output")
253
239
 
254
- # # Plot multitaper spectrogram
255
- # if plot_on:
256
- # # convert from power to dB
257
- # spect_data = nanpow2db(mt_spectrogram)
258
- #
259
- # # Set x and y axes
260
- # dx = stimes[1] - stimes[0]
261
- # dy = sfreqs[1] - sfreqs[0]
262
- # extent = [stimes[0] - dx, stimes[-1] + dx, sfreqs[-1] + dy, sfreqs[0] - dy]
263
- #
264
- # # Plot spectrogram
265
- # if ax is None:
266
- # fig, ax = plt.subplots()
267
- # else:
268
- # fig = ax.get_figure()
269
- # im = ax.imshow(spect_data, extent=extent, aspect="auto")
270
- # fig.colorbar(im, ax=ax, label="PSD (dB)", shrink=0.8)
271
- # ax.set_xlabel("Time (HH:MM:SS)")
272
- # ax.set_ylabel("Frequency (Hz)")
273
- # im.set_cmap(plt.cm.get_cmap("cet_rainbow4"))
274
- # ax.invert_yaxis()
275
- #
276
- # # Scale colormap
277
- # if clim_scale:
278
- # clim = np.percentile(spect_data, [5, 98]) # from 5th percentile to 98th
279
- # im.set_clim(clim) # actually change colorbar scale
280
- #
281
- # fig.show()
282
- # if return_fig:
283
- # return mt_spectrogram, stimes, sfreqs, (fig, ax)
284
-
285
240
  return mt_spectrogram, stimes, sfreqs
286
241
 
287
242
 
@@ -568,18 +523,6 @@ def nanpow2db(y):
568
523
  return ydB
569
524
 
570
525
 
571
- # Helper #
572
- def is_outlier(data):
573
- smad = 1.4826 * np.median(
574
- abs(data - np.median(data))
575
- ) # scaled median absolute deviation
576
- outlier_mask = (
577
- abs(data - np.median(data)) > 3 * smad
578
- ) # outliers are more than 3 smads away from median
579
- outlier_mask = outlier_mask | np.isnan(data) | np.isinf(data)
580
- return outlier_mask
581
-
582
-
583
526
  # CALCULATE MULTITAPER SPECTRUM ON SINGLE SEGMENT
584
527
  def calc_mts_segment(
585
528
  data_segment,
@@ -1,3 +1,5 @@
1
+ """EEG/EMG signal processing, mixture z-scoring, and training image generation."""
2
+
1
3
  import logging
2
4
  import os
3
5
  import warnings
@@ -1,3 +1,5 @@
1
+ """Temperature scaling for model confidence calibration."""
2
+
1
3
  import logging
2
4
 
3
5
  import numpy as np
accusleepy/validation.py CHANGED
@@ -1,3 +1,5 @@
1
+ """Validation utilities for brain state labels and recordings."""
2
+
1
3
  import numpy as np
2
4
 
3
5
  from accusleepy.brain_state_set import BrainStateSet
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: accusleepy
3
- Version: 0.9.3
3
+ Version: 0.10.1
4
4
  Summary: Python implementation of AccuSleep
5
5
  License: GPL-3.0-only
6
6
  Author: Zeke Barger
@@ -11,14 +11,12 @@ Classifier: Programming Language :: Python :: 3
11
11
  Classifier: Programming Language :: Python :: 3.11
12
12
  Classifier: Programming Language :: Python :: 3.12
13
13
  Classifier: Programming Language :: Python :: 3.13
14
- Requires-Dist: fastparquet (>=2024.11.0,<2025.0.0)
15
- Requires-Dist: joblib (>=1.4.2,<2.0.0)
16
14
  Requires-Dist: matplotlib (>=3.10.1,<4.0.0)
17
15
  Requires-Dist: numpy (>=2.2.4,<3.0.0)
18
16
  Requires-Dist: pandas (>=2.2.3,<3.0.0)
19
17
  Requires-Dist: pillow (>=11.1.0,<12.0.0)
20
- Requires-Dist: pre-commit (>=4.2.0,<5.0.0)
21
- Requires-Dist: pyside6 (>=6.9.0,<6.9.3)
18
+ Requires-Dist: pyarrow (>=23.0.0,<24.0.0)
19
+ Requires-Dist: pyside6 (>=6.10.1,<7.0.0)
22
20
  Requires-Dist: scipy (>=1.15.2,<2.0.0)
23
21
  Requires-Dist: torch (>=2.8.0,<3.0.0)
24
22
  Requires-Dist: torchvision (>=0.23.0,<1.0.0)
@@ -79,9 +77,8 @@ please consult the [developer guide](accusleepy/gui/text/dev_guide.md).
79
77
 
80
78
  ## Changelog
81
79
 
82
- - 0.8.1-0.9.3: Improved error handling and code quality
83
- - 0.8.0: More configurable settings, visual improvements
84
- - 0.7.1-0.7.3: Bugfixes, code cleanup
80
+ - 0.10.0-0.10.1: Improved zoom behavior, updated dependencies
81
+ - 0.7.1-0.9.3: Bugfixes, code cleanup, additional config settings
85
82
  - 0.7.0: More settings can be configured in the UI
86
83
  - 0.6.0: Confidence scores can now be displayed and saved. Retraining your models is recommended
87
84
  since the new calibration feature will make the confidence scores more accurate.