Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -25,7 +25,6 @@ import cartopy.crs as ccrs
|
|
| 25 |
import cartopy.feature as cfeature
|
| 26 |
import plotly.graph_objects as go
|
| 27 |
import plotly.express as px
|
| 28 |
-
import plotly.io as pio
|
| 29 |
from plotly.subplots import make_subplots
|
| 30 |
|
| 31 |
from sklearn.manifold import TSNE
|
|
@@ -977,17 +976,22 @@ def generate_genesis_prediction_monthly(month, oni_value, year=2025):
|
|
| 977 |
genesis_gpi = gpi_field[max_i, max_j]
|
| 978 |
|
| 979 |
# Determine probability of actual genesis
|
| 980 |
-
|
| 981 |
-
|
| 982 |
-
|
| 983 |
-
|
| 984 |
-
|
| 985 |
-
|
| 986 |
-
|
| 987 |
-
|
| 988 |
-
|
| 989 |
-
|
| 990 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 991 |
|
| 992 |
# Generate storm tracks for genesis events
|
| 993 |
storm_predictions = []
|
|
@@ -1683,6 +1687,66 @@ Storm {storm['storm_id']}:
|
|
| 1683 |
logging.error(f"Error creating prediction summary: {e}")
|
| 1684 |
return f"Error generating summary: {str(e)}"
|
| 1685 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1686 |
# -----------------------------
|
| 1687 |
# FIXED: ADVANCED ML FEATURES WITH ROBUST ERROR HANDLING
|
| 1688 |
# -----------------------------
|
|
@@ -3009,7 +3073,7 @@ def create_interface():
|
|
| 3009 |
""")
|
| 3010 |
|
| 3011 |
with gr.Row():
|
| 3012 |
-
genesis_animation = gr.
|
| 3013 |
|
| 3014 |
with gr.Row():
|
| 3015 |
genesis_summary = gr.Textbox(label="📋 Monthly Genesis Analysis Summary", lines=25)
|
|
@@ -3022,28 +3086,18 @@ def create_interface():
|
|
| 3022 |
f"Genesis prediction run for month={month}, oni={oni}: {len(prediction_data.get('genesis_events', []))} events"
|
| 3023 |
)
|
| 3024 |
|
| 3025 |
-
|
| 3026 |
-
genesis_fig = create_genesis_animation(prediction_data, animation)
|
| 3027 |
-
|
| 3028 |
-
# Convert to HTML with inline Plotly JS for HF Spaces without CDN access
|
| 3029 |
-
genesis_html = pio.to_html(
|
| 3030 |
-
genesis_fig,
|
| 3031 |
-
include_plotlyjs='inline',
|
| 3032 |
-
full_html=False
|
| 3033 |
-
)
|
| 3034 |
|
| 3035 |
# Generate summary
|
| 3036 |
summary_text = create_prediction_summary(prediction_data)
|
| 3037 |
|
| 3038 |
-
return
|
| 3039 |
|
| 3040 |
except Exception as e:
|
| 3041 |
import traceback
|
| 3042 |
error_msg = f"Genesis prediction failed: {str(e)}\n\nDetails:\n{traceback.format_exc()}"
|
| 3043 |
logging.error(error_msg)
|
| 3044 |
-
|
| 3045 |
-
err_html = pio.to_html(err_fig, include_plotlyjs='inline', full_html=False)
|
| 3046 |
-
return err_html, error_msg
|
| 3047 |
|
| 3048 |
generate_genesis_btn.click(
|
| 3049 |
fn=run_genesis_prediction,
|
|
|
|
| 25 |
import cartopy.feature as cfeature
|
| 26 |
import plotly.graph_objects as go
|
| 27 |
import plotly.express as px
|
|
|
|
| 28 |
from plotly.subplots import make_subplots
|
| 29 |
|
| 30 |
from sklearn.manifold import TSNE
|
|
|
|
| 976 |
genesis_gpi = gpi_field[max_i, max_j]
|
| 977 |
|
| 978 |
# Determine probability of actual genesis
|
| 979 |
+
# Probability influenced by ONI to mimic El Niño/La Niña effects
|
| 980 |
+
genesis_prob = np.clip(0.3 + genesis_gpi / 4.0 + 0.2 * np.tanh(oni_value), 0, 0.9)
|
| 981 |
+
|
| 982 |
+
if np.random.random() < genesis_prob:
|
| 983 |
+
event = {
|
| 984 |
+
'day': day,
|
| 985 |
+
'lat': genesis_lat,
|
| 986 |
+
'lon': genesis_lon,
|
| 987 |
+
'gpi': genesis_gpi,
|
| 988 |
+
'probability': genesis_prob,
|
| 989 |
+
'date': f"{year}-{month:02d}-{day:02d}"
|
| 990 |
+
}
|
| 991 |
+
logging.info(
|
| 992 |
+
f"Genesis on day {day}: lat={genesis_lat:.1f} lon={genesis_lon:.1f} GPI={genesis_gpi:.2f} prob={genesis_prob:.2f}"
|
| 993 |
+
)
|
| 994 |
+
genesis_events.append(event)
|
| 995 |
|
| 996 |
# Generate storm tracks for genesis events
|
| 997 |
storm_predictions = []
|
|
|
|
| 1687 |
logging.error(f"Error creating prediction summary: {e}")
|
| 1688 |
return f"Error generating summary: {str(e)}"
|
| 1689 |
|
| 1690 |
+
def generate_genesis_video(prediction_data):
|
| 1691 |
+
"""Create a simple MP4/GIF animation for the genesis prediction"""
|
| 1692 |
+
try:
|
| 1693 |
+
daily_maps = prediction_data.get('daily_gpi_maps', [])
|
| 1694 |
+
if not daily_maps:
|
| 1695 |
+
return None
|
| 1696 |
+
|
| 1697 |
+
storms = prediction_data.get('storm_predictions', [])
|
| 1698 |
+
lat_range = daily_maps[0]['lat_range']
|
| 1699 |
+
lon_range = daily_maps[0]['lon_range']
|
| 1700 |
+
|
| 1701 |
+
fig, ax = plt.subplots(figsize=(8, 6), subplot_kw={'projection': ccrs.PlateCarree()})
|
| 1702 |
+
ax.set_extent([lon_range.min()-5, lon_range.max()+5,
|
| 1703 |
+
lat_range.min()-5, lat_range.max()+5])
|
| 1704 |
+
ax.coastlines()
|
| 1705 |
+
ax.add_feature(cfeature.BORDERS, linewidth=0.5)
|
| 1706 |
+
|
| 1707 |
+
img = ax.imshow(
|
| 1708 |
+
daily_maps[0]['gpi_field'], origin='lower',
|
| 1709 |
+
extent=[lon_range.min(), lon_range.max(), lat_range.min(), lat_range.max()],
|
| 1710 |
+
vmin=0, vmax=3, cmap='viridis', alpha=0.8
|
| 1711 |
+
)
|
| 1712 |
+
cbar = plt.colorbar(img, ax=ax, orientation='vertical', pad=0.02, label='GPI')
|
| 1713 |
+
|
| 1714 |
+
lines = [ax.plot([], [], 'k-', lw=2)[0] for _ in storms]
|
| 1715 |
+
points = [ax.plot([], [], 'ro')[0] for _ in storms]
|
| 1716 |
+
|
| 1717 |
+
title = ax.set_title('')
|
| 1718 |
+
|
| 1719 |
+
def animate(i):
|
| 1720 |
+
day = daily_maps[i]['day']
|
| 1721 |
+
img.set_data(daily_maps[i]['gpi_field'])
|
| 1722 |
+
for line, point, storm in zip(lines, points, storms):
|
| 1723 |
+
past = [p for p in storm.get('track', []) if p['day'] <= day]
|
| 1724 |
+
if not past:
|
| 1725 |
+
continue
|
| 1726 |
+
lats = [p['lat'] for p in past]
|
| 1727 |
+
lons = [p['lon'] for p in past]
|
| 1728 |
+
line.set_data(lons, lats)
|
| 1729 |
+
point.set_data(lons[-1], lats[-1])
|
| 1730 |
+
title.set_text(f"Day {day} of {prediction_data['month']:02d}/{prediction_data.get('year', 2025)}")
|
| 1731 |
+
return [img, *lines, *points, title]
|
| 1732 |
+
|
| 1733 |
+
anim = animation.FuncAnimation(fig, animate, frames=len(daily_maps), interval=600, blit=False)
|
| 1734 |
+
|
| 1735 |
+
if shutil.which('ffmpeg'):
|
| 1736 |
+
writer = animation.FFMpegWriter(fps=2)
|
| 1737 |
+
suffix = '.mp4'
|
| 1738 |
+
else:
|
| 1739 |
+
writer = animation.PillowWriter(fps=2)
|
| 1740 |
+
suffix = '.gif'
|
| 1741 |
+
|
| 1742 |
+
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=suffix, dir=tempfile.gettempdir())
|
| 1743 |
+
anim.save(temp_file.name, writer=writer)
|
| 1744 |
+
plt.close(fig)
|
| 1745 |
+
return temp_file.name
|
| 1746 |
+
except Exception as e:
|
| 1747 |
+
logging.error(f"Error generating genesis video: {e}")
|
| 1748 |
+
return None
|
| 1749 |
+
|
| 1750 |
# -----------------------------
|
| 1751 |
# FIXED: ADVANCED ML FEATURES WITH ROBUST ERROR HANDLING
|
| 1752 |
# -----------------------------
|
|
|
|
| 3073 |
""")
|
| 3074 |
|
| 3075 |
with gr.Row():
|
| 3076 |
+
genesis_animation = gr.Video(label="🗺️ Daily Genesis Potential & Storm Development")
|
| 3077 |
|
| 3078 |
with gr.Row():
|
| 3079 |
genesis_summary = gr.Textbox(label="📋 Monthly Genesis Analysis Summary", lines=25)
|
|
|
|
| 3086 |
f"Genesis prediction run for month={month}, oni={oni}: {len(prediction_data.get('genesis_events', []))} events"
|
| 3087 |
)
|
| 3088 |
|
| 3089 |
+
video_path = generate_genesis_video(prediction_data)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3090 |
|
| 3091 |
# Generate summary
|
| 3092 |
summary_text = create_prediction_summary(prediction_data)
|
| 3093 |
|
| 3094 |
+
return video_path, summary_text
|
| 3095 |
|
| 3096 |
except Exception as e:
|
| 3097 |
import traceback
|
| 3098 |
error_msg = f"Genesis prediction failed: {str(e)}\n\nDetails:\n{traceback.format_exc()}"
|
| 3099 |
logging.error(error_msg)
|
| 3100 |
+
return None, error_msg
|
|
|
|
|
|
|
| 3101 |
|
| 3102 |
generate_genesis_btn.click(
|
| 3103 |
fn=run_genesis_prediction,
|