jimmy60504 commited on
Commit
14b5ab9
·
1 Parent(s): f202901

docs: refactor event handling functions and streamline output parameters

Browse files
Files changed (1) hide show
  1. app.py +15 -94
app.py CHANGED
@@ -1003,27 +1003,6 @@ def create_intensity_map(pga_list, target_names, epicenter_lat=None, epicenter_l
1003
  hoverinfo='skip'
1004
  ))
1005
 
1006
- # 如果有震央位置,標記震央(紅色大點)
1007
- if epicenter_lat and epicenter_lon:
1008
- fig.add_trace(go.Scattermap(
1009
- lat=[epicenter_lat],
1010
- lon=[epicenter_lon],
1011
- mode='markers',
1012
- marker=dict(size=25, color='red'),
1013
- text=[f'震央<br>({epicenter_lat:.3f}, {epicenter_lon:.3f})'],
1014
- hovertemplate='%{text}<extra></extra>',
1015
- name='震央',
1016
- showlegend=True
1017
- ))
1018
-
1019
- fig.add_trace(go.Scattermap(
1020
- lat=[epicenter_lat],
1021
- lon=[epicenter_lon],
1022
- mode='markers',
1023
- marker=dict(size=10, color='white'),
1024
- showlegend=False
1025
- ))
1026
-
1027
  # 設置地圖佈局
