euler314 commited on
Commit
6485687
·
verified ·
1 Parent(s): c7943cc

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +154 -73
app.py CHANGED
@@ -354,78 +354,159 @@ class TyphoonAnalyzer:
354
  }
355
 
356
  def create_tracks_plot(self, data):
357
- """Create typhoon tracks visualization"""
358
- fig = go.Figure()
359
-
360
- fig.update_layout(
361
- title={
362
- 'text': 'Typhoon Tracks',
363
- 'y':0.95,
364
- 'x':0.5,
365
- 'xanchor': 'center',
366
- 'yanchor': 'top'
367
- },
368
- showlegend=True,
369
- legend=dict(
370
- yanchor="top",
371
- y=0.99,
372
- xanchor="left",
373
- x=0.01,
374
- bgcolor='rgba(255, 255, 255, 0.8)'
375
- ),
376
- geo=dict(
377
- projection_type='mercator',
378
- showland=True,
379
- showcoastlines=True,
380
- landcolor='rgb(243, 243, 243)',
381
- countrycolor='rgb(204, 204, 204)',
382
- coastlinecolor='rgb(214, 214, 214)',
383
- showocean=True,
384
- oceancolor='rgb(230, 250, 255)',
385
- showlakes=True,
386
- lakecolor='rgb(230, 250, 255)',
387
- lataxis=dict(range=[0, 50]),
388
- lonaxis=dict(range=[100, 180]),
389
- center=dict(lat=20, lon=140),
390
- bgcolor='rgba(255, 255, 255, 0.5)'
391
- ),
392
- paper_bgcolor='rgba(255, 255, 255, 0.5)',
393
- plot_bgcolor='rgba(255, 255, 255, 0.5)'
394
- )
395
-
396
- for category in COLOR_MAP.keys():
397
- category_data = data[data['Category'] == category]
398
-
399
- # Group by SID to get individual typhoon tracks
400
- for _, storm in category_data.groupby('SID'):
401
- # Create single track for each typhoon
402
- track_data = self.typhoon_data[self.typhoon_data['SID'] == storm['SID'].iloc[0]]
403
- track_data = track_data.sort_values('ISO_TIME')
404
-
405
- fig.add_trace(go.Scattergeo(
406
- lon=track_data['LON'],
407
- lat=track_data['LAT'],
408
- mode='lines',
409
- line=dict(
410
- width=2,
411
- color=COLOR_MAP[category]
412
- ),
413
- name=category,
414
- legendgroup=category,
415
- showlegend=True if storm.iloc[0]['SID'] == category_data.iloc[0]['SID'] else False,
416
- hovertemplate=(
417
- f"Name: {storm['NAME'].iloc[0]}<br>" +
418
- f"Category: {category}<br>" +
419
- f"Wind Speed: {storm['USA_WIND'].iloc[0]:.1f} kt<br>" +
420
- f"Pressure: {storm['WMO_PRES'].iloc[0]:.1f} hPa<br>" +
421
- f"Date: {track_data['ISO_TIME'].dt.strftime('%Y-%m-%d %H:%M').iloc[0]}<br>" +
422
- f"Lat: %{lat:.2f}°N<br>" +
423
- f"Lon: %{lon:.2f}°E<br>" +
424
- "<extra></extra>"
425
- )
426
- ))
427
-
428
- return fig
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
429
  def get_typhoons_for_year(self, year):
430
  """Get list of typhoons for a specific year"""
431
  year_data = self.typhoon_data[self.typhoon_data['ISO_TIME'].dt.year == year]
@@ -830,7 +911,7 @@ def create_interface():
830
 
831
  def update_typhoon_choices(year):
832
  typhoons = analyzer.get_typhoons_for_year(year)
833
- return gr.Dropdown.update(choices=typhoons, value=None)
834
 
835
  # Connect events for main analysis
836
  analyze_btn.click(
 
354
  }
355
 
356
  def create_tracks_plot(self, data):
