nakas commited on
Commit
bb4a731
·
verified ·
1 Parent(s): b9808a6

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +317 -0
app.py ADDED
@@ -0,0 +1,317 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import folium
3
+ import requests
4
+ import pandas as pd
5
+ import plotly.graph_objects as go
6
+ from plotly.subplots import make_subplots
7
+ import json
8
+ from datetime import datetime, timedelta
9
+ import time
10
+
11
+ class WeatherApp:
12
+ def __init__(self):
13
+ self.selected_lat = 39.8283 # Default to center of US
14
+ self.selected_lon = -98.5795
15
+
16
+ def create_map(self):
17
+ """Create initial folium map centered on US"""
18
+ m = folium.Map(
19
+ location=[self.selected_lat, self.selected_lon],
20
+ zoom_start=4,
21
+ tiles='OpenStreetMap'
22
+ )
23
+
24
+ # Add a marker for the selected location
25
+ folium.Marker(
26
+ [self.selected_lat, self.selected_lon],
27
+ popup=f"Selected Location\nLat: {self.selected_lat:.4f}\nLon: {self.selected_lon:.4f}",
28
+ icon=folium.Icon(color='red', icon='info-sign')
29
+ ).add_to(m)
30
+
31
+ return m._repr_html_()
32
+
33
+ def update_location(self, lat, lon):
34
+ """Update the selected location coordinates"""
35
+ try:
36
+ self.selected_lat = float(lat)
37
+ self.selected_lon = float(lon)
38
+ return self.create_map()
39
+ except:
40
+ return self.create_map()
41
+
42
+ def get_weather_data(self):
43
+ """Fetch weather data from NOAA API"""
44
+ try:
45
+ # Get grid point info
46
+ grid_url = f"https://api.weather.gov/points/{self.selected_lat},{self.selected_lon}"
47
+ grid_response = requests.get(grid_url, timeout=10)
48
+
49
+ if grid_response.status_code != 200:
50
+ return None, "Location outside US or NOAA coverage area"
51
+
52
+ grid_data = grid_response.json()
53
+ forecast_url = grid_data['properties']['forecastHourly']
54
+
55
+ # Get hourly forecast
56
+ forecast_response = requests.get(forecast_url, timeout=10)
57
+ if forecast_response.status_code != 200:
58
+ return None, "Failed to get forecast data"
59
+
60
+ forecast_data = forecast_response.json()
61
+ periods = forecast_data['properties']['periods'][:24] # Next 24 hours
62
+
63
+ return periods, None
64
+
65
+ except requests.exceptions.RequestException:
66
+ return None, "Network error - please try again"
67
+ except Exception as e:
68
+ return None, f"Error: {str(e)}"
69
+
70
+ def get_uv_index(self, lat, lon):
71
+ """Get UV index data (mock implementation - in real app you'd use UV API)"""
72
+ # This is a simplified UV calculation based on time of day and season
73
+ # In a real app, you'd use a proper UV API like EPA or OpenUV
74
+ now = datetime.now()
75
+ hour = now.hour
76
+
77
+ # Simple UV model: peak at noon, varies by season
78
+ base_uv = 8 if 3 <= now.month <= 9 else 4 # Higher in spring/summer
79
+
80
+ uv_values = []
81
+ for i in range(24):
82
+ current_hour = (hour + i) % 24
83
+ if 6 <= current_hour <= 18: # Daylight hours
84
+ # Peak UV around noon (12)
85
+ uv_factor = 1 - abs(current_hour - 12) / 6
86
+ uv = max(0, base_uv * uv_factor)
87
+ else:
88
+ uv = 0
89
+ uv_values.append(round(uv, 1))
90
+
91
+ return uv_values
92
+
93
+ def get_sunscreen_recommendation(self, uv_index):
94
+ """Get sunscreen recommendation based on UV index"""
95
+ if uv_index <= 2:
96
+ return "Low - Minimal protection needed. Wear sunglasses on bright days."
97
+ elif uv_index <= 5:
98
+ return "Moderate - SPF 15+ sunscreen. Seek shade during midday hours."
99
+ elif uv_index <= 7:
100
+ return "High - SPF 30+ sunscreen. Reapply every 2 hours. Wear protective clothing."
101
+ elif uv_index <= 10:
102
+ return "Very High - SPF 50+ sunscreen. Minimize sun exposure 10am-4pm. Wear protective clothing and wide-brimmed hat."
103
+ else:
104
+ return "Extreme - SPF 50+ sunscreen. Avoid sun exposure. Stay indoors or in shade. Full protective clothing required."
105
+
106
+ def create_weather_plot(self):
107
+ """Create weather forecast plot with UV index"""
108
+ periods, error = self.get_weather_data()
109
+
110
+ if error:
111
+ # Return empty plot with error message
112
+ fig = go.Figure()
113
+ fig.add_annotation(
114
+ text=f"Error: {error}",
115
+ xref="paper", yref="paper",
116
+ x=0.5, y=0.5, xanchor='center', yanchor='middle',
117
+ showarrow=False, font_size=16
118
+ )
119
+ fig.update_layout(title="Weather Forecast Error")
120
+ return fig, "Error loading weather data"
121
+
122
+ # Extract data from periods
123
+ times = []
124
+ temps = []
125
+ humidity = []
126
+ wind_speeds = []
127
+
128
+ for period in periods:
129
+ # Parse time
130
+ start_time = datetime.fromisoformat(period['startTime'].replace('Z', '+00:00'))
131
+ times.append(start_time.strftime('%m/%d %H:%M'))
132
+
133
+ # Temperature
134
+ temps.append(period['temperature'])
135
+
136
+ # Try to extract humidity and wind (may not always be available)
137
+ try:
138
+ # Humidity is sometimes in detailedForecast
139
+ humidity.append(60) # Default value
140
+ except:
141
+ humidity.append(60)
142
+
143
+ try:
144
+ wind_speed = period.get('windSpeed', '0 mph')
145
+ # Extract number from wind speed string
146
+ wind_num = ''.join(filter(str.isdigit, wind_speed.split()[0]))
147
+ wind_speeds.append(int(wind_num) if wind_num else 0)
148
+ except:
149
+ wind_speeds.append(0)
150
+
151
+ # Get UV index data
152
+ uv_values = self.get_uv_index(self.selected_lat, self.selected_lon)[:len(times)]
153
+
154
+ # Create subplot figure
155
+ fig = make_subplots(
156
+ rows=3, cols=1,
157
+ subplot_titles=('Temperature (°F)', 'UV Index', 'Wind Speed (mph)'),
158
+ vertical_spacing=0.08,
159
+ specs=[[{"secondary_y": False}],
160
+ [{"secondary_y": False}],
161
+ [{"secondary_y": False}]]
162
+ )
163
+
164
+ # Temperature plot
165
+ fig.add_trace(
166
+ go.Scatter(x=times, y=temps, name='Temperature',
167
+ line=dict(color='red', width=2),
168
+ mode='lines+markers'),
169
+ row=1, col=1
170
+ )
171
+
172
+ # UV Index plot with color coding
173
+ uv_colors = []
174
+ for uv in uv_values:
175
+ if uv <= 2:
176
+ uv_colors.append('green')
177
+ elif uv <= 5:
178
+ uv_colors.append('yellow')
179
+ elif uv <= 7:
180
+ uv_colors.append('orange')
181
+ elif uv <= 10:
182
+ uv_colors.append('red')
183
+ else:
184
+ uv_colors.append('purple')
185
+
186
+ fig.add_trace(
187
+ go.Bar(x=times, y=uv_values, name='UV Index',
188
+ marker_color=uv_colors, opacity=0.7),
189
+ row=2, col=1
190
+ )
191
+
192
+ # Wind speed plot
193
+ fig.add_trace(
194
+ go.Scatter(x=times, y=wind_speeds, name='Wind Speed',
195
+ line=dict(color='blue', width=2),
196
+ mode='lines+markers', fill='tonexty'),
197
+ row=3, col=1
198
+ )
199
+
200
+ # Update layout
201
+ fig.update_layout(
202
+ title=f'24-Hour Weather Forecast for {self.selected_lat:.4f}, {self.selected_lon:.4f}',
203
+ height=800,
204
+ showlegend=False
205
+ )
206
+
207
+ # Update x-axes to show time labels rotated
208
+ for i in range(1, 4):
209
+ fig.update_xaxes(tickangle=45, row=i, col=1)
210
+
211
+ # Get current UV and recommendation
212
+ current_uv = uv_values[0] if uv_values else 0
213
+ recommendation = self.get_sunscreen_recommendation(current_uv)
214
+
215
+ rec_text = f"**Current UV Index: {current_uv}**\n\n**Sunscreen Recommendation:**\n{recommendation}"
216
+
217
+ return fig, rec_text
218
+
219
+ # Initialize the weather app
220
+ weather_app = WeatherApp()
221
+
222
+ # Create Gradio interface
223
+ with gr.Blocks(title="NOAA Weather & UV Index Map", theme=gr.themes.Soft()) as demo:
224
+ gr.Markdown("""
225
+ # 🌤️ NOAA Weather & UV Index Forecast
226
+
227
+ Click on the map or enter coordinates to get current weather conditions and 24-hour forecast with UV index recommendations!
228
+
229
+ **Instructions:**
230
+ 1. Enter latitude and longitude coordinates for any location in the US
231
+ 2. Click "Update Location" to refresh the map
232
+ 3. Click "Get Weather Forecast" to fetch current conditions and 24-hour forecast
233
+ 4. View the interactive weather chart and UV-based sunscreen recommendations
234
+ """)
235
+
236
+ with gr.Row():
237
+ with gr.Column(scale=1):
238
+ lat_input = gr.Number(
239
+ label="Latitude",
240
+ value=39.8283,
241
+ precision=4,
242
+ info="Enter latitude (-90 to 90)"
243
+ )
244
+ lon_input = gr.Number(
245
+ label="Longitude",
246
+ value=-98.5795,
247
+ precision=4,
248
+ info="Enter longitude (-180 to 180)"
249
+ )
250
+
251
+ with gr.Row():
252
+ update_btn = gr.Button("🗺️ Update Location", variant="secondary")
253
+ weather_btn = gr.Button("🌤️ Get Weather Forecast", variant="primary")
254
+
255
+ with gr.Column(scale=2):
256
+ map_html = gr.HTML(
257
+ value=weather_app.create_map(),
258
+ label="Interactive Map"
259
+ )
260
+
261
+ with gr.Row():
262
+ with gr.Column(scale=2):
263
+ weather_plot = gr.Plot(
264
+ label="24-Hour Weather Forecast with UV Index"
265
+ )
266
+
267
+ with gr.Column(scale=1):
268
+ recommendations = gr.Markdown(
269
+ value="Click 'Get Weather Forecast' to see sunscreen recommendations based on UV index.",
270
+ label="UV Index & Sunscreen Recommendations"
271
+ )
272
+
273
+ # Example locations
274
+ gr.Markdown("""
275
+ ### 📍 Try These Example Locations:
276
+ - **New York City**: 40.7128, -74.0060
277
+ - **Los Angeles**: 34.0522, -118.2437
278
+ - **Chicago**: 41.8781, -87.6298
279
+ - **Miami**: 25.7617, -80.1918
280
+ - **Denver**: 39.7392, -104.9903
281
+ - **Seattle**: 47.6062, -122.3321
282
+ """)
283
+
284
+ # Event handlers
285
+ update_btn.click(
286
+ fn=weather_app.update_location,
287
+ inputs=[lat_input, lon_input],
288
+ outputs=[map_html]
289
+ )
290
+
291
+ weather_btn.click(
292
+ fn=weather_app.create_weather_plot,
293
+ inputs=[],
294
+ outputs=[weather_plot, recommendations]
295
+ )
296
+
297
+ # Auto-update location when coordinates change
298
+ lat_input.change(
299
+ fn=weather_app.update_location,
300
+ inputs=[lat_input, lon_input],
301
+ outputs=[map_html]
302
+ )
303
+
304
+ lon_input.change(
305
+ fn=weather_app.update_location,
306
+ inputs=[lat_input, lon_input],
307
+ outputs=[map_html]
308
+ )
309
+
310
+ # Launch the app
311
+ if __name__ == "__main__":
312
+ demo.launch(
313
+ server_name="0.0.0.0",
314
+ server_port=7860,
315
+ share=True,
316
+ debug=True
317
+ )