import pandas as pd
import altair as alt
import solara
from solara.website.utils import apidoc
# Load the river data
file_path = 'merged_river_data.csv' # Ensure the path is correct on py.cafe
river_data = pd.read_csv(file_path)
# Convert ForecastData from string representation of lists to actual lists
river_data['ForecastData'] = river_data['ForecastData'].apply(eval)
# Convert RiverNumber to string for compatibility
river_data['RiverNumber'] = river_data['RiverNumber'].astype(str)
# Determine the bounds of the map based on the river points
min_lat, max_lat = river_data['XCoordinate'].min(), river_data['XCoordinate'].max()
min_lon, max_lon = river_data['YCoordinate'].min(), river_data['YCoordinate'].max()
center_lat = (min_lat + max_lat) / 2
center_lon = (min_lon + max_lon) / 2
# Create a map chart using Altair
background = alt.Chart(alt.topo_feature('https://cdn.jsdelivr.net/npm/world-atlas@2/countries-110m.json', 'countries')).mark_geoshape(
fill='lightgray',
stroke='white'
).properties(
width=800,
height=400
).project(
'mercator',
center=[center_lon, center_lat],
scale=500 # Adjust the scale for zoom level
)
points = alt.Chart(river_data).mark_circle(
size=10,
color='steelblue',
opacity=0.8
).encode(
longitude='YCoordinate:Q',
latitude='XCoordinate:Q',
tooltip=['RiverNumber:N', 'Name:N', 'Description:N']
)
map_chart = background + points
@solara.component
def Page():
click_data, set_click_data = solara.use_state({})
hover_data, set_hover_data = solara.use_state({})
def convert_to_dataframe(data):
if data:
relevant_keys = ["RiverNumber", "Name", "XCoordinate", "YCoordinate"]
filtered_data = {key: [data.get(key, '')] for key in relevant_keys}
return pd.DataFrame(filtered_data)
return pd.DataFrame()
click_df = convert_to_dataframe(click_data)
hover_df = convert_to_dataframe(hover_data)
def create_forecast_chart(river_number):
forecast_data = river_data[river_data['RiverNumber'] == river_number]['ForecastData'].values[0]
forecast_df = pd.DataFrame({
'Date': pd.date_range(start='2021-01-01', periods=len(forecast_data), freq='D'),
'Flow': forecast_data
})
forecast_df['RiverWatch'] = forecast_df['Flow'].rolling(window=7, min_periods=1).mean()
base = alt.Chart(forecast_df).encode(
x='Date:T'
)
area = base.mark_area(
color='black',
opacity=1.0
).encode(
y='Flow:Q'
)
line_river_watch = base.mark_line(
color='green'
).encode(
y='RiverWatch:Q'
)
line_1_5yr = alt.Chart(pd.DataFrame({
'Date': forecast_df['Date'],
'Threshold': [1500] * len(forecast_df)
})).mark_rule(
color='magenta'
).encode(
y='Threshold:Q'
)
line_10yr = alt.Chart(pd.DataFrame({
'Date': forecast_df['Date'],
'Threshold': [2000] * len(forecast_df)
})).mark_rule(
color='red',
strokeDash=[5, 5]
).encode(
y='Threshold:Q'
)
line_25yr = alt.Chart(pd.DataFrame({
'Date': forecast_df['Date'],
'Threshold': [2500] * len(forecast_df)
})).mark_rule(
color='red'
).encode(
y='Threshold:Q'
)
chart = alt.layer(area, line_river_watch, line_1_5yr, line_10yr, line_25yr).properties(
width=800,
height=400,
title=f"Forecast Data for River {river_number}"
).interactive()
return chart
with solara.Div() as main:
solara.AltairChart(map_chart, on_click=set_click_data, on_hover=set_hover_data)
solara.Markdown("### Click data:")
if not click_df.empty:
solara.DataFrame(click_df)
else:
solara.Markdown("No data")
if 'RiverNumber' in click_data:
solara.Markdown("### Forecast Data:")
forecast_chart = create_forecast_chart(click_data['RiverNumber'])
solara.AltairChart(forecast_chart)
else:
solara.Markdown("### Forecast Data: Click on a river point to view forecast data")
return main
# This is for documentation purposes
doc = apidoc(solara.AltairChart) # type: ignore