lyimo commited on
Commit
94d0332
·
verified ·
1 Parent(s): ec5b96f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +59 -149
app.py CHANGED
@@ -4,14 +4,19 @@ import numpy as np
4
  import plotly.express as px
5
  import folium
6
  from streamlit_folium import st_folium
7
- import requests
8
  # ----------------------------------------------------
9
  # 1. Load data
10
  # ----------------------------------------------------
11
  @st.cache_data
12
  def load_data():
 
13
  daily_df = pd.read_csv("daily_data_2013_2024.csv", parse_dates=["date"])
14
  monthly_df = pd.read_csv("monthly_data_2013_2024.csv")
 
 
 
 
15
  return daily_df, monthly_df
16
 
17
  daily_data, monthly_data = load_data()
@@ -30,7 +35,7 @@ st.title("Malaria & Dengue Outbreak Analysis (2013–2024)")
30
 
31
  st.sidebar.header("Filters & Options")
32
 
33
- # Choose disease type
34
  disease_choice = st.sidebar.radio("Select Disease", ["Malaria", "Dengue"])
35
 
36
  # Choose data granularity
@@ -40,75 +45,71 @@ data_choice = st.sidebar.radio("Data Granularity", ["Monthly", "Daily"])
40
  location_list = list(LOCATIONS.keys())
41
  selected_locations = st.sidebar.multiselect("Select Location(s)", location_list, default=location_list)
42
 
43
- # For monthly data
44
  if data_choice == "Monthly":
45
  year_min = int(monthly_data["year"].min())
46
  year_max = int(monthly_data["year"].max())
47
- year_range = st.sidebar.slider(
48
- "Select Year Range",
49
- min_value=year_min,
50
- max_value=year_max,
51
- value=(year_min, year_max)
52
- )
53
- # For daily data
54
  else:
55
  date_min = daily_data["date"].min()
56
  date_max = daily_data["date"].max()
57
- date_range = st.sidebar.date_input(
58
- "Select Date Range",
59
- [date_min, date_max],
60
- min_value=date_min,
61
- max_value=date_max
62
- )
63
 
64
  # ----------------------------------------------------
65
  # 3. Filter data based on user input
66
  # ----------------------------------------------------
67
  if data_choice == "Monthly":
 
68
  df = monthly_data[monthly_data["location"].isin(selected_locations)].copy()
69
  # Filter year range
70
  df = df[(df["year"] >= year_range[0]) & (df["year"] <= year_range[1])]
71
- # Create a "date" column for monthly data
 
 
72
  df["date"] = pd.to_datetime(df["year"].astype(str) + "-" + df["month"].astype(str) + "-01")
73
-
74
  else:
 
75
  df = daily_data[daily_data["location"].isin(selected_locations)].copy()
76
  # Filter date range
77
- df = df[
78
- (df["date"] >= pd.to_datetime(date_range[0]))
79
- & (df["date"] <= pd.to_datetime(date_range[1]))
80
- ]
81
 
82
  # ----------------------------------------------------
83
  # 4. Interactive Plotly Time-Series
84
  # ----------------------------------------------------
85
  st.subheader(f"{data_choice} {disease_choice} Risk & Climate Parameters")
86
 
 
87
  risk_col = "malaria_risk" if disease_choice == "Malaria" else "dengue_risk"
88
 
89
  if data_choice == "Monthly":
90
- fig = px.line(
91
- df, x="date", y=risk_col, color="location",
92
- title=f"{disease_choice} Risk Over Time ({data_choice})"
93
- )
94
  fig.update_layout(yaxis_title="Risk (0–1)")
 
95
  st.plotly_chart(fig, use_container_width=True)
96
 
 
97
  col1, col2 = st.columns(2)
98
  with col1:
99
- fig_temp = px.line(
100
- df, x="date", y="temp_avg", color="location",
101
- title="Average Temperature (°C)"
102
- )
103
  st.plotly_chart(fig_temp, use_container_width=True)
104
  with col2:
105
- fig_rain = px.line(
106
- df, x="date", y="monthly_rainfall_mm", color="location",
107
- title="Monthly Rainfall (mm)"
108
- )
109
  st.plotly_chart(fig_rain, use_container_width=True)
110
 
111
- # Show outbreak months
112
  if disease_choice == "Malaria":
113
  flag_col = "malaria_outbreak"
114
  else:
@@ -117,33 +118,26 @@ if data_choice == "Monthly":
117
  outbreak_months = df[df[flag_col] == True]
118
  if not outbreak_months.empty:
