cwadayi commited on
Commit
de88d4d
·
verified ·
1 Parent(s): b30ee3e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +56 -42
app.py CHANGED
@@ -62,7 +62,7 @@ def _to_float(x):
62
  """
63
  將各種數字表達轉成 float:
64
  - 純數字:23.5
65
- - 含單位/文字:'23.5°N'、'121.6 E'、'25.3 公里' -> 取第一個浮點數
66
  - 其他不可解析 -> None
67
  """
68
  if x is None:
@@ -91,7 +91,7 @@ def parse_ea0015(obj):
91
  ei = q.get("EarthquakeInfo") or q.get("earthquakeInfo") or {}
92
  epic = ei.get("Epicenter") or ei.get("epicenter") or {}
93
 
94
- # Magnitude 可能在 Magnitude 或 EarthquakeMagnitude 物件裡
95
  mago = (
96
  ei.get("Magnitude") or ei.get("magnitude")
97
  or ei.get("EarthquakeMagnitude") or ei.get("earthquakeMagnitude")
@@ -170,57 +170,71 @@ def plot_trend_path(df):
170
  fig.autofmt_xdate()
171
  return _save_fig_to_tmp(fig)
172
 
 
 
 
 
 
 
 
 
173
  def plot_map_path(df):
174
  """
175
- 優先使用 PyGMT 畫台灣地圖;若不可用則退回 matplotlib。
176
- 範圍:119/123, 21/26;顏色=深度(km),大小=規模
 
177
  """
178
- lon_min, lon_max, lat_min, lat_max = 119, 123, 21, 26
179
-
180
- # --- PyGMT 版 ---
181
- if HAS_PYGMT and not df.empty:
182
- d = df.dropna(subset=["Lon", "Lat"]).copy()
183
- if not d.empty:
184
- mag = pd.to_numeric(d["Magnitude"], errors="coerce").fillna(0).clip(lower=0)
185
- size_cm = 0.06 * (mag + 1.5) # 每點大小(cm)
186
- depth = pd.to_numeric(d["Depth_km"], errors="coerce").fillna(0)
187
-
188
- fig = pygmt.Figure()
189
- region = [lon_min, lon_max, lat_min, lat_max]
190
- fig.coast(
191
- region=region, projection="M12c",
192
- land="lightgray", water="white",
193
- shorelines="0.5p,black", borders="1/0.6p,black",
194
- frame=["WSen", "xaf", "yaf"]
195
- )
196
- fig.plot(
197
- x=d["Lon"].to_list(), y=d["Lat"].to_list(),
198
- style="cc", sizes=size_cm.to_list(),
199
- color=depth.to_list(), cmap="roma", pen="0.25p,black"
200
- )
201
- fig.colorbar(frame=["x+lDepth (km)"], cmap=True, position="JMR+w7c/0.4c+o0.6c/0c")
202
- fig.basemap(map_scale="jBL+w50k+o0.6c/0.6c+f+lkm")
203
-
204
- outpath = tempfile.NamedTemporaryFile(delete=False, suffix=".png").name
205
- fig.savefig(outpath, dpi=220)
206
- return outpath
207
-
208
- # --- Matplotlib 備援 ---
209
  if df.empty:
210
  return None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
211
  fig, ax = plt.subplots(figsize=(6, 6))
212
  ax.set_xlim(lon_min, lon_max)
213
  ax.set_ylim(lat_min, lat_max)
214
 
215
- mag = pd.to_numeric(df["Magnitude"], errors="coerce").fillna(0).clip(lower=0)
216
- s = (mag + 2) ** 3
217
- depth = pd.to_numeric(df["Depth_km"], errors="coerce")
218
-
219
- sc = ax.scatter(df["Lon"], df["Lat"], s=s, c=depth, alpha=0.85, edgecolor="black")
220
  cb = plt.colorbar(sc, ax=ax, fraction=0.046, pad=0.04)
221
  cb.set_label("Depth (km)")
222
- ax.set_xlabel("Longitude (°E)"); ax.set_ylabel("Latitude (°N)")
223
- ax.set_title("Epicenters in Taiwan Region (119–123E, 21–26N)")
 
224
  ax.grid(True, linestyle="--", alpha=0.3)
225
  return _save_fig_to_tmp(fig)
226
 
 
62
  """
63
  將各種數字表達轉成 float:
64
  - 純數字:23.5
65
+ - 含單位/文字:'23.5°N'、'121.6 E'、'25.3 公里' -> 擷取第一個浮點數
66
  - 其他不可解析 -> None
67
  """
68
  if x is None:
 
91
  ei = q.get("EarthquakeInfo") or q.get("earthquakeInfo") or {}
92
  epic = ei.get("Epicenter") or ei.get("epicenter") or {}
93
 
94
+ # Magnitude 可能在 Magnitude 或 EarthquakeMagnitude
95
  mago = (
96
  ei.get("Magnitude") or ei.get("magnitude")
97
  or ei.get("EarthquakeMagnitude") or ei.get("earthquakeMagnitude")
 
170
  fig.autofmt_xdate()
171
  return _save_fig_to_tmp(fig)
172
 
173
+ def _auto_region_from_df(d, pad=0.5):
174
+ """由資料自動推算地圖範圍,並加上邊界緩衝(degrees)。"""
175
+ lon_min = float(pd.to_numeric(d["Lon"], errors="coerce").min())
176
+ lon_max = float(pd.to_numeric(d["Lon"], errors="coerce").max())
177
+ lat_min = float(pd.to_numeric(d["Lat"], errors="coerce").min())
178
+ lat_max = float(pd.to_numeric(d["Lat"], errors="coerce").max())
179
+ return [lon_min - pad, lon_max + pad, lat_min - pad, lat_max + pad]
180
+
181
  def plot_map_path(df):
182
  """
183
+ 優先使用 PyGMT 畫台灣地圖(含海岸線);若不可用則退回 matplotlib。
184
+ - 自動依據資料決定地圖範圍(避免漏點)
185
+ - 顏色:深度(km);大小:規模
186
  """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
187
  if df.empty:
188
  return None
189
+
190
+ # 先清一下 NaN
191
+ d = df.dropna(subset=["Lon", "Lat"]).copy()
192
+ if d.empty:
193
+ return None
194
+
195
+ # 數值化
196
+ d["Magnitude"] = pd.to_numeric(d["Magnitude"], errors="coerce").fillna(0).clip(lower=0)
197
+ d["Depth_km"] = pd.to_numeric(d["Depth_km"], errors="coerce").fillna(0)
198
+
199
+ # --- PyGMT 版(DataFrame API + 海岸線 + 自動範圍) ---
200
+ if HAS_PYGMT:
201
+ d["Size"] = 0.06 * (d["Magnitude"] + 1.5) # cm
202
+ region = _auto_region_from_df(d, pad=0.5)
203
+
204
+ fig = pygmt.Figure()
205
+ fig.coast(
206
+ region=region, projection="M12c",
207
+ land="lightgray", water="white",
208
+ shorelines="0.5p,black", borders="1/0.6p,black",
209
+ frame=["WSen", "xaf", "yaf"]
210
+ )
211
+ fig.plot(
212
+ data=d, x="Lon", y="Lat",
213
+ style="c", size="Size",
214
+ color="Depth_km", cmap="roma", pen="0.25p,black"
215
+ )
216
+ fig.colorbar(frame=["x+lDepth (km)"], cmap=True, position="JMR+w7c/0.4c+o0.6c/0c")
217
+ fig.basemap(map_scale="jBL+w50k+o0.6c/0.6c+f+lkm")
218
+
219
+ outpath = tempfile.NamedTemporaryFile(delete=False, suffix=".png").name
220
+ fig.savefig(outpath, dpi=220)
221
+ return outpath
222
+
223
+ # --- Matplotlib 備援(自動範圍 + 簡易海岸線無法;以格線為主) ---
224
+ region = _auto_region_from_df(d, pad=0.5)
225
+ lon_min, lon_max, lat_min, lat_max = region
226
+
227
  fig, ax = plt.subplots(figsize=(6, 6))
228
  ax.set_xlim(lon_min, lon_max)
229
  ax.set_ylim(lat_min, lat_max)
230
 
231
+ s = (d["Magnitude"] + 2) ** 3
232
+ sc = ax.scatter(d["Lon"], d["Lat"], s=s, c=d["Depth_km"], alpha=0.85, edgecolor="black")
 
 
 
233
  cb = plt.colorbar(sc, ax=ax, fraction=0.046, pad=0.04)
234
  cb.set_label("Depth (km)")
235
+ ax.set_xlabel("Longitude (°E)")
236
+ ax.set_ylabel("Latitude (°N)")
237
+ ax.set_title("Epicenters (auto region)")
238
  ax.grid(True, linestyle="--", alpha=0.3)
239
  return _save_fig_to_tmp(fig)
240