audrey06100 commited on
Commit
83b7c6a
·
1 Parent(s): ef20573
Files changed (2) hide show
  1. app.py +176 -102
  2. channel_mapping.py +21 -19
app.py CHANGED
@@ -44,14 +44,24 @@ icunet = """
44
  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.
45
  """
46
 
47
- chkbox_js = """
48
  (app_state, channel_info) => {
49
  app_state = JSON.parse(JSON.stringify(app_state));
50
  channel_info = JSON.parse(JSON.stringify(channel_info));
51
- if(app_state.state == "finished") return;
 
 
 
 
 
 
 
 
 
 
52
 
53
  // add figure of in_montage
54
- document.querySelector("#chkbox-group> div:nth-of-type(2)").style.cssText = `
55
  position: relative;
56
  width: 560px;
57
  height: 560px;
@@ -59,13 +69,31 @@ chkbox_js = """
59
  `;
60
 
61
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  // add indication for the missing channels
63
- let channel = channel_info.missingChannels[0]
64
- let left = channel_info.templateByName[channel].css_position[0];
65
- let bottom = channel_info.templateByName[channel].css_position[1];
66
 
67
  let rule = `
68
- #chkbox-group> div:nth-of-type(2)::after{
69
  content: '';
70
  position: absolute;
71
  background-color: red;
@@ -81,35 +109,15 @@ chkbox_js = """
81
  let exist = 0;
82
  const styleSheet = document.styleSheets[0];
83
  for(let i=0; i<styleSheet.cssRules.length; i++){
84
- if(styleSheet.cssRules[i].selectorText == "#chkbox-group> div:nth-of-type(2)::after"){
85
  exist = 1;
86
- console.log('exist!');
87
  styleSheet.deleteRule(i);
88
  styleSheet.insertRule(rule, styleSheet.cssRules.length);
89
  break;
90
  }
91
  }
92
  if(exist == 0) styleSheet.insertRule(rule, styleSheet.cssRules.length);
93
-
94
-
95
- // move the checkboxes
96
- let all_chkbox = document.querySelectorAll("#chkbox-group> div:nth-of-type(2)> label");
97
- //all_chkbox = Array.apply(null, all_chkbox);
98
-
99
- Array.from(all_chkbox).forEach((item, index) => {
100
- channel = channel_info.inputByIndex[index];
101
- left = channel_info.inputByName[channel].css_position[0];
102
- bottom = channel_info.inputByName[channel].css_position[1];
103
- console.log(`left: ${left}, bottom: ${bottom}`);
104
-
105
- item.style.cssText = `
106
- position: absolute;
107
- left: ${left};
108
- bottom: ${bottom};
109
- `;
110
- item.className = "";
111
- item.querySelector(":scope> span").innerText = "";
112
- });
113
  }
114
  """
115
 
@@ -117,14 +125,40 @@ indication_js = """
117
  (app_state, channel_info) => {
118
  app_state = JSON.parse(JSON.stringify(app_state));
119
  channel_info = JSON.parse(JSON.stringify(channel_info));
120
- if(app_state.state == "finished") return;
121
 
122
- let channel = channel_info.missingChannels[app_state["fillingCount"]-1]
123
- let left = channel_info.templateByName[channel].css_position[0];
124
- let bottom = channel_info.templateByName[channel].css_position[1];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
 
126
  let rule = `
127
- #chkbox-group> div:nth-of-type(2)::after{
128
  content: '';
129
  position: absolute;
130
  background-color: red;
@@ -140,9 +174,9 @@ indication_js = """
140
  let exist = 0;
141
  const styleSheet = document.styleSheets[0];