1028
  fig.update_layout(
1029
  map=dict(
@@ -1072,41 +1051,6 @@ def load_observed_intensity_image(event_name):
1072
  return None
1073
 
1074
 
1075
- def on_event_select(event_name):
1076
- """當選擇事件時立即載入實際觀測震度圖"""
1077
- observed_intensity_path = load_observed_intensity_image(event_name)
1078
- if observed_intensity_path:
1079
- return observed_intensity_path
1080
- else:
1081
- return None
1082
-
1083
-
1084
- def on_event_change(event_name, start_time, duration, epicenter_lon, epicenter_lat):
1085
- """
1086
- 當選擇事件時,同時更新波形地圖、波形圖、實際觀測圖
1087
-
1088
- Returns:
1089
- (station_map, waveform_plot, info_text, observed_intensity_path)
1090
- """
1091
- try:
1092
- # 同時更新波形地圖
1093
- station_map, waveform_plot, info_text, _ = load_and_display_waveform(
1094
- event_name, start_time, duration, epicenter_lon, epicenter_lat
1095
- )
1096
-
1097
- # 同時更新實際觀測圖
1098
- observed_intensity_path = load_observed_intensity_image(event_name)
1099
-
1100
- return station_map, waveform_plot, info_text, observed_intensity_path
1101
-
1102
- except Exception as e:
1103
- logger.error(f"事件切換時發生錯誤: {e}")
1104
- return None, None, f"錯誤: {str(e)}", None
1105
-
1106
-
1107
-
1108
-
1109
-
1110
  def load_and_display_waveform(event_name, start_time, duration):
1111
  """載入並顯示波形,讓使用者確認範圍
1112
 
@@ -1139,24 +1083,14 @@ def load_and_display_waveform(event_name, start_time, duration):
1139
  # 4. 創建輸入測站地圖
1140
  station_map = create_input_station_map(selected_stations, epicenter_lat, epicenter_lon)
1141
 
1142
- # 明示實際用站數(少於 25 站時顯示警告)
1143
- info_text = f"✅ 已載入波形資料\n"
1144
- info_text += f"開始時間: {start_time:.1f} 秒\n"
1145
- info_text += f"時間長度: {duration:.1f} 秒 ({start_time:.1f} - {end_time:.1f})\n"
1146
- info_text += f"震央位置: ({epicenter_lon:.4f}, {epicenter_lat:.4f})\n"
1147
- info_text += f"選擇了 {len(selected_stations)} 個最近的測站"
1148
- if len(selected_stations) < 25:
1149
- info_text += f" ⚠️(目標 25 個,實際 {len(selected_stations)} 個)"
1150
- info_text += "\n請確認波形範圍後,點擊「執行預測」按鈕"
1151
-
1152
  logger.info("波形載入完成")
1153
- return station_map, waveform_plot, info_text, gr.update(interactive=True)
1154
 
1155
  except Exception as e:
1156
  logger.error(f"波形載入發生錯誤: {e}")
1157
  import traceback
1158
  traceback.print_exc()
1159
- return None, None, f"錯誤: {str(e)}", gr.update(interactive=False)
1160
 
1161
 
1162
  def predict_intensity(event_name, start_time, duration):
@@ -1267,26 +1201,14 @@ def predict_intensity(event_name, start_time, duration):
1267
  # 載入實際觀測震度圖(filepath;左側以 800 高顯示)
1268
  observed_intensity_path = load_observed_intensity_image(event_name)
1269
 
1270
- # 統計資訊(包含目標點數)
1271
- max_intensity = max([calculate_intensity(pga, label=True) for pga in pga_list])
1272
- stats = f"✅ 預測完成!\n"
1273
- stats += f"開始時間: {start_time:.1f} 秒\n"
1274
- stats += f"時間長度: {duration:.1f} 秒 ({start_time:.1f} - {end_time:.1f})\n"
1275
- stats += f"震央位置: ({epicenter_lon:.4f}, {epicenter_lat:.4f})\n"
1276
- stats += f"使用測站數: {len(waveforms)} / 25\n"
1277
- if missing_components_count > 0:
1278
- stats += f"⚠️ 缺少 N/E 分量測站數: {missing_components_count} (已以 Z 分量代替)\n"
1279
- stats += f"預測目標點數: {len(all_target_names)}\n"
1280
- stats += f"預測最大震度: {max_intensity}"
1281
-
1282
  logger.info("預測完成!")
1283
- return observed_intensity_path, intensity_map, stats
1284
 
1285
  except Exception as e:
1286
  logger.error(f"預測過程發生錯誤: {e}")
1287
  import traceback
1288
  traceback.print_exc()
1289
- return None, None, f"錯誤: {str(e)}"
1290
 
1291
 
1292
  def on_full_workflow(event_name, start_time, duration):
@@ -1296,7 +1218,7 @@ def on_full_workflow(event_name, start_time, duration):
1296
  此函數用於首次應用加載與事件切換時自動執行完整流程
1297
 
1298
  返回所有必要的 UI 組件輸出:
1299
- (station_map, waveform_plot, info_text, predicted_map, stats_text, observed_img)
1300
 
1301
  spec #2:測站選擇上限 (25 站)、波形取樣率 (100 Hz)、時間窗長度 (30 秒)
1302
  spec #3:推論流程、PGA → 震度轉換
@@ -1306,27 +1228,27 @@ def on_full_workflow(event_name, start_time, duration):
1306
 
1307
  # 步驟 1: 載入波形
1308
  logger.info(f"[on_full_workflow] 步驟 1/3: 波形載入...")
1309
- station_map, waveform_plot, info_text, _ = load_and_display_waveform(
1310
  event_name, start_time, duration
1311
  )
1312
 
1313
  if station_map is None:
1314
  logger.error("[on_full_workflow] 波形載入失敗")
1315
- return None, None, info_text, None, "波形載入失敗", None
1316
 
1317
  # 步驟 2: 執行推論
1318
  logger.info(f"[on_full_workflow] 步驟 2/3: 模型推論...")
1319
- observed_img, predicted_map, stats_text = predict_intensity(
1320
  event_name, start_time, duration
1321
  )
1322
 
1323
  if predicted_map is None:
1324
  logger.error("[on_full_workflow] 推論失敗")
1325
- return station_map, waveform_plot, info_text, None, stats_text, observed_img
1326
 
1327
  logger.info(f"[on_full_workflow] 步驟 3/3: 完成")
1328
 
1329
- return station_map, waveform_plot, info_text, predicted_map, stats_text, observed_img
1330
 
1331
  except Exception as e:
1332
  logger.error(f"[on_full_workflow] 完整工作流發生錯誤: {e}")
@@ -1354,8 +1276,7 @@ with gr.Blocks(title="TTSAM 震度預測系統", fill_height=True) as demo:
1354
  系統會自動選擇距離震央最近的 25 個測站
1355
  """)
1356
 
1357
- info_output = gr.Textbox(label="狀態資訊", lines=6, interactive=False)
1358
- stats_output = gr.Textbox(label="預測統計", lines=4, interactive=False)
1359
 
1360
  # 右上:輸入參數
1361
  with gr.Column(scale=1):
@@ -1416,19 +1337,19 @@ with gr.Blocks(title="TTSAM 震度預測系統", fill_height=True) as demo:
1416
  *on_full_workflow(event_name, start_time, duration),
1417
  ),
1418
  inputs=[event_dropdown, start_slider, duration_slider],
1419
- outputs=[input_station_map, waveform_plot, info_output, predicted_intensity_map, stats_output, observed_intensity_image]
1420
  )
1421
 
1422
  load_waveform_btn.click(
1423
  fn=load_and_display_waveform,
1424
  inputs=[event_dropdown, start_slider, duration_slider],
1425
- outputs=[input_station_map, waveform_plot, info_output, predict_btn]
1426
  )
1427
 
1428
  predict_btn.click(
1429
  fn=predict_intensity,
1430
  inputs=[event_dropdown, start_slider, duration_slider],
1431
- outputs=[observed_intensity_image, predicted_intensity_map, stats_output]
1432
  )
1433
 
1434
  # 應用啟動時自動執行完整工作流
@@ -1437,7 +1358,7 @@ with gr.Blocks(title="TTSAM 震度預測系統", fill_height=True) as demo:
1437
  *on_full_workflow(event_name, start_time, duration),
