jimmy60504 commited on
Commit
9894f5b
·
1 Parent(s): 12f3211

add waveform loading functionality and update Gradio interface for user interaction

Browse files
Files changed (1) hide show
  1. app.py +62 -14
app.py CHANGED
@@ -601,6 +601,40 @@ def plot_intensity_map(pga_list, target_names):
601
  return fig
602
 
603
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
604
  def predict_intensity(event_name, start_time, end_time, epicenter_lon, epicenter_lat, vs30_input):
605
  """執行震度預測"""
606
  try:
@@ -614,7 +648,7 @@ def predict_intensity(event_name, start_time, end_time, epicenter_lon, epicenter
614
  selected_stations = select_nearest_stations(st, epicenter_lat, epicenter_lon, n_stations=25)
615
 
616
  if len(selected_stations) == 0:
617
- return None, None, "錯誤:找不到有效的測站資料"
618
 
619
  # 3. 從選定的測站提取波形
620
  logger.info(f"提取波形資料(時間範圍: {start_time}-{end_time} 秒)...")
@@ -623,7 +657,7 @@ def predict_intensity(event_name, start_time, end_time, epicenter_lon, epicenter
623
  )
624
 
625
  if len(waveforms) == 0:
626
- return None, None, "錯誤:無法提取波形資料"
627
 
628
  # 4. Padding 到 25 個測站(模型要求)
629
  max_stations = 25
@@ -660,24 +694,24 @@ def predict_intensity(event_name, start_time, end_time, epicenter_lon, epicenter
660
  pga_list = torch.sum(weight * mu, dim=2).cpu().detach().numpy().flatten().tolist()
661
 
662
  # 8. 繪製結果
663
- waveform_plot = plot_waveform(st, selected_stations, start_time, end_time)
664
  intensity_plot = plot_intensity_map(pga_list, target_names)
665
 
666
  # 9. 統計資訊
667
  max_intensity = max([calculate_intensity(pga, label=True) for pga in pga_list])
668
- stats = f"選取時間範圍: {start_time:.1f} - {end_time:.1f} 秒\n"
 
669
  stats += f"震央位置: ({epicenter_lon:.4f}, {epicenter_lat:.4f})\n"
670
  stats += f"使用測站數: {len(waveforms)} / 25\n"
671
  stats += f"預測最大震度: {max_intensity}"
672
 
673
  logger.info("預測完成!")
674
- return waveform_plot, intensity_plot, stats
675
 
676
  except Exception as e:
677
  logger.error(f"預測過程發生錯誤: {e}")
678
  import traceback
679
  traceback.print_exc()
680
- return None, None, f"錯誤: {str(e)}"
681
 
682
 
683
  # ============ Gradio 介面 ============
@@ -712,32 +746,46 @@ with gr.Blocks(title="TTSAM 震度預測系統") as demo:
712
  info="剪力波速度(預設 600 m/s,若有 Vs30 資料會自動覆蓋)"
713
  )
714
 
715
- predict_btn = gr.Button("🔮 執行預測", variant="primary")
 
716
 
717
  gr.Markdown("""
718
- ### 說明
719
- - 系統會根據震央位置自動選擇最近的 25 個測站
720
- - 從選定的時間範圍提取波形資料(30 秒)
721
- - 預測全台灣目標測站的震度分布
 
 
 
722
  """)
723
 
 
 
724
  # 右側:震度分布圖
725
  with gr.Column(scale=1):
726
  gr.Markdown("## 預測震度分布")
727
  intensity_plot = gr.Plot(label="震度分布圖")
728
- stats_output = gr.Textbox(label="預測統計", lines=3)
729
 
730
  # 下方:波形圖
731
  with gr.Row():
732
  gr.Markdown("## 輸入波形")
733
  with gr.Row():
734
- waveform_plot = gr.Plot(label="地震波形")
735
 
736
  # 綁定事件
 
 
 
 
 
 
 
 
737
  predict_btn.click(
738
  fn=predict_intensity,
739
  inputs=[event_dropdown, start_slider, end_slider, epicenter_lon_input, epicenter_lat_input, vs30_input],
740
- outputs=[waveform_plot, intensity_plot, stats_output]
741
  )
742
 
743
  demo.launch()
 
601
  return fig
602
 
603
 
604
+ def load_and_display_waveform(event_name, start_time, end_time, epicenter_lon, epicenter_lat):
605
+ """載入並顯示波形,讓使用者確認範圍"""
606
+ try:
607
+ # 1. 載入完整的 mseed 檔案
608
+ logger.info(f"載入地震事件: {event_name}")
609
+ st = load_waveform(event_name)
610
+ logger.info(f"載入了 {len(st)} 個 trace")
611
+
612
+ # 2. 根據震央距離選擇最近的 25 個測站
613
+ logger.info(f"選擇距離震央 ({epicenter_lat}, {epicenter_lon}) 最近的測站...")
614
+ selected_stations = select_nearest_stations(st, epicenter_lat, epicenter_lon, n_stations=25)
615
+
616
+ if len(selected_stations) == 0:
617
+ return None, "錯誤:找不到有效的測站資料", gr.update(interactive=False)
618
+
619
+ # 3. 繪製波形
620
+ waveform_plot = plot_waveform(st, selected_stations, start_time, end_time)
621
+
622
+ info_text = f"✅ 已載入波形資料\n"
623
+ info_text += f"選取時間範圍: {start_time:.1f} - {end_time:.1f} 秒\n"
624
+ info_text += f"震央位置: ({epicenter_lon:.4f}, {epicenter_lat:.4f})\n"
625
+ info_text += f"選擇了 {len(selected_stations)} 個最近的測站\n"
626
+ info_text += f"請確認波形範圍後,點擊「執行預測」按鈕"
627
+
628
+ logger.info("波形載入完成")
629
+ return waveform_plot, info_text, gr.update(interactive=True)
630
+
631
+ except Exception as e:
632
+ logger.error(f"波形載入發生錯誤: {e}")
633
+ import traceback
634
+ traceback.print_exc()
635
+ return None, f"錯誤: {str(e)}", gr.update(interactive=False)
636
+
637
+
638
  def predict_intensity(event_name, start_time, end_time, epicenter_lon, epicenter_lat, vs30_input):
639
  """執行震度預測"""
640
  try:
 
648
  selected_stations = select_nearest_stations(st, epicenter_lat, epicenter_lon, n_stations=25)
649
 
650
  if len(selected_stations) == 0:
651
+ return None, "錯誤:找不到有效的測站資料"
652
 
653
  # 3. 從選定的測站提取波形
654
  logger.info(f"提取波形資料(時間範圍: {start_time}-{end_time} 秒)...")
 
657
  )