142
  for(let i=0; i<styleSheet.cssRules.length; i++){
143
- if(styleSheet.cssRules[i].selectorText == "#chkbox-group> div:nth-of-type(2)::after"){
144
  exist = 1;
145
- console.log('exist!');
146
  styleSheet.deleteRule(i);
147
  styleSheet.insertRule(rule, styleSheet.cssRules.length);
148
  break;
@@ -310,8 +344,8 @@ with gr.Blocks() as demo:
310
  #### determine the next step ####
311
  #################################
312
 
313
- in_num = len(channel_info["inputByName"])
314
- matched_num = 30 - len(channel_info["missingChannels"])
315
 
316
  # if the input channels(>=30) has all the 30 template channels
317
  # -> Stage2.decode data
@@ -360,23 +394,20 @@ with gr.Blocks() as demo:
360
 
361
  def init_next_step(app_state, channel_info, selected_radio, selected_chkbox):
362
 
363
- channel_info["missingChannels"] = [channel for channel in channel_info["templateByName"]
364
- if channel_info["templateByName"][channel]["matched"]==False]
365
- app_state.update({
366
- "fillingCount" : 1,
367
- "totalFillingNum" : len(channel_info["missingChannels"])
368
- })
369
-
370
  # step1 -> step2
371
  if app_state["state"] == "step2-initializing":
372
- app_state["state"] = "step2-selecting"
 
 
 
 
 
 
 
373
 
374
- name = channel_info["missingChannels"][0]
375
  label = name+' (1/'+str(app_state["totalFillingNum"])+')'
376
-
377
- unassigned = [channel for channel in channel_info["inputByName"]
378
- if channel_info["inputByName"][channel]["assigned"]==False]
379
- if len(unassigned)==1 or app_state["totalFillingNum"]==1:
380
  btn_label = "Next step"
381
  else:
382
  btn_label = "Next"
@@ -386,14 +417,22 @@ with gr.Blocks() as demo:
386
  desc_md : gr.Markdown("### step2"),
387
  tpl_montage : gr.Image(visible=False),
388
  map_montage : gr.Image(visible=False),
389
- radio : gr.Radio(choices=unassigned, value=[], label=label, visible=True),
390
  step2_btn : gr.Button(btn_label, visible=True),
391
  next_btn : gr.Button(visible=False)}
392
 
393
  # step1 -> step3
394
  elif app_state["state"] == "step3-initializing":
395
-
 
 
 
 
 
 
 
396
  return {app_state_json : app_state,
 
397
  desc_md : gr.Markdown("### step3"),
398
  tpl_montage : gr.Image(visible=False),
399
  map_montage : gr.Image(visible=False),
@@ -405,22 +444,31 @@ with gr.Blocks() as demo:
405
  elif app_state["state"] == "step2-selecting":
406
 
407
  # save info before clicking on next_btn
408
- if selected_radio != []:
409
- prev_target_name = channel_info["missingChannels"][app_state["fillingCount"]-1]
410
- prev_target_idx = channel_info["templateByName"][prev_target_name]["index"]
411
-
 
412
  selected_idx = channel_info["inputByName"][selected_radio]["index"]
413
  app_state["stage1NewOrder"][prev_target_idx] = [selected_idx]
414
 
415
  channel_info["templateByName"][prev_target_name]["matched"] = True
416
- channel_info["inputByName"][selected_radio]["assigned"] = True
417
- print(prev_target_name, '<-', selected_radio)
 
 
 
 
 
 
 
418
 
419
  # if all the unmatched template channels were filled by input channels
420
  # -> Stage2
421
- if app_state["fillingCount"] == app_state["totalFillingNum"]:
422
- app_state["state"] = "finished"
423
  gr.Info('The mapping process is finished!')
 
424
 
425
  return {app_state_json : app_state,
426
  channel_info_json : channel_info,
@@ -431,8 +479,12 @@ with gr.Blocks() as demo:
431
 
432
  # -> step3
433
  else:
434
- app_state["state"] = "step3-initializing"
435
-
 
 
 
 
436
  return {app_state_json : app_state,
437
  channel_info_json : channel_info,
438
  desc_md : gr.Markdown("### step3"),
@@ -443,18 +495,23 @@ with gr.Blocks() as demo:
443
 
444
  # step3 -> Stage2.decode data
445
  elif app_state["state"] == "step3-selecting":
446
- app_state["state"] = "finished"
447
- gr.Info('The mapping process is finished!')
448
 
449
  # save info before clicking on next_btn
450
- if selected_chkbox != []:
451
- prev_target_name = channel_info["missingChannels"][app_state["fillingCount"]-1]
452
- prev_target_idx = channel_info["templateByName"][prev_target_name]["index"]
453
-
 
454
  selected_idx = [channel_info["inputByName"][channel]["index"] for channel in selected_chkbox]
455
- app_state["stage1NewOrder"][prev_target_idx] = selected_idx
456
-
457
- #print('Selection for missing channel "{}"({}): {}'.format(prev_target_name, prev_target_idx, selected))
 
 
 
 
 
 
458
 
459
  return {app_state_json : app_state,
460
  desc_md : gr.Markdown(visible=False),
@@ -469,7 +526,7 @@ with gr.Blocks() as demo:
469
  chkbox_group, fillmode_btn, step2_btn, next_btn, run_btn]
470
  ).success(
471
  fn = None,
472
- js = indication_js,
473
  inputs = [app_state_json, channel_info_json],
474
  outputs = []
475
  )
@@ -479,36 +536,36 @@ with gr.Blocks() as demo:
479
  def update_radio(app_state, channel_info, selected):
480
 
481
  # save info before clicking on next_btn
482
- if selected != []:
483
- prev_target_name = channel_info["missingChannels"][app_state["fillingCount"]-1]
484
- prev_target_idx = channel_info["templateByName"][prev_target_name]["index"]
485
-
 
486
  selected_idx = channel_info["inputByName"][selected]["index"]
487
  app_state["stage1NewOrder"][prev_target_idx] = [selected_idx]
488
 
489
  channel_info["templateByName"][prev_target_name]["matched"] = True
490
  channel_info["inputByName"][selected]["assigned"] = True
491
- print(prev_target_name, '<-', selected)
492
 
493
  # update the current round
494
  app_state["fillingCount"] += 1
495
- unassigned = [channel for channel in channel_info["inputByName"]
496
- if channel_info["inputByName"][channel]["assigned"]==False]
497
 
498
- target_name = channel_info["missingChannels"][app_state["fillingCount"]-1]
499
-
500
  radio_label = target_name+' ('+str(app_state["fillingCount"])+'/'+str(app_state["totalFillingNum"])+')'
501
 
502
- if len(unassigned)==1 or app_state["fillingCount"]==app_state["totalFillingNum"]:
503
  return {app_state_json : app_state,
504
  channel_info_json : channel_info,
505
- radio : gr.Radio(choices=unassigned, value=[], label=radio_label),
506
  step2_btn : gr.Button(visible=False),
507
  next_btn : gr.Button("Next step", visible=True)}
508
  else:
509
  return {app_state_json : app_state,
510
  channel_info_json : channel_info,
511
- radio : gr.Radio(choices=unassigned, value=[], label=radio_label)}
512
 
513
  step2_btn.click(
514
  fn = update_radio,
@@ -523,8 +580,6 @@ with gr.Blocks() as demo:
523
  )
524
 
525
  # step3
526
- @fillmode_btn.click(inputs = [app_state_json, channel_info_json, in_fill_mode],
527
- outputs = [app_state_json, in_fill_mode, fillmode_btn, chkbox_group, step3_btn, run_btn])
528
  def fill_value(app_state, channel_info, fill_mode):
529
 
530
  if fill_mode == 'zero':
@@ -541,7 +596,7 @@ with gr.Blocks() as demo:
541
  app_state["state"] = "step3-selecting"
542
  app_state = find_neighbors(app_state, channel_info, fill_mode)
543
 
544
- name = channel_info["missingChannels"][0]
545
  idx = channel_info["templateByName"][name]["index"]
546
  value = app_state["stage1NewOrder"][idx]
547
  value = [channel_info["inputByIndex"][i] for i in value]
@@ -554,22 +609,33 @@ with gr.Blocks() as demo:
554
  value=value, label=label, visible=True),
555
  step3_btn : gr.Button(visible=True)}
556
 
 
 
 
 
 
 
 
 
 
 
 
557
  def update_chkbox(app_state, channel_info, selected):
558
 
559
  # save info before clicking on next_btn
560
- if selected != []:
561
- prev_target_name = channel_info["missingChannels"][app_state["fillingCount"]-1]
562
- prev_target_idx = channel_info["templateByName"][prev_target_name]["index"]
563
-
 
564
  selected_idx = [channel_info["inputByName"][channel]["index"] for channel in selected]
565
  app_state["stage1NewOrder"][prev_target_idx] = selected_idx
566
-
567
- #print('Selection for missing channel "{}"({}): {}'.format(prev_target_name, prev_target_idx, selected))
568
 
569
- # update next round
570
  app_state["fillingCount"] += 1
571
 
572
- target_name = channel_info["missingChannels"][app_state["fillingCount"]-1]
573
  target_idx = channel_info["templateByName"][target_name]["index"]
574
 
575
  chkbox_value = app_state["stage1NewOrder"][target_idx]
@@ -606,11 +672,14 @@ with gr.Blocks() as demo:
606
 
607
  def reset_run(app_state, channel_info, raw_data, model_name):
608
  filepath = app_state["filepath"]
 
 
 
609
  input_name = os.path.basename(str(raw_data))
610
  output_name = os.path.splitext(input_name)[0]+'_'+model_name+'.csv'
611
 
612
- in_num = len(channel_info["inputByName"])
613
- matched_num = len([channel for channel in channel_info["inputByName"]
614
  if channel_info["inputByName"][channel]["matched"]==True])
615
  batch_num = math.ceil((in_num-matched_num)/30) + 1
616
 
@@ -619,12 +688,16 @@ with gr.Blocks() as demo:
619
  "runnigState" : "stage1",
620
  "batchCount" : 1,
621
  "totalBatchNum" : batch_num,
622
- "stage2NewOrder" : [[]]*30
 
623
  })
