cwadayi commited on
Commit
b359d50
Β·
verified Β·
1 Parent(s): 3b98756

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +163 -38
src/streamlit_app.py CHANGED
@@ -1,40 +1,165 @@
1
- import altair as alt
2
- import numpy as np
3
- import pandas as pd
4
  import streamlit as st
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
- """
7
- # Welcome to Streamlit!
8
-
9
- Edit `/streamlit_app.py` to customize this app to your heart's desire :heart:.
10
- If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
11
- forums](https://discuss.streamlit.io).
12
-
13
- In the meantime, below is an example of what you can do with just a few lines of code:
14
- """
15
-
16
- num_points = st.slider("Number of points in spiral", 1, 10000, 1100)
17
- num_turns = st.slider("Number of turns in spiral", 1, 300, 31)
18
-
19
- indices = np.linspace(0, 1, num_points)
20
- theta = 2 * np.pi * num_turns * indices
21
- radius = indices
22
-
23
- x = radius * np.cos(theta)
24
- y = radius * np.sin(theta)
25
-
26
- df = pd.DataFrame({
27
- "x": x,
28
- "y": y,
29
- "idx": indices,
30
- "rand": np.random.randn(num_points),
31
- })
32
-
33
- st.altair_chart(alt.Chart(df, height=700, width=700)
34
- .mark_point(filled=True)
35
- .encode(
36
- x=alt.X("x", axis=None),
37
- y=alt.Y("y", axis=None),
38
- color=alt.Color("idx", legend=None, scale=alt.Scale()),
39
- size=alt.Size("rand", legend=None, scale=alt.Scale(range=[1, 150])),
40
- ))
 
 
 
 
1
  import streamlit as st
