Spaces:
Sleeping
Sleeping
Commit
·
2cb93fb
1
Parent(s):
3166abf
update
Browse files- app.py +34 -23
- app_utils.py +1 -2
app.py
CHANGED
@@ -20,14 +20,14 @@ The following steps will guide you through the process of mapping your EEG chann
|
|
20 |
|
21 |
### Step1: Initial Matching and Scaling
|
22 |
After clicking on ``Mapping`` button, we will first match your channels to our template channels by their names. Using the matched channels as reference points, we will apply Thin Plate Spline (TPS) transformation to scale your montage to align with our template's dimensions. The template montage and your scaled montage will be displayed side by side for comparison. Channels that do not have a match in our template will be **highlighted in red**.
|
23 |
-
- If your data includes all the 30 template channels, you will
|
24 |
- If your data doesn't include all the 30 template channels and you have some channels that do not match the template, you will be directed to **Step2**.
|
25 |
- If all your channels are included in our template but you have fewer than 30 channels, you will be directed to **Step3**.
|
26 |
|
27 |
### Step2: Forwarding Unmatched Channels
|
28 |
In this step, you will handle the channels that didn't have a direct match with our template, by manually assigning them to the template channels that are still empty, ensuring the most efficient use of your data.
|
29 |
Your unmatched channels, previously highlighted in red, will be shown on your montage with a radio button displayed above each. You can choose to forward the data from these unmatched channels to the empty template channels. The interface will display each empty template channel in sequence, allowing you to select which of your unmatched channels to forward.
|
30 |
-
- If all empty template channels are filled by your selections, you will
|
31 |
- If there are still empty template channels remaining, you will be directed to **Step3**.
|
32 |
|
33 |
### Step3: Filling Remaining Template Channels
|
@@ -35,11 +35,12 @@ To run the models successfully, we need to ensure that all 30 template channels
|
|
35 |
- **Mean** method: Each empty template channel is filled with the average value of data from the nearest input channels. By default, the 4 closest input channels (determined after aligning your montage to the template's scale using TPS) are selected for this averaging process. On the interface, you will see checkboxes displayed above each of your channel. The 4 nearest channels are pre-selected by default for each empty template channels, but you can modify these selections as needed. If you uncheck all the checkboxes for a particular template channel, it will be filled with zeros.
|
36 |
- **Zero** method: All empty template channels are filled with zeros.
|
37 |
Choose the method that best suits your needs, considering that the model's performance may vary depending on the method used.
|
38 |
-
Once all template channels are filled, you will
|
39 |
|
40 |
### Mapping Results
|
41 |
-
After completing the previous steps, your channels will be aligned with the template channels required by our models.
|
42 |
-
|
|
|
43 |
|
44 |
## 2. Decode data
|
45 |
After clicking the ``Run`` button, we will process your EEG data based on the mapping results. If necessary, your data will be devided into batches and run the models on each batch sequentially, ensuring that all channels are properly processed.
|
@@ -57,16 +58,14 @@ init_js = """
|
|
57 |
channel_info = JSON.parse(JSON.stringify(channel_info));
|
58 |
stage1_info = app_info.stage1
|
59 |
|
60 |
-
let selector, attribute;
|
61 |
let channel, left, bottom;
|
62 |
|
63 |
if(stage1_info.state == "step2-selecting"){
|
64 |
selector = "#radio-group > div:nth-of-type(2)";
|
65 |
-
//classname = "radio";
|
66 |
attribute = "value";
|
67 |
}else if(stage1_info.state == "step3-2-selecting"){
|
68 |
selector = "#chkbox-group > div:nth-of-type(2)";
|
69 |
-
//classname = "chkbox";
|
70 |
attribute = "name";
|
71 |
}else return;
|
72 |
|
@@ -90,7 +89,7 @@ init_js = """
|
|
90 |
bottom = channel_info.inputDict[channel].css_position[1];
|
91 |
|
92 |
item.style.cssText = `position: absolute; left: ${left}; bottom: ${bottom};`;
|
93 |
-
item.className = "";
|
94 |
item.querySelector(":scope > span").innerText = "";
|
95 |
});
|
96 |
|
@@ -252,7 +251,7 @@ with gr.Blocks() as demo:
|
|
252 |
fillmode_btn = gr.Button("OK", visible=False, scale=1)
|
253 |
chkbox_group = gr.CheckboxGroup(elem_id="chkbox-group", visible=False)
|
254 |
# step4 : mapping results
|
255 |
-
out_json_file = gr.File(
|
256 |
res_md = gr.Markdown("""
|
257 |
(Download this file if you plan to run the models using the source code.)
|
258 |
""", visible=False)
|
@@ -386,7 +385,7 @@ with gr.Blocks() as demo:
|
|
386 |
if stage1_info["state"] == "step1-initializing":
|
387 |
yield {desc_md : gr.Markdown("Mapping...", visible=True)}
|
388 |
|
389 |
-
# match the names
|
390 |
stage1_info, channel_info, tpl_montage, in_montage = app_utils.match_names(stage1_info, channel_info)
|
391 |
# scale the coordinates
|
392 |
channel_info = app_utils.align_coords(channel_info, tpl_montage, in_montage)
|
@@ -429,17 +428,20 @@ with gr.Blocks() as demo:
|
|
429 |
# step1 to step4
|
430 |
# the in_channels has all the 30 tpl_channels (in_num>=30)
|
431 |
if matched_num == 30:
|
|
|
|
|
|
|
|
|
432 |
# finalize and save the mapping results
|
433 |
filename = filepath+"mapping_result.json"
|
434 |
stage1_info, stage2_info, channel_info = app_utils.mapping_result(
|
435 |
stage1_info, stage2_info, channel_info, filename)
|
436 |
-
#gr.Info('The mapping process has been finished.')
|
437 |
stage1_info["state"] = "finished"
|
438 |
app_info["stage1"] = stage1_info
|
439 |
app_info["stage2"] = stage2_info
|
440 |
yield {app_info_json : app_info,
|
441 |
channel_info_json : channel_info,
|
442 |
-
desc_md : gr.Markdown(
|
443 |
tpl_img : gr.Image(visible=False),
|
444 |
mapped_img : gr.Image(visible=False),
|
445 |
next_btn : gr.Button(visible=False),
|
@@ -455,7 +457,7 @@ with gr.Blocks() as demo:
|
|
455 |
Select one of your unmatched channels to forward its data to the empty template channel
|
456 |
currently indicated in red.
|
457 |
"""
|
458 |
-
# initialize the progress indication label
|
459 |
stage1_info.update({
|
460 |
"fillingCount" : 1,
|
461 |
"totalFillingNum" : len(stage1_info["missingTemplates"])
|
@@ -528,19 +530,22 @@ with gr.Blocks() as demo:
|
|
528 |
|
529 |
# -----------------------------determine the next step------------------------------
|
530 |
# step2 to step4
|
531 |
-
# all the unmatched tpl_channels were filled
|
532 |
if len(stage1_info["missingTemplates"]) == 0:
|
|
|
|
|
|
|
|
|
533 |
# finalize and save the mapping results
|
534 |
filename = filepath+"mapping_result.json"
|
535 |
stage1_info, stage2_info, channel_info = app_utils.mapping_result(
|
536 |
stage1_info, stage2_info, channel_info, filename)
|
537 |
-
#gr.Info('The mapping process has been finished.')
|
538 |
stage1_info["state"] = "finished"
|
539 |
app_info["stage1"] = stage1_info
|
540 |
app_info["stage2"] = stage2_info
|
541 |
yield {app_info_json : app_info,
|
542 |
channel_info_json : channel_info,
|
543 |
-
desc_md : gr.Markdown(
|
544 |
radio_group : gr.Radio(visible=False),
|
545 |
out_json_file : gr.File(filename, visible=True),
|
546 |
res_md : gr.Markdown(visible=True),
|
@@ -571,17 +576,20 @@ with gr.Blocks() as demo:
|
|
571 |
|
572 |
# step3-1 to step4
|
573 |
if fillmode == "zero":
|
|
|
|
|
|
|
|
|
574 |
# finalize and save the mapping results
|
575 |
filename = filepath+"mapping_result.json"
|
576 |
stage1_info, stage2_info, channel_info = app_utils.mapping_result(
|
577 |
stage1_info, stage2_info, channel_info, filename)
|
578 |
-
#gr.Info('The mapping process has been finished.')
|
579 |
stage1_info["state"] = "finished"
|
580 |
app_info["stage1"] = stage1_info
|
581 |
app_info["stage2"] = stage2_info
|
582 |
yield {app_info_json : app_info,
|
583 |
channel_info_json : channel_info,
|
584 |
-
desc_md : gr.Markdown(
|
585 |
in_fillmode : gr.Dropdown(visible=False),
|
586 |
fillmode_btn : gr.Button(visible=False),
|
587 |
out_json_file : gr.File(filename, visible=True),
|
@@ -645,17 +653,20 @@ with gr.Blocks() as demo:
|
|
645 |
stage1_info["mappingData"][0]["newOrder"][prev_target_idx] = selected_indices
|
646 |
#print(f'{prev_target_name}({prev_target_idx}): {selected_indices}')
|
647 |
# ----------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
648 |
# finalize and save the mapping results
|
649 |
filename = filepath+"mapping_result.json"
|
650 |
stage1_info, stage2_info, channel_info = app_utils.mapping_result(
|
651 |
stage1_info, stage2_info, channel_info, filename)
|
652 |
-
#gr.Info('The mapping process has been finished.')
|
653 |
stage1_info["state"] = "finished"
|
654 |
app_info["stage1"] = stage1_info
|
655 |
app_info["stage2"] = stage2_info
|
656 |
yield {app_info_json : app_info,
|
657 |
channel_info_json : channel_info,
|
658 |
-
desc_md : gr.Markdown(
|
659 |
chkbox_group : gr.CheckboxGroup(visible=False),
|
660 |
next_btn : gr.Button(visible=False),
|
661 |
out_json_file : gr.File(filename, visible=True),
|
@@ -874,8 +885,8 @@ with gr.Blocks() as demo:
|
|
874 |
#utils.dataDelete(filepath+"temp_data/")
|
875 |
#os.mkdir(filepath+"temp_data/")
|
876 |
except FileNotFoundError:
|
877 |
-
print('break1!!')
|
878 |
break_flag = True
|
|
|
879 |
break
|
880 |
except OSError as e:
|
881 |
print(e)
|
@@ -898,8 +909,8 @@ with gr.Blocks() as demo:
|
|
898 |
# step4: Restore original order
|
899 |
app_utils.restore_order(i, data_shape, new_idx, fill_flags, filepath+"temp_data/denoised.csv", new_filename)
|
900 |
except FileNotFoundError:
|
901 |
-
print('break2!!')
|
902 |
break_flag = True
|
|
|
903 |
break
|
904 |
# ----------------------------------------------------------------------------------
|
905 |
utils.dataDelete(filepath+"temp_data/")
|
|
|
20 |
|
21 |
### Step1: Initial Matching and Scaling
|
22 |
After clicking on ``Mapping`` button, we will first match your channels to our template channels by their names. Using the matched channels as reference points, we will apply Thin Plate Spline (TPS) transformation to scale your montage to align with our template's dimensions. The template montage and your scaled montage will be displayed side by side for comparison. Channels that do not have a match in our template will be **highlighted in red**.
|
23 |
+
- If your data includes all the 30 template channels, you will be directed to **Mapping Results**.
|
24 |
- If your data doesn't include all the 30 template channels and you have some channels that do not match the template, you will be directed to **Step2**.
|
25 |
- If all your channels are included in our template but you have fewer than 30 channels, you will be directed to **Step3**.
|
26 |
|
27 |
### Step2: Forwarding Unmatched Channels
|
28 |
In this step, you will handle the channels that didn't have a direct match with our template, by manually assigning them to the template channels that are still empty, ensuring the most efficient use of your data.
|
29 |
Your unmatched channels, previously highlighted in red, will be shown on your montage with a radio button displayed above each. You can choose to forward the data from these unmatched channels to the empty template channels. The interface will display each empty template channel in sequence, allowing you to select which of your unmatched channels to forward.
|
30 |
+
- If all empty template channels are filled by your selections, you will be directed to **Mapping Results**.
|
31 |
- If there are still empty template channels remaining, you will be directed to **Step3**.
|
32 |
|
33 |
### Step3: Filling Remaining Template Channels
|
|
|
35 |
- **Mean** method: Each empty template channel is filled with the average value of data from the nearest input channels. By default, the 4 closest input channels (determined after aligning your montage to the template's scale using TPS) are selected for this averaging process. On the interface, you will see checkboxes displayed above each of your channel. The 4 nearest channels are pre-selected by default for each empty template channels, but you can modify these selections as needed. If you uncheck all the checkboxes for a particular template channel, it will be filled with zeros.
|
36 |
- **Zero** method: All empty template channels are filled with zeros.
|
37 |
Choose the method that best suits your needs, considering that the model's performance may vary depending on the method used.
|
38 |
+
Once all template channels are filled, you will be directed to **Mapping Results**.
|
39 |
|
40 |
### Mapping Results
|
41 |
+
After completing the previous steps, your channels will be aligned with the template channels required by our models.
|
42 |
+
- In case there are still some channels that haven't been mapped, we will automatically batch and optimally assign them to the template. This ensures that even channels not initially mapped will still be included in the final results.
|
43 |
+
- Once the channel mapping process is completed, a **JSON file** containing the mapping results will be generated. This file is necessary only if you plan to run the models using the source code; otherwise, you can ignore it.
|
44 |
|
45 |
## 2. Decode data
|
46 |
After clicking the ``Run`` button, we will process your EEG data based on the mapping results. If necessary, your data will be devided into batches and run the models on each batch sequentially, ensuring that all channels are properly processed.
|
|
|
58 |
channel_info = JSON.parse(JSON.stringify(channel_info));
|
59 |
stage1_info = app_info.stage1
|
60 |
|
61 |
+
let selector, attribute;
|
62 |
let channel, left, bottom;
|
63 |
|
64 |
if(stage1_info.state == "step2-selecting"){
|
65 |
selector = "#radio-group > div:nth-of-type(2)";
|
|
|
66 |
attribute = "value";
|
67 |
}else if(stage1_info.state == "step3-2-selecting"){
|
68 |
selector = "#chkbox-group > div:nth-of-type(2)";
|
|
|
69 |
attribute = "name";
|
70 |
}else return;
|
71 |
|
|
|
89 |
bottom = channel_info.inputDict[channel].css_position[1];
|
90 |
|
91 |
item.style.cssText = `position: absolute; left: ${left}; bottom: ${bottom};`;
|
92 |
+
item.className = "";
|
93 |
item.querySelector(":scope > span").innerText = "";
|
94 |
});
|
95 |
|
|
|
251 |
fillmode_btn = gr.Button("OK", visible=False, scale=1)
|
252 |
chkbox_group = gr.CheckboxGroup(elem_id="chkbox-group", visible=False)
|
253 |
# step4 : mapping results
|
254 |
+
out_json_file = gr.File(visible=False)
|
255 |
res_md = gr.Markdown("""
|
256 |
(Download this file if you plan to run the models using the source code.)
|
257 |
""", visible=False)
|
|
|
385 |
if stage1_info["state"] == "step1-initializing":
|
386 |
yield {desc_md : gr.Markdown("Mapping...", visible=True)}
|
387 |
|
388 |
+
# match the names
|
389 |
stage1_info, channel_info, tpl_montage, in_montage = app_utils.match_names(stage1_info, channel_info)
|
390 |
# scale the coordinates
|
391 |
channel_info = app_utils.align_coords(channel_info, tpl_montage, in_montage)
|
|
|
428 |
# step1 to step4
|
429 |
# the in_channels has all the 30 tpl_channels (in_num>=30)
|
430 |
if matched_num == 30:
|
431 |
+
md = """
|
432 |
+
### Mapping Results
|
433 |
+
The mapping process has been finished.
|
434 |
+
"""
|
435 |
# finalize and save the mapping results
|
436 |
filename = filepath+"mapping_result.json"
|
437 |
stage1_info, stage2_info, channel_info = app_utils.mapping_result(
|
438 |
stage1_info, stage2_info, channel_info, filename)
|
|
|
439 |
stage1_info["state"] = "finished"
|
440 |
app_info["stage1"] = stage1_info
|
441 |
app_info["stage2"] = stage2_info
|
442 |
yield {app_info_json : app_info,
|
443 |
channel_info_json : channel_info,
|
444 |
+
desc_md : gr.Markdown(md),
|
445 |
tpl_img : gr.Image(visible=False),
|
446 |
mapped_img : gr.Image(visible=False),
|
447 |
next_btn : gr.Button(visible=False),
|
|
|
457 |
Select one of your unmatched channels to forward its data to the empty template channel
|
458 |
currently indicated in red.
|
459 |
"""
|
460 |
+
# initialize the progress indication label
|
461 |
stage1_info.update({
|
462 |
"fillingCount" : 1,
|
463 |
"totalFillingNum" : len(stage1_info["missingTemplates"])
|
|
|
530 |
|
531 |
# -----------------------------determine the next step------------------------------
|
532 |
# step2 to step4
|
533 |
+
# all the unmatched tpl_channels were filled
|
534 |
if len(stage1_info["missingTemplates"]) == 0:
|
535 |
+
md = """
|
536 |
+
### Mapping Results
|
537 |
+
The mapping process has been finished.
|
538 |
+
"""
|
539 |
# finalize and save the mapping results
|
540 |
filename = filepath+"mapping_result.json"
|
541 |
stage1_info, stage2_info, channel_info = app_utils.mapping_result(
|
542 |
stage1_info, stage2_info, channel_info, filename)
|
|
|
543 |
stage1_info["state"] = "finished"
|
544 |
app_info["stage1"] = stage1_info
|
545 |
app_info["stage2"] = stage2_info
|
546 |
yield {app_info_json : app_info,
|
547 |
channel_info_json : channel_info,
|
548 |
+
desc_md : gr.Markdown(md),
|
549 |
radio_group : gr.Radio(visible=False),
|
550 |
out_json_file : gr.File(filename, visible=True),
|
551 |
res_md : gr.Markdown(visible=True),
|
|
|
576 |
|
577 |
# step3-1 to step4
|
578 |
if fillmode == "zero":
|
579 |
+
md = """
|
580 |
+
### Mapping Results
|
581 |
+
The mapping process has been finished.
|
582 |
+
"""
|
583 |
# finalize and save the mapping results
|
584 |
filename = filepath+"mapping_result.json"
|
585 |
stage1_info, stage2_info, channel_info = app_utils.mapping_result(
|
586 |
stage1_info, stage2_info, channel_info, filename)
|
|
|
587 |
stage1_info["state"] = "finished"
|
588 |
app_info["stage1"] = stage1_info
|
589 |
app_info["stage2"] = stage2_info
|
590 |
yield {app_info_json : app_info,
|
591 |
channel_info_json : channel_info,
|
592 |
+
desc_md : gr.Markdown(md),
|
593 |
in_fillmode : gr.Dropdown(visible=False),
|
594 |
fillmode_btn : gr.Button(visible=False),
|
595 |
out_json_file : gr.File(filename, visible=True),
|
|
|
653 |
stage1_info["mappingData"][0]["newOrder"][prev_target_idx] = selected_indices
|
654 |
#print(f'{prev_target_name}({prev_target_idx}): {selected_indices}')
|
655 |
# ----------------------------------------------------------------------------------
|
656 |
+
md = """
|
657 |
+
### Mapping Results
|
658 |
+
The mapping process has been finished.
|
659 |
+
"""
|
660 |
# finalize and save the mapping results
|
661 |
filename = filepath+"mapping_result.json"
|
662 |
stage1_info, stage2_info, channel_info = app_utils.mapping_result(
|
663 |
stage1_info, stage2_info, channel_info, filename)
|
|
|
664 |
stage1_info["state"] = "finished"
|
665 |
app_info["stage1"] = stage1_info
|
666 |
app_info["stage2"] = stage2_info
|
667 |
yield {app_info_json : app_info,
|
668 |
channel_info_json : channel_info,
|
669 |
+
desc_md : gr.Markdown(md),
|
670 |
chkbox_group : gr.CheckboxGroup(visible=False),
|
671 |
next_btn : gr.Button(visible=False),
|
672 |
out_json_file : gr.File(filename, visible=True),
|
|
|
885 |
#utils.dataDelete(filepath+"temp_data/")
|
886 |
#os.mkdir(filepath+"temp_data/")
|
887 |
except FileNotFoundError:
|
|
|
888 |
break_flag = True
|
889 |
+
print(e)
|
890 |
break
|
891 |
except OSError as e:
|
892 |
print(e)
|
|
|
909 |
# step4: Restore original order
|
910 |
app_utils.restore_order(i, data_shape, new_idx, fill_flags, filepath+"temp_data/denoised.csv", new_filename)
|
911 |
except FileNotFoundError:
|
|
|
912 |
break_flag = True
|
913 |
+
print(e)
|
914 |
break
|
915 |
# ----------------------------------------------------------------------------------
|
916 |
utils.dataDelete(filepath+"temp_data/")
|
app_utils.py
CHANGED
@@ -1,6 +1,5 @@
|
|
1 |
import utils
|
2 |
import os
|
3 |
-
import time
|
4 |
import math
|
5 |
import json
|
6 |
import numpy as np
|
@@ -355,7 +354,7 @@ def mapping_result(stage1_info, stage2_info, channel_info, filename):
|
|
355 |
}
|
356 |
with open(filename, 'w') as jsonfile:
|
357 |
jsonfile.write(json.dumps(new_dict))
|
358 |
-
|
359 |
stage2_info["totalBatchNum"] = batch_num
|
360 |
return stage1_info, stage2_info, channel_info
|
361 |
|
|
|
1 |
import utils
|
2 |
import os
|
|
|
3 |
import math
|
4 |
import json
|
5 |
import numpy as np
|
|
|
354 |
}
|
355 |
with open(filename, 'w') as jsonfile:
|
356 |
jsonfile.write(json.dumps(new_dict))
|
357 |
+
|
358 |
stage2_info["totalBatchNum"] = batch_num
|
359 |
return stage1_info, stage2_info, channel_info
|
360 |
|