1438
  ),
1439
  inputs=[event_dropdown, start_slider, duration_slider],
1440
- outputs=[input_station_map, waveform_plot, info_output, predicted_intensity_map, stats_output, observed_intensity_image]
1441
  )
1442
 
1443
  demo.launch()
 
1003
  hoverinfo='skip'
1004
  ))
1005
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1006
  # 設置地圖佈局
1007
  fig.update_layout(
1008
  map=dict(
 
1051
  return None
1052
 
1053
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1054
  def load_and_display_waveform(event_name, start_time, duration):
1055
  """載入並顯示波形,讓使用者確認範圍
1056
 
 
1083
  # 4. 創建輸入測站地圖
1084
  station_map = create_input_station_map(selected_stations, epicenter_lat, epicenter_lon)
1085
 
 
 
 
 
 
 
 
 
 
 
1086
  logger.info("波形載入完成")
1087
+ return station_map, waveform_plot, gr.update(interactive=True)
1088
 
1089
  except Exception as e:
1090
  logger.error(f"波形載入發生錯誤: {e}")
1091
  import traceback
1092
  traceback.print_exc()
1093
+ return None, None, gr.update(interactive=False)
1094
 
1095
 
1096
  def predict_intensity(event_name, start_time, duration):
 
1201
  # 載入實際觀測震度圖(filepath;左側以 800 高顯示)
1202
  observed_intensity_path = load_observed_intensity_image(event_name)
1203
 
 
 
 
 
 
 
 
 
 
 
 
 
1204
  logger.info("預測完成!")
1205
+ return observed_intensity_path, intensity_map
1206
 
1207
  except Exception as e:
1208
  logger.error(f"預測過程發生錯誤: {e}")
1209
  import traceback
1210
  traceback.print_exc()
1211
+ return None, None
1212
 
1213
 
1214
  def on_full_workflow(event_name, start_time, duration):
 
1218
  此函數用於首次應用加載與事件切換時自動執行完整流程
1219
 
1220
  返回所有必要的 UI 組件輸出:
1221
+ (station_map, waveform_plot, predicted_map, observed_img)
1222
 
1223
  spec #2:測站選擇上限 (25 站)、波形取樣率 (100 Hz)、時間窗長度 (30 秒)
1224
  spec #3:推論流程、PGA → 震度轉換
 
1228
 
1229
  # 步驟 1: 載入波形
1230
  logger.info(f"[on_full_workflow] 步驟 1/3: 波形載入...")
1231
+ station_map, waveform_plot, _ = load_and_display_waveform(
1232
  event_name, start_time, duration
1233
  )
1234
 
1235
  if station_map is None:
1236
  logger.error("[on_full_workflow] 波形載入失敗")
1237
+ return None, None, None, None
1238
 
1239
  # 步驟 2: 執行推論
1240
  logger.info(f"[on_full_workflow] 步驟 2/3: 模型推論...")
1241
+ observed_img, predicted_map = predict_intensity(
1242
  event_name, start_time, duration
1243
  )
1244
 
1245
  if predicted_map is None:
1246
  logger.error("[on_full_workflow] 推論失敗")
1247
+ return station_map, waveform_plot, None, observed_img
1248
 
1249
  logger.info(f"[on_full_workflow] 步驟 3/3: 完成")
1250
 
1251
+ return station_map, waveform_plot, predicted_map, observed_img
1252
 
1253
  except Exception as e:
1254
  logger.error(f"[on_full_workflow] 完整工作流發生錯誤: {e}")
 
1276
  系統會自動選擇距離震央最近的 25 個測站
1277
  """)
1278
 
1279
+
 
1280
 
1281
  # 右上:輸入參數
1282
  with gr.Column(scale=1):
 
1337
  *on_full_workflow(event_name, start_time, duration),
1338
  ),
1339
  inputs=[event_dropdown, start_slider, duration_slider],
1340
+ outputs=[input_station_map, waveform_plot, predicted_intensity_map, observed_intensity_image]
1341
  )
1342
 
1343
  load_waveform_btn.click(
1344
  fn=load_and_display_waveform,
1345
  inputs=[event_dropdown, start_slider, duration_slider],
1346
+ outputs=[input_station_map, waveform_plot, predict_btn]
1347
  )
1348
 
1349
  predict_btn.click(
1350
  fn=predict_intensity,
1351
  inputs=[event_dropdown, start_slider, duration_slider],
1352
+ outputs=[observed_intensity_image, predicted_intensity_map]
1353
  )
1354
 
1355
  # 應用啟動時自動執行完整工作流
 
1358
  *on_full_workflow(event_name, start_time, duration),
1359
  ),
1360
  inputs=[event_dropdown, start_slider, duration_slider],
1361
+ outputs=[input_station_map, waveform_plot, predicted_intensity_map, observed_intensity_image]
1362
  )
1363
 
1364
  demo.launch()