cwadayi commited on
Commit
2eccf6c
ยท
verified ยท
1 Parent(s): 4fcf8ef

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +29 -50
src/streamlit_app.py CHANGED
@@ -12,16 +12,20 @@ st.set_page_config(
12
  )
13
 
14
  # --- FDSN Client & Caching ---
15
- # Initialize the IRIS FDSN client
16
  client = Client("IRIS")
17
 
 
18
  @st.cache_data
19
- def search_earthquakes(start_time, end_time, min_mag, min_lat, max_lat, min_lon, max_lon):
20
  """
21
  Searches for earthquake events using the ObsPy client.
22
- Results are cached to prevent re-running the same query.
23
  """
24
  try:
 
 
 
 
25
  catalog = client.get_events(
26
  starttime=start_time,
27
  endtime=end_time,
@@ -30,7 +34,7 @@ def search_earthquakes(start_time, end_time, min_mag, min_lat, max_lat, min_lon,
30
  minlongitude=min_lon,
31
  maxlongitude=max_lon,
32
  minmagnitude=min_mag,
33
- orderby="time-asc" # Order by time, ascending
34
  )
35
  return catalog
36
  except Exception as e:
@@ -38,50 +42,39 @@ def search_earthquakes(start_time, end_time, min_mag, min_lat, max_lat, min_lon,
38
  return None
39
 
40
  @st.cache_data
41
- def get_waveforms_for_event(_event): # Caching requires hashable arguments
42
  """
43
  Retrieves and processes seismic waveforms for a given event.
44
  _event is a tuple of event properties to make it hashable for caching.
45
  """
46
- event_time_str, event_lat, event_lon, event_depth = _event
47
  event_time = UTCDateTime(event_time_str)
48
 
49
- # Define a time window around the event origin time
50
- t_start = event_time - 30 # 30 seconds before
51
- t_end = event_time + 5 * 60 # 5 minutes after
52
 
53
  try:
54
- # Fetch waveforms from the TW network for broadband channels
55
  stream = client.get_waveforms(
56
- network="TW",
57
- station="*",
58
- location="*",
59
- channel="BH*", # Broadband High Gain channels (BHZ, BHN, BHE)
60
- starttime=t_start,
61
- endtime=t_end,
62
- attach_response=True # Attach instrument response
63
  )
64
  if len(stream) > 0:
65
- # Pre-processing: Detrend, taper, and remove instrument response
66
  stream.detrend("linear")
67
  stream.taper(max_percentage=0.05, type="cosine")
68
- stream.remove_response(output="VEL") # Convert to velocity (m/s)
69
  return stream
70
  else:
71
  return None
72
  except Exception:
73
- # Return None if no data is available or an error occurs
74
  return None
75
 
76
-
77
  # --- Streamlit User Interface ---
78
  st.title("๐ŸŒ‹ Taiwan Earthquake Explorer")
79
  st.markdown("Search, map, and visualize seismic data from the TW network via IRIS FDSN.")
80
 
81
- # --- Sidebar for Search Controls ---
82
  st.sidebar.header("๐Ÿ” Search Parameters")
83
 
84
- # Date and Time Inputs
85
  default_start = UTCDateTime("2024-04-02T23:00:00")
86
  default_end = UTCDateTime("2024-04-03T01:00:00")
87
  start_date = st.sidebar.date_input("Start Date", value=default_start.date)
@@ -89,11 +82,9 @@ start_time_str = st.sidebar.text_input("Start Time (UTC)", value=default_start.s
89
  end_date = st.sidebar.date_input("End Date", value=default_end.date)
90
  end_time_str = st.sidebar.text_input("End Time (UTC)", value=default_end.strftime("%H:%M:%S"))
91
 
92
- # Combine date and time
93
  start_utc = UTCDateTime(f"{start_date}T{start_time_str}")
94
  end_utc = UTCDateTime(f"{end_date}T{end_time_str}")
95
 
96
- # Magnitude and Location Inputs
97
  st.sidebar.markdown("---")
98
  min_mag = st.sidebar.slider("Minimum Magnitude", 2.0, 8.0, 5.5)
99
 
@@ -106,25 +97,20 @@ max_lon = st.sidebar.number_input("Max Longitude", value=122.5, format="%.2f")
106
 
107
  # --- Main App Logic ---
108
  if st.sidebar.button("Search for Earthquakes", type="primary"):
109
- catalog = search_earthquakes(start_utc, end_utc, min_mag, min_lat, max_lat, min_lon, max_lon)
 
110
 
111
  if catalog and len(catalog) > 0:
112
  st.success(f"โœ… Found {len(catalog)} earthquake(s).")
113
-
114
- # --- Process and Display Data ---
115
- event_data = []
116
- for event in catalog:
117
- origin = event.preferred_origin() or event.origins[0]
118
- magnitude = event.preferred_magnitude() or event.magnitudes[0]
119
- event_data.append({
120
- "Time (UTC)": origin.time.strftime('%Y-%m-%d %H:%M:%S'),
121
- "Latitude": origin.latitude,
122
- "Longitude": origin.longitude,
123
- "Depth (km)": origin.depth / 1000.0,
124
- "Magnitude": magnitude.mag,
125
- "Mag Type": magnitude.magnitude_type
126
- })
127
-
128
  event_df = pd.DataFrame(event_data)
129
 
130
  st.subheader("๐Ÿ—บ๏ธ Earthquake Map")
@@ -136,7 +122,6 @@ if st.sidebar.button("Search for Earthquakes", type="primary"):
136
  st.markdown("---")
137
  st.subheader(" seismograph Seismic Waveform Viewer")
138
 
139
- # --- Waveform Selection and Display ---
140
  event_options = {f"{row['Time (UTC)']} - Mag: {row['Magnitude']:.1f}": index for index, row in event_df.iterrows()}
141
  selected_event_str = st.selectbox("Select an event to view waveforms:", options=event_options.keys())
142
 
@@ -145,20 +130,13 @@ if st.sidebar.button("Search for Earthquakes", type="primary"):
145
  selected_event = catalog[selected_index]
146
  origin = selected_event.preferred_origin() or selected_event.origins[0]
147
 
148
- # Create a hashable tuple for caching
149
- event_tuple = (
150
- str(origin.time),
151
- origin.latitude,
152
- origin.longitude,
153
- origin.depth
154
- )
155
 
156
  with st.spinner("Fetching waveforms from TW network... This may take a moment."):
157
  waveforms = get_waveforms_for_event(event_tuple)
158
 
159
  if waveforms and len(waveforms) > 0:
160
  st.success(f"๐Ÿ“Š Found and processed {len(waveforms)} waveform traces.")
161
- # Plotting the waveforms
162
  fig, ax = plt.subplots(figsize=(12, len(waveforms) * 1.5))
163
  waveforms.plot(fig=fig, handle=True)
164
  ax.set_title(f"Seismic Waveforms for Event: {selected_event_str}")
@@ -168,3 +146,4 @@ if st.sidebar.button("Search for Earthquakes", type="primary"):
168
 
169
  else:
170
  st.warning("No earthquakes found matching your criteria. Try expanding the search window or lowering the magnitude.")
 
 
12
  )
13
 
14
  # --- FDSN Client & Caching ---
 
15
  client = Client("IRIS")
16
 
17
+ # CORRECTED FUNCTION
18
  @st.cache_data
19
+ def search_earthquakes(start_time_str, end_time_str, min_mag, min_lat, max_lat, min_lon, max_lon):
20
  """
21
  Searches for earthquake events using the ObsPy client.
22
+ Accepts time as strings to enable caching.
23
  """
24
  try:
25
+ # Convert string arguments back to UTCDateTime objects inside the function
26
+ start_time = UTCDateTime(start_time_str)
27
+ end_time = UTCDateTime(end_time_str)
28
+
29
  catalog = client.get_events(
30
  starttime=start_time,
31
  endtime=end_time,
 
34
  minlongitude=min_lon,
35
  maxlongitude=max_lon,
36
  minmagnitude=min_mag,
37
+ orderby="time-asc"
38
  )
39
  return catalog
40
  except Exception as e:
 
42
  return None
43
 
44
  @st.cache_data
45
+ def get_waveforms_for_event(_event):
46
  """
47
  Retrieves and processes seismic waveforms for a given event.
48
  _event is a tuple of event properties to make it hashable for caching.
49
  """
50
+ event_time_str, _, _, _ = _event
51
  event_time = UTCDateTime(event_time_str)
52
 
53
+ t_start = event_time - 30
54
+ t_end = event_time + 5 * 60
 
55
 
56
  try:
 
57
  stream = client.get_waveforms(
58
+ network="TW", station="*", location="*", channel="BH*",
59
+ starttime=t_start, endtime=t_end, attach_response=True
 
 
 
 
 
60
  )
61
  if len(stream) > 0:
 
62
  stream.detrend("linear")
63
  stream.taper(max_percentage=0.05, type="cosine")
64
+ stream.remove_response(output="VEL")
65
  return stream
66
  else:
67
  return None
68
  except Exception:
 
69
  return None
70
 
 
71
  # --- Streamlit User Interface ---
72
  st.title("๐ŸŒ‹ Taiwan Earthquake Explorer")
73
  st.markdown("Search, map, and visualize seismic data from the TW network via IRIS FDSN.")
74
 
 
75
  st.sidebar.header("๐Ÿ” Search Parameters")
76
 
77
+ # --- Sidebar Controls ---
78
  default_start = UTCDateTime("2024-04-02T23:00:00")
79
  default_end = UTCDateTime("2024-04-03T01:00:00")
80
  start_date = st.sidebar.date_input("Start Date", value=default_start.date)
 
82
  end_date = st.sidebar.date_input("End Date", value=default_end.date)
83
  end_time_str = st.sidebar.text_input("End Time (UTC)", value=default_end.strftime("%H:%M:%S"))
84
 
 
85
  start_utc = UTCDateTime(f"{start_date}T{start_time_str}")
86
  end_utc = UTCDateTime(f"{end_date}T{end_time_str}")
87
 
 
88
  st.sidebar.markdown("---")
89
  min_mag = st.sidebar.slider("Minimum Magnitude", 2.0, 8.0, 5.5)
90
 
 
97
 
98
  # --- Main App Logic ---
99
  if st.sidebar.button("Search for Earthquakes", type="primary"):
100
+ # CORRECTED FUNCTION CALL: Pass times as ISO strings
101
+ catalog = search_earthquakes(start_utc.isoformat(), end_utc.isoformat(), min_mag, min_lat, max_lat, min_lon, max_lon)
102
 
103
  if catalog and len(catalog) > 0:
104
  st.success(f"โœ… Found {len(catalog)} earthquake(s).")
105
+
106
+ event_data = [{
107
+ "Time (UTC)": (event.preferred_origin() or event.origins[0]).time.strftime('%Y-%m-%d %H:%M:%S'),
108
+ "Latitude": (event.preferred_origin() or event.origins[0]).latitude,
109
+ "Longitude": (event.preferred_origin() or event.origins[0]).longitude,
110
+ "Depth (km)": (event.preferred_origin() or event.origins[0]).depth / 1000.0,
111
+ "Magnitude": (event.preferred_magnitude() or event.magnitudes[0]).mag,
112
+ "Mag Type": (event.preferred_magnitude() or event.magnitudes[0]).magnitude_type
113
+ } for event in catalog]
 
 
 
 
 
 
114
  event_df = pd.DataFrame(event_data)
115
 
116
  st.subheader("๐Ÿ—บ๏ธ Earthquake Map")
 
122
  st.markdown("---")
123
  st.subheader(" seismograph Seismic Waveform Viewer")
124
 
 
125
  event_options = {f"{row['Time (UTC)']} - Mag: {row['Magnitude']:.1f}": index for index, row in event_df.iterrows()}
126
  selected_event_str = st.selectbox("Select an event to view waveforms:", options=event_options.keys())
127
 
 
130
  selected_event = catalog[selected_index]
131
  origin = selected_event.preferred_origin() or selected_event.origins[0]
132
 
133
+ event_tuple = (str(origin.time), origin.latitude, origin.longitude, origin.depth)
 
 
 
 
 
 
134
 
135
  with st.spinner("Fetching waveforms from TW network... This may take a moment."):
136
  waveforms = get_waveforms_for_event(event_tuple)
137
 
138
  if waveforms and len(waveforms) > 0:
139
  st.success(f"๐Ÿ“Š Found and processed {len(waveforms)} waveform traces.")
 
140
  fig, ax = plt.subplots(figsize=(12, len(waveforms) * 1.5))
141
  waveforms.plot(fig=fig, handle=True)
142
  ax.set_title(f"Seismic Waveforms for Event: {selected_event_str}")
 
146
 
147
  else:
148
  st.warning("No earthquakes found matching your criteria. Try expanding the search window or lowering the magnitude.")
149
+