cwadayi commited on
Commit
91e1a52
·
verified ·
1 Parent(s): a284b49

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +139 -1
app.py CHANGED
@@ -180,4 +180,142 @@ def plot_map_path(df):
180
  d["Magnitude"] = pd.to_numeric(d["Magnitude"], errors="coerce").fillna(0).clip(lower=0)
181
  d["Depth_km"] = pd.to_numeric(d["Depth_km"], errors="coerce")
182
 
183
- # 自動
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
180
  d["Magnitude"] = pd.to_numeric(d["Magnitude"], errors="coerce").fillna(0).clip(lower=0)
181
  d["Depth_km"] = pd.to_numeric(d["Depth_km"], errors="coerce")
182
 
183
+ # 自動範圍 + padding
184
+ pad = 0.5
185
+ lon_min, lon_max = d["Lon"].min() - pad, d["Lon"].max() + pad
186
+ lat_min, lat_max = d["Lat"].min() - pad, d["Lat"].max() + pad
187
+
188
+ # 點大小(可依喜好調係數)
189
+ size = (d["Magnitude"] + 2) ** 3
190
+
191
+ # 繪圖
192
+ fig, ax = plt.subplots(figsize=(6, 6))
193
+ ax.set_xlim(lon_min, lon_max)
194
+ ax.set_ylim(lat_min, lat_max)
195
+
196
+ sc = ax.scatter(d["Lon"], d["Lat"], s=size, c=d["Depth_km"],
197
+ edgecolor="black", alpha=0.9)
198
+
199
+ cb = plt.colorbar(sc, ax=ax, fraction=0.046, pad=0.04)
200
+ cb.set_label("Depth (km)")
201
+
202
+ ax.set_xlabel("Longitude (°E)")
203
+ ax.set_ylabel("Latitude (°N)")
204
+ ax.set_title("Epicenters (auto region, simple map)")
205
+ ax.grid(True, linestyle="--", alpha=0.3)
206
+
207
+ return _save_fig_to_tmp(fig)
208
+
209
+ # -----------------------------
210
+ # 表格輸出(tabulate 可選)
211
+ # -----------------------------
212
+ def _format_taipei(series):
213
+ try:
214
+ if series.dt.tz is None:
215
+ s = series.dt.tz_localize(TAIPEI_TZ)
216
+ else:
217
+ s = series.dt.tz_convert(TAIPEI_TZ)
218
+ return s.dt.strftime("%Y-%m-%d %H:%M:%S %Z")
219
+ except Exception:
220
+ return series.astype(str)
221
+
222
+ def _to_simple_md_table(df: pd.DataFrame) -> str:
223
+ cols = list(df.columns)
224
+ header = "|" + "|".join(cols) + "|\n"
225
+ sep = "|" + "|".join(["---"] * len(cols)) + "|\n"
226
+ rows = []
227
+ for _, r in df.iterrows():
228
+ cells = []
229
+ for c in cols:
230
+ v = r.get(c, "")
231
+ cells.append("" if pd.isna(v) else str(v))
232
+ rows.append("|" + "|".join(cells) + "|")
233
+ return header + sep + "\n".join(rows)
234
+
235
+ def df_to_markdown(df, top_n=100):
236
+ if df.empty:
237
+ return "(查無資料)"
238
+ cols = ["OriginTime", "Magnitude", "Depth_km", "Lat", "Lon", "Location", "ReportURL"]
239
+ cols = [c for c in cols if c in df.columns]
240
+ slim = df[cols].head(top_n).copy()
241
+ if "OriginTime" in slim.columns:
242
+ slim["OriginTime"] = _format_taipei(slim["OriginTime"])
243
+ header = f"共 {len(df)} 筆,顯示前 {min(len(slim), top_n)} 筆\n\n"
244
+ if HAS_TABULATE:
245
+ table = slim.to_markdown(index=False)
246
+ else:
247
+ table = _to_simple_md_table(slim.reset_index(drop=True))
248
+ return header + table
249
+
250
+ # -----------------------------
251
+ # 主流程
252
+ # -----------------------------
253
+ def query_and_render(time_from, time_to, sort_order):
254
+ try:
255
+ raw = fetch_reports(time_from, time_to)
256
+ df = parse_ea0015(raw)
257
+ if df.empty:
258
+ return "(查無資料)", None, None, None
259
+
260
+ if sort_order == "OriginTime (舊→新)":
261
+ df = df.sort_values("OriginTime", ascending=True, na_position="last").reset_index(drop=True)
262
+
263
+ md = df_to_markdown(df)
264
+ trend_path = plot_trend_path(df)
265
+ map_path = plot_map_path(df)
266
+
267
+ csv_bytes = df.to_csv(index=False).encode("utf-8-sig")
268
+ csv_path = tempfile.NamedTemporaryFile(delete=False, suffix=".csv", prefix="CWA_E-A0015-001_").name
269
+ with open(csv_path, "wb") as f:
270
+ f.write(csv_bytes)
271
+
272
+ return md, trend_path, map_path, csv_path
273
+ except Exception as e:
274
+ return f"錯誤:{e}", None, None, None
275
+
276
+ # -----------------------------
277
+ # 介面
278
+ # -----------------------------
279
+ default_from, default_to = set_time_range(days=3)
280
+
281
+ with gr.Blocks(fill_height=True) as demo:
282
+ gr.Markdown("## CWA 顯著有感地震報告 (E-A0015-001)\n預設查詢最近 3 天(台北時間)")
283
+
284
+ with gr.Column():
285
+ time_from = gr.Textbox(label="timeFrom yyyy-MM-ddTHH:mm:ss", value=default_from)
286
+ time_to = gr.Textbox(label="timeTo yyyy-MM-ddTHH:mm:ss", value=default_to)
287
+
288
+ with gr.Row():
289
+ btn_12h = gr.Button("最近 12 小時")
290
+ btn_24h = gr.Button("最近 24 小時")
291
+ btn_3d = gr.Button("最近 3 天")
292
+ btn_5d = gr.Button("最近 5 天")
293
+
294
+ sort_dd = gr.Dropdown(
295
+ choices=["OriginTime (新→舊)", "OriginTime (舊→新)"],
296
+ value="OriginTime (新→舊)",
297
+ label="排序",
298
+ )
299
+
300
+ run_btn = gr.Button("查詢", variant="primary")
301
+
302
+ table_out = gr.Markdown("(尚未查詢)")
303
+ trend_out = gr.Image(label="趨勢圖", type="filepath")
304
+ map_out = gr.Image(label="台灣範圍圖(簡易)", type="filepath")
305
+ dl_btn = gr.DownloadButton(label="下載 CSV") # 回傳路徑即可
306
+
307
+ # 快速鍵
308
+ btn_12h.click(lambda: set_time_range(hours=12), outputs=[time_from, time_to])
309
+ btn_24h.click(lambda: set_time_range(hours=24), outputs=[time_from, time_to])
310
+ btn_3d.click(lambda: set_time_range(days=3), outputs=[time_from, time_to])
311
+ btn_5d.click(lambda: set_time_range(days=5), outputs=[time_from, time_to])
312
+
313
+ # ���詢
314
+ run_btn.click(
315
+ query_and_render,
316
+ inputs=[time_from, time_to, sort_dd],
317
+ outputs=[table_out, trend_out, map_out, dl_btn],
318
+ )
319
+
320
+ if __name__ == "__main__":
321
+ demo.launch()