Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1236,9 +1236,64 @@ def create_genesis_animation(prediction_data, enable_animation=True):
|
|
| 1236 |
intensities = [pt['intensity'] for pt in current_track]
|
| 1237 |
categories = [pt['category'] for pt in current_track]
|
| 1238 |
|
| 1239 |
-
#
|
| 1240 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1241 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1242 |
# Create frame
|
| 1243 |
frames.append(go.Frame(
|
| 1244 |
data=frame_data,
|
|
@@ -1266,8 +1321,50 @@ def create_genesis_animation(prediction_data, enable_animation=True):
|
|
| 1266 |
|
| 1267 |
fig.frames = frames
|
| 1268 |
|
| 1269 |
-
# Set up initial frame, add
|
| 1270 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1271 |
|
| 1272 |
else:
|
| 1273 |
# STATIC VERSION (Final state overview)
|
|
@@ -1295,8 +1392,26 @@ def create_genesis_animation(prediction_data, enable_animation=True):
|
|
| 1295 |
)
|
| 1296 |
)
|
| 1297 |
|
| 1298 |
-
# Add complete storm tracks
|
| 1299 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1300 |
|
| 1301 |
# FINAL LAYOUT (Professional meteorological style)
|
| 1302 |
fig.update_layout(
|
|
@@ -1336,7 +1451,7 @@ def create_genesis_animation(prediction_data, enable_animation=True):
|
|
| 1336 |
)
|
| 1337 |
|
| 1338 |
return fig
|
| 1339 |
-
|
| 1340 |
except Exception as e:
|
| 1341 |
logging.error(f"Error creating professional genesis animation: {e}")
|
| 1342 |
import traceback
|
|
|
|
| 1236 |
intensities = [pt['intensity'] for pt in current_track]
|
| 1237 |
categories = [pt['category'] for pt in current_track]
|
| 1238 |
|
| 1239 |
+
# Get colors based on intensity (Saffir-Simpson-like scale)
|
| 1240 |
+
colors = []
|
| 1241 |
+
for intensity in intensities:
|
| 1242 |
+
if intensity < 34:
|
| 1243 |
+
colors.append('#80808080') # Gray - TD
|
| 1244 |
+
elif intensity < 64:
|
| 1245 |
+
colors.append('#0000FF80') # Blue - TS
|
| 1246 |
+
elif intensity < 83:
|
| 1247 |
+
colors.append('#00FF0080') # Green - Cat 1
|
| 1248 |
+
elif intensity < 96:
|
| 1249 |
+
colors.append('#FFFF0080') # Yellow - Cat 2
|
| 1250 |
+
elif intensity < 113:
|
| 1251 |
+
colors.append('#FFA50080') # Orange - Cat 3
|
| 1252 |
+
elif intensity < 137:
|
| 1253 |
+
colors.append('#FF000080') # Red - Cat 4
|
| 1254 |
+
else:
|
| 1255 |
+
colors.append('#8B000080') # DarkRed - Cat 5
|
| 1256 |
|
| 1257 |
+
# Historical track line
|
| 1258 |
+
frame_data.append(
|
| 1259 |
+
go.Scattergeo(
|
| 1260 |
+
lat=lats,
|
| 1261 |
+
lon=lons,
|
| 1262 |
+
mode='lines',
|
| 1263 |
+
line=dict(
|
| 1264 |
+
width=2,
|
| 1265 |
+
color='gray'
|
| 1266 |
+
),
|
| 1267 |
+
name=f"{storm_id} Track",
|
| 1268 |
+
showlegend=(day_idx == 0),
|
| 1269 |
+
hoverinfo='skip'
|
| 1270 |
+
)
|
| 1271 |
+
)
|
| 1272 |
+
|
| 1273 |
+
# Current position marker
|
| 1274 |
+
frame_data.append(
|
| 1275 |
+
go.Scattergeo(
|
| 1276 |
+
lat=[lats[-1]],
|
| 1277 |
+
lon=[lons[-1]],
|
| 1278 |
+
mode='markers',
|
| 1279 |
+
marker=dict(
|
| 1280 |
+
size=10,
|
| 1281 |
+
symbol='circle',
|
| 1282 |
+
color=colors[-1]
|
| 1283 |
+
),
|
| 1284 |
+
name=f"{storm_id} Position",
|
| 1285 |
+
showlegend=(day_idx == 0),
|
| 1286 |
+
hovertemplate=(
|
| 1287 |
+
f"{storm_id}<br>"
|
| 1288 |
+
f"Lat: {lats[-1]:.1f}°N<br>"
|
| 1289 |
+
f"Lon: {lons[-1]:.1f}°E<br>"
|
| 1290 |
+
f"Intensity: {intensities[-1]} kt<br>"
|
| 1291 |
+
f"Category: {categories[-1]}<br>"
|
| 1292 |
+
'<extra></extra>'
|
| 1293 |
+
)
|
| 1294 |
+
)
|
| 1295 |
+
)
|
| 1296 |
+
|
| 1297 |
# Create frame
|
| 1298 |
frames.append(go.Frame(
|
| 1299 |
data=frame_data,
|
|
|
|
| 1321 |
|
| 1322 |
fig.frames = frames
|
| 1323 |
|
| 1324 |
+
# Set up initial frame, add play/pause controls, sliders, etc.
|
| 1325 |
+
slider_steps = [
|
| 1326 |
+
dict(method="animate",
|
| 1327 |
+
args=[[frame.name], {
|
| 1328 |
+
"mode": "immediate",
|
| 1329 |
+
"frame": {"duration": 500, "redraw": True},
|
| 1330 |
+
"transition": {"duration": 0}
|
| 1331 |
+
}],
|
| 1332 |
+
label=frame.name)
|
| 1333 |
+
for frame in frames
|
| 1334 |
+
]
|
| 1335 |
+
|
| 1336 |
+
fig.update_layout(
|
| 1337 |
+
updatemenus=[dict(
|
| 1338 |
+
type="buttons",
|
| 1339 |
+
showactive=False,
|
| 1340 |
+
y=0,
|
| 1341 |
+
x=1.05,
|
| 1342 |
+
xanchor="right",
|
| 1343 |
+
yanchor="top",
|
| 1344 |
+
pad=dict(t=0, r=10),
|
| 1345 |
+
buttons=[
|
| 1346 |
+
dict(label="▶️ Play",
|
| 1347 |
+
method="animate",
|
| 1348 |
+
args=[None, {
|
| 1349 |
+
"frame": {"duration": 500, "redraw": True},
|
| 1350 |
+
"fromcurrent": True,
|
| 1351 |
+
"transition": {"duration": 0}
|
| 1352 |
+
}]),
|
| 1353 |
+
dict(label="⏸️ Pause",
|
| 1354 |
+
method="animate",
|
| 1355 |
+
args=[[None], {
|
| 1356 |
+
"frame": {"duration": 0, "redraw": False},
|
| 1357 |
+
"mode": "immediate",
|
| 1358 |
+
"transition": {"duration": 0}
|
| 1359 |
+
}])
|
| 1360 |
+
]
|
| 1361 |
+
)],
|
| 1362 |
+
sliders=[dict(
|
| 1363 |
+
active=0,
|
| 1364 |
+
pad=dict(t=50),
|
| 1365 |
+
steps=slider_steps
|
| 1366 |
+
)]
|
| 1367 |
+
)
|
| 1368 |
|
| 1369 |
else:
|
| 1370 |
# STATIC VERSION (Final state overview)
|
|
|
|
| 1392 |
)
|
| 1393 |
)
|
| 1394 |
|
| 1395 |
+
# Add complete storm tracks
|
| 1396 |
+
for storm in storm_predictions:
|
| 1397 |
+
track = storm['track']
|
| 1398 |
+
if track:
|
| 1399 |
+
lats = [pt['lat'] for pt in track]
|
| 1400 |
+
lons = [pt['lon'] for pt in track]
|
| 1401 |
+
fig.add_trace(
|
| 1402 |
+
go.Scattergeo(
|
| 1403 |
+
lat=lats,
|
| 1404 |
+
lon=lons,
|
| 1405 |
+
mode='lines+markers',
|
| 1406 |
+
line=dict(width=2, color='gray'),
|
| 1407 |
+
marker=dict(
|
| 1408 |
+
size=6,
|
| 1409 |
+
symbol='circle',
|
| 1410 |
+
color='red'
|
| 1411 |
+
),
|
| 1412 |
+
name=f"{storm['storm_id']} Full Track"
|
| 1413 |
+
)
|
| 1414 |
+
)
|
| 1415 |
|
| 1416 |
# FINAL LAYOUT (Professional meteorological style)
|
| 1417 |
fig.update_layout(
|
|
|
|
| 1451 |
)
|
| 1452 |
|
| 1453 |
return fig
|
| 1454 |
+
|
| 1455 |
except Exception as e:
|
| 1456 |
logging.error(f"Error creating professional genesis animation: {e}")
|
| 1457 |
import traceback
|