Py.Cafe

Sindhup24/

geoglows-river-forecast

Geoglows River Forecast Visualization

DocsPricing
  • app.py
  • requirements.txt
app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import zarr
import s3fs
import pandas as pd
import altair as alt
import solara
import ipyleaflet
from ipywidgets import HTML

# Function to fetch forecast data
def get_forecast_data(river_number, date):
    s3_bucket_url = f's3://geoglows-v2-forecasts/{date}.zarr/'
    s3 = s3fs.S3FileSystem(anon=True)
    try:
        mapper = s3fs.S3Map(root=s3_bucket_url, s3=s3, check=False)
        zarr_group = zarr.open_group(mapper, mode='r')
        rivid_array = zarr_group['rivid'][:]
        if river_number in rivid_array:
            river_index = list(rivid_array).index(river_number)
            qout_array = zarr_group['Qout'][:, :, river_index]
            time_array = zarr_group['time'][:]
            ensemble_array = zarr_group['ensemble'][:]
            forecast_df = pd.DataFrame(qout_array, columns=time_array)
            forecast_df.index = [f"ensemble_{i}" for i in ensemble_array]
            forecast_df.columns = time_array
            forecast_df = forecast_df.transpose()
            forecast_df.reset_index(inplace=True)
            forecast_df = forecast_df.melt(id_vars=["index"], var_name="ensemble", value_name="flow")
            forecast_df.rename(columns={"index": "date"}, inplace=True)
            return forecast_df
        else:
            return pd.DataFrame()
    except Exception as e:
        print(f"Error accessing data for RiverNumber {river_number} on {date}: {e}")
        return pd.DataFrame()

# Function to create Altair plot
def create_altair_plot(forecast_data):
    return_periods = {
        "period": ["2-year", "5-year", "10-year"],
        "flow": [20, 25, 30]
    }
    return_period_df = pd.DataFrame(return_periods)
    
    base = alt.Chart(forecast_data).mark_line().encode(
        x='date:T',
        y='flow:Q',
        color='ensemble:N'
    ).properties(
        title='Forecast Data with Return Period Overlay'
    )

    return_period_chart = alt.Chart(return_period_df).mark_rule(color='red').encode(
        y='flow:Q',
        size=alt.value(2),
        tooltip=['period:N', 'flow:Q']
    ).properties(
        title='Return Periods'
    )

    combined_chart = alt.layer(base, return_period_chart).resolve_scale(
        y='independent'
    )

    return combined_chart

# Sample river data with lat, lon, and river numbers
river_data = pd.DataFrame({
    'RiverNumber': [110123714, 110123715, 110123716],
    'Latitude': [40.7128, 34.0522, 37.7749],
    'Longitude': [-74.0060, -118.2437, -122.4194]
})

# Define the river number and date for fetching data
date = '2024040100'  # Replace with the desired date

# Function to show forecast plot
def show_forecast(event=None, river_number=None):
    forecast_data = get_forecast_data(river_number, date)
    if not forecast_data.empty:
        chart = create_altair_plot(forecast_data)
        chart_html = chart.to_html()
        display_html.value = chart_html
    else:
        display_html.value = f"<p>No forecast data found for RiverNumber {river_number} on {date}.</p>"

# Create map with river points
map_center = (39.8283, -98.5795)  # Center of the US
m = ipyleaflet.Map(center=map_center, zoom=4)

for index, row in river_data.iterrows():
    marker = ipyleaflet.Marker(location=(row['Latitude'], row['Longitude']), draggable=False)
    river_number = row['RiverNumber']
    marker.on_click(lambda event, river_number=river_number: show_forecast(event, river_number))
    m.add_layer(marker)

# HTML widget to display the chart
display_html = HTML()
display_html.value = "<p>Click on a river point to see the forecast data.</p>"

# Layout
solara.Page(
    solara.Column(
        solara.Widget(m),
        solara.Widget(display_html)
    )
)