119
  st.write(f"**Months with likely {disease_choice} outbreak:**")
120
- st.dataframe(outbreak_months[[
121
- "location","year","month","temp_avg","humidity","monthly_rainfall_mm",flag_col
122
- ]])
123
  else:
124
  st.write(f"No months meet the {disease_choice} outbreak criteria in this selection.")
125
 
126
  else:
127
- # Daily data
128
- fig = px.line(
129
- df, x="date", y=risk_col, color="location",
130
- title=f"{disease_choice} Daily Risk Over Time (2013–2024)"
131
- )
132
  fig.update_layout(yaxis_title="Risk (0–1)")
133
  st.plotly_chart(fig, use_container_width=True)
134
 
 
135
  col1, col2 = st.columns(2)
136
  with col1:
137
- fig_temp = px.line(
138
- df, x="date", y="temp_avg", color="location",
139
- title="Daily Avg Temperature (°C)"
140
- )
141
  st.plotly_chart(fig_temp, use_container_width=True)
142
  with col2:
143
- fig_rain = px.line(
144
- df, x="date", y="daily_rainfall_mm", color="location",
145
- title="Daily Rainfall (mm)"
146
- )
147
  st.plotly_chart(fig_rain, use_container_width=True)
148
 
149
  # ----------------------------------------------------
@@ -151,118 +145,59 @@ else:
151
  # ----------------------------------------------------
152
  st.subheader(f"Correlation Heatmap - {data_choice} Data")
153
 
 
154
  if data_choice == "Monthly":
155
  subset_cols = ["temp_avg", "humidity", "monthly_rainfall_mm", "malaria_risk", "dengue_risk"]
156
  else:
157
  subset_cols = ["temp_avg", "humidity", "daily_rainfall_mm", "malaria_risk", "dengue_risk"]
158
 
159
  corr_df = df[subset_cols].corr()
160
- fig_corr = px.imshow(
161
- corr_df, text_auto=True, aspect="auto",
162
- title="Correlation Matrix of Weather & Risk"
163
- )
164
  st.plotly_chart(fig_corr, use_container_width=True)
165
 
166
  # ----------------------------------------------------
167
- # 6. Add Real-Time Weather in Folium Map + Outbreak Info
168
  # ----------------------------------------------------
169
  st.subheader("Interactive Map")
170
  st.markdown(
171
  """
172
- **Note**: We only have 3 locations for the CSV data.
173
- Markers now also show **real-time weather** from OpenWeather & an **outbreak** indicator.
174
  """
175
  )
176
 
177
- # --- 6A. Helper function to get current weather from OpenWeather ---
178
- API_KEY = "c5b5c5ee6c497c6b1869ed926582a1ea" # <-- Your OpenWeather API key
179
-
180
- def get_current_weather(lat, lon, api_key=API_KEY):
181
- """
182
- Fetch current weather data from OpenWeather for given lat/lon.
183
- Returns a dict with {temp, humidity, description} if successful; else None.
184
- """
185
- url = f"https://api.openweathermap.org/data/2.5/weather?lat={lat}&lon={lon}&appid={api_key}&units=metric"
186
- try:
187
- resp = requests.get(url)
188
- if resp.status_code == 200:
189
- data = resp.json()
190
- # Extract a few relevant fields:
191
- current_temp = data["main"]["temp"]
192
- humidity = data["main"]["humidity"]
193
- weather_desc = data["weather"][0]["description"]
194
- return {
195
- "temp": current_temp,
196
- "humidity": humidity,
197
- "description": weather_desc
198
- }
199
- else:
200
- return None
201
- except Exception as e:
202
- # In production, you'd handle logging or fallback here
203
- return None
204
-
205
- # --- 6B. Create Folium Map ---
206
  m = folium.Map(location=[-6.0, 35.0], zoom_start=6)
207
 
208
- if disease_choice == "Malaria":
209
- outbreak_flag_col = "malaria_outbreak"
210
- else:
211
- outbreak_flag_col = "dengue_outbreak"
212
-
213
- # For each location, we show both the CSV-based stats AND real-time weather
214
  if data_choice == "Monthly":
 
 
215
  for loc in selected_locations:
216
  loc_info = LOCATIONS[loc]
217
  loc_df = df[df["location"] == loc]
218
 
219
  if loc_df.empty:
220
  continue
221
-
222
- # Averages from the CSV data
223
  avg_risk = loc_df[risk_col].mean()
224
  avg_temp = loc_df["temp_avg"].mean()
