streamlit_obspy / src /streamlit_app.py
cwadayi's picture
Update src/streamlit_app.py
2eccf6c verified
import streamlit as st
import pandas as pd
from obspy import UTCDateTime
from obspy.clients.fdsn import Client
import matplotlib.pyplot as plt
# --- App Configuration ---
st.set_page_config(
page_title="Taiwan Earthquake Explorer πŸ‡ΉπŸ‡Ό",
page_icon="πŸŒ‹",
layout="wide"
)
# --- FDSN Client & Caching ---
client = Client("IRIS")
# CORRECTED FUNCTION
@st.cache_data
def search_earthquakes(start_time_str, end_time_str, min_mag, min_lat, max_lat, min_lon, max_lon):
"""
Searches for earthquake events using the ObsPy client.
Accepts time as strings to enable caching.
"""
try:
# Convert string arguments back to UTCDateTime objects inside the function
start_time = UTCDateTime(start_time_str)
end_time = UTCDateTime(end_time_str)
catalog = client.get_events(
starttime=start_time,
endtime=end_time,
minlatitude=min_lat,
maxlatitude=max_lat,
minlongitude=min_lon,
maxlongitude=max_lon,
minmagnitude=min_mag,
orderby="time-asc"
)
return catalog
except Exception as e:
st.error(f"Could not retrieve event data: {e}")
return None
@st.cache_data
def get_waveforms_for_event(_event):
"""
Retrieves and processes seismic waveforms for a given event.
_event is a tuple of event properties to make it hashable for caching.
"""
event_time_str, _, _, _ = _event
event_time = UTCDateTime(event_time_str)
t_start = event_time - 30
t_end = event_time + 5 * 60
try:
stream = client.get_waveforms(
network="TW", station="*", location="*", channel="BH*",
starttime=t_start, endtime=t_end, attach_response=True
)
if len(stream) > 0:
stream.detrend("linear")
stream.taper(max_percentage=0.05, type="cosine")
stream.remove_response(output="VEL")
return stream
else:
return None
except Exception:
return None
# --- Streamlit User Interface ---
st.title("πŸŒ‹ Taiwan Earthquake Explorer")
st.markdown("Search, map, and visualize seismic data from the TW network via IRIS FDSN.")
st.sidebar.header("πŸ” Search Parameters")
# --- Sidebar Controls ---
default_start = UTCDateTime("2024-04-02T23:00:00")
default_end = UTCDateTime("2024-04-03T01:00:00")
start_date = st.sidebar.date_input("Start Date", value=default_start.date)
start_time_str = st.sidebar.text_input("Start Time (UTC)", value=default_start.strftime("%H:%M:%S"))
end_date = st.sidebar.date_input("End Date", value=default_end.date)
end_time_str = st.sidebar.text_input("End Time (UTC)", value=default_end.strftime("%H:%M:%S"))
start_utc = UTCDateTime(f"{start_date}T{start_time_str}")
end_utc = UTCDateTime(f"{end_date}T{end_time_str}")
st.sidebar.markdown("---")
min_mag = st.sidebar.slider("Minimum Magnitude", 2.0, 8.0, 5.5)
st.sidebar.markdown("---")
st.sidebar.subheader("Geographical Region (Taiwan)")
min_lat = st.sidebar.number_input("Min Latitude", value=21.5, format="%.2f")
max_lat = st.sidebar.number_input("Max Latitude", value=25.5, format="%.2f")
min_lon = st.sidebar.number_input("Min Longitude", value=120.0, format="%.2f")
max_lon = st.sidebar.number_input("Max Longitude", value=122.5, format="%.2f")
# --- Main App Logic ---
if st.sidebar.button("Search for Earthquakes", type="primary"):
# CORRECTED FUNCTION CALL: Pass times as ISO strings
catalog = search_earthquakes(start_utc.isoformat(), end_utc.isoformat(), min_mag, min_lat, max_lat, min_lon, max_lon)
if catalog and len(catalog) > 0:
st.success(f"βœ… Found {len(catalog)} earthquake(s).")
event_data = [{
"Time (UTC)": (event.preferred_origin() or event.origins[0]).time.strftime('%Y-%m-%d %H:%M:%S'),
"Latitude": (event.preferred_origin() or event.origins[0]).latitude,
"Longitude": (event.preferred_origin() or event.origins[0]).longitude,
"Depth (km)": (event.preferred_origin() or event.origins[0]).depth / 1000.0,
"Magnitude": (event.preferred_magnitude() or event.magnitudes[0]).mag,
"Mag Type": (event.preferred_magnitude() or event.magnitudes[0]).magnitude_type
} for event in catalog]
event_df = pd.DataFrame(event_data)
st.subheader("πŸ—ΊοΈ Earthquake Map")
st.map(event_df, latitude='Latitude', longitude='Longitude', size='Magnitude', zoom=6)
st.subheader("πŸ“Š Earthquake Catalog Table")
st.dataframe(event_df)
st.markdown("---")
st.subheader(" seismograph Seismic Waveform Viewer")
event_options = {f"{row['Time (UTC)']} - Mag: {row['Magnitude']:.1f}": index for index, row in event_df.iterrows()}
selected_event_str = st.selectbox("Select an event to view waveforms:", options=event_options.keys())
if selected_event_str:
selected_index = event_options[selected_event_str]
selected_event = catalog[selected_index]
origin = selected_event.preferred_origin() or selected_event.origins[0]
event_tuple = (str(origin.time), origin.latitude, origin.longitude, origin.depth)
with st.spinner("Fetching waveforms from TW network... This may take a moment."):
waveforms = get_waveforms_for_event(event_tuple)
if waveforms and len(waveforms) > 0:
st.success(f"πŸ“Š Found and processed {len(waveforms)} waveform traces.")
fig, ax = plt.subplots(figsize=(12, len(waveforms) * 1.5))
waveforms.plot(fig=fig, handle=True)
ax.set_title(f"Seismic Waveforms for Event: {selected_event_str}")
st.pyplot(fig)
else:
st.warning("Could not retrieve any waveform data for the selected event from the TW network.")
else:
st.warning("No earthquakes found matching your criteria. Try expanding the search window or lowering the magnitude.")