nakas commited on
Commit
5a17d59
·
verified ·
1 Parent(s): ebff5fc

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +105 -34
app.py CHANGED
@@ -35,9 +35,28 @@ class WeatherApp:
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"""
@@ -87,22 +106,23 @@ class WeatherApp:
87
  for i in range(24):
88
  current_hour = (hour + i) % 24
89
 
90
- # Determine weather condition (simplified model)
91
  import random
92
- random.seed(int(lat * lon * i)) # Deterministic randomness
93
  condition_rand = random.random()
94
 
95
- if condition_rand < 0.6:
96
- condition = "☀️ Sunny"
 
97
  cloud_factor = 1.0
98
- elif condition_rand < 0.8:
99
- condition = "Partly Cloudy"
100
  cloud_factor = 0.7
101
- elif condition_rand < 0.95:
102
- condition = "☁️ Cloudy"
103
  cloud_factor = 0.4
104
  else:
105
- condition = "🌧️ Rainy"
106
  cloud_factor = 0.2
107
 
108
  weather_conditions.append(condition)
@@ -202,10 +222,10 @@ class WeatherApp:
202
  time_labels.append(start_time.strftime('%m/%d\n%H:%M'))
203
  temps.append(period['temperature'])
204
 
205
- # Get UV index and weather conditions
206
  uv_values, weather_conditions = self.get_uv_index(self.selected_lat, self.selected_lon)
207
- uv_values = uv_values[:len(times)]
208
- weather_conditions = weather_conditions[:len(times)]
209
 
210
  # Create combined temperature and UV plot
211
  fig = go.Figure()
@@ -245,13 +265,13 @@ class WeatherApp:
245
  yaxis='y2'
246
  ))
247
 
248
- # Update layout with dual y-axes
249
  fig.update_layout(
250
  title=dict(
251
  text=f'24-Hour Weather Forecast: {self.selected_lat:.4f}°, {self.selected_lon:.4f}°',
252
  font=dict(size=18, color='#2C3E50')
253
  ),
254
- height=600, # Increased height for more space
255
  xaxis=dict(
256
  title="Time",
257
  tickvals=times,
@@ -259,7 +279,9 @@ class WeatherApp:
259
  tickangle=45,
260
  showgrid=True,
261
  gridwidth=1,
262
- gridcolor='rgba(128,128,128,0.2)'
 
 
263
  ),
264
  yaxis=dict(
265
  title=dict(text="Temperature (°F)", font=dict(color='#FF6B6B')),
@@ -267,14 +289,16 @@ class WeatherApp:
267
  tickfont=dict(color='#FF6B6B'),
268
  showgrid=True,
269
  gridwidth=1,
270
- gridcolor='rgba(255,107,107,0.2)'
 
271
  ),
272
  yaxis2=dict(
273
  title=dict(text="UV Index", font=dict(color='#4A90E2')),
274
  overlaying='y',
275
  side='right',
276
  tickfont=dict(color='#4A90E2'),
277
- range=[0, max(12, max(uv_values) * 1.1)]
 
278
  ),
279
  plot_bgcolor='rgba(248,249,250,0.8)',
280
  paper_bgcolor='white',
@@ -286,29 +310,34 @@ class WeatherApp:
286
  xanchor="right",
287
  x=1
288
  ),
289
- margin=dict(l=60, r=60, t=80, b=150) # More margin for conditions
 
290
  )
291
 
292
- # Add weather conditions as annotations below x-axis
 
 
 
293
  for i, (time_idx, condition) in enumerate(zip(times, weather_conditions)):
294
- if i % 3 == 0: # Show every 3rd condition to avoid crowding
295
  fig.add_annotation(
296
  x=time_idx,
297
- y=-0.15, # Below x-axis
298
- text=condition,
299
  showarrow=False,
300
- font=dict(size=10),
301
  xref='x',
302
  yref='paper',
303
  xanchor='center'
304
  )
305
 
306
  # Add UV risk zones as background colors
307
- fig.add_hrect(y0=0, y1=2, fillcolor="rgba(76,175,80,0.1)", layer="below", line_width=0, yref='y2')
308
- fig.add_hrect(y0=3, y1=5, fillcolor="rgba(255,193,7,0.1)", layer="below", line_width=0, yref='y2')
309
- fig.add_hrect(y0=6, y1=7, fillcolor="rgba(255,152,0,0.1)", layer="below", line_width=0, yref='y2')
310
- fig.add_hrect(y0=8, y1=10, fillcolor="rgba(244,67,54,0.1)", layer="below", line_width=0, yref='y2')
311
- fig.add_hrect(y0=11, y1=15, fillcolor="rgba(156,39,176,0.1)", layer="below", line_width=0, yref='y2')
 
312
 
313
  # Get comprehensive recommendations
314
  recommendations = self.get_comprehensive_sunscreen_recommendations(uv_values)
@@ -377,14 +406,26 @@ with gr.Blocks(title="NOAA Weather & UV Index Map", theme=gr.themes.Soft()) as d
377
  update_btn = gr.Button("🗺️ Update Location", variant="secondary", size="sm")
378
  weather_btn = gr.Button("🧴 Get Sunscreen Report", variant="primary", size="lg")
379
 
 
 
 
 
 
 
 
 
 
 
 
380
  gr.Markdown("""