225
  avg_rain = loc_df["monthly_rainfall_mm"].mean()
226
 
227
- # Check if there's an outbreak in the filtered monthly data
228
- outbreak_count = loc_df[loc_df[outbreak_flag_col] == True].shape[0]
229
- outbreak_status = "Yes" if outbreak_count > 0 else "No"
230
-
231
- # Fetch real-time weather
232
- weather_now = get_current_weather(loc_info["lat"], loc_info["lon"], API_KEY)
233
-
234
- if weather_now:
235
- rt_temp = weather_now["temp"]
236
- rt_hum = weather_now["humidity"]
237
- rt_desc = weather_now["description"]
238
- else:
239
- rt_temp = None
240
- rt_hum = None
241
- rt_desc = "N/A"
242
-
243
- # Build the popup HTML
244
  popup_html = f"""
245
  <b>{loc}</b><br/>
246
  Disease: {disease_choice}<br/>
247
- Outbreak Now (in selection)? {outbreak_status}<br/>
248
- <br/>
249
- <u>Historical/Forecasted Averages (CSV)</u><br/>
250
- Avg Risk (selected range): {avg_risk:.2f}<br/>
251
  Avg Temp (°C): {avg_temp:.2f}<br/>
252
  Avg Rainfall (mm): {avg_rain:.2f}<br/>
253
- <br/>
254
- <u>Real-Time Weather (OpenWeather)</u><br/>
255
- Current Temp (°C): {rt_temp if rt_temp else 'N/A'}<br/>
256
- Current Humidity (%): {rt_hum if rt_hum else 'N/A'}<br/>
257
- Conditions: {rt_desc}
258
  """
259
-
260
  folium.Marker(
261
  location=[loc_info["lat"], loc_info["lon"]],
262
  popup=popup_html,
263
  tooltip=f"{loc} ({disease_choice})"
264
  ).add_to(m)
265
-
266
  else:
267
  # Daily data
268
  for loc in selected_locations:
@@ -271,42 +206,17 @@ else:
271
 
272
  if loc_df.empty:
273
  continue
274
-
275
  avg_risk = loc_df[risk_col].mean()
276
  avg_temp = loc_df["temp_avg"].mean()
277
  avg_rain = loc_df["daily_rainfall_mm"].mean()
278
 
279
- # Check outbreak
280
- outbreak_count = loc_df[loc_df[outbreak_flag_col] == True].shape[0]
281
- outbreak_status = "Yes" if outbreak_count > 0 else "No"
282
-
283
- # Real-time weather
284
- weather_now = get_current_weather(loc_info["lat"], loc_info["lon"], API_KEY)
285
- if weather_now:
286
- rt_temp = weather_now["temp"]
287
- rt_hum = weather_now["humidity"]
288
- rt_desc = weather_now["description"]
289
- else:
290
- rt_temp = None
291
- rt_hum = None
292
- rt_desc = "N/A"
293
-
294
  popup_html = f"""
295
  <b>{loc}</b><br/>
296
  Disease: {disease_choice}<br/>
297
- Outbreak Now (in selection)? {outbreak_status}<br/>
298
- <br/>
299
- <u>Historical/Forecasted Averages (CSV)</u><br/>
300
- Avg Risk (selected range): {avg_risk:.2f}<br/>
301
  Avg Temp (°C): {avg_temp:.2f}<br/>
302
  Avg Rain (mm/day): {avg_rain:.2f}<br/>
303
- <br/>
304
- <u>Real-Time Weather (OpenWeather)</u><br/>
305
- Current Temp (°C): {rt_temp if rt_temp else 'N/A'}<br/>
306
- Current Humidity (%): {rt_hum if rt_hum else 'N/A'}<br/>
307
- Conditions: {rt_desc}
308
  """
