Spaces:
Sleeping
Sleeping
Commit
·
7a54f74
1
Parent(s):
29201f7
update css
Browse files- app.py +116 -76
- channel_mapping.py +40 -43
app.py
CHANGED
@@ -34,7 +34,7 @@ If your data doesn't contain all of the mentioned channels, there are 3 imputati
|
|
34 |
Firstly, we will attempt to find neighboring channel to use as alternative. For instance, if the required channel is **FC3** but you only have **FC1**, we will use it as a replacement for **FC3**.
|
35 |
Then, depending on the **Imputation** way you chose, we will:
|
36 |
- **zero**: fill the missing channels with zeros.
|
37 |
-
- **adjacent**: fill the missing channels using neighboring channels which are located closer to the center. For example, if the required channel is **
|
38 |
>Note: The imputed channels **need to be removed** after the data being reconstructed.
|
39 |
|
40 |
### Mapping result
|
@@ -63,6 +63,39 @@ icunet = """
|
|
63 |
Electroencephalography (EEG) signals are often contaminated with artifacts. It is imperative to develop a practical and reliable artifact removal method to prevent the misinterpretation of neural signals and the underperformance of brain–computer interfaces. Based on the U-Net architecture, we developed a new artifact removal model, IC-U-Net, for removing pervasive EEG artifacts and reconstructing brain signals. IC-U-Net was trained using mixtures of brain and non-brain components decomposed by independent component analysis. It uses an ensemble of loss functions to model complex signal fluctuations in EEG recordings. The effectiveness of the proposed method in recovering brain activities and removing various artifacts (e.g., eye blinks/movements, muscle activities, and line/channel noise) was demonstrated in a simulation study and four real-world EEG experiments. IC-U-Net can reconstruct a multi-channel EEG signal and is applicable to most artifact types, offering a promising end-to-end solution for automatically removing artifacts from EEG recordings. It also meets the increasing need to image natural brain dynamics in a mobile setting.
|
64 |
"""
|
65 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
66 |
|
67 |
with gr.Blocks() as demo:
|
68 |
|
@@ -71,8 +104,7 @@ with gr.Blocks() as demo:
|
|
71 |
with gr.Row():
|
72 |
gr.Markdown(
|
73 |
"""
|
74 |
-
|
75 |
-
(...)
|
76 |
"""
|
77 |
)
|
78 |
with gr.Row():
|
@@ -100,29 +132,17 @@ with gr.Blocks() as demo:
|
|
100 |
""",
|
101 |
visible=False
|
102 |
)
|
103 |
-
#chk_md = gr.Markdown(
|
104 |
-
# """
|
105 |
-
# select...
|
106 |
-
# """,
|
107 |
-
# visible=False
|
108 |
-
# )
|
109 |
with gr.Row():
|
110 |
tpl_montage = gr.Image("./template_montage.png", label="Template montage", visible=False)
|
111 |
map_montage = gr.Image(label="Choosen channels", visible=False)
|
112 |
-
|
113 |
-
|
114 |
-
with gr.Column():
|
115 |
-
#chk_block = gr.HTML(chk_html)
|
116 |
-
#in_montage = gr.Image(label="Input montage")
|
117 |
-
chs_chkbox = gr.CheckboxGroup(elem_classes="chs-chkbox", label="")
|
118 |
-
next_btn = gr.Button("Next", interactive=False)
|
119 |
miss_txtbox = gr.Textbox(label="Missing channels", visible=False)
|
120 |
tpl_loc_file = gr.File("./template_chanlocs.loc", show_label=False, visible=False)
|
121 |
-
#test_file = gr.File(label="test")
|
122 |
with gr.Column():
|
123 |
gr.Markdown(
|
124 |
"""
|
125 |
-
# 2.Decode Data
|
126 |
"""
|
127 |
)
|
128 |
with gr.Row():
|
@@ -146,7 +166,7 @@ with gr.Blocks() as demo:
|
|
146 |
with gr.Tab("QuickStart"):
|
147 |
gr.Markdown(quickstart)
|
148 |
|
149 |
-
#demo.load(js=
|
150 |
|
151 |
def reset_layout(raw_data):
|
152 |
# establish temp folder
|
@@ -157,15 +177,16 @@ with gr.Blocks() as demo:
|
|
157 |
utils.dataDelete(filepath+"/temp_data/")
|
158 |
os.mkdir(filepath+"/temp_data/")
|
159 |
#print(e)
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
|
|
|
|
165 |
run_btn : gr.Button(interactive=False),
|
166 |
tpl_montage : gr.Image(visible=False),
|
167 |
-
map_montage : gr.Image(value=None, visible=False),
|
168 |
-
in_montage : gr.Image(value=None, visible=False),
|
169 |
miss_txtbox : gr.Textbox(visible=False),
|
170 |
res_md : gr.Markdown(visible=False),
|
171 |
tpl_loc_file : gr.File(visible=False)}
|
@@ -181,7 +202,7 @@ with gr.Blocks() as demo:
|
|
181 |
})
|
182 |
#print("Missing channels:", state_obj["missingChannelsIndex"])
|
183 |
return {state_json : state_obj,
|
184 |
-
|
185 |
else:
|
186 |
reorder_data(raw_data, channels_obj["newOrder"], fill_mode, state_obj)
|
187 |
|
@@ -202,23 +223,29 @@ with gr.Blocks() as demo:
|
|
202 |
def show_montage(state_obj, raw_loc):
|
203 |
filepath = state_obj["filepath"]
|
204 |
raw_montage = read_custom_montage(raw_loc)
|
|
|
|
|
205 |
for i in range(len(raw_montage.ch_names)):
|
206 |
channel = raw_montage.ch_names[i]
|
207 |
raw_montage.rename_channels({channel: str.upper(channel)})
|
208 |
|
209 |
if state_obj["state"] == "initializing":
|
210 |
filename = filepath+"raw_montage_"+str(random.randint(1,10000))+".png"
|
|
|
211 |
raw_fig = raw_montage.plot()
|
212 |
-
raw_fig.
|
|
|
213 |
|
214 |
-
return {
|
215 |
-
|
216 |
-
|
|
|
217 |
|
218 |
elif state_obj["state"] == "finished":
|
219 |
# didn't find any way to hide the dark points...
|
220 |
# tmp
|
221 |
filename = filepath+"mapped_montage_"+str(random.randint(1,10000))+".png"
|
|
|
222 |
|
223 |
show_names= []
|
224 |
for channel in state_obj["inputByName"]:
|
@@ -227,36 +254,37 @@ with gr.Blocks() as demo:
|
|
227 |
continue
|
228 |
show_names.append(channel)
|
229 |
mapped_fig = raw_montage.plot(show_names=show_names)
|
230 |
-
mapped_fig.
|
|
|
231 |
|
232 |
-
return {
|
233 |
-
|
234 |
-
map_montage : gr.Image(value=filename, visible=True)}
|
235 |
|
236 |
elif state_obj["state"] == "selecting":
|
237 |
-
#
|
238 |
-
return {in_montage : gr.Image()}
|
|
|
239 |
|
240 |
def generate_chkbox(state_obj):
|
241 |
if state_obj["state"] == "initializing":
|
242 |
in_channels = [channel for channel in state_obj["inputByName"]]
|
243 |
state_obj["state"] = "selecting"
|
244 |
-
# and img....?
|
245 |
|
246 |
first_idx = state_obj["missingChannelsIndex"][0]
|
247 |
first_name = state_obj["templateByIndex"][first_idx]
|
248 |
chkbox_label = first_name+' (1/'+str(state_obj["totalFillingNum"]+1)+')'
|
249 |
return {state_json : state_obj,
|
250 |
-
chs_chkbox : gr.CheckboxGroup(choices=in_channels, label=chkbox_label),
|
251 |
next_btn : gr.Button(interactive=True)}
|
252 |
else:
|
253 |
-
return {state_json :
|
254 |
|
255 |
|
256 |
map_btn.click(
|
257 |
fn = reset_layout,
|
258 |
inputs = in_raw_data,
|
259 |
-
outputs = [state_json,
|
260 |
res_md, tpl_loc_file]
|
261 |
|
262 |
).success(
|
@@ -267,67 +295,79 @@ with gr.Blocks() as demo:
|
|
267 |
).success(
|
268 |
fn = mapping_result,
|
269 |
inputs = [state_json, channels_json, in_raw_data, in_fill_mode],
|
270 |
-
outputs = [state_json,
|
271 |
|
272 |
).success(
|
273 |
fn = show_montage,
|
274 |
inputs = [state_json, in_raw_loc],
|
275 |
-
outputs = [
|
276 |
|
277 |
).success(
|
278 |
fn = generate_chkbox,
|
279 |
inputs = state_json,
|
280 |
outputs = [state_json, chs_chkbox, next_btn]
|
|
|
|
|
|
|
|
|
|
|
281 |
)
|
282 |
|
283 |
|
284 |
def check_next(state_obj, selected, raw_data, fill_mode):
|
285 |
if state_obj["state"] == "selecting":
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
286 |
if state_obj["fillingCount"] <= state_obj["totalFillingNum"]:
|
|
|
|
|
|
|
|
|
287 |
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
state_obj["newOrder"]
|
294 |
-
|
295 |
-
print('Selection for missing channel "{}"({}): {}'.format(prev_target_name, prev_target_idx, selected))
|
296 |
|
297 |
-
|
298 |
-
state_obj["
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
chkbox_label = target_name+' ('+str(state_obj["fillingCount"]+1)+'/'+str(state_obj["totalFillingNum"]+1)+')'
|
303 |
-
btn_label = "Submit" if state_obj["fillingCount"]==state_obj["totalFillingNum"] else "Next"
|
304 |
-
|
305 |
-
return {state_json : state_obj,
|
306 |
-
chs_chkbox : gr.CheckboxGroup(value=[], label=chkbox_label),
|
307 |
-
next_btn : gr.Button(btn_label)}
|
308 |
-
else:
|
309 |
-
state_obj["state"] = "finished"
|
310 |
-
reorder_data(raw_data, state_obj["newOrder"], fill_mode, state_obj)
|
311 |
-
|
312 |
-
missing_channels = [state_obj["templateByIndex"][idx] for idx in state_obj["missingChannelsIndex"]]
|
313 |
-
missing_channels = ', '.join(missing_channels)
|
314 |
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
|
|
321 |
|
322 |
next_btn.click(
|
323 |
fn = check_next,
|
324 |
inputs = [state_json, chs_chkbox, in_raw_data, in_fill_mode],
|
325 |
-
outputs = [state_json,
|
326 |
|
327 |
).success(
|
328 |
fn = show_montage,
|
329 |
inputs = [state_json, in_raw_loc],
|
330 |
-
outputs = [
|
331 |
)
|
332 |
|
333 |
|
|
|
34 |
Firstly, we will attempt to find neighboring channel to use as alternative. For instance, if the required channel is **FC3** but you only have **FC1**, we will use it as a replacement for **FC3**.
|
35 |
Then, depending on the **Imputation** way you chose, we will:
|
36 |
- **zero**: fill the missing channels with zeros.
|
37 |
+
- **adjacent**: fill the missing channels using neighboring channels which are located closer to the center. For example, if the required channel is **FC3** but you only have **F3, C3**, then we will choose **C3** as the imputing value for **FC3**.
|
38 |
>Note: The imputed channels **need to be removed** after the data being reconstructed.
|
39 |
|
40 |
### Mapping result
|
|
|
63 |
Electroencephalography (EEG) signals are often contaminated with artifacts. It is imperative to develop a practical and reliable artifact removal method to prevent the misinterpretation of neural signals and the underperformance of brain–computer interfaces. Based on the U-Net architecture, we developed a new artifact removal model, IC-U-Net, for removing pervasive EEG artifacts and reconstructing brain signals. IC-U-Net was trained using mixtures of brain and non-brain components decomposed by independent component analysis. It uses an ensemble of loss functions to model complex signal fluctuations in EEG recordings. The effectiveness of the proposed method in recovering brain activities and removing various artifacts (e.g., eye blinks/movements, muscle activities, and line/channel noise) was demonstrated in a simulation study and four real-world EEG experiments. IC-U-Net can reconstruct a multi-channel EEG signal and is applicable to most artifact types, offering a promising end-to-end solution for automatically removing artifacts from EEG recordings. It also meets the increasing need to image natural brain dynamics in a mobile setting.
|
64 |
"""
|
65 |
|
66 |
+
chkbox_js = """
|
67 |
+
(state_json) => {
|
68 |
+
state_json = JSON.parse(JSON.stringify(state_json));
|
69 |
+
if(state_json.state == "finished") return;
|
70 |
+
|
71 |
+
document.querySelector("#chs-chkbox>div:nth-of-type(2)").style.cssText = `
|
72 |
+
position: relative;
|
73 |
+
width: 560px;
|
74 |
+
height: 560px;
|
75 |
+
background: url("file=${state_json.files.raw_montage}");
|
76 |
+
`;
|
77 |
+
|
78 |
+
let all_chkbox = document.querySelectorAll("#chs-chkbox> div:nth-of-type(2)> label");
|
79 |
+
all_chkbox = Array.apply(null, all_chkbox);
|
80 |
+
|
81 |
+
all_chkbox.forEach((item, index) => {
|
82 |
+
let channel = state_json.inputByIndex[index];
|
83 |
+
let left = state_json.inputByName[channel].css_position[0];
|
84 |
+
let bottom = state_json.inputByName[channel].css_position[1];
|
85 |
+
//console.log(`left: ${left}, bottom: ${bottom}`);
|
86 |
+
|
87 |
+
item.style.cssText = `
|
88 |
+
position: absolute;
|
89 |
+
left: ${left};
|
90 |
+
bottom: ${bottom};
|
91 |
+
`;
|
92 |
+
item.className = "";
|
93 |
+
item.querySelector("span").innerText = "";
|
94 |
+
});
|
95 |
+
|
96 |
+
}
|
97 |
+
"""
|
98 |
+
|
99 |
|
100 |
with gr.Blocks() as demo:
|
101 |
|
|
|
104 |
with gr.Row():
|
105 |
gr.Markdown(
|
106 |
"""
|
107 |
+
|
|
|
108 |
"""
|
109 |
)
|
110 |
with gr.Row():
|
|
|
132 |
""",
|
133 |
visible=False
|
134 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
135 |
with gr.Row():
|
136 |
tpl_montage = gr.Image("./template_montage.png", label="Template montage", visible=False)
|
137 |
map_montage = gr.Image(label="Choosen channels", visible=False)
|
138 |
+
chs_chkbox = gr.CheckboxGroup(elem_id="chs-chkbox", label="", visible=False)
|
139 |
+
next_btn = gr.Button("Next", interactive=False, visible=False)
|
|
|
|
|
|
|
|
|
|
|
140 |
miss_txtbox = gr.Textbox(label="Missing channels", visible=False)
|
141 |
tpl_loc_file = gr.File("./template_chanlocs.loc", show_label=False, visible=False)
|
|
|
142 |
with gr.Column():
|
143 |
gr.Markdown(
|
144 |
"""
|
145 |
+
# 2.Decode Data
|
146 |
"""
|
147 |
)
|
148 |
with gr.Row():
|
|
|
166 |
with gr.Tab("QuickStart"):
|
167 |
gr.Markdown(quickstart)
|
168 |
|
169 |
+
#demo.load(js=js)
|
170 |
|
171 |
def reset_layout(raw_data):
|
172 |
# establish temp folder
|
|
|
177 |
utils.dataDelete(filepath+"/temp_data/")
|
178 |
os.mkdir(filepath+"/temp_data/")
|
179 |
#print(e)
|
180 |
+
state_obj = {
|
181 |
+
"filepath": filepath+"/temp_data/",
|
182 |
+
"files": {}
|
183 |
+
}
|
184 |
+
return {state_json : state_obj,
|
185 |
+
chs_chkbox : gr.CheckboxGroup(choices=[], value=[], label="", visible=False), # choices, value ???
|
186 |
+
next_btn : gr.Button("Next", interactive=False, visible=False),
|
187 |
run_btn : gr.Button(interactive=False),
|
188 |
tpl_montage : gr.Image(visible=False),
|
189 |
+
map_montage : gr.Image(value=None, visible=False),
|
|
|
190 |
miss_txtbox : gr.Textbox(visible=False),
|
191 |
res_md : gr.Markdown(visible=False),
|
192 |
tpl_loc_file : gr.File(visible=False)}
|
|
|
202 |
})
|
203 |
#print("Missing channels:", state_obj["missingChannelsIndex"])
|
204 |
return {state_json : state_obj,
|
205 |
+
next_btn : gr.Button(visible=True)}
|
206 |
else:
|
207 |
reorder_data(raw_data, channels_obj["newOrder"], fill_mode, state_obj)
|
208 |
|
|
|
223 |
def show_montage(state_obj, raw_loc):
|
224 |
filepath = state_obj["filepath"]
|
225 |
raw_montage = read_custom_montage(raw_loc)
|
226 |
+
|
227 |
+
# convert all channel names to uppercase
|
228 |
for i in range(len(raw_montage.ch_names)):
|
229 |
channel = raw_montage.ch_names[i]
|
230 |
raw_montage.rename_channels({channel: str.upper(channel)})
|
231 |
|
232 |
if state_obj["state"] == "initializing":
|
233 |
filename = filepath+"raw_montage_"+str(random.randint(1,10000))+".png"
|
234 |
+
state_obj["files"]["raw_montage"] = filename
|
235 |
raw_fig = raw_montage.plot()
|
236 |
+
raw_fig.set_size_inches(5.6, 5.6)
|
237 |
+
raw_fig.savefig(filename, pad_inches=0)
|
238 |
|
239 |
+
return {state_json : state_obj}#,
|
240 |
+
#tpl_montage : gr.Image(visible=True),
|
241 |
+
#in_montage : gr.Image(value=filename, visible=True),
|
242 |
+
#map_montage : gr.Image(visible=False)}
|
243 |
|
244 |
elif state_obj["state"] == "finished":
|
245 |
# didn't find any way to hide the dark points...
|
246 |
# tmp
|
247 |
filename = filepath+"mapped_montage_"+str(random.randint(1,10000))+".png"
|
248 |
+
state_obj["files"]["map_montage"] = filename
|
249 |
|
250 |
show_names= []
|
251 |
for channel in state_obj["inputByName"]:
|
|
|
254 |
continue
|
255 |
show_names.append(channel)
|
256 |
mapped_fig = raw_montage.plot(show_names=show_names)
|
257 |
+
mapped_fig.set_size_inches(5.6, 5.6)
|
258 |
+
mapped_fig.savefig(filename, pad_inches=0)
|
259 |
|
260 |
+
return {state_json : state_obj,
|
261 |
+
tpl_montage : gr.Image(visible=True),
|
262 |
+
map_montage : gr.Image(value=filename, visible=True)}
|
263 |
|
264 |
elif state_obj["state"] == "selecting":
|
265 |
+
# update in_montage here ?
|
266 |
+
#return {in_montage : gr.Image()}
|
267 |
+
return {state_json : state_obj}
|
268 |
|
269 |
def generate_chkbox(state_obj):
|
270 |
if state_obj["state"] == "initializing":
|
271 |
in_channels = [channel for channel in state_obj["inputByName"]]
|
272 |
state_obj["state"] = "selecting"
|
|
|
273 |
|
274 |
first_idx = state_obj["missingChannelsIndex"][0]
|
275 |
first_name = state_obj["templateByIndex"][first_idx]
|
276 |
chkbox_label = first_name+' (1/'+str(state_obj["totalFillingNum"]+1)+')'
|
277 |
return {state_json : state_obj,
|
278 |
+
chs_chkbox : gr.CheckboxGroup(choices=in_channels, label=chkbox_label, visible=True),
|
279 |
next_btn : gr.Button(interactive=True)}
|
280 |
else:
|
281 |
+
return {state_json : state_obj}
|
282 |
|
283 |
|
284 |
map_btn.click(
|
285 |
fn = reset_layout,
|
286 |
inputs = in_raw_data,
|
287 |
+
outputs = [state_json, chs_chkbox, next_btn, run_btn, tpl_montage, map_montage, miss_txtbox,
|
288 |
res_md, tpl_loc_file]
|
289 |
|
290 |
).success(
|
|
|
295 |
).success(
|
296 |
fn = mapping_result,
|
297 |
inputs = [state_json, channels_json, in_raw_data, in_fill_mode],
|
298 |
+
outputs = [state_json, chs_chkbox, next_btn, miss_txtbox, res_md, tpl_loc_file, run_btn]
|
299 |
|
300 |
).success(
|
301 |
fn = show_montage,
|
302 |
inputs = [state_json, in_raw_loc],
|
303 |
+
outputs = [state_json, tpl_montage, map_montage]
|
304 |
|
305 |
).success(
|
306 |
fn = generate_chkbox,
|
307 |
inputs = state_json,
|
308 |
outputs = [state_json, chs_chkbox, next_btn]
|
309 |
+
).success(
|
310 |
+
fn = None,
|
311 |
+
js = chkbox_js,
|
312 |
+
inputs = state_json,
|
313 |
+
outputs = []
|
314 |
)
|
315 |
|
316 |
|
317 |
def check_next(state_obj, selected, raw_data, fill_mode):
|
318 |
if state_obj["state"] == "selecting":
|
319 |
+
|
320 |
+
# save info before clicking on next_btn
|
321 |
+
prev_target_idx = state_obj["missingChannelsIndex"][state_obj["fillingCount"]]
|
322 |
+
prev_target_name = state_obj["templateByIndex"][prev_target_idx]
|
323 |
+
|
324 |
+
selected_idx = [state_obj["inputByName"][channel]["index"] for channel in selected]
|
325 |
+
state_obj["newOrder"][prev_target_idx] = selected_idx
|
326 |
+
|
327 |
+
if len(selected)==1 and state_obj["inputByName"][selected[0]]["used"]==False:
|
328 |
+
state_obj["inputByName"][selected[0]]["used"] = True
|
329 |
+
state_obj["missingChannelsIndex"][state_obj["fillingCount"]] = -1
|
330 |
+
|
331 |
+
print('Selection for missing channel "{}"({}): {}'.format(prev_target_name, prev_target_idx, selected))
|
332 |
+
|
333 |
+
# update next round
|
334 |
+
state_obj["fillingCount"] += 1
|
335 |
if state_obj["fillingCount"] <= state_obj["totalFillingNum"]:
|
336 |
+
target_idx = state_obj["missingChannelsIndex"][state_obj["fillingCount"]]
|
337 |
+
target_name = state_obj["templateByIndex"][target_idx]
|
338 |
+
chkbox_label = target_name+' ('+str(state_obj["fillingCount"]+1)+'/'+str(state_obj["totalFillingNum"]+1)+')'
|
339 |
+
btn_label = "Submit" if state_obj["fillingCount"]==state_obj["totalFillingNum"] else "Next"
|
340 |
|
341 |
+
return {state_json : state_obj,
|
342 |
+
chs_chkbox : gr.CheckboxGroup(value=[], label=chkbox_label),
|
343 |
+
next_btn : gr.Button(btn_label)}
|
344 |
+
else:
|
345 |
+
state_obj["state"] = "finished"
|
346 |
+
reorder_data(raw_data, state_obj["newOrder"], fill_mode, state_obj)
|
|
|
|
|
347 |
|
348 |
+
missing_channels = []
|
349 |
+
for idx in state_obj["missingChannelsIndex"]:
|
350 |
+
if idx != -1:
|
351 |
+
missing_channels.append(state_obj["templateByIndex"][idx])
|
352 |
+
missing_channels = ', '.join(missing_channels)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
353 |
|
354 |
+
return {state_json : state_obj,
|
355 |
+
chs_chkbox : gr.CheckboxGroup(visible=False),
|
356 |
+
next_btn : gr.Button(visible=False),
|
357 |
+
res_md : gr.Markdown(visible=True),
|
358 |
+
miss_txtbox : gr.Textbox(value=missing_channels, visible=True),
|
359 |
+
tpl_loc_file : gr.File(visible=True),
|
360 |
+
run_btn : gr.Button(interactive=True)}
|
361 |
|
362 |
next_btn.click(
|
363 |
fn = check_next,
|
364 |
inputs = [state_json, chs_chkbox, in_raw_data, in_fill_mode],
|
365 |
+
outputs = [state_json, chs_chkbox, next_btn, run_btn, res_md, miss_txtbox, tpl_loc_file]
|
366 |
|
367 |
).success(
|
368 |
fn = show_montage,
|
369 |
inputs = [state_json, in_raw_loc],
|
370 |
+
outputs = [state_json, tpl_montage, map_montage]
|
371 |
)
|
372 |
|
373 |
|
channel_mapping.py
CHANGED
@@ -7,7 +7,6 @@ import mne
|
|
7 |
from mne.channels import read_custom_montage
|
8 |
|
9 |
def reorder_data(filename, old_idx, fill_mode, state_obj):
|
10 |
-
#filepath = os.path.dirname(str(filename))
|
11 |
old_data = utils.read_train_data(filename)
|
12 |
new_data = np.zeros((30, old_data.shape[1]))
|
13 |
new_filename = state_obj["filepath"]+'mapped.csv'
|
@@ -27,21 +26,21 @@ def reorder_data(filename, old_idx, fill_mode, state_obj):
|
|
27 |
new_data[i, :] = np.mean(tmp_data, axis=0)
|
28 |
|
29 |
#print('new data shape: ', new_data.shape)
|
30 |
-
#utils.save_data(new_data, filepath+'/temp_data/mapped.csv')
|
31 |
utils.save_data(new_data, new_filename)
|
32 |
return
|
33 |
|
34 |
|
35 |
class Channel:
|
36 |
|
37 |
-
def __init__(self, index, name=None, used=False, coord=None, topo_index=None,
|
38 |
|
39 |
self.name = name
|
40 |
self.index = index
|
41 |
self.used = used
|
42 |
self.coord = coord
|
|
|
43 |
self.topo_index = topo_index
|
44 |
-
self.
|
45 |
|
46 |
def prefix(self):
|
47 |
ret = ''.join(filter(str.isalpha, self.name))
|
@@ -52,10 +51,6 @@ class Channel:
|
|
52 |
|
53 |
|
54 |
def pack_data(new_idx, missing_channels, tpl_dict, in_dict, tpl_ordered_name, in_ordered_name):
|
55 |
-
|
56 |
-
# tmp...
|
57 |
-
for ch in in_dict:
|
58 |
-
in_dict[ch].coord = None
|
59 |
|
60 |
return {
|
61 |
"newOrder" : [([i] if i!=-1 else []) for i in new_idx],
|
@@ -71,32 +66,41 @@ def mapping(data_file, loc_file, fill_mode):
|
|
71 |
|
72 |
data = utils.read_train_data(data_file)
|
73 |
|
|
|
|
|
74 |
template_montage = read_custom_montage("./template_chanlocs.loc")
|
75 |
input_montage = read_custom_montage(loc_file)
|
76 |
-
#template_montage.plot()
|
77 |
-
#input_montage.plot()
|
78 |
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
for i in range(
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
98 |
new_idx = [-1]*30
|
99 |
-
#new_idx_name = ['']*30 # tmp
|
100 |
missing_channels = []
|
101 |
exact_missing_channels = []
|
102 |
z_row_idx = data.shape[0]
|
@@ -113,7 +117,7 @@ def mapping(data_file, loc_file, fill_mode):
|
|
113 |
'T6': 'P8',
|
114 |
'TP7': 'T5\'',
|
115 |
'TP8': 'T6\'',
|
116 |
-
|
117 |
|
118 |
for i in range(30):
|
119 |
channel = template_montage.ch_names[i]
|
@@ -134,16 +138,13 @@ def mapping(data_file, loc_file, fill_mode):
|
|
134 |
continue
|
135 |
|
136 |
new_idx[i] = input_dict[channel].index
|
137 |
-
#new_idx_name[i] = channel # tmp
|
138 |
input_dict[channel].used = True
|
139 |
|
140 |
if finish_flag == 1:
|
141 |
second2 = time.time()
|
142 |
print('Finish at stage 1 ! (',second2 - second1,'s)')
|
143 |
-
print('new idx order:', new_idx)
|
144 |
-
#print('new_idx_name:', new_idx_name) # tmp
|
145 |
|
146 |
-
#reorder_data(input_file, new_idx, fill_mode)
|
147 |
channels_obj = pack_data(new_idx, [],
|
148 |
template_dict, input_dict,
|
149 |
template_montage.ch_names, input_montage.ch_names)
|
@@ -180,7 +181,7 @@ def mapping(data_file, loc_file, fill_mode):
|
|
180 |
ver = 'front' if i<3 else 'center' if i==3 else 'back'
|
181 |
hor = 'left' if j<2 else 'center' if j==2 else 'right'
|
182 |
template_dict[channel].topo_index = [i, j]
|
183 |
-
template_dict[channel].
|
184 |
|
185 |
if i > 1 and j in [0, 4]:
|
186 |
temporal_channels.append(channel)
|
@@ -217,8 +218,8 @@ def mapping(data_file, loc_file, fill_mode):
|
|
217 |
|
218 |
curr_row = template_dict[channel].topo_index[0]
|
219 |
curr_col = template_dict[channel].topo_index[1]
|
220 |
-
curr_ver = template_dict[channel].
|
221 |
-
curr_hor = template_dict[channel].
|
222 |
|
223 |
impute_channel = ''
|
224 |
|
@@ -257,7 +258,6 @@ def mapping(data_file, loc_file, fill_mode):
|
|
257 |
elif curr_hor == 'left' or curr_hor == 'right':
|
258 |
|
259 |
ver_ctrl = 1 if curr_ver=='front' else 2 if curr_ver=='back' else 3 # bit0: row+1, bit1: row-1
|
260 |
-
#ver_dir = 1 if curr_ver == 'front' else -1
|
261 |
|
262 |
# search horizontally
|
263 |
cnt = 0
|
@@ -293,16 +293,13 @@ def mapping(data_file, loc_file, fill_mode):
|
|
293 |
impute_channel = 'CZ'
|
294 |
|
295 |
new_idx[i] = input_dict[impute_channel].index
|
296 |
-
#new_idx_name[i] = impute_channel # tmp
|
297 |
if input_dict[impute_channel].used == True: # this channel is shared with others
|
298 |
missing_channels.append(i)
|
299 |
input_dict[impute_channel].used = True
|
300 |
|
301 |
second2 = time.time()
|
302 |
print('Finish at stage 2 ! (',second2 - second1,'s)')
|
303 |
-
print('new_idx:', new_idx)
|
304 |
-
#print('missing_channels:', missing_channels)
|
305 |
-
#reorder_data(input_file, new_idx, fill_mode)
|
306 |
|
307 |
channels_obj = pack_data(new_idx, missing_channels,
|
308 |
template_dict, input_dict,
|
|
|
7 |
from mne.channels import read_custom_montage
|
8 |
|
9 |
def reorder_data(filename, old_idx, fill_mode, state_obj):
|
|
|
10 |
old_data = utils.read_train_data(filename)
|
11 |
new_data = np.zeros((30, old_data.shape[1]))
|
12 |
new_filename = state_obj["filepath"]+'mapped.csv'
|
|
|
26 |
new_data[i, :] = np.mean(tmp_data, axis=0)
|
27 |
|
28 |
#print('new data shape: ', new_data.shape)
|
|
|
29 |
utils.save_data(new_data, new_filename)
|
30 |
return
|
31 |
|
32 |
|
33 |
class Channel:
|
34 |
|
35 |
+
def __init__(self, index, name=None, used=False, coord=None, css_position=None, topo_index=None, topo_position=None):
|
36 |
|
37 |
self.name = name
|
38 |
self.index = index
|
39 |
self.used = used
|
40 |
self.coord = coord
|
41 |
+
self.css_position = css_position
|
42 |
self.topo_index = topo_index
|
43 |
+
self.topo_position = topo_position
|
44 |
|
45 |
def prefix(self):
|
46 |
ret = ''.join(filter(str.isalpha, self.name))
|
|
|
51 |
|
52 |
|
53 |
def pack_data(new_idx, missing_channels, tpl_dict, in_dict, tpl_ordered_name, in_ordered_name):
|
|
|
|
|
|
|
|
|
54 |
|
55 |
return {
|
56 |
"newOrder" : [([i] if i!=-1 else []) for i in new_idx],
|
|
|
66 |
|
67 |
data = utils.read_train_data(data_file)
|
68 |
|
69 |
+
template_dict = {}
|
70 |
+
input_dict = {}
|
71 |
template_montage = read_custom_montage("./template_chanlocs.loc")
|
72 |
input_montage = read_custom_montage(loc_file)
|
|
|
|
|
73 |
|
74 |
+
montages = [template_montage, input_montage]
|
75 |
+
dicts = [template_dict, input_dict]
|
76 |
+
num = [30, len(input_montage.ch_names)]
|
77 |
+
|
78 |
+
for i in range(2):
|
79 |
+
fig = montages[i].plot()
|
80 |
+
fig.set_size_inches(5.6, 5.6)
|
81 |
+
ax = fig.axes[0]
|
82 |
+
ax.set_aspect('equal')
|
83 |
+
ax.figure.canvas.draw() #update the figure
|
84 |
+
coords = ax.collections[0].get_offsets().data
|
85 |
+
abs_coords = ax.transData.transform(coords)
|
86 |
+
#print("abs_coords)
|
87 |
+
for j in range(num[i]):
|
88 |
+
channel = montages[i].ch_names[j]
|
89 |
+
|
90 |
+
# convert all channel names to uppercase
|
91 |
+
montages[i].rename_channels({channel: str.upper(channel)})
|
92 |
+
|
93 |
+
css_left = (abs_coords[j][0]-11)/560
|
94 |
+
css_bottom = (abs_coords[j][1]-7)/560
|
95 |
+
channel = str.upper(channel)
|
96 |
+
dicts[i][channel] = Channel(index=j,
|
97 |
+
name=channel,
|
98 |
+
coord=montages[i].get_positions()['ch_pos'][channel],
|
99 |
+
css_position=[str(round(css_left*100, 2))+"%", str(round(css_bottom*100, 2))+"%"]
|
100 |
+
)
|
101 |
+
|
102 |
+
|
103 |
new_idx = [-1]*30
|
|
|
104 |
missing_channels = []
|
105 |
exact_missing_channels = []
|
106 |
z_row_idx = data.shape[0]
|
|
|
117 |
'T6': 'P8',
|
118 |
'TP7': 'T5\'',
|
119 |
'TP8': 'T6\'',
|
120 |
+
}
|
121 |
|
122 |
for i in range(30):
|
123 |
channel = template_montage.ch_names[i]
|
|
|
138 |
continue
|
139 |
|
140 |
new_idx[i] = input_dict[channel].index
|
|
|
141 |
input_dict[channel].used = True
|
142 |
|
143 |
if finish_flag == 1:
|
144 |
second2 = time.time()
|
145 |
print('Finish at stage 1 ! (',second2 - second1,'s)')
|
146 |
+
#print('new idx order:', new_idx)
|
|
|
147 |
|
|
|
148 |
channels_obj = pack_data(new_idx, [],
|
149 |
template_dict, input_dict,
|
150 |
template_montage.ch_names, input_montage.ch_names)
|
|
|
181 |
ver = 'front' if i<3 else 'center' if i==3 else 'back'
|
182 |
hor = 'left' if j<2 else 'center' if j==2 else 'right'
|
183 |
template_dict[channel].topo_index = [i, j]
|
184 |
+
template_dict[channel].topo_position = [ver, hor]
|
185 |
|
186 |
if i > 1 and j in [0, 4]:
|
187 |
temporal_channels.append(channel)
|
|
|
218 |
|
219 |
curr_row = template_dict[channel].topo_index[0]
|
220 |
curr_col = template_dict[channel].topo_index[1]
|
221 |
+
curr_ver = template_dict[channel].topo_position[0]
|
222 |
+
curr_hor = template_dict[channel].topo_position[1]
|
223 |
|
224 |
impute_channel = ''
|
225 |
|
|
|
258 |
elif curr_hor == 'left' or curr_hor == 'right':
|
259 |
|
260 |
ver_ctrl = 1 if curr_ver=='front' else 2 if curr_ver=='back' else 3 # bit0: row+1, bit1: row-1
|
|
|
261 |
|
262 |
# search horizontally
|
263 |
cnt = 0
|
|
|
293 |
impute_channel = 'CZ'
|
294 |
|
295 |
new_idx[i] = input_dict[impute_channel].index
|
|
|
296 |
if input_dict[impute_channel].used == True: # this channel is shared with others
|
297 |
missing_channels.append(i)
|
298 |
input_dict[impute_channel].used = True
|
299 |
|
300 |
second2 = time.time()
|
301 |
print('Finish at stage 2 ! (',second2 - second1,'s)')
|
302 |
+
#print('new_idx:', new_idx)
|
|
|
|
|
303 |
|
304 |
channels_obj = pack_data(new_idx, missing_channels,
|
305 |
template_dict, input_dict,
|