357
+ """Create typhoon tracks visualization"""
358
+ fig = go.Figure()
359
+
360
+ fig.update_layout(
361
+ title={
362
+ 'text': 'Typhoon Tracks',
363
+ 'y':0.95,
364
+ 'x':0.5,
365
+ 'xanchor': 'center',
366
+ 'yanchor': 'top'
367
+ },
368
+ showlegend=True,
369
+ legend=dict(
370
+ yanchor="top",
371
+ y=0.99,
372
+ xanchor="left",
373
+ x=0.01,
374
+ bgcolor='rgba(255, 255, 255, 0.8)'
375
+ ),
376
+ geo=dict(
377
+ projection_type='mercator',
378
+ showland=True,
379
+ showcoastlines=True,
380
+ landcolor='rgb(243, 243, 243)',
381
+ countrycolor='rgb(204, 204, 204)',
382
+ coastlinecolor='rgb(214, 214, 214)',
383
+ showocean=True,
384
+ oceancolor='rgb(230, 250, 255)',
385
+ showlakes=True,
386
+ lakecolor='rgb(230, 250, 255)',
387
+ lataxis=dict(range=[0, 50]),
388
+ lonaxis=dict(range=[100, 180]),
389
+ center=dict(lat=20, lon=140),
390
+ bgcolor='rgba(255, 255, 255, 0.5)'
391
+ ),
392
+ paper_bgcolor='rgba(255, 255, 255, 0.5)',
393
+ plot_bgcolor='rgba(255, 255, 255, 0.5)'
394
+ )
395
+
396
+ for category in COLOR_MAP.keys():
397
+ category_data = data[data['Category'] == category]
398
+ for _, storm in category_data.groupby('SID'):
399
+ track_data = self.typhoon_data[self.typhoon_data['SID'] == storm['SID'].iloc[0]]
400
+ track_data = track_data.sort_values('ISO_TIME')
401
+
402
+ fig.add_trace(go.Scattergeo(
403
+ lon=track_data['LON'],
404
+ lat=track_data['LAT'],
405
+ mode='lines',
406
+ line=dict(
407
+ width=2,
408
+ color=COLOR_MAP[category]
409
+ ),
410
+ name=category,
411
+ legendgroup=category,
412
+ showlegend=True if storm.iloc[0]['SID'] == category_data.iloc[0]['SID'] else False,
413
+ hovertemplate=(
414
+ f"Name: {storm['NAME'].iloc[0]}<br>" +
415
+ f"Category: {category}<br>" +
416
+ f"Wind Speed: {storm['USA_WIND'].iloc[0]:.1f} kt<br>" +
417
+ f"Pressure: {storm['WMO_PRES'].iloc[0]:.1f} hPa<br>" +
418
+ f"Date: {track_data['ISO_TIME'].dt.strftime('%Y-%m-%d %H:%M').iloc[0]}<br>" +
419
+ f"Lat: {track_data['LAT'].iloc[0]:.2f}°N<br>" +
420
+ f"Lon: {track_data['LON'].iloc[0]:.2f}°E<br>" +
421
+ "<extra></extra>"
422
+ )
423
+ ))
424
+
425
+ return fig
426
+
427
+ def analyze_clusters(self, year, n_clusters):
428
+ """Analyze typhoon clusters for a specific year"""
429
+ year_data = self.typhoon_data[self.typhoon_data['SEASON'] == year]
430
+ if year_data.empty:
431
+ return go.Figure(), "No data available for selected year"
432
+
433
+ # Prepare data for clustering
434
+ routes = []
435
+ for _, storm in year_data.groupby('SID'):
436
+ if len(storm) > 1:
437
+ # Standardize route length
438
+ t = np.linspace(0, 1, len(storm))
439
+ t_new = np.linspace(0, 1, 100)
440
+ lon_interp = interp1d(t, storm['LON'], kind='linear')(t_new)
441
+ lat_interp = interp1d(t, storm['LAT'], kind='linear')(t_new)
442
+ routes.append(np.column_stack((lon_interp, lat_interp)))
443
+
444
+ if len(routes) < n_clusters:
445
+ return go.Figure(), f"Not enough typhoons ({len(routes)}) for {n_clusters} clusters"
446
+
447
+ # Perform clustering
448
+ routes_array = np.array(routes)
449
+ routes_reshaped = routes_array.reshape(routes_array.shape[0], -1)
450
+ kmeans = KMeans(n_clusters=n_clusters, random_state=42)
451
+ clusters = kmeans.fit_predict(routes_reshaped)
452
+
453
+ # Create visualization
454
+ fig = go.Figure()
455
+
456
+ # Set layout
457
+ fig.update_layout(
458
+ title=f'Typhoon Route Clusters ({year})',
459
+ showlegend=True,
460
+ geo=dict(
461
+ projection_type='mercator',
462
+ showland=True,
463
+ showcoastlines=True,
464
+ landcolor='rgb(243, 243, 243)',
465
+ countrycolor='rgb(204, 204, 204)',
466
+ coastlinecolor='rgb(214, 214, 214)',
467
+ showocean=True,
468
+ oceancolor='rgb(230, 250, 255)',
469
+ lataxis=dict(range=[0, 50]),
470
+ lonaxis=dict(range=[100, 180]),
471
+ center=dict(lat=20, lon=140)
472
+ )
473
+ )
474
+
475
+ # Plot routes colored by cluster
476
+ for route, cluster_id in zip(routes, clusters):
477
+ fig.add_trace(go.Scattergeo(
478
+ lon=route[:, 0],
479
+ lat=route[:, 1],
480
+ mode='lines',
481
+ line=dict(
482
+ width=1,
483
+ color=f'hsl({cluster_id * 360/n_clusters}, 50%, 50%)'
484
+ ),
485
+ name=f'Cluster {cluster_id + 1}',
486
+ showlegend=False
487
+ ))
488
+
489
+ # Plot cluster centers
490
+ for i in range(n_clusters):
491
+ center = kmeans.cluster_centers_[i].reshape(-1, 2)
492
+ fig.add_trace(go.Scattergeo(
493
+ lon=center[:, 0],
494
+ lat=center[:, 1],
495
+ mode='lines',
496
+ name=f'Cluster {i+1} Center',
497
+ line=dict(
498
+ width=3,
499
+ color=f'hsl({i * 360/n_clusters}, 100%, 50%)'
500
+ )
501
+ ))
502
+
503
+ # Generate statistics text
504
+ stats_text = "### Clustering Results\n\n"
505
+ cluster_counts = np.bincount(clusters)
506
+ for i in range(n_clusters):
507
+ stats_text += f"- Cluster {i+1}: {cluster_counts[i]} typhoons\n"
508
+
509
+ return fig, stats_text
510
  def get_typhoons_for_year(self, year):
511
  """Get list of typhoons for a specific year"""
512
  year_data = self.typhoon_data[self.typhoon_data['ISO_TIME'].dt.year == year]
 
911
 
912
  def update_typhoon_choices(year):
913
  typhoons = analyzer.get_typhoons_for_year(year)
914
+ return gr.update(choices=typhoons, value=None)
915
 
916
  # Connect events for main analysis
917
  analyze_btn.click(