309
-
310
  folium.Marker(
311
  location=[loc_info["lat"], loc_info["lon"]],
312
  popup=popup_html,
 
4
  import plotly.express as px
5
  import folium
6
  from streamlit_folium import st_folium
7
+
8
  # ----------------------------------------------------
9
  # 1. Load data
10
  # ----------------------------------------------------
11
  @st.cache_data
12
  def load_data():
13
+ # Load daily and monthly CSV from local files (or a URL if needed)
14
  daily_df = pd.read_csv("daily_data_2013_2024.csv", parse_dates=["date"])
15
  monthly_df = pd.read_csv("monthly_data_2013_2024.csv")
16
+
17
+ # If monthly_df also needs a 'date' column for plotting (like first day of month), you can create:
18
+ # monthly_df["date"] = pd.to_datetime(monthly_df["year"].astype(str) + "-" + monthly_df["month"].astype(str) + "-01")
19
+
20
  return daily_df, monthly_df
21
 
22
  daily_data, monthly_data = load_data()
 
35
 
36
  st.sidebar.header("Filters & Options")
37
 
38
+ # Choose disease type to focus on
39
  disease_choice = st.sidebar.radio("Select Disease", ["Malaria", "Dengue"])
40
 
41
  # Choose data granularity
 
45
  location_list = list(LOCATIONS.keys())
46
  selected_locations = st.sidebar.multiselect("Select Location(s)", location_list, default=location_list)
47
 
48
+ # For monthly data, let user select a year range
49
  if data_choice == "Monthly":
50
  year_min = int(monthly_data["year"].min())
51
  year_max = int(monthly_data["year"].max())
52
+ year_range = st.sidebar.slider("Select Year Range",
53
+ min_value=year_min,
54
+ max_value=year_max,
55
+ value=(year_min, year_max))
56
+ # For daily data, let user select a date range
 
 
57
  else:
58
  date_min = daily_data["date"].min()
59
  date_max = daily_data["date"].max()
60
+ date_range = st.sidebar.date_input("Select Date Range",
61
+ [date_min, date_max],
62
+ min_value=date_min,
63
+ max_value=date_max)
 
 
64
 
65
  # ----------------------------------------------------
66
  # 3. Filter data based on user input
67
  # ----------------------------------------------------
68
  if data_choice == "Monthly":
69
+ # Subset monthly data for selected locations
70
  df = monthly_data[monthly_data["location"].isin(selected_locations)].copy()
71
  # Filter year range
72
  df = df[(df["year"] >= year_range[0]) & (df["year"] <= year_range[1])]
73
+
74
+ # Create a "date" column for monthly plotting (1st of each month)
75
+ # This can help create a time-series for Plotly
76
  df["date"] = pd.to_datetime(df["year"].astype(str) + "-" + df["month"].astype(str) + "-01")
77
+
78
  else:
79
+ # Subset daily data
80
  df = daily_data[daily_data["location"].isin(selected_locations)].copy()
81
  # Filter date range
82
+ df = df[(df["date"] >= pd.to_datetime(date_range[0])) & (df["date"] <= pd.to_datetime(date_range[1]))]
 
 
 
83
 
84
  # ----------------------------------------------------
85
  # 4. Interactive Plotly Time-Series
86
  # ----------------------------------------------------
87
  st.subheader(f"{data_choice} {disease_choice} Risk & Climate Parameters")
88
 
89
+ # Decide which columns are relevant
90
  risk_col = "malaria_risk" if disease_choice == "Malaria" else "dengue_risk"
91
 
92
  if data_choice == "Monthly":
93
+ # We'll plot a line chart of risk, temperature, and rainfall vs. date
94
+ fig = px.line(df, x="date", y=risk_col, color="location",
95
+ title=f"{disease_choice} Risk Over Time ({data_choice})")
 
96
  fig.update_layout(yaxis_title="Risk (0–1)")
97
+
98
  st.plotly_chart(fig, use_container_width=True)
99
 
100
+ # Optionally plot temperature / rainfall on another figure
101
  col1, col2 = st.columns(2)
102
  with col1:
103
+ fig_temp = px.line(df, x="date", y="temp_avg", color="location",
104
+ title="Average Temperature (°C)")
 
 
105
  st.plotly_chart(fig_temp, use_container_width=True)
106
  with col2:
107
+ # 'monthly_rainfall_mm' is total monthly rainfall
108
+ fig_rain = px.line(df, x="date", y="monthly_rainfall_mm", color="location",
109
+ title="Monthly Rainfall (mm)")
 
110
  st.plotly_chart(fig_rain, use_container_width=True)
111
 
112
+ # Show outbreak flags if focusing on monthly
113
  if disease_choice == "Malaria":
114
  flag_col = "malaria_outbreak"
115
  else:
 
118
  outbreak_months = df[df[flag_col] == True]
119
  if not outbreak_months.empty:
120
  st.write(f"**Months with likely {disease_choice} outbreak:**")
121
+ st.dataframe(outbreak_months[["location","year","month","temp_avg","humidity","monthly_rainfall_mm",flag_col]])
 
 
122
  else:
123
  st.write(f"No months meet the {disease_choice} outbreak criteria in this selection.")
124
 
125
  else:
126
+ # For daily data, plot daily risk
127
+ fig = px.line(df, x="date", y=risk_col, color="location",
128
+ title=f"{disease_choice} Daily Risk Over Time (2013–2024)")
 
 
129
  fig.update_layout(yaxis_title="Risk (0–1)")
130
  st.plotly_chart(fig, use_container_width=True)
131
 
132
+ # Similarly, temperature & daily rainfall
133
  col1, col2 = st.columns(2)
134
  with col1:
135
+ fig_temp = px.line(df, x="date", y="temp_avg", color="location",
136
+ title="Daily Avg Temperature (°C)")
 
 
137
  st.plotly_chart(fig_temp, use_container_width=True)
138
  with col2:
139
+ fig_rain = px.line(df, x="date", y="daily_rainfall_mm", color="location",
140
+ title="Daily Rainfall (mm)")
 
 
141
  st.plotly_chart(fig_rain, use_container_width=True)
142
 
143
  # ----------------------------------------------------
 
145
  # ----------------------------------------------------
146
  st.subheader(f"Correlation Heatmap - {data_choice} Data")
147
 
148
+ # We'll pick relevant numeric columns
149
  if data_choice == "Monthly":
150
  subset_cols = ["temp_avg", "humidity", "monthly_rainfall_mm", "malaria_risk", "dengue_risk"]
151
  else:
152
  subset_cols = ["temp_avg", "humidity", "daily_rainfall_mm", "malaria_risk", "dengue_risk"]
153
 
154
  corr_df = df[subset_cols].corr()
155
+ fig_corr = px.imshow(corr_df, text_auto=True, aspect="auto",
156
+ title="Correlation Matrix of Weather & Risk")
 
 
157
  st.plotly_chart(fig_corr, use_container_width=True)
158
 
159
  # ----------------------------------------------------
160
+ # 6. Interactive Map (Folium)
161
  # ----------------------------------------------------
162
  st.subheader("Interactive Map")
163
  st.markdown(
164
  """
165
+ **Note**: We only have 3 locations. Each marker popup shows some aggregated
166
+ stats for the displayed data range.
167
  """
168
  )
169
 
170
+ # Create a base map centered roughly in Tanzania
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
171
  m = folium.Map(location=[-6.0, 35.0], zoom_start=6)
172
 
173
+ # We'll show monthly or daily aggregates in the popups
 
 
 
 
 
174
  if data_choice == "Monthly":
175
+ # For each location, let's gather monthly avg for the current df
176
+ # Then we can show a simple summary in the popup
177
  for loc in selected_locations:
178
  loc_info = LOCATIONS[loc]
179
  loc_df = df[df["location"] == loc]
180
 
181
  if loc_df.empty:
182
  continue
183
+ # Basic stats: average risk, average rainfall, etc
 
184
  avg_risk = loc_df[risk_col].mean()
185
  avg_temp = loc_df["temp_avg"].mean()
186
  avg_rain = loc_df["monthly_rainfall_mm"].mean()
187
 
188
+ # Build popup HTML
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
189
  popup_html = f"""
190
  <b>{loc}</b><br/>
191
  Disease: {disease_choice}<br/>
192
+ Avg Risk (in selection): {avg_risk:.2f}<br/>
 
 
 
193
  Avg Temp (°C): {avg_temp:.2f}<br/>
194
  Avg Rainfall (mm): {avg_rain:.2f}<br/>
 
 
 
 
 
195
  """
 
196
  folium.Marker(
197
  location=[loc_info["lat"], loc_info["lon"]],
198
  popup=popup_html,
199
  tooltip=f"{loc} ({disease_choice})"
200
  ).add_to(m)
 
201
  else:
202
  # Daily data
203
  for loc in selected_locations:
 
206
 
207
  if loc_df.empty:
208
  continue
 
209
  avg_risk = loc_df[risk_col].mean()
210
  avg_temp = loc_df["temp_avg"].mean()
211
  avg_rain = loc_df["daily_rainfall_mm"].mean()
212
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
213
  popup_html = f"""
214
  <b>{loc}</b><br/>
215
  Disease: {disease_choice}<br/>
216
+ Avg Risk (in selection): {avg_risk:.2f}<br/>
 
 
 
217
  Avg Temp (°C): {avg_temp:.2f}<br/>
218
  Avg Rain (mm/day): {avg_rain:.2f}<br/>
 
 
 
 
 
219
  """
 
220
  folium.Marker(
221
  location=[loc_info["lat"], loc_info["lon"]],
222
  popup=popup_html,