624
 
625
- delete_file(filepath+'mapped.csv')
626
- delete_file(filepath+'denoised.csv')
 
 
627
  return {app_state_json : app_state,
 
628
  run_btn : gr.Button(interactive=False),
629
  batch_md : gr.Markdown(visible=False),
630
  out_denoised_data : gr.File(visible=False)}
@@ -644,6 +717,7 @@ with gr.Blocks() as demo:
644
  if app_state["batchCount"] > 1:
645
  app_state, channel_info = mapping_stage2(app_state, channel_info, fill_mode)
646
  if app_state["runnigState"] == "finished":
 
647
  break
648
 
649
  reorder_to_template(app_state, raw_data)
@@ -669,7 +743,7 @@ with gr.Blocks() as demo:
669
  run_btn.click(
670
  fn = reset_run,
671
  inputs = [app_state_json, channel_info_json, in_raw_data, in_model_name],
672
- outputs = [app_state_json, run_btn, batch_md, out_denoised_data]
673
 
674
  ).success(
675
  fn = run_model,
 
44
  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.
45
  """
46
 
47
+ init_js = """
48
  (app_state, channel_info) => {
49
  app_state = JSON.parse(JSON.stringify(app_state));
50
  channel_info = JSON.parse(JSON.stringify(channel_info));
51
+
52
+ let selector, attribute;
53
+ let channel, left, bottom;
54
+
55
+ if(app_state.state == "step2-selecting"){
56
+ selector = "#radio> div:nth-of-type(2)";
57
+ attribute = "value";
58
+ }else if(app_state.state == "step3-selecting"){
59
+ selector = "#chkbox-group> div:nth-of-type(2)";
60
+ attribute = "name";
61
+ }else return;
62
 
63
  // add figure of in_montage
64
+ document.querySelector(selector).style.cssText = `
65
  position: relative;
66
  width: 560px;
67
  height: 560px;
 
69
  `;
70
 
71
 
72
+ // move the radios/checkboxes
73
+ let all_elem = document.querySelectorAll(selector+"> label");
74
+ Array.from(all_elem).forEach((item) => {
75
+ channel = item.querySelector("input").getAttribute(attribute);
76
+ left = channel_info.inputByName[channel].css_position[0];
77
+ bottom = channel_info.inputByName[channel].css_position[1];
78
+ //console.log(`channel: ${channel}, left: ${left}, bottom: ${bottom}`);
79
+
80
+ item.style.cssText = `
81
+ position: absolute;
82
+ left: ${left};
83
+ bottom: ${bottom};
84
+ `;
85
+ item.className = "";
86
+ item.querySelector(":scope> span").innerText = "";
87
+ });
88
+
89
+
90
  // add indication for the missing channels
91
+ channel = app_state.missingTemplates[0]
92
+ left = channel_info.templateByName[channel].css_position[0];
93
+ bottom = channel_info.templateByName[channel].css_position[1];
94
 
95
  let rule = `
96
+ ${selector}::after{
97
  content: '';
98
  position: absolute;
99
  background-color: red;
 
109
  let exist = 0;
110
  const styleSheet = document.styleSheets[0];
111
  for(let i=0; i<styleSheet.cssRules.length; i++){
112
+ if(styleSheet.cssRules[i].selectorText == selector+"::after"){
113
  exist = 1;
114
+ //console.log('exist!');
115
  styleSheet.deleteRule(i);
116
  styleSheet.insertRule(rule, styleSheet.cssRules.length);
117
  break;
118
  }
119
  }
120
  if(exist == 0) styleSheet.insertRule(rule, styleSheet.cssRules.length);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
  }
122
  """
123
 
 
125
  (app_state, channel_info) => {
126
  app_state = JSON.parse(JSON.stringify(app_state));
127
  channel_info = JSON.parse(JSON.stringify(channel_info));
 
128
 
129
+ let selector;
130
+ let channel, left, bottom;
131
+
132
+ if(app_state.state == "step2-selecting"){
133
+ selector = "#radio> div:nth-of-type(2)";
134
+
135
+ // update the radios
136
+ let all_elem = document.querySelectorAll(selector+"> label");
137
+ Array.from(all_elem).forEach((item) => {
138
+ channel = item.querySelector("input").value;
139
+ left = channel_info.inputByName[channel].css_position[0];
140
+ bottom = channel_info.inputByName[channel].css_position[1];
141
+ //console.log(`channel: ${channel}, left: ${left}, bottom: ${bottom}`);
142
+
143
+ item.style.cssText = `
144
+ position: absolute;
145
+ left: ${left};
146
+ bottom: ${bottom};
147
+ `;
148
+ item.className = "";
149
+ item.querySelector(":scope> span").innerText = "";
150
+ });
151
+ }else if(app_state.state == "step3-selecting"){
152
+ selector = "#chkbox-group> div:nth-of-type(2)";
153
+ }else return;
154
+
155
+ // update indication
156
+ channel = app_state.missingTemplates[app_state["fillingCount"]-1]
157
+ left = channel_info.templateByName[channel].css_position[0];
158
+ bottom = channel_info.templateByName[channel].css_position[1];
159
 
160
  let rule = `
161
+ ${selector}::after{
162
  content: '';
163
  position: absolute;
164
  background-color: red;
 
174
  let exist = 0;
175
  const styleSheet = document.styleSheets[0];
176
  for(let i=0; i<styleSheet.cssRules.length; i++){
177
+ if(styleSheet.cssRules[i].selectorText == selector+"::after"){
178
  exist = 1;
179
+ //console.log('exist!');
180
  styleSheet.deleteRule(i);
181
  styleSheet.insertRule(rule, styleSheet.cssRules.length);
182
  break;
 
344
  #### determine the next step ####
345
  #################################
346
 
347
+ in_num = len(channel_info["inputByIndex"])
348
+ matched_num = 30 - len(app_state["missingTemplates"])
349
 
350
  # if the input channels(>=30) has all the 30 template channels
351
  # -> Stage2.decode data
 
394
 
395
  def init_next_step(app_state, channel_info, selected_radio, selected_chkbox):
396
 
 
 
 
 
 
 
 
397
  # step1 -> step2
398
  if app_state["state"] == "step2-initializing":
399
+ print('step1 -> step2')
400
+ app_state["missingTemplates"] = [channel for channel in channel_info["templateByIndex"]
401
+ if channel_info["templateByName"][channel]["matched"]==False]
402
+ app_state.update({
403
+ "state" : "step2-selecting",
404
+ "fillingCount" : 1,
405
+ "totalFillingNum" : len(app_state["missingTemplates"])
406
+ })
407
 
408
+ name = app_state["missingTemplates"][0]
409
  label = name+' (1/'+str(app_state["totalFillingNum"])+')'
410
+ if len(app_state["stage1UnassignedInputs"])==1 or app_state["totalFillingNum"]==1:
 
 
 
411
  btn_label = "Next step"
412
  else:
413
  btn_label = "Next"
 
417
  desc_md : gr.Markdown("### step2"),
418
  tpl_montage : gr.Image(visible=False),
419
  map_montage : gr.Image(visible=False),
420
+ radio : gr.Radio(choices=app_state["stage1UnassignedInputs"], value=[], label=label, visible=True),
421
  step2_btn : gr.Button(btn_label, visible=True),
422
  next_btn : gr.Button(visible=False)}
423
 
424
  # step1 -> step3
425
  elif app_state["state"] == "step3-initializing":
426
+ print('step1 -> step3')
427
+ app_state["missingTemplates"] = [channel for channel in channel_info["templateByIndex"]
428
+ if channel_info["templateByName"][channel]["matched"]==False]
429
+ app_state.update({
430
+ "state" : "step3-initializing",
431
+ "fillingCount" : 1,
432
+ "totalFillingNum" : len(app_state["missingTemplates"])
433
+ })
434
  return {app_state_json : app_state,
435
+ channel_info_json : channel_info,
436
  desc_md : gr.Markdown("### step3"),
437
  tpl_montage : gr.Image(visible=False),
438
  map_montage : gr.Image(visible=False),
 
444
  elif app_state["state"] == "step2-selecting":
445
 
446
  # save info before clicking on next_btn
447
+ prev_target_name = app_state["missingTemplates"][app_state["fillingCount"]-1]
448
+ prev_target_idx = channel_info["templateByName"][prev_target_name]["index"]
449
+ if selected_radio == []:
450
+ app_state["stage1NewOrder"][prev_target_idx] = []
451
+ else:
452
  selected_idx = channel_info["inputByName"][selected_radio]["index"]
453
  app_state["stage1NewOrder"][prev_target_idx] = [selected_idx]
454
 
455
  channel_info["templateByName"][prev_target_name]["matched"] = True
456
+ channel_info["inputByName"][selected_radio]["assigned"] = True
457
+ print(prev_target_name, '<-', selected_radio)
458
+
459
+ app_state.update({
460
+ "stage1UnassignedInputs" : [channel for channel in channel_info["inputByIndex"]
461
+ if channel_info["inputByName"][channel]["assigned"]==False],
462
+ "missingTemplates" : [channel for channel in channel_info["templateByIndex"]
463
+ if channel_info["templateByName"][channel]["matched"]==False]
464
+ })
465
 
466
  # if all the unmatched template channels were filled by input channels
467
  # -> Stage2
468
+ if len(app_state["missingTemplates"]) == 0:
469
+ print('step2 -> Stage2')
470
  gr.Info('The mapping process is finished!')
471
+ app_state["state"] = "finished"
472
 
473
  return {app_state_json : app_state,
474
  channel_info_json : channel_info,
 
479
 
480
  # -> step3
481
  else:
482
+ print('step2 -> step3')
483
+ app_state.update({
484
+ "state" : "step3-initializing",
485
+ "fillingCount" : 1,
486
+ "totalFillingNum" : len(app_state["missingTemplates"])
487
+ })
488
  return {app_state_json : app_state,
489
  channel_info_json : channel_info,
490
  desc_md : gr.Markdown("### step3"),
 
495
 
496
  # step3 -> Stage2.decode data
497
  elif app_state["state"] == "step3-selecting":
 
 
498
 
499
  # save info before clicking on next_btn
500
+ prev_target_name = app_state["missingTemplates"][app_state["fillingCount"]-1]
501
+ prev_target_idx = channel_info["templateByName"][prev_target_name]["index"]
502
+ if selected_chkbox == []:
503
+ app_state["stage1NewOrder"][prev_target_idx] = []
504
+ else:
505
  selected_idx = [channel_info["inputByName"][channel]["index"] for channel in selected_chkbox]
506
+ app_state["stage1NewOrder"][prev_target_idx] = selected_idx
507
+ #print(f'{prev_target_name}({prev_target_idx}): {selected_chkbox}')
508
+
509
+ gr.Info('The mapping process is finished!')
510
+ app_state["state"] = "finished"
511
+ print('step3 -> Stage2')
512
+
513
+ app_state["missingTemplates"] = [channel for channel in channel_info["templateByIndex"]
514
+ if channel_info["templateByName"][channel]["matched"]==False]
515
 
516
  return {app_state_json : app_state,
517
  desc_md : gr.Markdown(visible=False),
 
526
  chkbox_group, fillmode_btn, step2_btn, next_btn, run_btn]
527
  ).success(
528
  fn = None,
529
+ js = init_js,
530
  inputs = [app_state_json, channel_info_json],
531
  outputs = []
532
  )
 
536
  def update_radio(app_state, channel_info, selected):
537
 
538
  # save info before clicking on next_btn
539
+ prev_target_name = app_state["missingTemplates"][app_state["fillingCount"]-1]
540
+ prev_target_idx = channel_info["templateByName"][prev_target_name]["index"]
541
+ if selected == []:
542
+ app_state["stage1NewOrder"][prev_target_idx] = []
543
+ else:
544
  selected_idx = channel_info["inputByName"][selected]["index"]
545
  app_state["stage1NewOrder"][prev_target_idx] = [selected_idx]
546
 
547
  channel_info["templateByName"][prev_target_name]["matched"] = True
548
  channel_info["inputByName"][selected]["assigned"] = True
549
+ print(prev_target_name, '<-', selected)
550
 
551
  # update the current round
552
  app_state["fillingCount"] += 1
553
+ app_state["stage1UnassignedInputs"] = [channel for channel in channel_info["inputByIndex"]
554
+ if channel_info["inputByName"][channel]["assigned"]==False]
555
 
556
+ target_name = app_state["missingTemplates"][app_state["fillingCount"]-1]
 
557
  radio_label = target_name+' ('+str(app_state["fillingCount"])+'/'+str(app_state["totalFillingNum"])+')'
558
 
559
+ if len(app_state["stage1UnassignedInputs"])==1 or app_state["fillingCount"]==app_state["totalFillingNum"]:
560
  return {app_state_json : app_state,
561
  channel_info_json : channel_info,
562
+ radio : gr.Radio(choices=app_state["stage1UnassignedInputs"], value=[], label=radio_label),
563
  step2_btn : gr.Button(visible=False),
564
  next_btn : gr.Button("Next step", visible=True)}
565
  else:
566
  return {app_state_json : app_state,
567
  channel_info_json : channel_info,
568
+ radio : gr.Radio(choices=app_state["stage1UnassignedInputs"], value=[], label=radio_label)}
569
 
570
  step2_btn.click(
571
  fn = update_radio,
 
580
  )
581
 
582
  # step3
 
 
583
  def fill_value(app_state, channel_info, fill_mode):
584
 
585
  if fill_mode == 'zero':
 
596
  app_state["state"] = "step3-selecting"
597
  app_state = find_neighbors(app_state, channel_info, fill_mode)
598
 
599
+ name = app_state["missingTemplates"][0]
600
  idx = channel_info["templateByName"][name]["index"]
601
  value = app_state["stage1NewOrder"][idx]
602
  value = [channel_info["inputByIndex"][i] for i in value]
 
609
  value=value, label=label, visible=True),
610
  step3_btn : gr.Button(visible=True)}
611
 
612
+ fillmode_btn.click(
613
+ fn = fill_value,
614
+ inputs = [app_state_json, channel_info_json, in_fill_mode],
615
+ outputs = [app_state_json, in_fill_mode, fillmode_btn, chkbox_group, step3_btn, run_btn]
616
+ ).success(
617
+ fn = None,
618
+ js = init_js,
619
+ inputs = [app_state_json, channel_info_json],
620
+ outputs = []
621
+ )
622
+
623
  def update_chkbox(app_state, channel_info, selected):
624
 
625
  # save info before clicking on next_btn
626
+ prev_target_name = app_state["missingTemplates"][app_state["fillingCount"]-1]
627
+ prev_target_idx = channel_info["templateByName"][prev_target_name]["index"]
628
+ if selected == []:
629
+ app_state["stage1NewOrder"][prev_target_idx] = []
630
+ else:
631
  selected_idx = [channel_info["inputByName"][channel]["index"] for channel in selected]
632
  app_state["stage1NewOrder"][prev_target_idx] = selected_idx
633
+ #print('Selection for missing channel "{}"({}): {}'.format(prev_target_name, prev_target_idx, selected))
 
634
 
635
+ # update the current round
636
  app_state["fillingCount"] += 1
637
 
638
+ target_name = app_state["missingTemplates"][app_state["fillingCount"]-1]
639
  target_idx = channel_info["templateByName"][target_name]["index"]
640
 
641
  chkbox_value = app_state["stage1NewOrder"][target_idx]
 
672
 
673
  def reset_run(app_state, channel_info, raw_data, model_name):
674
  filepath = app_state["filepath"]
675
+ delete_file(filepath+'mapped.csv')
676
+ delete_file(filepath+'denoised.csv')
677
+
678
  input_name = os.path.basename(str(raw_data))
679
  output_name = os.path.splitext(input_name)[0]+'_'+model_name+'.csv'
680
 
681
+ in_num = len(channel_info["inputByIndex"])
682
+ matched_num = len([channel for channel in channel_info["inputByIndex"]
683
  if channel_info["inputByName"][channel]["matched"]==True])
684
  batch_num = math.ceil((in_num-matched_num)/30) + 1
685
 
 
688
  "runnigState" : "stage1",
689
  "batchCount" : 1,
690
  "totalBatchNum" : batch_num,
691
+ "stage2UnassignedInputs" : app_state["stage1UnassignedInputs"],
692
+ "stage2NewOrder" : [[]]*30,
693
  })
694
 
695
+ # reset in.assigned back to the state after Stage1
696
+ for channel in app_state["stage1UnassignedInputs"]:
697
+ channel_info["inputByName"][channel]["assigned"] = False
698
+
699
  return {app_state_json : app_state,
700
+ channel_info_json : channel_info,
701
  run_btn : gr.Button(interactive=False),
702
  batch_md : gr.Markdown(visible=False),
703
  out_denoised_data : gr.File(visible=False)}
 
717
  if app_state["batchCount"] > 1:
718
  app_state, channel_info = mapping_stage2(app_state, channel_info, fill_mode)
719
  if app_state["runnigState"] == "finished":
720
+ #yield {batch_md : gr.Markdown("error", visible=True)}
721
  break
722
 
723
  reorder_to_template(app_state, raw_data)
 
743
  run_btn.click(
744
  fn = reset_run,
745
  inputs = [app_state_json, channel_info_json, in_raw_data, in_model_name],
746
+ outputs = [app_state_json, channel_info_json, run_btn, batch_md, out_denoised_data]
747
 
748
  ).success(
749
  fn = run_model,
channel_mapping.py CHANGED
@@ -15,8 +15,8 @@ def reorder_to_template(app_state, filename):
15
  old_data = utils.read_train_data(filename) # original raw data
16
  new_data = np.zeros((30, old_data.shape[1])) # reordered raw data
17
  new_filename = app_state["filepath"]+'mapped.csv'
18
- print('new order 1:', app_state["stage1NewOrder"])
19
- print('new order 2:', app_state["stage2NewOrder"])
20
 
21
  zero_arr = np.zeros((1, old_data.shape[1]))
22
  old_data = np.concatenate((old_data, zero_arr), axis=0)
@@ -41,7 +41,7 @@ def reorder_to_origin(app_state, channel_info, filename, new_filename):
41
  template_order = channel_info["templateByIndex"]
42
 
43
  if app_state["runnigState"] == "stage1":
44
- new_data = np.zeros((len(channel_info["inputByName"]), old_data.shape[1]))
45
  else:
46
  new_data = utils.read_train_data(new_filename)
47
 
@@ -94,7 +94,7 @@ def align_coords(channel_info, template_montage, input_montage):
94
  input_dict = channel_info["inputByName"]
95
  template_order = channel_info["templateByIndex"]
96
  input_order = channel_info["inputByIndex"]
97
- matched = [channel for channel in input_dict if input_dict[channel]["matched"]==True]
98
 
99
  # 2-d (for the indication of missing template channel's position when fill_mode:'mean_manual')
100
  fig = [template_montage.plot(), input_montage.plot()]
@@ -168,8 +168,8 @@ def find_neighbors(app_state, channel_info, fill_mode):
168
  template_order = channel_info["templateByIndex"]
169
  input_order = channel_info["inputByIndex"]
170
  #z_row_idx = channel_info["dataShape"][0]
171
- unmatched = [channel for channel in template_dict if template_dict[channel]["matched"]==False]
172
- if unmatched == []:
173
  return app_state # change mothing
174
 
175
 
@@ -177,11 +177,11 @@ def find_neighbors(app_state, channel_info, fill_mode):
177
  in_coords = np.array([in_coords[i] for i in range(len(in_coords))])
178
 
179
  # use KNN to choose k nearest channels
180
- k = 4 if len(input_dict)>4 else len(input_dict)
181
  knn = NearestNeighbors(n_neighbors=k, metric='euclidean')
182
  knn.fit(in_coords)
183
 
184
- for channel in unmatched:
185
  distances, indices = knn.kneighbors(np.array(template_dict[channel]["coord"]).reshape(1,-1))
186
  selected = [input_order[i] for i in indices[0]]
187
  print(channel, ':', selected)
@@ -202,8 +202,8 @@ def mapping_stage1(app_state, channel_info, loc_file):
202
 
203
  template_montage, input_montage, template_dict, input_dict = read_montage_data(loc_file)
204
  template_order = template_montage.ch_names
 
205
  new_idx = [[]]*30
206
- missing_channels = []
207
  alias = {
208
  'T3': 'T7',
209
  'T4': 'T8',
@@ -227,19 +227,18 @@ def mapping_stage1(app_state, channel_info, loc_file):
227
  template_dict[channel].matched = True
228
  input_dict[channel].matched = True
229
  input_dict[channel].assigned = True
230
- else:
231
- missing_channels.append(channel)
232
 
233
  channel_info.update({
234
- "missingChannels" : missing_channels,
235
  "templateByName" : {k : v.__dict__ for k,v in template_dict.items()},
236
  "inputByName" : {k : v.__dict__ for k,v in input_dict.items()},
237
- "templateByIndex" : template_montage.ch_names,
238
- "inputByIndex" : input_montage.ch_names
239
  })
240
  app_state.update({
241
  "stage1NewOrder" : new_idx,
242
- "runnigState" : "stage1"
 
 
243
  })
244
 
245
  # align input, template's coordinates
@@ -257,7 +256,8 @@ def mapping_stage2(app_state, channel_info, fill_mode):
257
  template_dict = channel_info["templateByName"]
258
  input_dict = channel_info["inputByName"]
259
  template_order = channel_info["templateByIndex"]
260
- unassigned = [channel for channel in input_dict if input_dict[channel]["assigned"]==False]
 
261
  if unassigned == []:
262
  app_state["runnigState"] = "finished"
263
  return app_state, channel_info
@@ -265,7 +265,7 @@ def mapping_stage2(app_state, channel_info, fill_mode):
265
  tpl_coords = np.array([template_dict[channel]["coord"] for channel in template_order])
266
  unassigned_coords = np.array([input_dict[channel]["coord"] for channel in unassigned])
267
 
268
- # set all tpl.matched to False
269
  for channel in template_dict:
270
  template_dict[channel]["matched"] = False
271
 
@@ -302,10 +302,12 @@ def mapping_stage2(app_state, channel_info, fill_mode):
302
  })
303
  app_state.update({
304
  "stage2NewOrder" : new_idx,
305
- "runnigState" : "stage2"
 
 
306
  })
307
 
308
- # fill the unmatched channels
309
  app_state = find_neighbors(app_state, channel_info, fill_mode)
310
 
311
  second2 = time.time()
 
15
  old_data = utils.read_train_data(filename) # original raw data
16
  new_data = np.zeros((30, old_data.shape[1])) # reordered raw data
17
  new_filename = app_state["filepath"]+'mapped.csv'
18
+ #print('new order 1:', app_state["stage1NewOrder"])
19
+ #print('new order 2:', app_state["stage2NewOrder"])
20
 
21
  zero_arr = np.zeros((1, old_data.shape[1]))
22
  old_data = np.concatenate((old_data, zero_arr), axis=0)
 
41
  template_order = channel_info["templateByIndex"]
42
 
43
  if app_state["runnigState"] == "stage1":
44
+ new_data = np.zeros((len(channel_info["inputByIndex"]), old_data.shape[1]))
45
  else:
46
  new_data = utils.read_train_data(new_filename)
47
 
 
94
  input_dict = channel_info["inputByName"]
95
  template_order = channel_info["templateByIndex"]
96
  input_order = channel_info["inputByIndex"]
97
+ matched = [channel for channel in input_order if input_dict[channel]["matched"]==True]
98
 
99
  # 2-d (for the indication of missing template channel's position when fill_mode:'mean_manual')
100
  fig = [template_montage.plot(), input_montage.plot()]
 
168
  template_order = channel_info["templateByIndex"]
169
  input_order = channel_info["inputByIndex"]
170
  #z_row_idx = channel_info["dataShape"][0]
171
+ missing_channels = app_state["missingTemplates"]
172
+ if missing_channels == []:
173
  return app_state # change mothing
174
 
175
 
 
177
  in_coords = np.array([in_coords[i] for i in range(len(in_coords))])
178
 
179
  # use KNN to choose k nearest channels
180
+ k = 4 if len(input_order)>4 else len(input_order)
181
  knn = NearestNeighbors(n_neighbors=k, metric='euclidean')
182
  knn.fit(in_coords)
183
 
184
+ for channel in missing_channels:
185
  distances, indices = knn.kneighbors(np.array(template_dict[channel]["coord"]).reshape(1,-1))
186
  selected = [input_order[i] for i in indices[0]]
187
  print(channel, ':', selected)
 
202
 
203
  template_montage, input_montage, template_dict, input_dict = read_montage_data(loc_file)
204
  template_order = template_montage.ch_names
205
+ input_order = input_montage.ch_names
206
  new_idx = [[]]*30
 
207
  alias = {
208
  'T3': 'T7',
209
  'T4': 'T8',
 
227
  template_dict[channel].matched = True
228
  input_dict[channel].matched = True
229
  input_dict[channel].assigned = True
 
 
230
 
231
  channel_info.update({
 
232
  "templateByName" : {k : v.__dict__ for k,v in template_dict.items()},
233
  "inputByName" : {k : v.__dict__ for k,v in input_dict.items()},
234
+ "templateByIndex" : template_order,
235
+ "inputByIndex" : input_order
236
  })
237
  app_state.update({
238
  "stage1NewOrder" : new_idx,
239
+ "runnigState" : "stage1",
240
+ "stage1UnassignedInputs" : [channel for channel in input_order if input_dict[channel].assigned==False],
241
+ "missingTemplates" : [channel for channel in template_order if template_dict[channel].matched==False]
242
  })
243
 
244
  # align input, template's coordinates
 
256
  template_dict = channel_info["templateByName"]
257
  input_dict = channel_info["inputByName"]
258
  template_order = channel_info["templateByIndex"]
259
+ input_order = channel_info["inputByIndex"]
260
+ unassigned = app_state["stage2UnassignedInputs"]
261
  if unassigned == []:
262
  app_state["runnigState"] = "finished"
263
  return app_state, channel_info
 
265
  tpl_coords = np.array([template_dict[channel]["coord"] for channel in template_order])
266
  unassigned_coords = np.array([input_dict[channel]["coord"] for channel in unassigned])
267
 
268
+ # reset all tpl.matched to False
269
  for channel in template_dict:
270
  template_dict[channel]["matched"] = False
271
 
 
302
  })
303
  app_state.update({
304
  "stage2NewOrder" : new_idx,
305
+ "runnigState" : "stage2",
306
+ "stage2UnassignedInputs" : [channel for channel in input_order if input_dict[channel]["assigned"]==False],
307
+ "missingTemplates" : [channel for channel in template_order if template_dict[channel]["matched"]==False]
308
  })
309
 
310
+ # fill the missing_channels channels
311
  app_state = find_neighbors(app_state, channel_info, fill_mode)
312
 
313
  second2 = time.time()