euler314 commited on
Commit
aa74248
·
verified ·
1 Parent(s): d08ab3b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +74 -138
app.py CHANGED
@@ -118,7 +118,7 @@ def load_ibtracs_data():
118
 
119
  def convert_typhoondata(input_file, output_file):
120
  with open(input_file, 'r') as infile:
121
- next(infile); next(infile) # Skip header lines
122
  reader = csv.reader(infile)
123
  sid_data = defaultdict(list)
124
  for row in reader:
@@ -174,7 +174,7 @@ def merge_data(oni_long, typhoon_max):
174
  return pd.merge(typhoon_max, oni_long, on=['Year', 'Month'])
175
 
176
  def categorize_typhoon(wind_speed):
177
- wind_speed_kt = wind_speed # Assuming input is already in knots
178
  if wind_speed_kt >= 137:
179
  return 'C5 Super Typhoon'
180
  elif wind_speed_kt >= 113:
@@ -293,7 +293,7 @@ def generate_main_analysis(start_year, start_month, end_year, end_month, enso_ph
293
 
294
  return tracks_fig, wind_scatter, pressure_scatter, regression_fig, slopes_text
295
 
296
- # Path animation function with moving track
297
  def categorize_typhoon_by_standard(wind_speed, standard):
298
  if standard == 'taiwan':
299
  wind_speed_ms = wind_speed * 0.514444
@@ -319,143 +319,76 @@ def categorize_typhoon_by_standard(wind_speed, standard):
319
  return 'Tropical Storm', atlantic_standard['Tropical Storm']['color']
320
  return 'Tropical Depression', atlantic_standard['Tropical Depression']['color']
321
 
322
- def generate_improved_animation(year, typhoon, standard):
323
  if not typhoon:
324
- return None
325
 
326
  typhoon_id = typhoon.split('(')[-1].strip(')')
327
  storm = ibtracs.get_storm(typhoon_id)
328
 
329
- # Create animation frames with growing track
330
- frames = []
331
- for i in range(len(storm.time)):
332
- category, color = categorize_typhoon_by_standard(storm.vmax[i], standard)
333
- frame_data = [
334
- go.Scattergeo(
335
- lon=storm.lon[:i+1], # Only include points up to current time
336
- lat=storm.lat[:i+1],
337
- mode='lines+markers',
338
- line=dict(width=2, color='blue'),
339
- marker=dict(size=8, color=color),
340
- name=f"{storm.name} at {storm.time[i].strftime('%Y-%m-%d %H:%M')}",
341
- text=[f"Time: {storm.time[i].strftime('%Y-%m-%d %H:%M')}<br>Wind: {storm.vmax[i]:.1f} kt<br>Category: {category}"],
342
- hoverinfo="text"
343
- )
344
- ]
345
- frames.append(go.Frame(data=frame_data, name=str(i)))
346
-
347
- # Initial figure with just the starting point
348
- category, color = categorize_typhoon_by_standard(storm.vmax[0], standard)
349
- fig = go.Figure(
350
- data=[
351
- go.Scattergeo(
352
- lon=[storm.lon[0]],
353
- lat=[storm.lat[0]],
354
- mode='markers',
355
- marker=dict(size=12, color=color),
356
- name="Start",
357
- text=[f"Start: {storm.time[0].strftime('%Y-%m-%d %H:%M')}<br>Wind: {storm.vmax[0]:.1f} kt<br>Category: {category}"],
358
- hoverinfo="text"
359
- )
360
- ],
361
- frames=frames
362
- )
363
-
364
- # Add category legend
365
- standard_dict = atlantic_standard if standard == 'atlantic' else taiwan_standard
366
- for cat, details in standard_dict.items():
367
- fig.add_trace(go.Scattergeo(
368
- lon=[None], lat=[None], mode='markers',
369
- marker=dict(size=10, color=details['color']),
370
- name=cat,
371
- showlegend=True
372
- ))
373
-
374
  # Map focus
375
  min_lat, max_lat = min(storm.lat), max(storm.lat)
376
  min_lon, max_lon = min(storm.lon), max(storm.lon)
377
  lat_padding = max((max_lat - min_lat) * 0.3, 5)
378
  lon_padding = max((max_lon - min_lon) * 0.3, 5)
379
 
380
- # Update layout with animation controls
381
- fig.update_layout(
382
- title=f"{year} {storm.name} Typhoon Path Animation",
383
- geo=dict(
384
- projection_type='natural earth',
385
- showland=True,
386
- showcoastlines=True,
387
- landcolor='rgb(243, 243, 243)',
388
- countrycolor='rgb(204, 204, 204)',
389
- coastlinecolor='rgb(204, 204, 204)',
390
- showocean=True,
391
- oceancolor='rgb(230, 230, 255)',
392
- lataxis={'range': [min_lat - lat_padding, max_lat + lat_padding]},
393
- lonaxis={'range': [min_lon - lon_padding, max_lon + lon_padding]}
394
- ),
395
- updatemenus=[{
396
- "buttons": [
397
- {
398
- "args": [None, {"frame": {"duration": 200, "redraw": True},
399
- "fromcurrent": True,
400
- "transition": {"duration": 0, "easing": "linear"},
401
- "mode": "immediate"}],
402
- "label": "Play",
403
- "method": "animate"
404
- },
405
- {
406
- "args": [[None], {"frame": {"duration": 0, "redraw": True},
407
- "mode": "immediate",
408
- "transition": {"duration": 0}}],
409
- "label": "Pause",
410
- "method": "animate"
411
- }
412
- ],
413
- "direction": "left",
414
- "pad": {"r": 10, "t": 10},
415
- "showactive": True,
416
- "type": "buttons",
417
- "x": 0.1,
418
- "xanchor": "left",
419
- "y": 0,
420
- "yanchor": "bottom"
421
- }],
422
- sliders=[{
423
- "active": 0,
424
- "yanchor": "top",
425
- "xanchor": "left",
426
- "currentvalue": {
427
- "font": {"size": 12},
428
- "prefix": "Time: ",
429
- "visible": True,
430
- "xanchor": "right"
431
- },
432
- "transition": {"duration": 0, "easing": "linear"},
433
- "pad": {"b": 10, "t": 50},
434
- "len": 0.9,
435
- "x": 0.1,
436
- "y": 0,
437
- "steps": [
438
- {
439
- "args": [[str(i)], {"frame": {"duration": 200, "redraw": True},
440
- "mode": "immediate",
441
- "transition": {"duration": 0}}],
442
- "label": storm.time[i].strftime('%m/%d %H:%M'),
443
- "method": "animate"
444
- } for i in range(len(storm.time))
445
- ]
446
- }],
447
- height=700,
448
- showlegend=True,
449
- legend=dict(
450
- yanchor="top",
451
- y=0.99,
452
- xanchor="left",
453
- x=0.01,
454
- bgcolor="rgba(255, 255, 255, 0.8)"
455
- ),
456
- )
457
 
458
- return fig
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
459
 
460
  # Logistic regression functions
461
  def perform_wind_regression(start_year, start_month, end_year, end_month):
@@ -504,7 +437,7 @@ with gr.Blocks(title="Typhoon Analysis Dashboard") as demo:
504
  ### Features:
505
  - **Track Visualization**: View typhoon tracks by time period and ENSO phase
506
  - **Statistical Analysis**: Examine relationships between ONI values and typhoon characteristics
507
- - **Path Animation**: Watch animated typhoon paths with intensity classification
508
  - **Regression Analysis**: Perform statistical regression on typhoon data
509
 
510
  Select a tab above to begin your analysis.
@@ -664,16 +597,15 @@ with gr.Blocks(title="Typhoon Analysis Dashboard") as demo:
664
  typhoon_dropdown = gr.Dropdown(label="Typhoon")
665
  standard_dropdown = gr.Dropdown(label="Classification Standard", choices=['atlantic', 'taiwan'], value='atlantic')
666
 
667
- animate_btn = gr.Button("Generate Animation")
668
- path_plot = gr.Plot(label="Typhoon Path Animation", elem_id="animation_plot")
669
  animation_info = gr.Markdown("""
670
  ### Animation Instructions
671
  1. Select a year and typhoon from the dropdowns
672
  2. Choose a classification standard (Atlantic or Taiwan)
673
- 3. Click "Generate Animation"
674
- 4. Use the "Play" button to watch the typhoon track grow over time
675
- 5. Use the slider to manually navigate through the typhoon's path
676
- 6. The blue line represents the growing track, with markers colored by intensity
677
  """)
678
 
679
  def update_typhoon_options(year):
@@ -684,18 +616,22 @@ with gr.Blocks(title="Typhoon Analysis Dashboard") as demo:
684
 
685
  year_dropdown.change(fn=update_typhoon_options, inputs=year_dropdown, outputs=typhoon_dropdown)
686
  animate_btn.click(
687
- fn=generate_improved_animation,
688
  inputs=[year_dropdown, typhoon_dropdown, standard_dropdown],
689
- outputs=path_plot
690
  )
691
 
692
  # Custom CSS for better spacing and visibility
693
  gr.HTML("""
694
  <style>
695
- #tracks_plot, #animation_plot {
696
  height: 700px !important;
697
  width: 100%;
698
  }
 
 
 
 
699
  .plot-container {
700
  min-height: 600px;
701
  }
 
118
 
119
  def convert_typhoondata(input_file, output_file):
120
  with open(input_file, 'r') as infile:
121
+ next(infile); next(infile)
122
  reader = csv.reader(infile)
123
  sid_data = defaultdict(list)
124
  for row in reader:
 
174
  return pd.merge(typhoon_max, oni_long, on=['Year', 'Month'])
175
 
176
  def categorize_typhoon(wind_speed):
177
+ wind_speed_kt = wind_speed
178
  if wind_speed_kt >= 137:
179
  return 'C5 Super Typhoon'
180
  elif wind_speed_kt >= 113:
 
293
 
294
  return tracks_fig, wind_scatter, pressure_scatter, regression_fig, slopes_text
295
 
296
+ # Path animation function using Gallery
297
  def categorize_typhoon_by_standard(wind_speed, standard):
298
  if standard == 'taiwan':
299
  wind_speed_ms = wind_speed * 0.514444
 
319
  return 'Tropical Storm', atlantic_standard['Tropical Storm']['color']
320
  return 'Tropical Depression', atlantic_standard['Tropical Depression']['color']
321
 
322
+ def generate_track_gallery(year, typhoon, standard):
323
  if not typhoon:
324
+ return []
325
 
326
  typhoon_id = typhoon.split('(')[-1].strip(')')
327
  storm = ibtracs.get_storm(typhoon_id)
328
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
329
  # Map focus
330
  min_lat, max_lat = min(storm.lat), max(storm.lat)
331
  min_lon, max_lon = min(storm.lon), max(storm.lon)
332
  lat_padding = max((max_lat - min_lat) * 0.3, 5)
333
  lon_padding = max((max_lon - min_lon) * 0.3, 5)
334
 
335
+ # Generate a sequence of figures
336
+ gallery = []
337
+ for i in range(len(storm.time)):
338
+ fig = go.Figure()
339
+
340
+ # Add the growing track up to the current point
341
+ category, color = categorize_typhoon_by_standard(storm.vmax[i], standard)
342
+ fig.add_trace(go.Scattergeo(
343
+ lon=storm.lon[:i+1],
344
+ lat=storm.lat[:i+1],
345
+ mode='lines+markers',
346
+ line=dict(width=2, color='blue'),
347
+ marker=dict(size=8, color=color),
348
+ name=f"{storm.name}",
349
+ text=[f"Time: {storm.time[j].strftime('%Y-%m-%d %H:%M')}<br>Wind: {storm.vmax[j]:.1f} kt<br>Category: {categorize_typhoon_by_standard(storm.vmax[j], standard)[0]}" for j in range(i+1)],
350
+ hoverinfo="text"
351
+ ))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
352
 
353
+ # Add category legend
354
+ standard_dict = atlantic_standard if standard == 'atlantic' else taiwan_standard
355
+ for cat, details in standard_dict.items():
356
+ fig.add_trace(go.Scattergeo(
357
+ lon=[None], lat=[None], mode='markers',
358
+ marker=dict(size=10, color=details['color']),
359
+ name=cat,
360
+ showlegend=True
361
+ ))
362
+
363
+ # Update layout
364
+ fig.update_layout(
365
+ title=f"{year} {storm.name} at {storm.time[i].strftime('%Y-%m-%d %H:%M')}",
366
+ geo=dict(
367
+ projection_type='natural earth',
368
+ showland=True,
369
+ showcoastlines=True,
370
+ landcolor='rgb(243, 243, 243)',
371
+ countrycolor='rgb(204, 204, 204)',
372
+ coastlinecolor='rgb(204, 204, 204)',
373
+ showocean=True,
374
+ oceancolor='rgb(230, 230, 255)',
375
+ lataxis={'range': [min_lat - lat_padding, max_lat + lat_padding]},
376
+ lonaxis={'range': [min_lon - lon_padding, max_lon + lon_padding]}
377
+ ),
378
+ height=700,
379
+ showlegend=True,
380
+ legend=dict(
381
+ yanchor="top",
382
+ y=0.99,
383
+ xanchor="left",
384
+ x=0.01,
385
+ bgcolor="rgba(255, 255, 255, 0.8)"
386
+ )
387
+ )
388
+
389
+ gallery.append(fig)
390
+
391
+ return gallery
392
 
393
  # Logistic regression functions
394
  def perform_wind_regression(start_year, start_month, end_year, end_month):
 
437
  ### Features:
438
  - **Track Visualization**: View typhoon tracks by time period and ENSO phase
439
  - **Statistical Analysis**: Examine relationships between ONI values and typhoon characteristics
440
+ - **Path Animation**: View a gallery of typhoon path progression over time
441
  - **Regression Analysis**: Perform statistical regression on typhoon data
442
 
443
  Select a tab above to begin your analysis.
 
597
  typhoon_dropdown = gr.Dropdown(label="Typhoon")
598
  standard_dropdown = gr.Dropdown(label="Classification Standard", choices=['atlantic', 'taiwan'], value='atlantic')
599
 
600
+ animate_btn = gr.Button("Generate Animation Gallery")
601
+ path_gallery = gr.Gallery(label="Typhoon Path Progression", elem_id="path_gallery", columns=1, height="auto")
602
  animation_info = gr.Markdown("""
603
  ### Animation Instructions
604
  1. Select a year and typhoon from the dropdowns
605
  2. Choose a classification standard (Atlantic or Taiwan)
606
+ 3. Click "Generate Animation Gallery"
607
+ 4. Scroll through the gallery to see the typhoon track growing over time
608
+ 5. Each image represents a step in the typhoon's path, with the blue line extending and markers showing intensity
 
609
  """)
610
 
611
  def update_typhoon_options(year):
 
616
 
617
  year_dropdown.change(fn=update_typhoon_options, inputs=year_dropdown, outputs=typhoon_dropdown)
618
  animate_btn.click(
619
+ fn=generate_track_gallery,
620
  inputs=[year_dropdown, typhoon_dropdown, standard_dropdown],
621
+ outputs=path_gallery
622
  )
623
 
624
  # Custom CSS for better spacing and visibility
625
  gr.HTML("""
626
  <style>
627
+ #tracks_plot {
628
  height: 700px !important;
629
  width: 100%;
630
  }
631
+ #path_gallery .gallery-item {
632
+ height: 700px !important;
633
+ width: 100% !important;
634
+ }
635
  .plot-container {
636
  min-height: 600px;
637
  }