Spaces:
Running
Running
Commit
·
4a61ef8
1
Parent(s):
b88beb1
refactor app.py and .dockerignore to rename ground truth references to observed intensity and update directory structure
Browse files- .dockerignore +1 -1
- app.py +27 -27
- {ground_truth → intensity_map}/20240403.png +0 -0
.dockerignore
CHANGED
|
@@ -6,7 +6,7 @@ intensityMap.html
|
|
| 6 |
# station/ 和 waveform/ 會在運行時從外部掛載
|
| 7 |
station/
|
| 8 |
waveform/
|
| 9 |
-
|
| 10 |
```
|
| 11 |
|
| 12 |
**Structure Decision**: 維持單一專案根目錄佈局,Gradio 介面在 `app.py`;地圖以 HTML/folium/Gradio HTML 容器渲染。
|
|
|
|
| 6 |
# station/ 和 waveform/ 會在運行時從外部掛載
|
| 7 |
station/
|
| 8 |
waveform/
|
| 9 |
+
intensity_map/
|
| 10 |
```
|
| 11 |
|
| 12 |
**Structure Decision**: 維持單一專案根目錄佈局,Gradio 介面在 `app.py`;地圖以 HTML/folium/Gradio HTML 容器渲染。
|
app.py
CHANGED
|
@@ -725,13 +725,13 @@ def create_intensity_map(pga_list, target_names, epicenter_lat=None, epicenter_l
|
|
| 725 |
import folium
|
| 726 |
from folium import plugins
|
| 727 |
|
| 728 |
-
# [T006] 創建地圖,設定固定高度 800(寬度 100
|
| 729 |
m = folium.Map(
|
| 730 |
location=[23.5, 121],
|
| 731 |
zoom_start=7,
|
| 732 |
tiles='OpenStreetMap',
|
| 733 |
width='100%',
|
| 734 |
-
height='800px' # [T006] 固定高度 800px
|
| 735 |
)
|
| 736 |
|
| 737 |
# 如果有震央位置,標記震央
|
|
@@ -833,11 +833,11 @@ def create_intensity_map(pga_list, target_names, epicenter_lat=None, epicenter_l
|
|
| 833 |
return m
|
| 834 |
|
| 835 |
|
| 836 |
-
def
|
| 837 |
"""
|
| 838 |
-
從
|
| 839 |
|
| 840 |
-
[T011]
|
| 841 |
"""
|
| 842 |
import os
|
| 843 |
|
|
@@ -847,25 +847,25 @@ def load_ground_truth_image(event_name):
|
|
| 847 |
event_date = os.path.basename(event_file).replace('.mseed', '')
|
| 848 |
|
| 849 |
# 嘗試不同的圖片格式
|
| 850 |
-
|
| 851 |
possible_extensions = ['.png', '.jpg', '.jpeg', '.gif']
|
| 852 |
|
| 853 |
for ext in possible_extensions:
|
| 854 |
-
image_path = os.path.join(
|
| 855 |
if os.path.exists(image_path):
|
| 856 |
-
logger.info(f"
|
| 857 |
return image_path
|
| 858 |
|
| 859 |
# [T011] 圖片不存在時記錄警告(UI 會用預設高度 800 顯示空白占位)
|
| 860 |
-
logger.warning(f"[T011]
|
| 861 |
return None
|
| 862 |
|
| 863 |
|
| 864 |
def on_event_select(event_name):
|
| 865 |
-
"""
|
| 866 |
-
|
| 867 |
-
if
|
| 868 |
-
return
|
| 869 |
else:
|
| 870 |
# 如果找不到圖片,返回 None(Gradio 會顯示空白)
|
| 871 |
return None
|
|
@@ -876,7 +876,7 @@ def create_input_station_map(selected_stations, epicenter_lat, epicenter_lon):
|
|
| 876 |
import folium
|
| 877 |
from folium import plugins
|
| 878 |
|
| 879 |
-
# [T007] 創建地圖,設定固定高度 800(寬度 100
|
| 880 |
m = folium.Map(
|
| 881 |
location=[epicenter_lat, epicenter_lon],
|
| 882 |
zoom_start=8,
|
|
@@ -1138,8 +1138,8 @@ def predict_intensity(event_name, start_time, duration, epicenter_lon, epicenter
|
|
| 1138 |
intensity_map = create_intensity_map(pga_list, target_names, epicenter_lat, epicenter_lon)
|
| 1139 |
map_html = intensity_map._repr_html_()
|
| 1140 |
|
| 1141 |
-
# [T010] 9.
|
| 1142 |
-
|
| 1143 |
|
| 1144 |
# [T010] 10. 統計資訊(包含目標點數)
|
| 1145 |
max_intensity = max([calculate_intensity(pga, label=True) for pga in pga_list])
|
|
@@ -1154,8 +1154,8 @@ def predict_intensity(event_name, start_time, duration, epicenter_lon, epicenter
|
|
| 1154 |
stats += f"預測最大震度: {max_intensity}"
|
| 1155 |
|
| 1156 |
logger.info("預測完成!")
|
| 1157 |
-
# [T010]
|
| 1158 |
-
return
|
| 1159 |
|
| 1160 |
except Exception as e:
|
| 1161 |
logger.error(f"預測過程發生錯誤: {e}")
|
|
@@ -1222,30 +1222,30 @@ with gr.Blocks(title="TTSAM 震度預測系統") as demo:
|
|
| 1222 |
gr.Markdown("## 輸入波形")
|
| 1223 |
waveform_plot = gr.Plot(label="地震波形(選定的 25 個測站)")
|
| 1224 |
|
| 1225 |
-
# ==========
|
| 1226 |
with gr.Row():
|
| 1227 |
# 左下:預測震度地圖
|
| 1228 |
with gr.Column(scale=1):
|
| 1229 |
gr.Markdown("## 預測震度分布")
|
| 1230 |
-
|
| 1231 |
|
| 1232 |
-
#
|
| 1233 |
with gr.Column(scale=1):
|
| 1234 |
-
gr.Markdown("##
|
| 1235 |
-
|
| 1236 |
label="實際觀測震度",
|
| 1237 |
type="filepath",
|
| 1238 |
height=800,
|
| 1239 |
-
value=
|
| 1240 |
)
|
| 1241 |
|
| 1242 |
|
| 1243 |
# 綁定事件
|
| 1244 |
-
#
|
| 1245 |
event_dropdown.change(
|
| 1246 |
fn=on_event_select,
|
| 1247 |
inputs=[event_dropdown],
|
| 1248 |
-
outputs=[
|
| 1249 |
)
|
| 1250 |
|
| 1251 |
# 第一步:載入波形
|
|
@@ -1259,7 +1259,7 @@ with gr.Blocks(title="TTSAM 震度預測系統") as demo:
|
|
| 1259 |
predict_btn.click(
|
| 1260 |
fn=predict_intensity,
|
| 1261 |
inputs=[event_dropdown, start_slider, duration_slider, epicenter_lon_input, epicenter_lat_input],
|
| 1262 |
-
outputs=[
|
| 1263 |
)
|
| 1264 |
|
| 1265 |
demo.launch()
|
|
|
|
| 725 |
import folium
|
| 726 |
from folium import plugins
|
| 727 |
|
| 728 |
+
# [T006] 創建地圖,設定固定高度 800(寬度 100%),與實際震度圖區塊一致
|
| 729 |
m = folium.Map(
|
| 730 |
location=[23.5, 121],
|
| 731 |
zoom_start=7,
|
| 732 |
tiles='OpenStreetMap',
|
| 733 |
width='100%',
|
| 734 |
+
height='800px' # [T006] 固定高度 800px,不再依實際震度圖尺寸動態調整
|
| 735 |
)
|
| 736 |
|
| 737 |
# 如果有震央位置,標記震央
|
|
|
|
| 833 |
return m
|
| 834 |
|
| 835 |
|
| 836 |
+
def load_observed_intensity_image(event_name):
|
| 837 |
"""
|
| 838 |
+
從 intensity_map 資料夾載入對應的實際觀測震度圖
|
| 839 |
|
| 840 |
+
[T011] 實際震度圖不存在時:顯示提示並用預設高度 800 呈現空白占位
|
| 841 |
"""
|
| 842 |
import os
|
| 843 |
|
|
|
|
| 847 |
event_date = os.path.basename(event_file).replace('.mseed', '')
|
| 848 |
|
| 849 |
# 嘗試不同的圖片格式
|
| 850 |
+
intensity_map_dir = "intensity_map"
|
| 851 |
possible_extensions = ['.png', '.jpg', '.jpeg', '.gif']
|
| 852 |
|
| 853 |
for ext in possible_extensions:
|
| 854 |
+
image_path = os.path.join(intensity_map_dir, f"{event_date}{ext}")
|
| 855 |
if os.path.exists(image_path):
|
| 856 |
+
logger.info(f"載入實際觀測震度圖: {image_path}")
|
| 857 |
return image_path
|
| 858 |
|
| 859 |
# [T011] 圖片不存在時記錄警告(UI 會用預設高度 800 顯示空白占位)
|
| 860 |
+
logger.warning(f"[T011] 找不到實際震度圖: {event_date}(將顯示空白占位)")
|
| 861 |
return None
|
| 862 |
|
| 863 |
|
| 864 |
def on_event_select(event_name):
|
| 865 |
+
"""當選擇事件時立即載入實際觀測震度圖"""
|
| 866 |
+
observed_intensity_path = load_observed_intensity_image(event_name)
|
| 867 |
+
if observed_intensity_path:
|
| 868 |
+
return observed_intensity_path
|
| 869 |
else:
|
| 870 |
# 如果找不到圖片,返回 None(Gradio 會顯示空白)
|
| 871 |
return None
|
|
|
|
| 876 |
import folium
|
| 877 |
from folium import plugins
|
| 878 |
|
| 879 |
+
# [T007] 創建地圖,設定固定高度 800(寬度 100%),與實際震度圖區塊一致
|
| 880 |
m = folium.Map(
|
| 881 |
location=[epicenter_lat, epicenter_lon],
|
| 882 |
zoom_start=8,
|
|
|
|
| 1138 |
intensity_map = create_intensity_map(pga_list, target_names, epicenter_lat, epicenter_lon)
|
| 1139 |
map_html = intensity_map._repr_html_()
|
| 1140 |
|
| 1141 |
+
# [T010] 9. 載入實際觀測震度圖(filepath;左側以 800 高顯示)
|
| 1142 |
+
observed_intensity_path = load_observed_intensity_image(event_name)
|
| 1143 |
|
| 1144 |
# [T010] 10. 統計資訊(包含目標點數)
|
| 1145 |
max_intensity = max([calculate_intensity(pga, label=True) for pga in pga_list])
|
|
|
|
| 1154 |
stats += f"預測最大震度: {max_intensity}"
|
| 1155 |
|
| 1156 |
logger.info("預測完成!")
|
| 1157 |
+
# [T010] 回傳:實際觀測震度圖(filepath;左側 800 高)、預測地圖(HTML;右側 800 高)、統計資訊
|
| 1158 |
+
return observed_intensity_path, map_html, stats
|
| 1159 |
|
| 1160 |
except Exception as e:
|
| 1161 |
logger.error(f"預測過程發生錯誤: {e}")
|
|
|
|
| 1222 |
gr.Markdown("## 輸入波形")
|
| 1223 |
waveform_plot = gr.Plot(label="地震波形(選定的 25 個測站)")
|
| 1224 |
|
| 1225 |
+
# ========== 下層:實際觀測 vs 預測結果 ==========
|
| 1226 |
with gr.Row():
|
| 1227 |
# 左下:預測震度地圖
|
| 1228 |
with gr.Column(scale=1):
|
| 1229 |
gr.Markdown("## 預測震度分布")
|
| 1230 |
+
predicted_intensity_map = gr.HTML(label="互動式震度地圖", elem_id="predicted_intensity_map")
|
| 1231 |
|
| 1232 |
+
# 右下:實際觀測震度圖
|
| 1233 |
with gr.Column(scale=1):
|
| 1234 |
+
gr.Markdown("## 實際觀測震度分布")
|
| 1235 |
+
observed_intensity_image = gr.Image(
|
| 1236 |
label="實際觀測震度",
|
| 1237 |
type="filepath",
|
| 1238 |
height=800,
|
| 1239 |
+
value=load_observed_intensity_image(list(EARTHQUAKE_EVENTS.keys())[0]) # 初始載入第一個事件的實際震度圖
|
| 1240 |
)
|
| 1241 |
|
| 1242 |
|
| 1243 |
# 綁定事件
|
| 1244 |
+
# 第零步:選擇事件時立即載入實際觀測震度圖
|
| 1245 |
event_dropdown.change(
|
| 1246 |
fn=on_event_select,
|
| 1247 |
inputs=[event_dropdown],
|
| 1248 |
+
outputs=[observed_intensity_image]
|
| 1249 |
)
|
| 1250 |
|
| 1251 |
# 第一步:載入波形
|
|
|
|
| 1259 |
predict_btn.click(
|
| 1260 |
fn=predict_intensity,
|
| 1261 |
inputs=[event_dropdown, start_slider, duration_slider, epicenter_lon_input, epicenter_lat_input],
|
| 1262 |
+
outputs=[observed_intensity_image, predicted_intensity_map, stats_output]
|
| 1263 |
)
|
| 1264 |
|
| 1265 |
demo.launch()
|
{ground_truth → intensity_map}/20240403.png
RENAMED
|
File without changes
|