381
- ### 📍 Popular Locations:
382
  - **NYC**: 40.7128, -74.0060
383
  - **LA**: 34.0522, -118.2437
384
  - **Chicago**: 41.8781, -87.6298
385
  - **Miami**: 25.7617, -80.1918
386
  - **Denver**: 39.7392, -104.9903
387
  - **Seattle**: 47.6062, -122.3321
 
388
  """)
389
 
390
  with gr.Column(scale=2):
@@ -436,7 +477,37 @@ with gr.Blocks(title="NOAA Weather & UV Index Map", theme=gr.themes.Soft()) as d
436
  update_btn.click(
437
  fn=weather_app.update_location,
438
  inputs=[lat_input, lon_input],
439
- outputs=[map_html]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
440
  )
441
 
442
  weather_btn.click(
@@ -449,13 +520,13 @@ with gr.Blocks(title="NOAA Weather & UV Index Map", theme=gr.themes.Soft()) as d
449
  lat_input.change(
450
  fn=weather_app.update_location,
451
  inputs=[lat_input, lon_input],
452
- outputs=[map_html]
453
  )
454
 
455
  lon_input.change(
456
  fn=weather_app.update_location,
457
  inputs=[lat_input, lon_input],
458
- outputs=[map_html]
459
  )
460
 
461
  # Launch the app
 
35
  try:
36
  self.selected_lat = float(lat)
37
  self.selected_lon = float(lon)
38
+ return self.create_map(), lat, lon
39
  except:
40
+ return self.create_map(), self.selected_lat, self.selected_lon
41
+
42
+ def set_city_coordinates(self, city_name):
43
+ """Set coordinates for major cities"""
44
+ cities = {
45
+ "New York City": (40.7128, -74.0060),
46
+ "Los Angeles": (34.0522, -118.2437),
47
+ "Chicago": (41.8781, -87.6298),
48
+ "Miami": (25.7617, -80.1918),
49
+ "Denver": (39.7392, -104.9903),
50
+ "Seattle": (47.6062, -122.3321),
51
+ "Bozeman, MT": (45.6770, -111.0429)
52
+ }
53
+
54
+ if city_name in cities:
55
+ lat, lon = cities[city_name]
56
+ self.selected_lat = lat
57
+ self.selected_lon = lon
58
+ return self.create_map(), lat, lon
59
+ return self.create_map(), self.selected_lat, self.selected_lon
60
 
61
  def get_weather_data(self):
62
  """Fetch weather data from NOAA API"""
 
106
  for i in range(24):
107
  current_hour = (hour + i) % 24
108
 
109
+ # Determine weather condition (more realistic distribution - less sunny)
110
  import random
111
+ random.seed(int(lat * lon * i + 42)) # Deterministic randomness
112
  condition_rand = random.random()
113
 
114
+ # Reduced sunny probability to make it more realistic
115
+ if condition_rand < 0.35: # Reduced from 0.6 to 0.35
116
+ condition = "Sunny"
117
  cloud_factor = 1.0
118
+ elif condition_rand < 0.60: # Increased partly cloudy
119
+ condition = "Partly Cloudy"
120
  cloud_factor = 0.7
121
+ elif condition_rand < 0.85: # Increased cloudy
122
+ condition = "Cloudy"
123
  cloud_factor = 0.4
124
  else:
125
+ condition = "Rainy"
126
  cloud_factor = 0.2
127
 
128
  weather_conditions.append(condition)
 
222
  time_labels.append(start_time.strftime('%m/%d\n%H:%M'))
223
  temps.append(period['temperature'])
224
 
225
+ # Get UV index and weather conditions - USE SAME LENGTH AS TEMPERATURE DATA
226
  uv_values, weather_conditions = self.get_uv_index(self.selected_lat, self.selected_lon)
227
+ uv_values = uv_values[:len(times)] # Ensure same length
228
+ weather_conditions = weather_conditions[:len(times)] # Ensure same length
229
 
230
  # Create combined temperature and UV plot
231
  fig = go.Figure()
 
265
  yaxis='y2'
266
  ))
267
 
268
+ # Update layout with dual y-axes and better spacing
269
  fig.update_layout(
270
  title=dict(
271
  text=f'24-Hour Weather Forecast: {self.selected_lat:.4f}°, {self.selected_lon:.4f}°',
272
  font=dict(size=18, color='#2C3E50')
273
  ),
274
+ height=700, # Increased height for more space
275
  xaxis=dict(
276
  title="Time",
277
  tickvals=times,
 
279
  tickangle=45,
280
  showgrid=True,
281
  gridwidth=1,
282
+ gridcolor='rgba(128,128,128,0.2)',
283
+ range=[-1.5, len(times) + 0.5], # More padding on sides to prevent squishing
284
+ fixedrange=True # Disable zooming/panning
285
  ),
286
  yaxis=dict(
287
  title=dict(text="Temperature (°F)", font=dict(color='#FF6B6B')),
 
289
  tickfont=dict(color='#FF6B6B'),
290
  showgrid=True,
291
  gridwidth=1,
292
+ gridcolor='rgba(255,107,107,0.2)',
293
+ fixedrange=True # Disable zooming/panning
294
  ),
295
  yaxis2=dict(
296
  title=dict(text="UV Index", font=dict(color='#4A90E2')),
297
  overlaying='y',
298
  side='right',
299
  tickfont=dict(color='#4A90E2'),
300
+ range=[0, max(12, max(uv_values) * 1.1) if uv_values else 12],
301
+ fixedrange=True # Disable zooming/panning
302
  ),
303
  plot_bgcolor='rgba(248,249,250,0.8)',
304
  paper_bgcolor='white',
 
310
  xanchor="right",
311
  x=1
312
  ),
313
+ margin=dict(l=100, r=100, t=100, b=220), # Much larger margins, especially on sides
314
+ dragmode=False, # Disable all dragging
315
  )
316
 
317
+ # Disable hover interactions
318
+ fig.update_traces(hoverinfo='none')
319
+
320
+ # Add weather conditions as text annotations with better spacing and readability
321
  for i, (time_idx, condition) in enumerate(zip(times, weather_conditions)):
322
+ if i % 2 == 0: # Show every other condition to avoid crowding
323
  fig.add_annotation(
324
  x=time_idx,
325
+ y=-0.28, # Further below x-axis
326
+ text=f"<b>{condition}</b>",
327
  showarrow=False,
328
+ font=dict(size=12, color='#2C3E50'),
329
  xref='x',
330
  yref='paper',
331
  xanchor='center'
332
  )
333
 
334
  # Add UV risk zones as background colors
335
+ if uv_values:
336
+ fig.add_hrect(y0=0, y1=2, fillcolor="rgba(76,175,80,0.1)", layer="below", line_width=0, yref='y2')
337
+ fig.add_hrect(y0=3, y1=5, fillcolor="rgba(255,193,7,0.1)", layer="below", line_width=0, yref='y2')
338
+ fig.add_hrect(y0=6, y1=7, fillcolor="rgba(255,152,0,0.1)", layer="below", line_width=0, yref='y2')
339
+ fig.add_hrect(y0=8, y1=10, fillcolor="rgba(244,67,54,0.1)", layer="below", line_width=0, yref='y2')
340
+ fig.add_hrect(y0=11, y1=15, fillcolor="rgba(156,39,176,0.1)", layer="below", line_width=0, yref='y2')
341
 
342
  # Get comprehensive recommendations
343
  recommendations = self.get_comprehensive_sunscreen_recommendations(uv_values)
 
406
  update_btn = gr.Button("🗺️ Update Location", variant="secondary", size="sm")
407
  weather_btn = gr.Button("🧴 Get Sunscreen Report", variant="primary", size="lg")
408
 
409
+ gr.Markdown("### 🏙️ Quick City Selection")
410
+ with gr.Row():
411
+ nyc_btn = gr.Button("🗽 NYC", size="sm")
412
+ la_btn = gr.Button("🌴 LA", size="sm")
413
+ chicago_btn = gr.Button("🏢 Chicago", size="sm")
414
+ with gr.Row():
415
+ miami_btn = gr.Button("🏖️ Miami", size="sm")
416
+ denver_btn = gr.Button("⛰️ Denver", size="sm")
417
+ seattle_btn = gr.Button("🌲 Seattle", size="sm")
418
+ bozeman_btn = gr.Button("🏔️ Bozeman, MT", size="sm", variant="secondary")
419
+
420
  gr.Markdown("""
