mirix commited on
Commit
f153d51
·
verified ·
1 Parent(s): e36c9d8

Upload 3 files

Browse files
Files changed (3) hide show
  1. app.py +355 -0
  2. requirements.txt +11 -0
  3. weather_icons_custom.json +1002 -0
app.py ADDED
@@ -0,0 +1,355 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ### app_refactored_openmeteo_strings.py ###
2
+
3
+ import gradio as gr
4
+ import pandas as pd
5
+ import numpy as np
6
+ import json
7
+ from datetime import datetime, timezone
8
+
9
+ import geopy
10
+ from geopy import distance
11
+ from geopy.geocoders import Nominatim
12
+ import srtm
13
+ import requests
14
+ import requests_cache
15
+ import openmeteo_requests
16
+ from retry_requests import retry
17
+ import plotly.graph_objects as go
18
+
19
+
20
+ # --- GLOBAL SETUP ---
21
+
22
+ elevation_data = srtm.get_data()
23
+ with open("weather_icons_custom.json", "r") as f:
24
+ icons = json.load(f)
25
+
26
+ cache_session = requests_cache.CachedSession(".cache", expire_after=3600)
27
+ retry_session = retry(cache_session, retries=5, backoff_factor=0.2)
28
+ openmeteo = openmeteo_requests.Client(session=retry_session)
29
+ geolocator = Nominatim(user_agent="snow_finder")
30
+
31
+ OVERPASS_URL = "https://maps.mail.ru/osm/tools/overpass/api/interpreter"
32
+ ICON_URL = "https://raw.githubusercontent.com/basmilius/weather-icons/refs/heads/dev/production/fill/svg/"
33
+
34
+ DEFAULT_LAT, DEFAULT_LON = 49.6116, 6.1319
35
+
36
+
37
+ # --- UTILS ---
38
+
39
+ def compute_bbox(lat, lon, dist_km):
40
+ origin = geopy.Point(lat, lon)
41
+ dest_sw = distance.distance(kilometers=dist_km).destination(origin, bearing=225)
42
+ dest_ne = distance.distance(kilometers=dist_km).destination(origin, bearing=45)
43
+ return f"{dest_sw.latitude},{dest_sw.longitude},{dest_ne.latitude},{dest_ne.longitude}"
44
+
45
+
46
+ def get_peaks_from_overpass(lat, lon, dist_km):
47
+ """Query Overpass API for nearby peaks and hills."""
48
+ bbox = compute_bbox(lat, lon, dist_km)
49
+ query = f"""
50
+ [out:json];
51
+ (
52
+ nwr[natural=peak]({bbox});
53
+ nwr[natural=hill]({bbox});
54
+ );
55
+ out body;
56
+ """
57
+ try:
58
+ r = requests.get(OVERPASS_URL, params={"data": query}, timeout=30)
59
+ r.raise_for_status()
60
+ data = r.json()
61
+ except Exception as e:
62
+ print(f"Error fetching peaks: {e}")
63
+ return pd.DataFrame()
64
+
65
+ peaks = {"name": [], "latitude": [], "longitude": [], "altitude": []}
66
+ for e in data.get("elements", []):
67
+ lat_e, lon_e = e.get("lat"), e.get("lon")
68
+ tags = e.get("tags", {})
69
+ peaks["latitude"].append(lat_e)
70
+ peaks["longitude"].append(lon_e)
71
+ peaks["name"].append(tags.get("name", "Unnamed Peak/Hill"))
72
+
73
+ ele = tags.get("ele")
74
+ if ele and str(ele).replace(".", "").replace("-", "").isnumeric():
75
+ peaks["altitude"].append(float(ele))
76
+ else:
77
+ try:
78
+ alt = elevation_data.get_elevation(lat_e, lon_e)
79
+ peaks["altitude"].append(alt if alt is not None else 0)
80
+ except Exception:
81
+ peaks["altitude"].append(0)
82
+
83
+ if not peaks["latitude"]:
84
+ return pd.DataFrame()
85
+
86
+ df = pd.DataFrame(peaks)
87
+ df["altitude"] = df["altitude"].round(0).astype(int)
88
+ df["distance_m"] = df.apply(
89
+ lambda r: distance.distance((r["latitude"], r["longitude"]), (lat, lon)).m, axis=1
90
+ )
91
+ return df
92
+
93
+
94
+ # --- WEATHER FETCH (STRING PARAMS VERSION) ---
95
+
96
+ def get_weather_for_peaks_iteratively(df_peaks, min_snow_cm, max_results=20, max_requests=100):
97
+ """Fetch weather for peaks with all params as strings to avoid iteration errors."""
98
+ if df_peaks.empty:
99
+ return pd.DataFrame()
100
+
101
+ url = "https://api.open-meteo.com/v1/forecast"
102
+ results, requests_made = [], 0
103
+
104
+ for _, row in df_peaks.iterrows():
105
+ if len(results) >= max_results or requests_made >= max_requests:
106
+ break
107
+
108
+ params = {
109
+ "latitude": str(row["latitude"]),
110
+ "longitude": str(row["longitude"]),
111
+ "elevation": str(row["altitude"]),
112
+ "hourly": "temperature_2m,is_day,weather_code,snow_depth",
113
+ "forecast_days": "1",
114
+ "timezone": "auto",
115
+ }
116
+
117
+ try:
118
+ # FIX: Get the list of responses and access the first one
119
+ responses = openmeteo.weather_api(url, params=params)
120
+ if not responses: # Check if the list is empty
121
+ continue
122
+ response = responses[0] # This is the critical fix
123
+
124
+ # Now proceed with your existing processing
125
+ hourly = response.Hourly()
126
+ if hourly is None:
127
+ continue
128
+
129
+ #times = hourly.Time()
130
+ #now_utc = datetime.now(timezone.utc)
131
+ #times_utc = datetime.fromtimestamp(times, tz=timezone.utc)
132
+ #idx = int(np.argmin([abs((t - now_utc).total_seconds()) for t in times_utc]))
133
+ idx = 0
134
+
135
+ temp_c = float(hourly.Variables(0).ValuesAsNumpy()[idx])
136
+ is_day = int(hourly.Variables(1).ValuesAsNumpy()[idx])
137
+ weather_code = int(hourly.Variables(2).ValuesAsNumpy()[idx])
138
+ snow_depth_m = float(hourly.Variables(3).ValuesAsNumpy()[idx])
139
+ snow_depth_cm = snow_depth_m * 100
140
+
141
+ if snow_depth_cm >= min_snow_cm:
142
+ results.append({
143
+ **row.to_dict(),
144
+ "temp_c": temp_c,
145
+ "is_day": is_day,
146
+ "weather_code": weather_code,
147
+ "snow_depth_m": snow_depth_m,
148
+ "snow_depth_cm": int(np.round(snow_depth_cm, 0))
149
+ })
150
+
151
+ except Exception as e:
152
+ print(f"Error fetching weather for {row['name']}: {e}")
153
+
154
+ requests_made += 1
155
+
156
+ return pd.DataFrame(results)
157
+
158
+
159
+ # --- POST-PROCESSING ---
160
+
161
+ def format_weather_data(df):
162
+ if df.empty:
163
+ return df
164
+
165
+ def icon_mapper(row):
166
+ code = str(int(row["weather_code"]))
167
+ tod = "day" if row["is_day"] == 1 else "night"
168
+ info = icons.get(code, {}).get(tod, {})
169
+ return ICON_URL + info.get("icon", ""), info.get("description", "Unknown")
170
+
171
+ df[["weather_icon", "weather_desc"]] = df.apply(icon_mapper, axis=1, result_type="expand")
172
+ df["distance_km"] = (df["distance_m"] / 1000).round(1)
173
+ df["temp_c_str"] = df["temp_c"].round(0).astype(int).astype(str) + "°C"
174
+ return df
175
+
176
+
177
+ def geocode_location(location_text):
178
+ try:
179
+ loc = geolocator.geocode(location_text, timeout=10)
180
+ if loc:
181
+ return loc.latitude, loc.longitude, f"Found: {loc.address}"
182
+ return None, None, f"Location '{location_text}' not found."
183
+ except Exception as e:
184
+ return None, None, f"Geocoding error: {e}"
185
+
186
+
187
+ # --- CORE LOGIC ---
188
+
189
+ def find_snowy_peaks(min_snow_cm, radius_km, lat, lon):
190
+ if lat is None or lon is None:
191
+ fig = create_empty_map(DEFAULT_LAT, DEFAULT_LON)
192
+ fig.update_layout(title_text="Enter valid coordinates.")
193
+ return fig, "Please enter coordinates."
194
+
195
+ if not (-90 <= lat <= 90 and -180 <= lon <= 180):
196
+ fig = create_empty_map(DEFAULT_LAT, DEFAULT_LON)
197
+ fig.update_layout(title_text="Invalid coordinates.")
198
+ return fig, "Coordinates out of range."
199
+
200
+ df_peaks = get_peaks_from_overpass(lat, lon, radius_km)
201
+ if df_peaks.empty:
202
+ fig = create_map_with_center(lat, lon)
203
+ fig.update_layout(title_text=f"No peaks found within {radius_km} km.")
204
+ return fig, f"No peaks found within {radius_km} km."
205
+
206
+ df_peaks = df_peaks.sort_values("distance_m").reset_index(drop=True)
207
+ df_weather = get_weather_for_peaks_iteratively(df_peaks, min_snow_cm)
208
+
209
+ if df_weather.empty:
210
+ fig = create_map_with_center(lat, lon)
211
+ fig.update_layout(title_text=f"No snowy peaks ≥ {min_snow_cm} cm.")
212
+ return fig, f"No peaks met the ≥ {min_snow_cm} cm snow requirement."
213
+
214
+ df_final = format_weather_data(df_weather)
215
+ fig = create_map_with_results(lat, lon, df_final)
216
+ fig.update_layout(title_text=f"Found {len(df_final)} snowy peaks!")
217
+ msg = f"🎉 Showing {len(df_final)} snowy peaks with ≥ {min_snow_cm} cm of snow."
218
+ return fig, msg
219
+
220
+
221
+ # --- MAP HELPERS ---
222
+
223
+ def create_empty_map(lat, lon):
224
+ fig = go.Figure()
225
+ fig.update_layout(
226
+ map=dict(style="open-street-map", center={"lat": lat, "lon": lon}, zoom=8),
227
+ margin={"r": 0, "t": 40, "l": 0, "b": 0},
228
+ height=1024,
229
+ width=1024,
230
+ )
231
+ return fig
232
+
233
+
234
+ def create_map_with_center(lat, lon):
235
+ fig = go.Figure(
236
+ go.Scattermap(
237
+ lat=[lat],
238
+ lon=[lon],
239
+ mode="markers",
240
+ marker=dict(size=24, color="white", opacity=0.8),
241
+ hoverinfo=None,
242
+ )
243
+ )
244
+ fig.add_trace(
245
+ go.Scattermap(
246
+ lat=[lat],
247
+ lon=[lon],
248
+ mode="markers",
249
+ marker=dict(size=12, color="white", symbol="landmark"),
250
+ text=["Search Center"],
251
+ hoverinfo="text",
252
+ )
253
+ )
254
+ fig.update_layout(
255
+ map=dict(style="open-street-map", center={"lat": lat, "lon": lon}, zoom=8),
256
+ margin={"r": 0, "t": 40, "l": 0, "b": 0},
257
+ height=1024,
258
+ width=1024,
259
+ )
260
+ return fig
261
+
262
+
263
+ def create_map_with_results(lat, lon, df_final):
264
+ fig = go.Figure()
265
+ fig.add_trace(
266
+ go.Scattermap(
267
+ lat=df_final["latitude"],
268
+ lon=df_final["longitude"],
269
+ mode="markers",
270
+ marker=dict(size=24, color="white", opacity=0.8),
271
+ hoverinfo=None,
272
+ )
273
+ )
274
+ fig.add_trace(
275
+ go.Scattermap(
276
+ lat=df_final["latitude"],
277
+ lon=df_final["longitude"],
278
+ mode="markers",
279
+ marker=dict(size=12, color="white", symbol="mountain"),
280
+ customdata=df_final[
281
+ ["name", "altitude", "distance_km", "snow_depth_cm", "weather_desc", "temp_c_str"]
282
+ ],
283
+ hovertemplate=(
284
+ "<b>%{customdata[0]}</b><br>"
285
+ "Altitude: %{customdata[1]} m<br>"
286
+ "Distance: %{customdata[2]} km<br>"
287
+ "<b>❄️ Snow: %{customdata[3]} cm</b><br>"
288
+ "Weather: %{customdata[4]}<br>"
289
+ "🌡 Temp: %{customdata[5]}<extra></extra>"
290
+ ),
291
+ )
292
+ )
293
+ fig.add_trace(
294
+ go.Scattermap(
295
+ lat=[lat],
296
+ lon=[lon],
297
+ mode="markers",
298
+ marker=dict(size=24, color="white", opacity=0.8),
299
+ hoverinfo=None,
300
+ )
301
+ )
302
+ fig.add_trace(
303
+ go.Scattermap(
304
+ lat=[lat],
305
+ lon=[lon],
306
+ mode="markers",
307
+ marker=dict(size=12, color="white", symbol="landmark"),
308
+ text=["Search Center"],
309
+ hoverinfo="text",
310
+ )
311
+ )
312
+ fig.update_layout(
313
+ map=dict(style="open-street-map", center={"lat": lat, "lon": lon}, zoom=9),
314
+ margin={"r": 0, "t": 40, "l": 0, "b": 0},
315
+ height=1024,
316
+ width=1024,
317
+ showlegend=False,
318
+ )
319
+ return fig
320
+
321
+
322
+ # --- GRADIO UI ---
323
+
324
+ with gr.Blocks(theme=gr.themes.Soft(), title="Snow Finder") as demo:
325
+ gr.Markdown("# ☃️ Snow Finder for Families")
326
+ gr.Markdown("Find nearby snowy peaks perfect for sledding and snowmen!")
327
+
328
+ with gr.Row():
329
+ with gr.Column(scale=1):
330
+ location_search = gr.Textbox(label="Search Location")
331
+ search_location_btn = gr.Button("🔍 Find Location")
332
+
333
+ lat_input = gr.Number(value=DEFAULT_LAT, label="Latitude", precision=4)
334
+ lon_input = gr.Number(value=DEFAULT_LON, label="Longitude", precision=4)
335
+ snow_slider = gr.Radio(choices=[1, 2, 3, 4, 5, 6], value=1, label="Min Snow (cm)")
336
+ radius_slider = gr.Radio(choices=[10, 20, 30, 40, 50, 60], value=30, label="Radius (km)")
337
+ search_button = gr.Button("❄️ Find Snow!", variant="primary")
338
+ status_output = gr.Textbox(lines=4, interactive=False)
339
+
340
+ with gr.Column(scale=2):
341
+ init_fig = create_map_with_center(DEFAULT_LAT, DEFAULT_LON)
342
+ init_fig.update_layout(title_text="Luxembourg City – Click 'Find Snow!' to start")
343
+ map_plot = gr.Plot(init_fig, label="Map")
344
+
345
+ search_location_btn.click(
346
+ fn=geocode_location, inputs=[location_search], outputs=[lat_input, lon_input, status_output]
347
+ )
348
+ search_button.click(
349
+ fn=find_snowy_peaks,
350
+ inputs=[snow_slider, radius_slider, lat_input, lon_input],
351
+ outputs=[map_plot, status_output],
352
+ )
353
+
354
+ if __name__ == "__main__":
355
+ demo.launch()
requirements.txt ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ geopy==2.4.1
2
+ gradio==5.49.0
3
+ numpy==2.3.3
4
+ openmeteo_requests==1.7.3
5
+ pandas==2.3.3
6
+ plotly==6.3.1
7
+ requests==2.32.5
8
+ requests_cache==1.2.1
9
+ retry_requests==2.0.0
10
+ SRTM.py==0.3.7
11
+ lxml==6.0.2
weather_icons_custom.json ADDED
@@ -0,0 +1,1002 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "0": {
3
+ "day": {
4
+ "description": "Sunny",
5
+ "icon": "clear-day.svg"
6
+ },
7
+ "night": {
8
+ "description": "Clear",
9
+ "icon": "clear-night.svg"
10
+ }
11
+ },
12
+ "1": {
13
+ "day": {
14
+ "description": "Mostly Sunny",
15
+ "icon": "partly-cloudy-day.svg"
16
+ },
17
+ "night": {
18
+ "description": "Mostly Clear",
19
+ "icon": "partly-cloudy-night.svg"
20
+ }
21
+ },
22
+ "2": {
23
+ "day": {
24
+ "description": "Partly Cloudy",
25
+ "icon": "overcast-day.svg"
26
+ },
27
+ "night": {
28
+ "description": "Partly Cloudy",
29
+ "icon": "overcast-night.svg"
30
+ }
31
+ },
32
+ "3": {
33
+ "day": {
34
+ "description": "Cloudy",
35
+ "icon": "cloudy.svg"
36
+ },
37
+ "night": {
38
+ "description": "Cloudy",
39
+ "icon": "cloudy.svg"
40
+ }
41
+ },
42
+ "4": {
43
+ "day": {
44
+ "description": "Smoke",
45
+ "icon": "smoke.svg"
46
+ },
47
+ "night": {
48
+ "description": "Smoke",
49
+ "icon": "smoke.svg"
50
+ }
51
+ },
52
+ "5": {
53
+ "day": {
54
+ "description": "Haze",
55
+ "icon": "haze-day.svg"
56
+ },
57
+ "night": {
58
+ "description": "Haze",
59
+ "icon": "haze-night.svg"
60
+ }
61
+ },
62
+ "6": {
63
+ "day": {
64
+ "description": "Some Dust",
65
+ "icon": "dust-day.svg"
66
+ },
67
+ "night": {
68
+ "description": "Some Dust",
69
+ "icon": "dust-night.svg"
70
+ }
71
+ },
72
+ "7": {
73
+ "day": {
74
+ "description": "Dust",
75
+ "icon": "dust.svg"
76
+ },
77
+ "night": {
78
+ "description": "Dust",
79
+ "icon": "dust.svg"
80
+ }
81
+ },
82
+ "8": {
83
+ "day": {
84
+ "description": "Dust / Sand Whirls",
85
+ "icon": "dust-wind.svg"
86
+ },
87
+ "night": {
88
+ "description": "Dust / Sand Whirls",
89
+ "icon": "dust-wind.svg"
90
+ }
91
+ },
92
+ "9": {
93
+ "day": {
94
+ "description": "Duststorms / Sandstorms",
95
+ "icon": "dust-wind.svg"
96
+ },
97
+ "night": {
98
+ "description": "Duststorms / Sandstorms",
99
+ "icon": "dust-wind.svg"
100
+ }
101
+ },
102
+ "10": {
103
+ "day": {
104
+ "description": "Mist",
105
+ "icon": "mist.svg"
106
+ },
107
+ "night": {
108
+ "description": "Mist",
109
+ "icon": "mist.svg"
110
+ }
111
+ },
112
+ "11": {
113
+ "day": {
114
+ "description": "Foggy Patches",
115
+ "icon": "fog-day.svg"
116
+ },
117
+ "night": {
118
+ "description": "Foggy Patches",
119
+ "icon": "fog-night.svg"
120
+ }
121
+ },
122
+ "12": {
123
+ "day": {
124
+ "description": "Foggy",
125
+ "icon": "fog.svg"
126
+ },
127
+ "night": {
128
+ "description": "Foggy",
129
+ "icon": "fog.svg"
130
+ }
131
+ },
132
+ "13": {
133
+ "day": {
134
+ "description": "Distant lightning",
135
+ "icon": "thunderstorms-day.svg"
136
+ },
137
+ "night": {
138
+ "description": "Distant lightning",
139
+ "icon": "thunderstorms-night.svg"
140
+ }
141
+ },
142
+ "14": {
143
+ "day": {
144
+ "description": "Distant drizzle",
145
+ "icon": "partly-cloudy-day-drizzle.svg"
146
+ },
147
+ "night": {
148
+ "description": "Distant drizzle",
149
+ "icon": "partly-cloudy-night-drizzle.svg"
150
+ }
151
+ },
152
+ "15": {
153
+ "day": {
154
+ "description": "Distant rain",
155
+ "icon": "partly-cloudy-day-drizzle.svg"
156
+ },
157
+ "night": {
158
+ "description": "Distant rain",
159
+ "icon": "partly-cloudy-night-drizzle.svg"
160
+ }
161
+ },
162
+ "16": {
163
+ "day": {
164
+ "description": "Rain within sight",
165
+ "icon": "partly-cloudy-day-drizzle.svg"
166
+ },
167
+ "night": {
168
+ "description": "Rain within sight",
169
+ "icon": "partly-cloudy-night-drizzle.svg"
170
+ }
171
+ },
172
+ "17": {
173
+ "day": {
174
+ "description": "Thunder",
175
+ "icon": "thunderstorms-day.svg"
176
+ },
177
+ "night": {
178
+ "description": "Thunder",
179
+ "icon": "thunderstorms-night.svg"
180
+ }
181
+ },
182
+ "18": {
183
+ "day": {
184
+ "description": "Squalls",
185
+ "icon": "wind.svg"
186
+ },
187
+ "night": {
188
+ "description": "Squalls",
189
+ "icon": "wind.svg"
190
+ }
191
+ },
192
+ "19": {
193
+ "day": {
194
+ "description": "Funnel clouds",
195
+ "icon": "tornado.svg"
196
+ },
197
+ "night": {
198
+ "description": "Funnel clouds",
199
+ "icon": "tornado.svg"
200
+ }
201
+ },
202
+ "20": {
203
+ "day": {
204
+ "description": "Drizzle (previous hour)",
205
+ "icon": "partly-cloudy-day-drizzle.svg"
206
+ },
207
+ "night": {
208
+ "description": "Drizzle (previous hour)",
209
+ "icon": "partly-cloudy-night-drizzle.svg"
210
+ }
211
+ },
212
+ "21": {
213
+ "day": {
214
+ "description": "Light rain (previous hour)",
215
+ "icon": "partly-cloudy-day-drizzle.svg"
216
+ },
217
+ "night": {
218
+ "description": "Light rain (previous hour)",
219
+ "icon": "partly-cloudy-night-drizzle.svg"
220
+ }
221
+ },
222
+ "22": {
223
+ "day": {
224
+ "description": "Light snow (previous hour)",
225
+ "icon": "partly-cloudy-day-snow.svg"
226
+ },
227
+ "night": {
228
+ "description": "Light snow (previous hour)",
229
+ "icon": "partly-cloudy-night-snow.svg"
230
+ }
231
+ },
232
+ "23": {
233
+ "day": {
234
+ "description": "Sleet / Snow / Hail (previous hour)",
235
+ "icon": "partly-cloudy-day-sleet.svg"
236
+ },
237
+ "night": {
238
+ "description": "Sleet / Snow / Hail (previous hour)",
239
+ "icon": "partly-cloudy-night-sleet.svg"
240
+ }
241
+ },
242
+ "24": {
243
+ "day": {
244
+ "description": "Freezing drizzle / rain (previous hour)",
245
+ "icon": "partly-cloudy-day-sleet.svg"
246
+ },
247
+ "night": {
248
+ "description": "Freezing drizzle / rain (previous hour)",
249
+ "icon": "partly-cloudy-night-sleet.svg"
250
+ }
251
+ },
252
+ "25": {
253
+ "day": {
254
+ "description": "Rain (previous hour)",
255
+ "icon": "partly-cloudy-day-drizzle.svg"
256
+ },
257
+ "night": {
258
+ "description": "Rain (previous hour)",
259
+ "icon": "partly-cloudy-night-drizzle.svg"
260
+ }
261
+ },
262
+ "26": {
263
+ "day": {
264
+ "description": "Snow (previous hour)",
265
+ "icon": "partly-cloudy-day-snow.svg"
266
+ },
267
+ "night": {
268
+ "description": "Snow (previous hour)",
269
+ "icon": "partly-cloudy-night-snow.svg"
270
+ }
271
+ },
272
+ "27": {
273
+ "day": {
274
+ "description": "Hail (previous hour)",
275
+ "icon": "partly-cloudy-day-hail.svg"
276
+ },
277
+ "night": {
278
+ "description": "Hail (previous hour)",
279
+ "icon": "partly-cloudy-night-hail.svg"
280
+ }
281
+ },
282
+ "28": {
283
+ "day": {
284
+ "description": "Fog (previous hour)",
285
+ "icon": "fog-day.svg"
286
+ },
287
+ "night": {
288
+ "description": "Fog (previous hour)",
289
+ "icon": "fog-night.svg"
290
+ }
291
+ },
292
+ "29": {
293
+ "day": {
294
+ "description": "Thunderstorm (previous hour)",
295
+ "icon": "thunderstorms-day.svg"
296
+ },
297
+ "night": {
298
+ "description": "Thunderstorm (previous hour)",
299
+ "icon": "thunderstorms-night.svg"
300
+ }
301
+ },
302
+ "30": {
303
+ "day": {
304
+ "description": "Slight duststorm (receding)",
305
+ "icon": "dust-day.svg"
306
+ },
307
+ "night": {
308
+ "description": "Slight duststorm (receding)",
309
+ "icon": "dust-night.svg"
310
+ }
311
+ },
312
+ "31": {
313
+ "day": {
314
+ "description": "Slight duststorm (ongoing)",
315
+ "icon": "dust-day.svg"
316
+ },
317
+ "night": {
318
+ "description": "Slight duststorm (ongoing)",
319
+ "icon": "dust-night.svg"
320
+ }
321
+ },
322
+ "32": {
323
+ "day": {
324
+ "description": "Duststorm (building up)",
325
+ "icon": "dust-wind.svg"
326
+ },
327
+ "night": {
328
+ "description": "Duststorm (building up)",
329
+ "icon": "dust-wind.svg"
330
+ }
331
+ },
332
+ "33": {
333
+ "day": {
334
+ "description": "Duststorm (receding)",
335
+ "icon": "dust-day.svg"
336
+ },
337
+ "night": {
338
+ "description": "Duststorm (receding)",
339
+ "icon": "dust-night.svg"
340
+ }
341
+ },
342
+ "34": {
343
+ "day": {
344
+ "description": "Duststorm (ongoing)",
345
+ "icon": "dust-wind.svg"
346
+ },
347
+ "night": {
348
+ "description": "Duststorm (ongoing)",
349
+ "icon": "dust-wind.svg"
350
+ }
351
+ },
352
+ "35": {
353
+ "day": {
354
+ "description": "Severe duststorm (building up)",
355
+ "icon": "dust-wind.svg"
356
+ },
357
+ "night": {
358
+ "description": "Severe duststorm (building up)",
359
+ "icon": "dust-wind.svg"
360
+ }
361
+ },
362
+ "36": {
363
+ "day": {
364
+ "description": "Slight Drifting Snow",
365
+ "icon": "wind.svg"
366
+ },
367
+ "night": {
368
+ "description": "Slight Drifting Snow",
369
+ "icon": "wind.svg"
370
+ }
371
+ },
372
+ "37": {
373
+ "day": {
374
+ "description": "Heavy Drifting Snow",
375
+ "icon": "wind.svg"
376
+ },
377
+ "night": {
378
+ "description": "Heavy Drifting Snow",
379
+ "icon": "wind.svg"
380
+ }
381
+ },
382
+ "38": {
383
+ "day": {
384
+ "description": "Slight Blowing Snow",
385
+ "icon": "wind.svg"
386
+ },
387
+ "night": {
388
+ "description": "Slight Blowing Snow",
389
+ "icon": "wind.svg"
390
+ }
391
+ },
392
+ "39": {
393
+ "day": {
394
+ "description": "Heavy Blowing Snow",
395
+ "icon": "wind.svg"
396
+ },
397
+ "night": {
398
+ "description": "Heavy Blowing Snow",
399
+ "icon": "wind.svg"
400
+ }
401
+ },
402
+ "40": {
403
+ "day": {
404
+ "description": "Distant fog",
405
+ "icon": "partly-cloudy-day-fog.svg"
406
+ },
407
+ "night": {
408
+ "description": "Distant fog",
409
+ "icon": "partly-cloudy-night-fog.svg"
410
+ }
411
+ },
412
+ "41": {
413
+ "day": {
414
+ "description": "Fog Patches",
415
+ "icon": "fog-day.svg"
416
+ },
417
+ "night": {
418
+ "description": "Fog Patches",
419
+ "icon": "fog-night.svg"
420
+ }
421
+ },
422
+ "42": {
423
+ "day": {
424
+ "description": "Low fog (receding)",
425
+ "icon": "fog-day.svg"
426
+ },
427
+ "night": {
428
+ "description": "Low fog (receding)",
429
+ "icon": "fog-night.svg"
430
+ }
431
+ },
432
+ "43": {
433
+ "day": {
434
+ "description": "Fog (receding)",
435
+ "icon": "partly-cloudy-day-fog.svg"
436
+ },
437
+ "night": {
438
+ "description": "Fog (receding)",
439
+ "icon": "partly-cloudy-night-fog.svg"
440
+ }
441
+ },
442
+ "44": {
443
+ "day": {
444
+ "description": "Low fog (ongoing)",
445
+ "icon": "partly-cloudy-day-fog.svg"
446
+ },
447
+ "night": {
448
+ "description": "Low fog (ongoing)",
449
+ "icon": "partly-cloudy-night-fog.svg"
450
+ }
451
+ },
452
+ "45": {
453
+ "day": {
454
+ "description": "Fog (ongoing)",
455
+ "icon": "fog.svg"
456
+ },
457
+ "night": {
458
+ "description": "Fog (ongoing)",
459
+ "icon": "fog.svg"
460
+ }
461
+ },
462
+ "46": {
463
+ "day": {
464
+ "description": "Low fog (building up)",
465
+ "icon": "partly-cloudy-day-fog.svg"
466
+ },
467
+ "night": {
468
+ "description": "Low fog (building up)",
469
+ "icon": "partly-cloudy-night-fog.svg"
470
+ }
471
+ },
472
+ "47": {
473
+ "day": {
474
+ "description": "Fog (building up)",
475
+ "icon": "fog.svg"
476
+ },
477
+ "night": {
478
+ "description": "Fog (building up)",
479
+ "icon": "fog.svg"
480
+ }
481
+ },
482
+ "48": {
483
+ "day": {
484
+ "description": "Low Freezing Fog",
485
+ "icon": "partly-cloudy-day-fog.svg"
486
+ },
487
+ "night": {
488
+ "description": "Low Freezing Fog",
489
+ "icon": "partly-cloudy-night-fog.svg"
490
+ }
491
+ },
492
+ "49": {
493
+ "day": {
494
+ "description": "Freezing Fog",
495
+ "icon": "fog.svg"
496
+ },
497
+ "night": {
498
+ "description": "Freezing Fog",
499
+ "icon": "fog.svg"
500
+ }
501
+ },
502
+ "50": {
503
+ "day": {
504
+ "description": "Light Intermittent Drizzle",
505
+ "icon": "partly-cloudy-day-drizzle.svg"
506
+ },
507
+ "night": {
508
+ "description": "Light Intermittent Drizzle",
509
+ "icon": "partly-cloudy-night-drizzle.svg"
510
+ }
511
+ },
512
+ "51": {
513
+ "day": {
514
+ "description": "Light Drizzle",
515
+ "icon": "drizzle.svg"
516
+ },
517
+ "night": {
518
+ "description": "Light Drizzle",
519
+ "icon": "drizzle.svg"
520
+ }
521
+ },
522
+ "52": {
523
+ "day": {
524
+ "description": "Intermittent Drizzle",
525
+ "icon": "drizzle.svg"
526
+ },
527
+ "night": {
528
+ "description": "Intermittent Drizzle",
529
+ "icon": "drizzle.svg"
530
+ }
531
+ },
532
+ "53": {
533
+ "day": {
534
+ "description": "Drizzle",
535
+ "icon": "drizzle.svg"
536
+ },
537
+ "night": {
538
+ "description": "Drizzle",
539
+ "icon": "drizzle.svg"
540
+ }
541
+ },
542
+ "54": {
543
+ "day": {
544
+ "description": "Dense Intermittent Drizzle",
545
+ "icon": "drizzle.svg"
546
+ },
547
+ "night": {
548
+ "description": "Dense Intermittent Drizzle",
549
+ "icon": "drizzle.svg"
550
+ }
551
+ },
552
+ "55": {
553
+ "day": {
554
+ "description": "Dense Drizzle",
555
+ "icon": "drizzle.svg"
556
+ },
557
+ "night": {
558
+ "description": "Dense Drizzle",
559
+ "icon": "drizzle.svg"
560
+ }
561
+ },
562
+ "56": {
563
+ "day": {
564
+ "description": "Slight Freezing Drizzle",
565
+ "icon": "sleet.svg"
566
+ },
567
+ "night": {
568
+ "description": "Slight Freezing Drizzle",
569
+ "icon": "sleet.svg"
570
+ }
571
+ },
572
+ "57": {
573
+ "day": {
574
+ "description": "Freezing Drizzle",
575
+ "icon": "sleet.svg"
576
+ },
577
+ "night": {
578
+ "description": "Freezing Drizzle",
579
+ "icon": "sleet.svg"
580
+ }
581
+ },
582
+ "58": {
583
+ "day": {
584
+ "description": "Light Rain / Drizzle",
585
+ "icon": "drizzle.svg"
586
+ },
587
+ "night": {
588
+ "description": "Light Rain / Drizzle",
589
+ "icon": "drizzle.svg"
590
+ }
591
+ },
592
+ "59": {
593
+ "day": {
594
+ "description": "Rain / Drizzle",
595
+ "icon": "drizzle.svg"
596
+ },
597
+ "night": {
598
+ "description": "Rain / Drizzle",
599
+ "icon": "drizzle.svg"
600
+ }
601
+ },
602
+ "60": {
603
+ "day": {
604
+ "description": "Light Intermittent Rain",
605
+ "icon": "partly-cloudy-day-rain.svg"
606
+ },
607
+ "night": {
608
+ "description": "Light Intermittent Rain",
609
+ "icon": "partly-cloudy-night-rain.svg"
610
+ }
611
+ },
612
+ "61": {
613
+ "day": {
614
+ "description": "Light Rain",
615
+ "icon": "drizzle.svg"
616
+ },
617
+ "night": {
618
+ "description": "Light Rain",
619
+ "icon": "drizzle.svg"
620
+ }
621
+ },
622
+ "62": {
623
+ "day": {
624
+ "description": "Intermittent Rain",
625
+ "icon": "drizzle.svg"
626
+ },
627
+ "night": {
628
+ "description": "Intermittent Rain",
629
+ "icon": "drizzle.svg"
630
+ }
631
+ },
632
+ "63": {
633
+ "day": {
634
+ "description": "Rain",
635
+ "icon": "rain.svg"
636
+ },
637
+ "night": {
638
+ "description": "Rain",
639
+ "icon": "rain.svg"
640
+ }
641
+ },
642
+ "64": {
643
+ "day": {
644
+ "description": "Heavy Intermittent Rain",
645
+ "icon": "rain.svg"
646
+ },
647
+ "night": {
648
+ "description": "Heavy Intermittent Rain",
649
+ "icon": "rain.svg"
650
+ }
651
+ },
652
+ "65": {
653
+ "day": {
654
+ "description": "Heavy Rain",
655
+ "icon": "rain.svg"
656
+ },
657
+ "night": {
658
+ "description": "Heavy Rain",
659
+ "icon": "rain.svg"
660
+ }
661
+ },
662
+ "66": {
663
+ "day": {
664
+ "description": "Slight Freezing Rain",
665
+ "icon": "sleet.svg"
666
+ },
667
+ "night": {
668
+ "description": "Slight Freezing Rain",
669
+ "icon": "sleet.svg"
670
+ }
671
+ },
672
+ "67": {
673
+ "day": {
674
+ "description": "Freezing Rain",
675
+ "icon": "sleet.svg"
676
+ },
677
+ "night": {
678
+ "description": "Freezing Rain",
679
+ "icon": "sleet.svg"
680
+ }
681
+ },
682
+ "68": {
683
+ "day": {
684
+ "description": "Light Sleet",
685
+ "icon": "sleet.svg"
686
+ },
687
+ "night": {
688
+ "description": "Light Sleet",
689
+ "icon": "sleet.svg"
690
+ }
691
+ },
692
+ "69": {
693
+ "day": {
694
+ "description": "Sleet",
695
+ "icon": "sleet.svg"
696
+ },
697
+ "night": {
698
+ "description": "Sleet",
699
+ "icon": "sleet.svg"
700
+ }
701
+ },
702
+ "70": {
703
+ "day": {
704
+ "description": "Light Intermittent Snowfalls",
705
+ "icon": "partly-cloudy-day-snow.svg"
706
+ },
707
+ "night": {
708
+ "description": "Light Intermittent Snowfalls",
709
+ "icon": "partly-cloudy-night-snow.svg"
710
+ }
711
+ },
712
+ "71": {
713
+ "day": {
714
+ "description": "Light Snowfall",
715
+ "icon": "snow.svg"
716
+ },
717
+ "night": {
718
+ "description": "Light Snowfall",
719
+ "icon": "snow.svg"
720
+ }
721
+ },
722
+ "72": {
723
+ "day": {
724
+ "description": "Intermittent Snowfalls",
725
+ "icon": "snow.svg"
726
+ },
727
+ "night": {
728
+ "description": "Intermittent Snowfalls",
729
+ "icon": "snow.svg"
730
+ }
731
+ },
732
+ "73": {
733
+ "day": {
734
+ "description": "Snowfall",
735
+ "icon": "snow.svg"
736
+ },
737
+ "night": {
738
+ "description": "Snowfall",
739
+ "icon": "snow.svg"
740
+ }
741
+ },
742
+ "74": {
743
+ "day": {
744
+ "description": "Heavy Intermittent Snowfalls",
745
+ "icon": "snow.svg"
746
+ },
747
+ "night": {
748
+ "description": "Heavy Intermittent Snowfalls",
749
+ "icon": "snow.svg"
750
+ }
751
+ },
752
+ "75": {
753
+ "day": {
754
+ "description": "Heavy Snowfall",
755
+ "icon": "snow.svg"
756
+ },
757
+ "night": {
758
+ "description": "Heavy Snowfall",
759
+ "icon": "snow.svg"
760
+ }
761
+ },
762
+ "76": {
763
+ "day": {
764
+ "description": "Diamond dust",
765
+ "icon": "snow.svg"
766
+ },
767
+ "night": {
768
+ "description": "Diamond dust",
769
+ "icon": "snow.svg"
770
+ }
771
+ },
772
+ "77": {
773
+ "day": {
774
+ "description": "Snow grains",
775
+ "icon": "hail.svg"
776
+ },
777
+ "night": {
778
+ "description": "Snow grains",
779
+ "icon": "hail.svg"
780
+ }
781
+ },
782
+ "78": {
783
+ "day": {
784
+ "description": "Sparse snow crystals",
785
+ "icon": "snow.svg"
786
+ },
787
+ "night": {
788
+ "description": "Sparse snow crystals",
789
+ "icon": "snow.svg"
790
+ }
791
+ },
792
+ "79": {
793
+ "day": {
794
+ "description": "Ice pellets",
795
+ "icon": "hail.svg"
796
+ },
797
+ "night": {
798
+ "description": "Ice pellets",
799
+ "icon": "hail.svg"
800
+ }
801
+ },
802
+ "80": {
803
+ "day": {
804
+ "description": "Light Rain Showers",
805
+ "icon": "drizzle.svg"
806
+ },
807
+ "night": {
808
+ "description": "Light Rain Showers",
809
+ "icon": "drizzle.svg"
810
+ }
811
+ },
812
+ "81": {
813
+ "day": {
814
+ "description": "Rain Showers",
815
+ "icon": "rain.svg"
816
+ },
817
+ "night": {
818
+ "description": "Rain Showers",
819
+ "icon": "rain.svg"
820
+ }
821
+ },
822
+ "82": {
823
+ "day": {
824
+ "description": "Very Heavy Rain Showers",
825
+ "icon": "rain.svg"
826
+ },
827
+ "night": {
828
+ "description": "Very Heavy Rain Showers",
829
+ "icon": "rain.svg"
830
+ }
831
+ },
832
+ "83": {
833
+ "day": {
834
+ "description": "Light Sleet Showers",
835
+ "icon": "sleet.svg"
836
+ },
837
+ "night": {
838
+ "description": "Light Sleet Showers",
839
+ "icon": "sleet.svg"
840
+ }
841
+ },
842
+ "84": {
843
+ "day": {
844
+ "description": "Sleet Showers",
845
+ "icon": "sleet.svg"
846
+ },
847
+ "night": {
848
+ "description": "Sleet Showers",
849
+ "icon": "sleet.svg"
850
+ }
851
+ },
852
+ "85": {
853
+ "day": {
854
+ "description": "Light Snow Showers",
855
+ "icon": "snow.svg"
856
+ },
857
+ "night": {
858
+ "description": "Light Snow Showers",
859
+ "icon": "snow.svg"
860
+ }
861
+ },
862
+ "86": {
863
+ "day": {
864
+ "description": "Snow Showers",
865
+ "icon": "snow.svg"
866
+ },
867
+ "night": {
868
+ "description": "Snow Showers",
869
+ "icon": "snow.svg"
870
+ }
871
+ },
872
+ "87": {
873
+ "day": {
874
+ "description": "Light Snow Pellets / Small Hail",
875
+ "icon": "hail.svg"
876
+ },
877
+ "night": {
878
+ "description": "Light Snow Pellets / Small Hail",
879
+ "icon": "hail.svg"
880
+ }
881
+ },
882
+ "88": {
883
+ "day": {
884
+ "description": "Snow Pellets / Small Hail",
885
+ "icon": "hail.svg"
886
+ },
887
+ "night": {
888
+ "description": "Snow Pellets / Small Hail",
889
+ "icon": "hail.svg"
890
+ }
891
+ },
892
+ "89": {
893
+ "day": {
894
+ "description": "Slight Hail Showers",
895
+ "icon": "hail.svg"
896
+ },
897
+ "night": {
898
+ "description": "Slight Hail Showers",
899
+ "icon": "hail.svg"
900
+ }
901
+ },
902
+ "90": {
903
+ "day": {
904
+ "description": "Hail Showers",
905
+ "icon": "hail.svg"
906
+ },
907
+ "night": {
908
+ "description": "Hail Showers",
909
+ "icon": "hail.svg"
910
+ }
911
+ },
912
+ "91": {
913
+ "day": {
914
+ "description": "Light rain (post-thunderstorm)",
915
+ "icon": "drizzle.svg"
916
+ },
917
+ "night": {
918
+ "description": "Light rain (post-thunderstorm)",
919
+ "icon": "drizzle.svg"
920
+ }
921
+ },
922
+ "92": {
923
+ "day": {
924
+ "description": "Rain (post-thunderstorm)",
925
+ "icon": "rain.svg"
926
+ },
927
+ "night": {
928
+ "description": "Rain (post-thunderstorm)",
929
+ "icon": "rain.svg"
930
+ }
931
+ },
932
+ "93": {
933
+ "day": {
934
+ "description": "Light snow (post-thunderstorm)",
935
+ "icon": "snow.svg"
936
+ },
937
+ "night": {
938
+ "description": "Light snow (post-thunderstorm)",
939
+ "icon": "snow.svg"
940
+ }
941
+ },
942
+ "94": {
943
+ "day": {
944
+ "description": "Snow (post-thunderstorm)",
945
+ "icon": "snow.svg"
946
+ },
947
+ "night": {
948
+ "description": "Snow (post-thunderstorm)",
949
+ "icon": "snow.svg"
950
+ }
951
+ },
952
+ "95": {
953
+ "day": {
954
+ "description": "Thunderstorm with Showers",
955
+ "icon": "thunderstorms-rain.svg"
956
+ },
957
+ "night": {
958
+ "description": "Thunderstorm with Showers",
959
+ "icon": "thunderstorms-rain.svg"
960
+ }
961
+ },
962
+ "96": {
963
+ "day": {
964
+ "description": "Thunderstorm with Hail",
965
+ "icon": "thunderstorms-rain.svg"
966
+ },
967
+ "night": {
968
+ "description": "Thunderstorm with Hail",
969
+ "icon": "thunderstorms-rain.svg"
970
+ }
971
+ },
972
+ "97": {
973
+ "day": {
974
+ "description": "Heavy Thunderstorm with Showers",
975
+ "icon": "thunderstorms-rain.svg"
976
+ },
977
+ "night": {
978
+ "description": "Heavy Thunderstorm with Showers",
979
+ "icon": "thunderstorms-rain.svg"
980
+ }
981
+ },
982
+ "98": {
983
+ "day": {
984
+ "description": "Thunderstorm with dust/sandstorm",
985
+ "icon": "thunderstorms.svg"
986
+ },
987
+ "night": {
988
+ "description": "Thunderstorm with dust/sandstorm",
989
+ "icon": "thunderstorms.svg"
990
+ }
991
+ },
992
+ "99": {
993
+ "day": {
994
+ "description": "Heavy Thunderstorm with Hail",
995
+ "icon": "thunderstorms-rain.svg"
996
+ },
997
+ "night": {
998
+ "description": "Heavy Thunderstorm with Hail",
999
+ "icon": "thunderstorms-rain.svg"
1000
+ }
1001
+ }
1002
+ }