Spaces:
Paused
Paused
Update app.py
Browse files
app.py
CHANGED
@@ -28,65 +28,86 @@ def get_location_key(lat, lon):
|
|
28 |
"apikey": API_KEY,
|
29 |
"q": f"{lat},{lon}",
|
30 |
}
|
31 |
-
|
32 |
-
|
33 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
34 |
|
35 |
def get_current_conditions(location_key):
|
|
|
|
|
36 |
url = f"{BASE_URL}/currentconditions/v1/{location_key}"
|
37 |
params = {
|
38 |
"apikey": API_KEY,
|
39 |
"details": "true",
|
40 |
}
|
41 |
-
|
42 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
43 |
|
44 |
def get_forecast(location_key):
|
|
|
|
|
45 |
url = f"{BASE_URL}/forecasts/v1/daily/5day/{location_key}"
|
46 |
params = {
|
47 |
"apikey": API_KEY,
|
48 |
"metric": "true",
|
49 |
}
|
50 |
-
|
51 |
-
|
|
|
|
|
|
|
|
|
|
|
52 |
|
53 |
def get_indices(location_key):
|
|
|
|
|
54 |
url = f"{BASE_URL}/indices/v1/daily/5day/{location_key}"
|
55 |
params = {
|
56 |
"apikey": API_KEY,
|
57 |
}
|
58 |
-
|
59 |
-
|
|
|
|
|
|
|
|
|
|
|
60 |
|
61 |
def get_alerts(location_key):
|
|
|
|
|
62 |
url = f"{BASE_URL}/alerts/v1/{location_key}"
|
63 |
params = {
|
64 |
"apikey": API_KEY,
|
65 |
}
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
|
|
|
|
|
|
|
|
|
|
70 |
app.layout = dbc.Container([
|
71 |
-
|
72 |
-
|
73 |
-
html.H1("Weather Dashboard", className="text-center mb-4"),
|
74 |
-
html.Div(id="loading-output"),
|
75 |
-
html.Div(id="alert-output"),
|
76 |
-
dbc.Row([
|
77 |
-
dbc.Col([
|
78 |
-
html.Div(id="current-weather-output"),
|
79 |
-
], width=6),
|
80 |
-
dbc.Col([
|
81 |
-
html.Div(id="forecast-output"),
|
82 |
-
], width=6),
|
83 |
-
]),
|
84 |
-
html.Div(id="indices-output"),
|
85 |
-
], width=12)
|
86 |
-
]),
|
87 |
-
dcc.Store(id="location-store"),
|
88 |
-
dcc.Interval(id="location-interval", interval=1000, max_intervals=1),
|
89 |
-
], fluid=True, className="mt-4")
|
90 |
|
91 |
@app.callback(
|
92 |
Output("location-store", "data"),
|
@@ -118,11 +139,17 @@ def update_weather(location):
|
|
118 |
nonlocal loading_output
|
119 |
try:
|
120 |
location_key = get_location_key(lat, lon)
|
|
|
|
|
|
|
121 |
current = get_current_conditions(location_key)
|
122 |
forecast = get_forecast(location_key)
|
123 |
indices = get_indices(location_key)
|
124 |
alerts = get_alerts(location_key)
|
125 |
|
|
|
|
|
|
|
126 |
current_weather = create_current_weather_card(current)
|
127 |
forecast_output = create_forecast_card(forecast)
|
128 |
indices_output = create_indices_card(indices)
|
@@ -133,7 +160,9 @@ def update_weather(location):
|
|
133 |
return current_weather, forecast_output, indices_output, alert_output
|
134 |
|
135 |
except Exception as e:
|
136 |
-
|
|
|
|
|
137 |
return "", "", "", ""
|
138 |
|
139 |
# Use threading to fetch data asynchronously
|
@@ -148,69 +177,7 @@ def update_weather(location):
|
|
148 |
current_weather, forecast_output, indices_output, alert_output = fetch_weather_data()
|
149 |
return loading_output, current_weather, forecast_output, indices_output, alert_output
|
150 |
|
151 |
-
|
152 |
-
return dbc.Card([
|
153 |
-
dbc.CardBody([
|
154 |
-
html.H4("Current Weather", className="card-title"),
|
155 |
-
html.P(f"Temperature: {current['Temperature']['Metric']['Value']}°C"),
|
156 |
-
html.P(f"Condition: {current['WeatherText']}"),
|
157 |
-
html.P(f"Feels Like: {current['RealFeelTemperature']['Metric']['Value']}°C"),
|
158 |
-
html.P(f"Wind: {current['Wind']['Speed']['Metric']['Value']} km/h"),
|
159 |
-
html.P(f"Humidity: {current['RelativeHumidity']}%"),
|
160 |
-
])
|
161 |
-
], className="mb-4")
|
162 |
-
|
163 |
-
def create_forecast_card(forecast):
|
164 |
-
daily_forecasts = forecast['DailyForecasts']
|
165 |
-
|
166 |
-
fig = go.Figure()
|
167 |
-
|
168 |
-
dates = [datetime.strptime(day['Date'], "%Y-%m-%dT%H:%M:%S%z").strftime("%m-%d") for day in daily_forecasts]
|
169 |
-
max_temps = [day['Temperature']['Maximum']['Value'] for day in daily_forecasts]
|
170 |
-
min_temps = [day['Temperature']['Minimum']['Value'] for day in daily_forecasts]
|
171 |
-
|
172 |
-
fig.add_trace(go.Scatter(x=dates, y=max_temps, name="Max Temp", line=dict(color="red")))
|
173 |
-
fig.add_trace(go.Scatter(x=dates, y=min_temps, name="Min Temp", line=dict(color="blue")))
|
174 |
-
|
175 |
-
fig.update_layout(
|
176 |
-
title="5-Day Temperature Forecast",
|
177 |
-
xaxis_title="Date",
|
178 |
-
yaxis_title="Temperature (°C)",
|
179 |
-
legend_title="Temperature",
|
180 |
-
height=400
|
181 |
-
)
|
182 |
-
|
183 |
-
return dbc.Card([
|
184 |
-
dbc.CardBody([
|
185 |
-
html.H4("5-Day Forecast", className="card-title"),
|
186 |
-
dcc.Graph(figure=fig)
|
187 |
-
])
|
188 |
-
], className="mb-4")
|
189 |
-
|
190 |
-
def create_indices_card(indices):
|
191 |
-
return dbc.Card([
|
192 |
-
dbc.CardBody([
|
193 |
-
html.H4("Weather Indices", className="card-title"),
|
194 |
-
html.Div([
|
195 |
-
html.P(f"{index['Name']}: {index['Category']}")
|
196 |
-
for index in indices[:5] # Display first 5 indices
|
197 |
-
])
|
198 |
-
])
|
199 |
-
], className="mb-4")
|
200 |
-
|
201 |
-
def create_alert_card(alerts):
|
202 |
-
if not alerts:
|
203 |
-
return html.Div()
|
204 |
-
|
205 |
-
return dbc.Card([
|
206 |
-
dbc.CardBody([
|
207 |
-
html.H4("Weather Alerts", className="card-title text-danger"),
|
208 |
-
html.Div([
|
209 |
-
html.P(alert['Text'])
|
210 |
-
for alert in alerts
|
211 |
-
])
|
212 |
-
])
|
213 |
-
], className="mb-4")
|
214 |
|
215 |
if __name__ == '__main__':
|
216 |
print("Starting the Dash application...")
|
|
|
28 |
"apikey": API_KEY,
|
29 |
"q": f"{lat},{lon}",
|
30 |
}
|
31 |
+
try:
|
32 |
+
response = requests.get(url, params=params)
|
33 |
+
response.raise_for_status() # Raise an exception for bad status codes
|
34 |
+
data = response.json()
|
35 |
+
if "Key" not in data:
|
36 |
+
raise ValueError("Location key not found in API response")
|
37 |
+
return data["Key"]
|
38 |
+
except requests.RequestException as e:
|
39 |
+
print(f"Error in get_location_key: {e}")
|
40 |
+
return None
|
41 |
|
42 |
def get_current_conditions(location_key):
|
43 |
+
if location_key is None:
|
44 |
+
return None
|
45 |
url = f"{BASE_URL}/currentconditions/v1/{location_key}"
|
46 |
params = {
|
47 |
"apikey": API_KEY,
|
48 |
"details": "true",
|
49 |
}
|
50 |
+
try:
|
51 |
+
response = requests.get(url, params=params)
|
52 |
+
response.raise_for_status()
|
53 |
+
data = response.json()
|
54 |
+
if not data:
|
55 |
+
raise ValueError("No current conditions data in API response")
|
56 |
+
return data[0]
|
57 |
+
except requests.RequestException as e:
|
58 |
+
print(f"Error in get_current_conditions: {e}")
|
59 |
+
return None
|
60 |
|
61 |
def get_forecast(location_key):
|
62 |
+
if location_key is None:
|
63 |
+
return None
|
64 |
url = f"{BASE_URL}/forecasts/v1/daily/5day/{location_key}"
|
65 |
params = {
|
66 |
"apikey": API_KEY,
|
67 |
"metric": "true",
|
68 |
}
|
69 |
+
try:
|
70 |
+
response = requests.get(url, params=params)
|
71 |
+
response.raise_for_status()
|
72 |
+
return response.json()
|
73 |
+
except requests.RequestException as e:
|
74 |
+
print(f"Error in get_forecast: {e}")
|
75 |
+
return None
|
76 |
|
77 |
def get_indices(location_key):
|
78 |
+
if location_key is None:
|
79 |
+
return None
|
80 |
url = f"{BASE_URL}/indices/v1/daily/5day/{location_key}"
|
81 |
params = {
|
82 |
"apikey": API_KEY,
|
83 |
}
|
84 |
+
try:
|
85 |
+
response = requests.get(url, params=params)
|
86 |
+
response.raise_for_status()
|
87 |
+
return response.json()
|
88 |
+
except requests.RequestException as e:
|
89 |
+
print(f"Error in get_indices: {e}")
|
90 |
+
return None
|
91 |
|
92 |
def get_alerts(location_key):
|
93 |
+
if location_key is None:
|
94 |
+
return None
|
95 |
url = f"{BASE_URL}/alerts/v1/{location_key}"
|
96 |
params = {
|
97 |
"apikey": API_KEY,
|
98 |
}
|
99 |
+
try:
|
100 |
+
response = requests.get(url, params=params)
|
101 |
+
response.raise_for_status()
|
102 |
+
return response.json()
|
103 |
+
except requests.RequestException as e:
|
104 |
+
print(f"Error in get_alerts: {e}")
|
105 |
+
return None
|
106 |
+
|
107 |
+
# App layout remains the same
|
108 |
app.layout = dbc.Container([
|
109 |
+
# ... (previous layout code)
|
110 |
+
])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
111 |
|
112 |
@app.callback(
|
113 |
Output("location-store", "data"),
|
|
|
139 |
nonlocal loading_output
|
140 |
try:
|
141 |
location_key = get_location_key(lat, lon)
|
142 |
+
if location_key is None:
|
143 |
+
raise ValueError("Failed to get location key")
|
144 |
+
|
145 |
current = get_current_conditions(location_key)
|
146 |
forecast = get_forecast(location_key)
|
147 |
indices = get_indices(location_key)
|
148 |
alerts = get_alerts(location_key)
|
149 |
|
150 |
+
if current is None or forecast is None or indices is None:
|
151 |
+
raise ValueError("Failed to fetch weather data")
|
152 |
+
|
153 |
current_weather = create_current_weather_card(current)
|
154 |
forecast_output = create_forecast_card(forecast)
|
155 |
indices_output = create_indices_card(indices)
|
|
|
160 |
return current_weather, forecast_output, indices_output, alert_output
|
161 |
|
162 |
except Exception as e:
|
163 |
+
error_message = f"Error fetching weather data: {str(e)}"
|
164 |
+
print(error_message) # Log the error
|
165 |
+
loading_output = html.Div(error_message, className="text-danger")
|
166 |
return "", "", "", ""
|
167 |
|
168 |
# Use threading to fetch data asynchronously
|
|
|
177 |
current_weather, forecast_output, indices_output, alert_output = fetch_weather_data()
|
178 |
return loading_output, current_weather, forecast_output, indices_output, alert_output
|
179 |
|
180 |
+
# The rest of the code (create_current_weather_card, create_forecast_card, etc.) remains the same
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
181 |
|
182 |
if __name__ == '__main__':
|
183 |
print("Starting the Dash application...")
|