421
+ ### 📍 Manual Coordinates:
422
  - **NYC**: 40.7128, -74.0060
423
  - **LA**: 34.0522, -118.2437
424
  - **Chicago**: 41.8781, -87.6298
425
  - **Miami**: 25.7617, -80.1918
426
  - **Denver**: 39.7392, -104.9903
427
  - **Seattle**: 47.6062, -122.3321
428
+ - **Bozeman, MT**: 45.6770, -111.0429
429
  """)
430
 
431
  with gr.Column(scale=2):
 
477
  update_btn.click(
478
  fn=weather_app.update_location,
479
  inputs=[lat_input, lon_input],
480
+ outputs=[map_html, lat_input, lon_input]
481
+ )
482
+
483
+ # City button event handlers
484
+ nyc_btn.click(
485
+ fn=lambda: weather_app.set_city_coordinates("New York City"),
486
+ outputs=[map_html, lat_input, lon_input]
487
+ )
488
+ la_btn.click(
489
+ fn=lambda: weather_app.set_city_coordinates("Los Angeles"),
490
+ outputs=[map_html, lat_input, lon_input]
491
+ )
492
+ chicago_btn.click(
493
+ fn=lambda: weather_app.set_city_coordinates("Chicago"),
494
+ outputs=[map_html, lat_input, lon_input]
495
+ )
496
+ miami_btn.click(
497
+ fn=lambda: weather_app.set_city_coordinates("Miami"),
498
+ outputs=[map_html, lat_input, lon_input]
499
+ )
500
+ denver_btn.click(
501
+ fn=lambda: weather_app.set_city_coordinates("Denver"),
502
+ outputs=[map_html, lat_input, lon_input]
503
+ )
504
+ seattle_btn.click(
505
+ fn=lambda: weather_app.set_city_coordinates("Seattle"),
506
+ outputs=[map_html, lat_input, lon_input]
507
+ )
508
+ bozeman_btn.click(
509
+ fn=lambda: weather_app.set_city_coordinates("Bozeman, MT"),
510
+ outputs=[map_html, lat_input, lon_input]
511
  )
512
 
513
  weather_btn.click(
 
520
  lat_input.change(
521
  fn=weather_app.update_location,
522
  inputs=[lat_input, lon_input],
523
+ outputs=[map_html, lat_input, lon_input]
524
  )
525
 
526
  lon_input.change(
527
  fn=weather_app.update_location,
528
  inputs=[lat_input, lon_input],
529
+ outputs=[map_html, lat_input, lon_input]
530
  )
531
 
532
  # Launch the app