misleep 0.2.3__tar.gz → 0.2.4__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.
- {misleep-0.2.3 → misleep-0.2.4}/PKG-INFO +1 -1
- {misleep-0.2.3 → misleep-0.2.4}/misleep/analysis/auto_stage.py +52 -30
- misleep-0.2.4/misleep/analysis/auto_stage_model/P30_EEG_F_lightgbm.pkl +0 -0
- misleep-0.2.4/misleep/analysis/auto_stage_model/P30_EEG_P_lightgbm.pkl +0 -0
- misleep-0.2.4/misleep/analysis/auto_stage_model/ado_EEG_F_lightgbm.pkl +0 -0
- misleep-0.2.4/misleep/analysis/auto_stage_model/ado_EEG_P_lightgbm.pkl +0 -0
- misleep-0.2.4/misleep/analysis/auto_stage_model/adult_EEG_F_lightgbm.pkl +0 -0
- misleep-0.2.4/misleep/analysis/auto_stage_model/adult_EEG_P_lightgbm.pkl +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/config.ini +3 -4
- {misleep-0.2.3 → misleep-0.2.4}/misleep/gui/dialog.py +10 -4
- {misleep-0.2.3 → misleep-0.2.4}/misleep/gui/main_window.py +12 -7
- {misleep-0.2.3 → misleep-0.2.4}/misleep/gui/uis/auto_stage_dialog_ui.py +26 -9
- {misleep-0.2.3 → misleep-0.2.4}/misleep/io/annotation_io.py +28 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep.egg-info/PKG-INFO +1 -1
- {misleep-0.2.3 → misleep-0.2.4}/misleep.egg-info/SOURCES.txt +6 -3
- {misleep-0.2.3 → misleep-0.2.4}/setup.py +7 -3
- misleep-0.2.3/misleep/analysis/auto_stage_model/EEG_F_lightgbm_20241221.pkl +0 -0
- misleep-0.2.3/misleep/analysis/auto_stage_model/EEG_P_lightgbm_20241221.pkl +0 -0
- misleep-0.2.3/misleep/analysis/classification.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/LICENSE +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/README.md +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/__init__.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/__main__.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/analysis/__init__.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/analysis/detection.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/gui/__init__.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/gui/about.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/gui/resources/__init__.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/gui/resources/entire_logo.png +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/gui/resources/logo.png +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/gui/resources/misleep.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/gui/resources/misleep.qrc +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/gui/show.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/gui/spec_window.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/gui/thread.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/gui/uis/SWA_detect_dialog_ui.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/gui/uis/__init__.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/gui/uis/about_ui.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/gui/uis/horizontal_line_dialog_ui.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/gui/uis/label_dialog_ui.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/gui/uis/main_window_ui.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/gui/uis/save_data_dialog_ui.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/gui/uis/spec_window_ui.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/gui/uis/spindle_detect_dialog_ui.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/gui/uis/state_spectral_dialog_ui.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/gui/uis/transfer_result_dialog_ui.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/gui/utils.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/io/__init__.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/io/base.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/io/signal_io.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/preprocessing/__init__.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/preprocessing/channel.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/preprocessing/signals.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/preprocessing/spectral.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/utils/__init__.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/utils/annotation.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/utils/logger_handler.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/utils/signals.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/viz/__init__.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/viz/hypnogram.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/viz/signals.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep/viz/spectral.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep.egg-info/dependency_links.txt +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep.egg-info/requires.txt +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/misleep.egg-info/top_level.txt +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/setup.cfg +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/test/test_annotation_io.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/test/test_loadmat73.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/test/test_midata.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/test/test_show.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/test/test_signal_io.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/test/test_signals_viz.py +0 -0
- {misleep-0.2.3 → misleep-0.2.4}/test/test_spectral_viz.py +0 -0
|
@@ -6,6 +6,7 @@ from scipy import stats
|
|
|
6
6
|
import antropy
|
|
7
7
|
import joblib
|
|
8
8
|
import copy
|
|
9
|
+
import lightgbm
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
def filter_power_line_noise(data, sf, noise_band='50-100-150'):
|
|
@@ -33,7 +34,7 @@ def split_window_data(data, sf, state, window_length=20, stride_length=5):
|
|
|
33
34
|
"""
|
|
34
35
|
|
|
35
36
|
# If the data is shorter than the window length, remove it
|
|
36
|
-
if data.shape[0]/sf <
|
|
37
|
+
if data.shape[0]/sf < window_length:
|
|
37
38
|
return []
|
|
38
39
|
|
|
39
40
|
window_data = []
|
|
@@ -45,15 +46,24 @@ def split_window_data(data, sf, state, window_length=20, stride_length=5):
|
|
|
45
46
|
|
|
46
47
|
return window_data
|
|
47
48
|
|
|
48
|
-
def
|
|
49
|
+
def delta_theta_ratio_theta(data, sf):
|
|
49
50
|
"""Calculate the delta/theta ratio from the original signal data
|
|
50
51
|
Note, here the data is 20 seconds, we only need the ratio from the 5 seconds beginning
|
|
51
52
|
"""
|
|
52
53
|
freq, t, Sxx = misleep.spectrogram(data, sf, window=1)
|
|
53
54
|
band_second = np.where(t < 5)
|
|
54
55
|
psd = np.sum(np.array([each[band_second] for each in Sxx]), axis=1)
|
|
55
|
-
band_power = misleep.band_power(psd, freq, bands=[[0.5, 4, 'delta'], [5, 9, 'theta']])
|
|
56
|
-
return band_power['delta'] / band_power['theta']
|
|
56
|
+
band_power = misleep.band_power(psd, freq, bands=[[0.5, 4, 'delta'], [5, 9, 'theta']], relative=True)
|
|
57
|
+
return band_power['delta'] / band_power['theta'], band_power['theta']
|
|
58
|
+
|
|
59
|
+
def self_zscore(feature, quantile=0.95):
|
|
60
|
+
"""Zscore the extracted features from the signal data, to exclude the abnormal signal, use 0.95 quantile
|
|
61
|
+
Return the quantile zscore feature data
|
|
62
|
+
"""
|
|
63
|
+
upper_quantile = np.quantile(feature, quantile)
|
|
64
|
+
feature = [each if each < upper_quantile else upper_quantile for each in feature]
|
|
65
|
+
return (feature - np.mean(feature)) / np.std(feature)
|
|
66
|
+
|
|
57
67
|
|
|
58
68
|
def get_data_features(data, sf, data_format='EEG'):
|
|
59
69
|
""" Get data features, data format can be 'EEG' or 'EMG'
|
|
@@ -67,11 +77,8 @@ def get_data_features(data, sf, data_format='EEG'):
|
|
|
67
77
|
# Time-domain features, both EEG and EMG
|
|
68
78
|
# 1. standard deviation
|
|
69
79
|
data_std = np.array([np.std(each[0][:int(5*sf)]) for each in data])
|
|
70
|
-
# Set those abnormal points to the upper quartile
|
|
71
|
-
data_std_upper_quantile = np.quantile(data_std, 0.95)
|
|
72
|
-
data_std = [each if each < data_std_upper_quantile else data_std_upper_quantile for each in data_std]
|
|
73
80
|
# Z-score the std features
|
|
74
|
-
window_feature_df[f'{data_format}_std_zscore'] = (data_std
|
|
81
|
+
window_feature_df[f'{data_format}_std_zscore'] = self_zscore(data_std)
|
|
75
82
|
|
|
76
83
|
# 2. Zero crossing rate for EEG and EMG
|
|
77
84
|
zerocross_rate = [antropy.num_zerocross(each[0][:int(5*sf)]) / (5*sf) for each in data]
|
|
@@ -81,46 +88,60 @@ def get_data_features(data, sf, data_format='EEG'):
|
|
|
81
88
|
hjorth = [antropy.hjorth_params(each[0][:int(5*sf)]) for each in data]
|
|
82
89
|
hjorth_M = [each[0] for each in hjorth]
|
|
83
90
|
hjorth_C = [each[1] for each in hjorth]
|
|
84
|
-
window_feature_df[f'{data_format}_Hjorth_M'] = (hjorth_M
|
|
85
|
-
window_feature_df[f'{data_format}_Hjorth_C'] = (hjorth_C
|
|
91
|
+
window_feature_df[f'{data_format}_Hjorth_M'] = self_zscore(hjorth_M)
|
|
92
|
+
window_feature_df[f'{data_format}_Hjorth_C'] = self_zscore(hjorth_C)
|
|
86
93
|
|
|
87
94
|
# 4. Permutation entropy
|
|
88
95
|
perm_entropy= [antropy.perm_entropy(each[0][:int(5*sf)]) for each in data]
|
|
89
|
-
window_feature_df[f'{data_format}_perm_entropy'] = (perm_entropy
|
|
96
|
+
window_feature_df[f'{data_format}_perm_entropy'] = self_zscore(perm_entropy)
|
|
90
97
|
|
|
91
98
|
# Some features only with EEG
|
|
92
99
|
if data_format.startswith('EEG'):
|
|
93
100
|
# 1. Skewness and kurtosis for EEG signal(s)
|
|
94
101
|
data_skewness = np.array([stats.skew(each[0][:int(5*sf)]) for each in data])
|
|
95
102
|
data_kurtosis = np.array([stats.kurtosis(each[0][:int(5*sf)]) for each in data])
|
|
96
|
-
window_feature_df[f'{data_format}_skewness_zscore'] = (data_skewness
|
|
97
|
-
window_feature_df[f'{data_format}_kurtosis_zscore'] = (data_kurtosis
|
|
103
|
+
window_feature_df[f'{data_format}_skewness_zscore'] = self_zscore(data_skewness)
|
|
104
|
+
window_feature_df[f'{data_format}_kurtosis_zscore'] = self_zscore(data_kurtosis)
|
|
98
105
|
# Frequency-domain features
|
|
99
106
|
# 1. delta/theta
|
|
100
|
-
delta_theta = [
|
|
101
|
-
|
|
107
|
+
delta_theta = [delta_theta_ratio_theta(each[0], sf) for each in data]
|
|
108
|
+
delta_theta_ratio = [each[0] for each in delta_theta]
|
|
109
|
+
theta = [each[1] for each in delta_theta]
|
|
110
|
+
window_feature_df[f'{data_format}_delta_theta_ratio'] = self_zscore(delta_theta_ratio)
|
|
111
|
+
window_feature_df[f'{data_format}_theta'] = self_zscore(theta)
|
|
102
112
|
|
|
103
113
|
return window_feature_df
|
|
104
114
|
|
|
105
|
-
def result_constraints(
|
|
115
|
+
def result_constraints(pred_prob):
|
|
106
116
|
"""
|
|
107
117
|
Once finished the prediction, add some constraints to make the result more smooth
|
|
108
118
|
1. No REM after Wake, set to NREM
|
|
109
119
|
2. All one epoch between two same state will be set to the around state
|
|
110
120
|
"""
|
|
111
121
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
122
|
+
"""
|
|
123
|
+
Once finished the prediction, add some constraints to make the result more smooth
|
|
124
|
+
1. REM threshold is lower, set to 0.15
|
|
125
|
+
2. No REM after Wake, set to NREM
|
|
126
|
+
3. All one epoch between two same state will be set to the around state
|
|
127
|
+
"""
|
|
128
|
+
|
|
129
|
+
pred_prob = copy.deepcopy(pred_prob)
|
|
130
|
+
pred_label = [each+1 for each in np.argmax(pred_prob, axis=1)]
|
|
131
|
+
pred_label = [2 if each[1] > 0.1 else pred_label[idx] for idx, each in enumerate(pred_prob)] # REM threshold
|
|
132
|
+
|
|
133
|
+
# for idx in range(1, len(pred_label)-1):
|
|
134
|
+
# label_ = pred_label[idx]
|
|
135
|
+
|
|
136
|
+
# if label_ == 3 and pred_label[idx+1] == 2: # REM after Wake
|
|
137
|
+
# pred_label[idx+1] = 1
|
|
138
|
+
# if pred_label[idx-1] ==pred_label[idx+1]: # Same state previous and after
|
|
139
|
+
# pred_label[idx] = pred_label[idx-1]
|
|
119
140
|
|
|
120
141
|
return pred_label
|
|
121
142
|
|
|
122
143
|
|
|
123
|
-
def auto_stage_gbm(EEG, EMG, sf, EEG_channel='F'):
|
|
144
|
+
def auto_stage_gbm(EEG, EMG, label, sf, EEG_channel='F', mouse_age='adult'):
|
|
124
145
|
"""
|
|
125
146
|
Auto stage with lightgbm method
|
|
126
147
|
|
|
@@ -134,12 +155,16 @@ def auto_stage_gbm(EEG, EMG, sf, EEG_channel='F'):
|
|
|
134
155
|
Sampling frequency of the EEG and EMG data, should be the same.
|
|
135
156
|
EEG_channel : string
|
|
136
157
|
Specify the channel of EEG, frontal or parietal. Options: {'F', 'P'}. Default is 'F' for frontal.
|
|
158
|
+
mouse_age : string
|
|
159
|
+
Specify which age model to use. {'adult', 'ado', 'P30'}, default is 'adult'.
|
|
160
|
+
Here the adult is > P56, ado is P30~P56, P30 is less than P30.
|
|
137
161
|
|
|
138
162
|
Return
|
|
139
163
|
------
|
|
140
164
|
pred_label : list
|
|
141
165
|
Predicted labels for every second. May less than the data length for about 15 seconds.
|
|
142
166
|
"""
|
|
167
|
+
|
|
143
168
|
EEG = split_window_data(EEG, sf, state=4) # All set the initial state '4'
|
|
144
169
|
EMG = split_window_data(EMG, sf, state=4)
|
|
145
170
|
|
|
@@ -147,12 +172,9 @@ def auto_stage_gbm(EEG, EMG, sf, EEG_channel='F'):
|
|
|
147
172
|
window_feature_df = pd.concat([get_data_features(EEG, sf, data_format='EEG'), get_data_features(EMG, sf, data_format='EMG')], axis=1)
|
|
148
173
|
window_feature_df = window_feature_df.filter(like='E')
|
|
149
174
|
|
|
150
|
-
|
|
151
|
-
gbm_model = joblib.load(r'./misleep/analysis/auto_stage_model/EEG_F_lightgbm_20241221.pkl')
|
|
152
|
-
if EEG_channel == 'P':
|
|
153
|
-
gbm_model = joblib.load(r'./misleep/analysis/auto_stage_model/EEG_P_lightgbm_20241221.pkl')
|
|
175
|
+
gbm_model = joblib.load(f'./misleep/analysis/auto_stage_model/{mouse_age}_EEG_{EEG_channel}_lightgbm.pkl')
|
|
154
176
|
|
|
155
|
-
|
|
156
|
-
pred_label = result_constraints(
|
|
177
|
+
pred_prob = gbm_model.predict_proba(window_feature_df, num_iteration=gbm_model.best_iteration_)
|
|
178
|
+
pred_label = result_constraints(pred_prob)
|
|
157
179
|
pred_label = [item for each in pred_label for item in [each]*5]
|
|
158
180
|
return pred_label
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[gui]
|
|
2
|
-
version = v0.2.
|
|
3
|
-
updatetime =
|
|
4
|
-
marker = ['
|
|
2
|
+
version = v0.2.4
|
|
3
|
+
updatetime = 2025/1/16
|
|
4
|
+
marker = ['good', 'first REM', 'WindEEG', 'W-R ', 'maker']
|
|
5
5
|
startend = ['burst-supression', 'REM', 'Wake', 'Spindle', 'SWA', 'start end label', 'start end label']
|
|
6
6
|
statemap = {"1": "NREM", "2": "REM", "3": "Wake", "4": "INIT", "5": "IS", "6": "MicroArousal"}
|
|
7
7
|
statecolor = {"1": "orange", "2": "skyblue", "3": "red", "4": "white", "5": "green", "6": "pink"}
|
|
@@ -10,4 +10,3 @@ statecolorbgalpha = 0.1
|
|
|
10
10
|
markerlinecolor = "red"
|
|
11
11
|
startendlinecolor = "blue"
|
|
12
12
|
openpath = E:
|
|
13
|
-
|
|
@@ -220,7 +220,7 @@ class transferResult_dialog(QDialog, Ui_TransferResultDialog):
|
|
|
220
220
|
df, analyse_df, start_end_df, marker_df = transfer_result(mianno=mianno, ac_time=ac_time)
|
|
221
221
|
|
|
222
222
|
fd, _ = QFileDialog.getSaveFileName(self, "Save transfered result",
|
|
223
|
-
f"{config['gui']['openpath']
|
|
223
|
+
f"{config['gui']['openpath']}",
|
|
224
224
|
"*.xlsx;;")
|
|
225
225
|
if fd == '':
|
|
226
226
|
return
|
|
@@ -901,20 +901,26 @@ class AutoStageDialog(QDialog, Ui_AutoStageDialog):
|
|
|
901
901
|
self.EMGchannelCombox.addItems(channels)
|
|
902
902
|
self.EMGchannelCombox.setCurrentIndex(1)
|
|
903
903
|
|
|
904
|
-
def auto_stage(self, midata):
|
|
904
|
+
def auto_stage(self, midata, mianno):
|
|
905
905
|
"""Auto stage with misleep data"""
|
|
906
906
|
|
|
907
907
|
EEG_channel_idx = self.EEGChannelCombox.currentIndex()
|
|
908
908
|
EMG_channel_idx = self.EMGchannelCombox.currentIndex()
|
|
909
909
|
EEG = deepcopy(midata.signals[EEG_channel_idx])
|
|
910
910
|
EMG = deepcopy(midata.signals[EMG_channel_idx])
|
|
911
|
+
label = deepcopy(mianno._sleep_state)
|
|
911
912
|
sf = deepcopy(midata.sf[EEG_channel_idx])
|
|
912
913
|
|
|
913
914
|
EEG_site = ['P', 'F'][self.EEGSiteCombox.currentIndex()]
|
|
915
|
+
mouse_age = ['adult', 'ado', 'P30'][self.AgeCombox.currentIndex()]
|
|
914
916
|
|
|
915
|
-
pred_label = auto_stage_gbm(EEG=EEG, EMG=EMG, sf=sf, EEG_channel=EEG_site)
|
|
917
|
+
pred_label = auto_stage_gbm(EEG=EEG, EMG=EMG, label=label, sf=sf, EEG_channel=EEG_site, mouse_age=mouse_age)
|
|
918
|
+
if self.SaveAnnoCheckbox.isChecked():
|
|
919
|
+
save_anno = True
|
|
920
|
+
else:
|
|
921
|
+
save_anno = False
|
|
916
922
|
|
|
917
|
-
return pred_label
|
|
923
|
+
return pred_label, save_anno
|
|
918
924
|
|
|
919
925
|
|
|
920
926
|
def okEvent(self):
|
|
@@ -1624,11 +1624,13 @@ class main_window(QMainWindow, Ui_MiSleep):
|
|
|
1624
1624
|
self.auto_stage_dialog.exec()
|
|
1625
1625
|
if self.auto_stage_dialog.closed:
|
|
1626
1626
|
return
|
|
1627
|
-
auto_stage_lst = self.auto_stage_dialog.auto_stage(self.midata)
|
|
1627
|
+
auto_stage_lst, save_anno = self.auto_stage_dialog.auto_stage(self.midata, self.mianno)
|
|
1628
1628
|
|
|
1629
1629
|
# Not sure which one is shorter, so get the minimum one
|
|
1630
1630
|
self.mianno._sleep_state[:min(len(self.mianno._sleep_state),len(auto_stage_lst))] = auto_stage_lst[:min(len(self.mianno._sleep_state),len(auto_stage_lst))]
|
|
1631
1631
|
|
|
1632
|
+
if save_anno:
|
|
1633
|
+
self.save_anno()
|
|
1632
1634
|
self.is_saved = False
|
|
1633
1635
|
self.AnnotationPathLabel.setText('*Annotation path:')
|
|
1634
1636
|
self.plot_signals()
|
|
@@ -1638,8 +1640,11 @@ class main_window(QMainWindow, Ui_MiSleep):
|
|
|
1638
1640
|
QMessageBox.about(self, "Error", "Auto stage ERROR")
|
|
1639
1641
|
return
|
|
1640
1642
|
|
|
1641
|
-
def save_anno(self):
|
|
1642
|
-
"""Save annotation into file
|
|
1643
|
+
def save_anno(self, just_save=False):
|
|
1644
|
+
"""Save annotation into file
|
|
1645
|
+
Just save: bool
|
|
1646
|
+
For when I only want to save a file but not cover the current labels
|
|
1647
|
+
"""
|
|
1643
1648
|
if self.anno_path == "":
|
|
1644
1649
|
anno_path, _ = QFileDialog.getOpenFileName(
|
|
1645
1650
|
self, "Select annotation file",
|
|
@@ -1649,15 +1654,15 @@ class main_window(QMainWindow, Ui_MiSleep):
|
|
|
1649
1654
|
|
|
1650
1655
|
if anno_path == "":
|
|
1651
1656
|
return
|
|
1652
|
-
|
|
1653
|
-
|
|
1657
|
+
if not just_save:
|
|
1658
|
+
self.anno_path = anno_path
|
|
1659
|
+
self.AnnoPathEdit.setText(self.anno_path)
|
|
1654
1660
|
|
|
1655
1661
|
save_thread = SaveThread(file=[self.mianno, self.midata],
|
|
1656
1662
|
file_path=self.anno_path)
|
|
1657
1663
|
saved = save_thread.save_anno()
|
|
1658
|
-
if saved:
|
|
1664
|
+
if saved and not just_save:
|
|
1659
1665
|
self.is_saved = True
|
|
1660
|
-
|
|
1661
1666
|
self.AnnotationPathLabel.setText('Annotation path:')
|
|
1662
1667
|
save_thread.quit()
|
|
1663
1668
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
|
|
3
|
-
# Form implementation generated from reading ui file '
|
|
3
|
+
# Form implementation generated from reading ui file './misleep/gui/uis/auto_stage_dialog.ui'
|
|
4
4
|
#
|
|
5
5
|
# Created by: PyQt5 UI code generator 5.15.9
|
|
6
6
|
#
|
|
@@ -14,7 +14,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
|
|
|
14
14
|
class Ui_AutoStageDialog(object):
|
|
15
15
|
def setupUi(self, AutoStageDialog):
|
|
16
16
|
AutoStageDialog.setObjectName("AutoStageDialog")
|
|
17
|
-
AutoStageDialog.resize(
|
|
17
|
+
AutoStageDialog.resize(408, 342)
|
|
18
18
|
icon = QtGui.QIcon()
|
|
19
19
|
icon.addPixmap(QtGui.QPixmap(":/logo/logo.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
|
20
20
|
AutoStageDialog.setWindowIcon(icon)
|
|
@@ -30,26 +30,38 @@ class Ui_AutoStageDialog(object):
|
|
|
30
30
|
self.groupBox.setObjectName("groupBox")
|
|
31
31
|
self.gridLayout_2 = QtWidgets.QGridLayout(self.groupBox)
|
|
32
32
|
self.gridLayout_2.setObjectName("gridLayout_2")
|
|
33
|
-
self.
|
|
34
|
-
self.
|
|
35
|
-
self.
|
|
33
|
+
self.AgeCombox = QtWidgets.QComboBox(self.groupBox)
|
|
34
|
+
self.AgeCombox.setObjectName("AgeCombox")
|
|
35
|
+
self.AgeCombox.addItem("")
|
|
36
|
+
self.AgeCombox.addItem("")
|
|
37
|
+
self.AgeCombox.addItem("")
|
|
38
|
+
self.gridLayout_2.addWidget(self.AgeCombox, 3, 1, 1, 2)
|
|
36
39
|
self.label = QtWidgets.QLabel(self.groupBox)
|
|
37
40
|
self.label.setObjectName("label")
|
|
38
41
|
self.gridLayout_2.addWidget(self.label, 0, 0, 1, 1)
|
|
39
|
-
self.
|
|
40
|
-
self.
|
|
41
|
-
self.gridLayout_2.addWidget(self.
|
|
42
|
+
self.label_3 = QtWidgets.QLabel(self.groupBox)
|
|
43
|
+
self.label_3.setObjectName("label_3")
|
|
44
|
+
self.gridLayout_2.addWidget(self.label_3, 3, 0, 1, 1)
|
|
42
45
|
self.EMGchannelCombox = QtWidgets.QComboBox(self.groupBox)
|
|
43
46
|
self.EMGchannelCombox.setObjectName("EMGchannelCombox")
|
|
44
47
|
self.gridLayout_2.addWidget(self.EMGchannelCombox, 1, 1, 1, 2)
|
|
45
48
|
self.EEGChannelCombox = QtWidgets.QComboBox(self.groupBox)
|
|
46
49
|
self.EEGChannelCombox.setObjectName("EEGChannelCombox")
|
|
47
50
|
self.gridLayout_2.addWidget(self.EEGChannelCombox, 0, 1, 1, 2)
|
|
51
|
+
self.label_2 = QtWidgets.QLabel(self.groupBox)
|
|
52
|
+
self.label_2.setObjectName("label_2")
|
|
53
|
+
self.gridLayout_2.addWidget(self.label_2, 2, 0, 1, 1)
|
|
54
|
+
self.label_8 = QtWidgets.QLabel(self.groupBox)
|
|
55
|
+
self.label_8.setObjectName("label_8")
|
|
56
|
+
self.gridLayout_2.addWidget(self.label_8, 1, 0, 1, 1)
|
|
48
57
|
self.EEGSiteCombox = QtWidgets.QComboBox(self.groupBox)
|
|
49
58
|
self.EEGSiteCombox.setObjectName("EEGSiteCombox")
|
|
50
59
|
self.EEGSiteCombox.addItem("")
|
|
51
60
|
self.EEGSiteCombox.addItem("")
|
|
52
61
|
self.gridLayout_2.addWidget(self.EEGSiteCombox, 2, 1, 1, 2)
|
|
62
|
+
self.SaveAnnoCheckbox = QtWidgets.QCheckBox(self.groupBox)
|
|
63
|
+
self.SaveAnnoCheckbox.setObjectName("SaveAnnoCheckbox")
|
|
64
|
+
self.gridLayout_2.addWidget(self.SaveAnnoCheckbox, 4, 0, 1, 3)
|
|
53
65
|
self.gridLayout.addWidget(self.groupBox, 0, 0, 1, 2)
|
|
54
66
|
|
|
55
67
|
self.retranslateUi(AutoStageDialog)
|
|
@@ -61,9 +73,14 @@ class Ui_AutoStageDialog(object):
|
|
|
61
73
|
self.OKBt.setText(_translate("AutoStageDialog", "Ok"))
|
|
62
74
|
self.CancelBt.setText(_translate("AutoStageDialog", "Cancel"))
|
|
63
75
|
self.groupBox.setTitle(_translate("AutoStageDialog", "Auto Stage options"))
|
|
64
|
-
self.
|
|
76
|
+
self.AgeCombox.setItemText(0, _translate("AutoStageDialog", "> P56"))
|
|
77
|
+
self.AgeCombox.setItemText(1, _translate("AutoStageDialog", "P30 - P56"))
|
|
78
|
+
self.AgeCombox.setItemText(2, _translate("AutoStageDialog", "< P30"))
|
|
65
79
|
self.label.setText(_translate("AutoStageDialog", "EEG channel:"))
|
|
80
|
+
self.label_3.setText(_translate("AutoStageDialog", "Mouse age:"))
|
|
81
|
+
self.label_2.setText(_translate("AutoStageDialog", "EEG site:"))
|
|
66
82
|
self.label_8.setText(_translate("AutoStageDialog", "EMG channel:"))
|
|
67
83
|
self.EEGSiteCombox.setItemText(0, _translate("AutoStageDialog", "Parietal"))
|
|
68
84
|
self.EEGSiteCombox.setItemText(1, _translate("AutoStageDialog", "Frontal"))
|
|
85
|
+
self.SaveAnnoCheckbox.setText(_translate("AutoStageDialog", "Cover current label"))
|
|
69
86
|
from misleep.gui.resources import misleep
|
|
@@ -135,6 +135,34 @@ def transfer_result(mianno, ac_time):
|
|
|
135
135
|
] = analyse_df[
|
|
136
136
|
['NREM_duration', 'NREM_bout', 'REM_duration', 'REM_bout', 'WAKE_duration',
|
|
137
137
|
'WAKE_bout', 'INIT_duration', 'INIT_bout']].astype(int)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
# gather the 12-h data to output the light phase and dark phase, set the first hour as ZT0 by default
|
|
141
|
+
|
|
142
|
+
try:
|
|
143
|
+
phase_data = pd.DataFrame()
|
|
144
|
+
phase_data['date_time'] = ['ZT0-ZT12', 'ZT12-ZT24']
|
|
145
|
+
phase_data['NREM_duration'] = [analyse_df['NREM_duration'].iloc[:12].sum(), analyse_df['NREM_duration'].iloc[12:24].sum()]
|
|
146
|
+
phase_data['NREM_bout'] = [analyse_df['NREM_bout'].iloc[:12].sum(), analyse_df['NREM_bout'].iloc[12:24].sum()]
|
|
147
|
+
phase_data['NREM_ave'] = phase_data.apply(lambda x: x['NREM_duration']/x['NREM_bout'] if x['NREM_bout']!=0 else 0, axis=1)
|
|
148
|
+
phase_data['NREM_percentage'] = phase_data.apply(lambda x: x['NREM_duration'] / 3600*12, axis=1)
|
|
149
|
+
phase_data['REM_duration'] = [analyse_df['REM_duration'].iloc[:12].sum(), analyse_df['REM_duration'].iloc[12:24].sum()]
|
|
150
|
+
phase_data['REM_bout'] = [analyse_df['REM_bout'].iloc[:12].sum(), analyse_df['REM_bout'].iloc[12:24].sum()]
|
|
151
|
+
phase_data['REM_ave'] = phase_data.apply(lambda x: x['REM_duration']/x['REM_bout'] if x['REM_bout']!=0 else 0, axis=1)
|
|
152
|
+
phase_data['REM_percentage'] = phase_data.apply(lambda x: x['REM_duration'] / 3600*12, axis=1)
|
|
153
|
+
phase_data['WAKE_duration'] = [analyse_df['WAKE_duration'].iloc[:12].sum(), analyse_df['WAKE_duration'].iloc[12:24].sum()]
|
|
154
|
+
phase_data['WAKE_bout'] = [analyse_df['WAKE_bout'].iloc[:12].sum(), analyse_df['WAKE_bout'].iloc[12:24].sum()]
|
|
155
|
+
phase_data['WAKE_ave'] = phase_data.apply(lambda x: x['WAKE_duration']/x['WAKE_bout'] if x['WAKE_bout']!=0 else 0, axis=1)
|
|
156
|
+
phase_data['WAKE_percentage'] = phase_data.apply(lambda x: x['WAKE_duration'] / 3600*12, axis=1)
|
|
157
|
+
phase_data['INIT_duration'] = [analyse_df['INIT_duration'].iloc[:12].sum(), analyse_df['INIT_duration'].iloc[12:24].sum()]
|
|
158
|
+
phase_data['INIT_bout'] = [analyse_df['INIT_bout'].iloc[:12].sum(), analyse_df['INIT_bout'].iloc[12:24].sum()]
|
|
159
|
+
phase_data['INIT_ave'] = phase_data.apply(lambda x: x['INIT_duration']/x['INIT_bout'] if x['INIT_bout']!=0 else 0, axis=1)
|
|
160
|
+
phase_data['INIT_percentage'] = phase_data.apply(lambda x: x['INIT_duration'] / 3600*12, axis=1)
|
|
161
|
+
|
|
162
|
+
analyse_df = pd.concat([analyse_df, phase_data])
|
|
163
|
+
analyse_df.reset_index(inplace=True)
|
|
164
|
+
except Exception as e:
|
|
165
|
+
pass
|
|
138
166
|
|
|
139
167
|
start_end_df = pd.DataFrame(start_end_label,
|
|
140
168
|
columns=['start_time', 'start_time_sec',
|
|
@@ -11,10 +11,13 @@ misleep.egg-info/requires.txt
|
|
|
11
11
|
misleep.egg-info/top_level.txt
|
|
12
12
|
misleep/analysis/__init__.py
|
|
13
13
|
misleep/analysis/auto_stage.py
|
|
14
|
-
misleep/analysis/classification.py
|
|
15
14
|
misleep/analysis/detection.py
|
|
16
|
-
misleep/analysis/auto_stage_model/
|
|
17
|
-
misleep/analysis/auto_stage_model/
|
|
15
|
+
misleep/analysis/auto_stage_model/P30_EEG_F_lightgbm.pkl
|
|
16
|
+
misleep/analysis/auto_stage_model/P30_EEG_P_lightgbm.pkl
|
|
17
|
+
misleep/analysis/auto_stage_model/ado_EEG_F_lightgbm.pkl
|
|
18
|
+
misleep/analysis/auto_stage_model/ado_EEG_P_lightgbm.pkl
|
|
19
|
+
misleep/analysis/auto_stage_model/adult_EEG_F_lightgbm.pkl
|
|
20
|
+
misleep/analysis/auto_stage_model/adult_EEG_P_lightgbm.pkl
|
|
18
21
|
misleep/gui/__init__.py
|
|
19
22
|
misleep/gui/about.py
|
|
20
23
|
misleep/gui/dialog.py
|
|
@@ -11,7 +11,7 @@ MAINTAINER_EMAIL = "swang@gmail.com"
|
|
|
11
11
|
URL = "https://github.com/BryanWang0702/MiSleep/"
|
|
12
12
|
LICENSE = "BSD (3-clause)"
|
|
13
13
|
DOWNLOAD_URL = "https://github.com/BryanWang0702/MiSleep/"
|
|
14
|
-
VERSION = "0.2.
|
|
14
|
+
VERSION = "0.2.4"
|
|
15
15
|
|
|
16
16
|
INSTALL_REQUIRES = [
|
|
17
17
|
"numpy>=1.18.1",
|
|
@@ -51,8 +51,12 @@ DATA_FILES = [
|
|
|
51
51
|
"misleep/gui/resources/misleep.qrc",
|
|
52
52
|
"misleep/gui/resources/logo.png",
|
|
53
53
|
"misleep/gui/resources/entire_logo.png",
|
|
54
|
-
"misleep/analysis/auto_stage_model/
|
|
55
|
-
"misleep/analysis/auto_stage_model/
|
|
54
|
+
"misleep/analysis/auto_stage_model/adult_EEG_F_lightgbm.pkl",
|
|
55
|
+
"misleep/analysis/auto_stage_model/adult_EEG_P_lightgbm.pkl",
|
|
56
|
+
"misleep/analysis/auto_stage_model/ado_EEG_F_lightgbm.pkl",
|
|
57
|
+
"misleep/analysis/auto_stage_model/ado_EEG_P_lightgbm.pkl",
|
|
58
|
+
"misleep/analysis/auto_stage_model/P30_EEG_F_lightgbm.pkl",
|
|
59
|
+
"misleep/analysis/auto_stage_model/P30_EEG_P_lightgbm.pkl"
|
|
56
60
|
],
|
|
57
61
|
)
|
|
58
62
|
]
|
|
Binary file
|
|
Binary file
|
|
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
|
|
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
|
|
File without changes
|