2
+ import pandas as pd
3
+ import requests
4
+ import plotly.express as px
5
+ from datetime import date, timedelta
6
+
7
+ # --- Page Configuration ---
8
+ st.set_page_config(
9
+ page_title="Earthquake Activity Explorer",
10
+ page_icon="πŸ—ΊοΈ",
11
+ layout="wide",
12
+ initial_sidebar_state="expanded"
13
+ )
14
+
15
+ # --- API Data Fetching Function ---
16
+ @st.cache_data(ttl=600) # Cache data for 10 minutes
17
+ def fetch_earthquakes(start_date, end_date, min_magnitude):
18
+ """
19
+ Fetches earthquake data from the specified API endpoint.
20
+ Returns a pandas DataFrame or None if an error occurs.
21
+ """
22
+ API_URL = "https://cwadayi-python-app.hf.space/earthquakes"
23
+ params = {
24
+ "start_date": start_date,
25
+ "end_date": end_date,
26
+ "min_magnitude": min_magnitude
27
+ }
28
+ try:
29
+ response = requests.get(API_URL, params=params, timeout=20)
30
+ response.raise_for_status() # Raises an HTTPError for bad responses (4xx or 5xx)
31
+ data = response.json()
32
+ if not data:
33
+ return pd.DataFrame() # Return empty dataframe if no data
34
+ return pd.DataFrame(data)
35
+ except requests.exceptions.RequestException as e:
36
+ st.error(f"API Request Failed: {e}")
37
+ return None
38
+ except ValueError: # Catches JSON decoding errors
39
+ st.error("Failed to decode API response. The API might be temporarily down.")
40
+ return None
41
+
42
+ # --- UI Design ---
43
+
44
+ # 1. Title
45
+ st.title("πŸ—ΊοΈ Global Earthquake Activity Explorer")
46
+ st.markdown("Analyze and visualize recent earthquake events around the world.")
47
+
48
+ # 2. Sidebar for User Inputs
49
+ with st.sidebar:
50
+ st.header("πŸ” Search Parameters")
51
+
52
+ # Use a date range of the last 90 days as a default
53
+ today = date.today()
54
+ default_start_date = today - timedelta(days=90)
55
+
56
+ start_date = st.date_input(
57
+ "Start Date",
58
+ value=default_start_date,
59
+ min_value=date(1900, 1, 1),
60
+ max_value=today,
61
+ help="Select the beginning of the date range."
62
+ )
63
+
64
+ end_date = st.date_input(
65
+ "End Date",
66
+ value=today,
67
+ min_value=start_date,
68
+ max_value=today,
69
+ help="Select the end of the date range."
70
+ )
71
+
72
+ min_magnitude = st.slider(
73
+ "Minimum Magnitude",
74
+ min_value=0.0,
75
+ max_value=10.0,
76
+ value=5.5, # A sensible default to avoid clutter
77
+ step=0.1,
78
+ help="Drag the slider to set the minimum magnitude for queried earthquakes."
79
+ )
80
+
81
+ # Action button to trigger the search
82
+ search_button = st.button("Search Earthquakes", type="primary", use_container_width=True)
83
+
84
+
85
+ # --- Main Content Area ---
86
+ if search_button:
87
+ with st.spinner('Fetching earthquake data from the server... Please wait.'):
88
+ # 3. Fetch data using the function
89
+ df = fetch_earthquakes(start_date, end_date, min_magnitude)
90
+
91
+ if df is not None and not df.empty:
92
+ st.success(f"Found {len(df)} earthquakes matching your criteria.")
93
+
94
+ # Reformat DataFrame for better display
95
+ df['time'] = pd.to_datetime(df['time'])
96
+ df['magnitude'] = df['mag'].astype(float)
97
+ df['depth'] = df['depth'].astype(float)
98
+
99
+ # --- Display Summary Metrics ---
100
+ st.subheader("πŸ“Š Summary Statistics")
101
+ col1, col2, col3 = st.columns(3)
102
+ col1.metric("Total Earthquakes", f"{len(df):,}")
103
+ col2.metric("Largest Magnitude", f"{df['magnitude'].max():.2f}")
104
+ col3.metric("Deepest Event (km)", f"{df['depth'].max():.2f}")
105
+
106
+ st.markdown("---")
107
+
108
+ # --- 4. Draw Earthquake Distribution Map ---
109
+ st.subheader("🌍 Interactive Earthquake Map")
110
+ st.markdown("Hover over points for details. Circle size represents magnitude.")
111
+
112
+ fig = px.scatter_geo(
113
+ df,
114
+ lat='latitude',
115
+ lon='longitude',
116
+ size='magnitude',
117
+ color='depth',
118
+ hover_name='place',
119
+ hover_data={
120
+ 'latitude': ':.2f',
121
+ 'longitude': ':.2f',
122
+ 'time': True,
123
+ 'magnitude': ':.2f',
124
+ 'depth': ':.2f km'
125
+ },
126
+ projection="natural earth",
127
+ title=f"Earthquakes from {start_date} to {end_date} (Magnitude > {min_magnitude})",
128
+ color_continuous_scale=px.colors.sequential.Plasma_r # Reverse Plasma for depth
129
+ )
130
+
131
+ fig.update_layout(
132
+ margin={"r":0,"t":40,"l":0,"b":0},
133
+ coloraxis_colorbar_title_text='Depth (km)'
134
+ )
135
+ st.plotly_chart(fig, use_container_width=True)
136
+
137
+ st.markdown("---")
138
 
139
+ # --- 5. Show Earthquakes in a Table ---
140
+ st.subheader("πŸ“‹ Detailed Earthquake Data")
141
+
142
+ # Select and rename columns for a cleaner table display
143
+ display_df = df[['time', 'place', 'magnitude', 'depth', 'url']].copy()
144
+ display_df.rename(columns={
145
+ 'time': 'Time (UTC)',
146
+ 'place': 'Location',
147
+ 'magnitude': 'Magnitude',
148
+ 'depth': 'Depth (km)',
149
+ 'url': 'More Info'
150
+ }, inplace=True)
151
+
152
+ st.dataframe(
153
+ display_df,
154
+ use_container_width=True,
155
+ height=400,
156
+ column_config={
157
+ "More Info": st.column_config.LinkColumn("USGS Event Page")
158
+ }
159
+ )
160
+ elif df is not None and df.empty:
161
+ st.warning(f"No earthquakes with magnitude {min_magnitude} or higher were found in the selected date range.")
162
+ else:
163
+ st.error("Could not retrieve data. Please try again later.")
164
+ else:
165
+ st.info("Please set your desired parameters in the sidebar and click 'Search Earthquakes' to begin.")