658
 
659
  if len(waveforms) == 0:
660
+ return None, "錯誤:無法提取波形資料"
661
 
662
  # 4. Padding 到 25 個測站(模型要求)
663
  max_stations = 25
 
694
  pga_list = torch.sum(weight * mu, dim=2).cpu().detach().numpy().flatten().tolist()
695
 
696
  # 8. 繪製結果
 
697
  intensity_plot = plot_intensity_map(pga_list, target_names)
698
 
699
  # 9. 統計資訊
700
  max_intensity = max([calculate_intensity(pga, label=True) for pga in pga_list])
701
+ stats = f" 預測完成!\n"
702
+ stats += f"選取時間範圍: {start_time:.1f} - {end_time:.1f} 秒\n"
703
  stats += f"震央位置: ({epicenter_lon:.4f}, {epicenter_lat:.4f})\n"
704
  stats += f"使用測站數: {len(waveforms)} / 25\n"
705
  stats += f"預測最大震度: {max_intensity}"
706
 
707
  logger.info("預測完成!")
708
+ return intensity_plot, stats
709
 
710
  except Exception as e:
711
  logger.error(f"預測過程發生錯誤: {e}")
712
  import traceback
713
  traceback.print_exc()
714
+ return None, f"錯誤: {str(e)}"
715
 
716
 
717
  # ============ Gradio 介面 ============
 
746
  info="剪力波速度(預設 600 m/s,若有 Vs30 資料會自動覆蓋)"
747
  )
748
 
749
+ load_waveform_btn = gr.Button("📊 載入波形", variant="secondary")
750
+ predict_btn = gr.Button("🔮 執行預測", variant="primary", interactive=False)
751
 
752
  gr.Markdown("""
753
+ ### 使用步驟
754
+ 1. 選擇地震事件和時間範圍
755
+ 2. 輸入震央位置
756
+ 3. 點擊「載入波形」確認波形範圍
757
+ 4. 確認無誤後,點擊「執行預測」
758
+
759
+ ℹ️ 系統會自動選擇距離震央最近的 25 個測站
760
  """)
761
 
762
+ info_output = gr.Textbox(label="狀態資訊", lines=5, interactive=False)
763
+
764
  # 右側:震度分布圖
765
  with gr.Column(scale=1):
766
  gr.Markdown("## 預測震度分布")
767
  intensity_plot = gr.Plot(label="震度分布圖")
768
+ stats_output = gr.Textbox(label="預測統計", lines=4)
769
 
770
  # 下方:波形圖
771
  with gr.Row():
772
  gr.Markdown("## 輸入波形")
773
  with gr.Row():
774
+ waveform_plot = gr.Plot(label="地震波形(前 10 個最近測站)")
775
 
776
  # 綁定事件
777
+ # 第一步:載入波形
778
+ load_waveform_btn.click(
779
+ fn=load_and_display_waveform,
780
+ inputs=[event_dropdown, start_slider, end_slider, epicenter_lon_input, epicenter_lat_input],
781
+ outputs=[waveform_plot, info_output, predict_btn]
782
+ )
783
+
784
+ # 第二步:執行預測
785
  predict_btn.click(
786
  fn=predict_intensity,
787
  inputs=[event_dropdown, start_slider, end_slider, epicenter_lon_input, epicenter_lat_input, vs30_input],
788
+ outputs=[intensity_plot, stats_output]
789
  )
790
 
791
  demo.launch()