shaheerawan3 commited on
Commit
a19568b
·
verified ·
1 Parent(s): 7dc4cfb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +232 -114
app.py CHANGED
@@ -10,19 +10,33 @@ import plotly.graph_objects as go
10
  from datetime import datetime, timedelta
11
  import json
12
  from io import StringIO
 
 
13
 
14
  # Page configuration
15
  st.set_page_config(layout="wide", page_title="Pakistan Climate & Disaster Monitor")
16
 
17
  class DataCollector:
18
- @staticmethod
19
- def fetch_usgs_earthquake_data():
20
- """Fetch earthquake data from USGS website (free, no API key needed)"""
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  url = "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/2.5_month.geojson"
22
  try:
23
  response = requests.get(url)
24
  data = response.json()
25
- # Filter for Pakistan region
26
  pakistan_data = {
27
  "type": "FeatureCollection",
28
  "features": [
@@ -36,149 +50,253 @@ class DataCollector:
36
  st.error(f"Error fetching earthquake data: {e}")
37
  return None
38
 
39
- @staticmethod
40
- def fetch_weather_data():
41
- """Fetch weather data from OpenMeteo (free, no API required)"""
42
- # Multiple cities in Pakistan
43
- cities = {
44
- 'Islamabad': {'lat': 33.7294, 'lon': 73.0931},
45
- 'Karachi': {'lat': 24.8607, 'lon': 67.0011},
46
- 'Lahore': {'lat': 31.5204, 'lon': 74.3587},
47
- 'Peshawar': {'lat': 34.0151, 'lon': 71.5249},
48
- 'Quetta': {'lat': 30.1798, 'lon': 66.9750}
49
- }
50
-
51
  weather_data = []
52
- for city, coords in cities.items():
53
- url = f"https://api.open-meteo.com/v1/forecast?latitude={coords['lat']}&longitude={coords['lon']}&daily=temperature_2m_max,temperature_2m_min,precipitation_sum&timezone=auto"
54
  try:
55
  response = requests.get(url)
56
  data = response.json()
57
- df = pd.DataFrame({
58
- 'Date': pd.to_datetime(data['daily']['time']),
59
- 'Temperature_Max': data['daily']['temperature_2m_max'],
60
- 'Temperature_Min': data['daily']['temperature_2m_min'],
61
- 'Precipitation': data['daily']['precipitation_sum'],
62
- 'City': city
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
  })
64
- weather_data.append(df)
65
  except Exception as e:
66
- st.error(f"Error fetching data for {city}: {e}")
67
  continue
68
 
69
- if weather_data:
70
- return pd.concat(weather_data, ignore_index=True)
71
- return None
72
 
73
- @staticmethod
74
- def fetch_air_quality_data():
75
- """Fetch air quality data from OpenMeteo Air Quality API (free)"""
76
- cities = {
77
- 'Islamabad': {'lat': 33.7294, 'lon': 73.0931},
78
- 'Karachi': {'lat': 24.8607, 'lon': 67.0011},
79
- 'Lahore': {'lat': 31.5204, 'lon': 74.3587}
80
- }
81
-
82
  aqi_data = []
83
- for city, coords in cities.items():
84
- url = f"https://air-quality-api.open-meteo.com/v1/air-quality?latitude={coords['lat']}&longitude={coords['lon']}&hourly=pm10,pm2_5,carbon_monoxide&timezone=auto"
85
  try:
86
  response = requests.get(url)
87
  data = response.json()
88
  df = pd.DataFrame({
89
- 'Time': pd.to_datetime(data['hourly']['time']),
90
  'PM10': data['hourly']['pm10'],
91
  'PM2.5': data['hourly']['pm2_5'],
92
  'CO': data['hourly']['carbon_monoxide'],
93
- 'City': city
 
 
94
  })
95
  aqi_data.append(df)
96
  except Exception as e:
97
  st.error(f"Error fetching AQI data for {city}: {e}")
98
  continue
99
 
100
- if aqi_data:
101
- return pd.concat(aqi_data, ignore_index=True)
102
- return None
103
 
104
- def show_climate_analysis():
105
- st.header("Climate Analysis")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
 
107
- data_collector = DataCollector()
108
  weather_data = data_collector.fetch_weather_data()
109
-
110
- if weather_data is not None:
111
- # City selector
112
- selected_city = st.selectbox("Select City", weather_data['City'].unique())
113
- city_data = weather_data[weather_data['City'] == selected_city]
114
-
115
- col1, col2 = st.columns(2)
116
-
117
- with col1:
118
- # Temperature trends
119
- fig = px.line(city_data,
120
- x='Date',
121
- y=['Temperature_Max', 'Temperature_Min'],
122
- title=f'Temperature Trends - {selected_city}')
123
- st.plotly_chart(fig)
124
-
125
- with col2:
126
- # Precipitation patterns
127
- fig = px.bar(city_data,
128
- x='Date',
129
- y='Precipitation',
 
 
 
130
  title=f'Daily Precipitation - {selected_city}')
131
- st.plotly_chart(fig)
132
-
133
- # Climate indicators
134
- st.subheader("Current Climate Indicators")
135
- latest_data = city_data.iloc[-1]
136
- cols = st.columns(3)
137
-
138
- with cols[0]:
139
- st.metric("Max Temperature", f"{latest_data['Temperature_Max']:.1f}°C")
140
- with cols[1]:
141
- st.metric("Min Temperature", f"{latest_data['Temperature_Min']:.1f}°C")
142
- with cols[2]:
143
- st.metric("Precipitation", f"{latest_data['Precipitation']:.1f}mm")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
 
145
- def show_environmental_data():
146
  st.header("Environmental Data")
147
 
148
- data_collector = DataCollector()
149
  aqi_data = data_collector.fetch_air_quality_data()
150
 
151
  if aqi_data is not None:
152
- # City selector
153
- selected_city = st.selectbox("Select City", aqi_data['City'].unique())
154
- city_data = aqi_data[aqi_data['City'] == selected_city]
155
-
156
- # Latest 24 hours of data
157
- recent_data = city_data.tail(24)
158
-
159
- # AQI time series
160
- st.subheader("Air Quality Indicators")
161
- metric = st.selectbox("Select Pollutant", ['PM10', 'PM2.5', 'CO'])
162
-
163
- fig = px.line(recent_data,
164
- x='Time',
165
- y=metric,
166
- title=f'{metric} Levels - {selected_city} (Last 24 Hours)')
167
- st.plotly_chart(fig)
168
-
169
- # Current conditions
170
- st.subheader("Current Air Quality")
171
- latest_data = city_data.iloc[-1]
172
- cols = st.columns(3)
173
-
174
- with cols[0]:
175
- st.metric("PM10", f"{latest_data['PM10']:.1f} µg/m³")
176
- with cols[1]:
177
- st.metric("PM2.5", f"{latest_data['PM2.5']:.1f} µg/m³")
178
- with cols[2]:
179
- st.metric("Carbon Monoxide", f"{latest_data['CO']:.1f} µg/m³")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
180
 
181
- # [Previous show_disaster_monitor and show_risk_assessment functions remain the same]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182
 
183
  if __name__ == "__main__":
184
- create_dashboard()
 
10
  from datetime import datetime, timedelta
11
  import json
12
  from io import StringIO
13
+ import streamlit.components.v1 as components
14
+ import base64
15
 
16
  # Page configuration
17
  st.set_page_config(layout="wide", page_title="Pakistan Climate & Disaster Monitor")
18
 
19
  class DataCollector:
20
+ def __init__(self):
21
+ self.cities = {
22
+ 'Islamabad': {'lat': 33.7294, 'lon': 73.0931},
23
+ 'Karachi': {'lat': 24.8607, 'lon': 67.0011},
24
+ 'Lahore': {'lat': 31.5204, 'lon': 74.3587},
25
+ 'Peshawar': {'lat': 34.0151, 'lon': 71.5249},
26
+ 'Quetta': {'lat': 30.1798, 'lon': 66.9750},
27
+ 'Multan': {'lat': 30.1575, 'lon': 71.5249},
28
+ 'Faisalabad': {'lat': 31.4504, 'lon': 73.1350},
29
+ 'Rawalpindi': {'lat': 33.6007, 'lon': 73.0679},
30
+ 'Gwadar': {'lat': 25.1216, 'lon': 62.3254},
31
+ 'Hyderabad': {'lat': 25.3960, 'lon': 68.3578}
32
+ }
33
+
34
+ def fetch_usgs_earthquake_data(self):
35
+ """Fetch earthquake data from USGS website"""
36
  url = "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/2.5_month.geojson"
37
  try:
38
  response = requests.get(url)
39
  data = response.json()
 
40
  pakistan_data = {
41
  "type": "FeatureCollection",
42
  "features": [
 
50
  st.error(f"Error fetching earthquake data: {e}")
51
  return None
52
 
53
+ def fetch_weather_data(self):
54
+ """Fetch weather data from OpenMeteo"""
 
 
 
 
 
 
 
 
 
 
55
  weather_data = []
56
+ for city, coords in self.cities.items():
57
+ url = f"https://api.open-meteo.com/v1/forecast?latitude={coords['lat']}&longitude={coords['lon']}&hourly=temperature_2m,relativehumidity_2m,precipitation,windspeed_10m&daily=temperature_2m_max,temperature_2m_min,precipitation_sum&timezone=auto"
58
  try:
59
  response = requests.get(url)
60
  data = response.json()
61
+
62
+ # Hourly data
63
+ hourly_df = pd.DataFrame({
64
+ 'datetime': pd.to_datetime(data['hourly']['time']),
65
+ 'temperature': data['hourly']['temperature_2m'],
66
+ 'humidity': data['hourly']['relativehumidity_2m'],
67
+ 'precipitation': data['hourly']['precipitation'],
68
+ 'wind_speed': data['hourly']['windspeed_10m']
69
+ })
70
+
71
+ # Daily data
72
+ daily_df = pd.DataFrame({
73
+ 'date': pd.to_datetime(data['daily']['time']),
74
+ 'temp_max': data['daily']['temperature_2m_max'],
75
+ 'temp_min': data['daily']['temperature_2m_min'],
76
+ 'precipitation_sum': data['daily']['precipitation_sum']
77
+ })
78
+
79
+ weather_data.append({
80
+ 'city': city,
81
+ 'hourly': hourly_df,
82
+ 'daily': daily_df,
83
+ 'coords': coords
84
  })
 
85
  except Exception as e:
86
+ st.error(f"Error fetching weather data for {city}: {e}")
87
  continue
88
 
89
+ return weather_data if weather_data else None
 
 
90
 
91
+ def fetch_air_quality_data(self):
92
+ """Fetch air quality data from OpenMeteo"""
 
 
 
 
 
 
 
93
  aqi_data = []
94
+ for city, coords in self.cities.items():
95
+ url = f"https://air-quality-api.open-meteo.com/v1/air-quality?latitude={coords['lat']}&longitude={coords['lon']}&hourly=pm10,pm2_5,carbon_monoxide,nitrogen_dioxide,ozone&timezone=auto"
96
  try:
97
  response = requests.get(url)
98
  data = response.json()
99
  df = pd.DataFrame({
100
+ 'datetime': pd.to_datetime(data['hourly']['time']),
101
  'PM10': data['hourly']['pm10'],
102
  'PM2.5': data['hourly']['pm2_5'],
103
  'CO': data['hourly']['carbon_monoxide'],
104
+ 'NO2': data['hourly']['nitrogen_dioxide'],
105
+ 'O3': data['hourly']['ozone'],
106
+ 'city': city
107
  })
108
  aqi_data.append(df)
109
  except Exception as e:
110
  st.error(f"Error fetching AQI data for {city}: {e}")
111
  continue
112
 
113
+ return pd.concat(aqi_data, ignore_index=True) if aqi_data else None
 
 
114
 
115
+ def create_cesium_component():
116
+ """Create Cesium 3D map component"""
117
+ cesium_html = """
118
+ <div id="cesiumContainer" style="width: 100%; height: 600px;"></div>
119
+ <script src="https://cesium.com/downloads/cesiumjs/releases/1.95/Build/Cesium/Cesium.js"></script>
120
+ <link href="https://cesium.com/downloads/cesiumjs/releases/1.95/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
121
+ <script>
122
+ Cesium.Ion.defaultAccessToken = 'your-access-token';
123
+ const viewer = new Cesium.Viewer('cesiumContainer', {
124
+ terrainProvider: Cesium.createWorldTerrain()
125
+ });
126
+ viewer.camera.flyTo({
127
+ destination: Cesium.Cartesian3.fromDegrees(69.3451, 30.3753, 1000000.0)
128
+ });
129
+ </script>
130
+ """
131
+ components.html(cesium_html, height=600)
132
+
133
+ def download_csv(df, filename):
134
+ """Generate download link for CSV file"""
135
+ csv = df.to_csv(index=False)
136
+ b64 = base64.b64encode(csv.encode()).decode()
137
+ href = f'<a href="data:file/csv;base64,{b64}" download="{filename}.csv">Download {filename} Data</a>'
138
+ return href
139
+
140
+ def show_weather_analysis(data_collector):
141
+ st.header("Weather Analysis")
142
 
 
143
  weather_data = data_collector.fetch_weather_data()
144
+ if weather_data:
145
+ selected_city = st.selectbox(
146
+ "Select City",
147
+ options=[data['city'] for data in weather_data]
148
+ )
149
+
150
+ city_data = next(data for data in weather_data if data['city'] == selected_city)
151
+
152
+ # Add download button for data
153
+ st.markdown(download_csv(city_data['hourly'], f"{selected_city}_weather_data"), unsafe_allow_html=True)
154
+
155
+ tabs = st.tabs(["Temperature", "Precipitation", "Wind", "Humidity"])
156
+
157
+ with tabs[0]:
158
+ fig = px.line(city_data['hourly'],
159
+ x='datetime',
160
+ y='temperature',
161
+ title=f'Temperature Trend - {selected_city}')
162
+ st.plotly_chart(fig, use_container_width=True)
163
+
164
+ with tabs[1]:
165
+ fig = px.bar(city_data['daily'],
166
+ x='date',
167
+ y='precipitation_sum',
168
  title=f'Daily Precipitation - {selected_city}')
169
+ st.plotly_chart(fig, use_container_width=True)
170
+
171
+ with tabs[2]:
172
+ fig = px.line(city_data['hourly'],
173
+ x='datetime',
174
+ y='wind_speed',
175
+ title=f'Wind Speed - {selected_city}')
176
+ st.plotly_chart(fig, use_container_width=True)
177
+
178
+ with tabs[3]:
179
+ fig = px.line(city_data['hourly'],
180
+ x='datetime',
181
+ y='humidity',
182
+ title=f'Humidity - {selected_city}')
183
+ st.plotly_chart(fig, use_container_width=True)
184
+
185
+ def show_disaster_monitor(data_collector):
186
+ st.header("Disaster Monitoring")
187
+
188
+ earthquake_data = data_collector.fetch_usgs_earthquake_data()
189
+
190
+ if earthquake_data:
191
+ # 3D visualization using Cesium
192
+ st.subheader("3D Terrain View")
193
+ create_cesium_component()
194
+
195
+ # Traditional map
196
+ st.subheader("Recent Earthquakes Map")
197
+ m = folium.Map(location=[30.3753, 69.3451], zoom_start=5)
198
+
199
+ for eq in earthquake_data['features']:
200
+ coords = eq['geometry']['coordinates']
201
+ mag = eq['properties']['mag']
202
+ time = datetime.fromtimestamp(eq['properties']['time']/1000)
203
+
204
+ folium.CircleMarker(
205
+ location=[coords[1], coords[0]],
206
+ radius=mag * 3,
207
+ color='red',
208
+ fill=True,
209
+ popup=f"Magnitude: {mag}<br>Time: {time}",
210
+ ).add_to(m)
211
+
212
+ folium_static(m)
213
+
214
+ # Earthquake data table
215
+ st.subheader("Recent Earthquakes")
216
+ eq_df = pd.DataFrame([
217
+ {
218
+ 'Time': datetime.fromtimestamp(eq['properties']['time']/1000),
219
+ 'Magnitude': eq['properties']['mag'],
220
+ 'Location': eq['properties']['place'],
221
+ 'Depth': eq['geometry']['coordinates'][2]
222
+ }
223
+ for eq in earthquake_data['features']
224
+ ])
225
+ st.dataframe(eq_df)
226
+ st.markdown(download_csv(eq_df, "earthquake_data"), unsafe_allow_html=True)
227
 
228
+ def show_environmental_data(data_collector):
229
  st.header("Environmental Data")
230
 
 
231
  aqi_data = data_collector.fetch_air_quality_data()
232
 
233
  if aqi_data is not None:
234
+ selected_city = st.selectbox("Select City", aqi_data['city'].unique())
235
+ city_data = aqi_data[aqi_data['city'] == selected_city].copy()
236
+
237
+ # Add download button
238
+ st.markdown(download_csv(city_data, f"{selected_city}_air_quality_data"), unsafe_allow_html=True)
239
+
240
+ # Air Quality Index calculation
241
+ city_data['AQI'] = (
242
+ city_data['PM2.5'] * 0.3 +
243
+ city_data['PM10'] * 0.2 +
244
+ city_data['NO2'] * 0.2 +
245
+ city_data['O3'] * 0.2 +
246
+ city_data['CO'] * 0.1
247
+ )
248
+
249
+ tabs = st.tabs(["Overall AQI", "Pollutants", "Trends"])
250
+
251
+ with tabs[0]:
252
+ current_aqi = city_data['AQI'].iloc[-1]
253
+ st.metric(
254
+ "Current Air Quality Index",
255
+ f"{current_aqi:.1f}",
256
+ delta=f"{current_aqi - city_data['AQI'].iloc[-2]:.1f}"
257
+ )
258
+
259
+ fig = px.line(city_data, x='datetime', y='AQI',
260
+ title=f'Air Quality Index - {selected_city}')
261
+ st.plotly_chart(fig, use_container_width=True)
262
+
263
+ with tabs[1]:
264
+ pollutants = ['PM2.5', 'PM10', 'CO', 'NO2', 'O3']
265
+ selected_pollutant = st.selectbox("Select Pollutant", pollutants)
266
+
267
+ fig = px.line(city_data, x='datetime', y=selected_pollutant,
268
+ title=f'{selected_pollutant} Levels - {selected_city}')
269
+ st.plotly_chart(fig, use_container_width=True)
270
+
271
+ with tabs[2]:
272
+ # 24-hour moving average
273
+ city_data['AQI_MA'] = city_data['AQI'].rolling(24).mean()
274
+
275
+ fig = go.Figure()
276
+ fig.add_trace(go.Scatter(x=city_data['datetime'], y=city_data['AQI'],
277
+ name='Raw AQI'))
278
+ fig.add_trace(go.Scatter(x=city_data['datetime'], y=city_data['AQI_MA'],
279
+ name='24-hour Moving Average'))
280
+ fig.update_layout(title=f'AQI Trends - {selected_city}')
281
+ st.plotly_chart(fig, use_container_width=True)
282
 
283
+ def main():
284
+ st.title("Pakistan Climate & Disaster Monitoring System")
285
+
286
+ data_collector = DataCollector()
287
+
288
+ # Sidebar navigation
289
+ page = st.sidebar.selectbox(
290
+ "Select Module",
291
+ ["Weather Analysis", "Disaster Monitor", "Environmental Data"]
292
+ )
293
+
294
+ if page == "Weather Analysis":
295
+ show_weather_analysis(data_collector)
296
+ elif page == "Disaster Monitor":
297
+ show_disaster_monitor(data_collector)
298
+ elif page == "Environmental Data":
299
+ show_environmental_data(data_collector)
300
 
301
  if __name__ == "__main__":
302
+ main()