Spaces:
Sleeping
Sleeping
| 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 | |
| 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 | |
| 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.") | |