File size: 5,017 Bytes
448e634
b359d50
 
 
 
ff71114
 
 
 
 
b359d50
 
ff71114
 
b359d50
 
 
 
ff71114
 
 
b359d50
ff71114
b359d50
ff71114
 
 
 
b359d50
ff71114
 
 
 
 
 
 
25ac52c
ff71114
 
 
 
 
 
 
 
25ac52c
 
ff71114
25ac52c
 
 
ff71114
 
 
 
25ac52c
ff71114
 
 
 
25ac52c
ff71114
 
 
 
b359d50
 
ff71114
 
b359d50
 
 
 
ff71114
 
 
 
b359d50
 
 
 
ff71114
 
b359d50
ff71114
 
 
 
 
 
 
 
 
 
 
 
25ac52c
ff71114
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b47d08c
ff71114
b47d08c
 
 
 
ff71114
 
 
 
 
 
 
 
b359d50
ff71114
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import streamlit as st
import pandas as pd
import plotly.express as px
from datetime import date, timedelta

# Import ObsPy for live data fetching
import obspy
from obspy.clients.fdsn import Client
from obspy import UTCDateTime

# --- Page Configuration ---
st.set_page_config(
    page_title="Live Earthquake Explorer (ObsPy)",
    page_icon="πŸ›°οΈ",
    layout="wide",
    initial_sidebar_state="expanded"
)

# --- Live Data Fetching Function using ObsPy ---
@st.cache_data(ttl=900)  # Cache the data for 15 minutes
def fetch_live_data(start_date, end_date, min_mag):
    """
    Fetches live earthquake data from the IRIS FDSN web service using ObsPy.
    """
    client = Client("IRIS")
    start_time = UTCDateTime(start_date)
    end_time = UTCDateTime(end_date) + timedelta(days=1)

    try:
        catalog = client.get_events(
            starttime=start_time,
            endtime=end_time,
            minmagnitude=min_mag
        )
    except Exception as e:
        st.error(f"Could not retrieve data from IRIS FDSN service: {e}")
        return pd.DataFrame()

    event_list = []
    for event in catalog:
        if not (event.preferred_origin() and event.preferred_magnitude()):
            continue

        origin = event.preferred_origin()
        magnitude = event.preferred_magnitude()

        # Get location description safely.
        description = "N/A"
        if hasattr(event, 'descriptions'):
            if event.descriptions and event.descriptions[0].text:
                description = event.descriptions[0].text

        event_list.append({
            "latitude": origin.latitude,
            "longitude": origin.longitude,
            "depth": origin.depth / 1000,
            "magnitude": magnitude.mag,
            "time": origin.time.datetime,
            "place": description,
        })

    if not event_list:
        return pd.DataFrame()

    return pd.DataFrame(event_list)

# --- UI Design ---
st.title("πŸ›°οΈ Live Earthquake Explorer with ObsPy")
st.markdown("Data is fetched in real-time from the **IRIS FDSN** web service.")

with st.sidebar:
    st.header("πŸ” Search Parameters")
    today = date.today()
    thirty_days_ago = today - timedelta(days=30)
    start_date = st.date_input("Start Date", value=thirty_days_ago)
    end_date = st.date_input("End Date", value=today)
    min_magnitude = st.slider("Minimum Magnitude", 0.0, 10.0, 5.0, 0.1)
    search_button = st.button("Search Earthquakes", type="primary", use_container_width=True)

# --- Main Content Area ---
if search_button:
    if start_date > end_date:
        st.error("Error: Start date cannot be after end date.")
    else:
        with st.spinner(f"Fetching earthquakes from {start_date} to {end_date}..."):
            df = fetch_live_data(start_date, end_date, min_magnitude)

        if not df.empty:
            st.success(f"Found {len(df)} earthquakes matching your criteria.")

            st.subheader("πŸ“Š Summary Statistics")
            col1, col2, col3 = st.columns(3)
            col1.metric("Total Earthquakes", f"{len(df):,}")
            col2.metric("Largest Magnitude", f"{df['magnitude'].max():.1f}")
            col3.metric("Deepest Event (km)", f"{df['depth'].max():.1f}")

            st.markdown("---")
            st.subheader("🌍 Interactive Earthquake Map")
            st.markdown("Hover over points for details. Circle size represents magnitude.")

            fig = px.scatter_geo(
                df,
                lat='latitude',
                lon='longitude',
                size='magnitude',
                color='depth',
                hover_name='place',
                hover_data={'latitude': ':.2f', 'longitude': ':.2f', 'time': '|%Y-%m-%d %H:%M', 'magnitude': ':.1f', 'depth': ':.1f km'},
                projection="natural earth",
                title=f"Live Earthquakes from {start_date} to {end_date} (Magnitude > {min_magnitude})",
                color_continuous_scale=px.colors.sequential.Plasma_r
            )
            fig.update_layout(margin={"r":0,"t":40,"l":0,"b":0}, coloraxis_colorbar_title_text='Depth (km)')
            st.plotly_chart(fig, use_container_width=True)

            # --- Show Earthquakes in a Table ---
            st.subheader("πŸ“‹ Detailed Earthquake Data")
            
            # This line is changed to show latitude and longitude instead of place.
            display_df = df[['time', 'latitude', 'longitude', 'magnitude', 'depth']].copy()
            
            st.dataframe(
                display_df.sort_values(by='time', ascending=False),
                use_container_width=True,
                height=400,
                column_config={"time": st.column_config.DatetimeColumn("Time (UTC)", format="YYYY-MM-DD HH:mm")}
            )
        else:
            st.warning("No earthquakes were found for the specified criteria. Try expanding the date range or lowering the magnitude.")
else:
    st.info("Set your desired parameters in the sidebar and click 'Search Earthquakes' to begin.")