gaia / visualize /visualize.py
Akram Sanad
small fix
ebcc2b0
import pandas as pd # stress hydrique and rendement, besoin en eau
import plotly.graph_objects as go
from typing import List
import plotly.express as px
from data_pipelines.historical_weather_data import (
download_historical_weather_data,
aggregate_hourly_weather_data,
)
import os
from forecast import get_forecast_data
from compute_et0_adjusted import compute_et0
import copy
def water_deficit(df, latitude, longitude, shading_coef=0, historic=True):
preprocessed_data = df.copy()
preprocessed_data["irradiance"] = preprocessed_data[
"Surface Downwelling Shortwave Radiation (W/m²)"
] * (1 - shading_coef)
preprocessed_data["air_temperature_min"] = preprocessed_data[
"Daily Minimum Near Surface Air Temperature (°C)"
]
preprocessed_data["air_temperature_max"] = preprocessed_data[
"Daily Maximum Near Surface Air Temperature (°C)"
]
if historic == True:
preprocessed_data["relative_humidity_min"] = preprocessed_data[
"Relative Humidity_min"
]
preprocessed_data["relative_humidity_max"] = preprocessed_data[
"Relative Humidity_max"
]
else:
preprocessed_data["relative_humidity_min"] = preprocessed_data[
"Relative Humidity (%)"
]
preprocessed_data["relative_humidity_max"] = preprocessed_data[
"Relative Humidity (%)"
]
preprocessed_data["wind_speed"] = preprocessed_data["Near Surface Wind Speed (m/s)"]
preprocessed_data["time"] = pd.to_datetime(
preprocessed_data["time"], errors="coerce"
)
preprocessed_data["month"] = preprocessed_data["time"].dt.month
preprocessed_data["day_of_year"] = preprocessed_data["time"].dt.dayofyear
et0 = compute_et0(preprocessed_data, latitude, longitude)
preprocessed_data["Evaporation (mm/day)"] = et0
preprocessed_data["Evaporation (mm/day)"] = preprocessed_data[
"Evaporation (mm/day)"
].clip(lower=0)
preprocessed_data["Precipitation (mm/day)"] = (
86400 * preprocessed_data["Precipitation (kg m-2 s-1)"]
)
preprocessed_data["Water Deficit (mm/day)"] = (
preprocessed_data["Evaporation (mm/day)"]
- preprocessed_data["Precipitation (mm/day)"]
)
return preprocessed_data
def concatenate_historic_forecast(
historic, forecast, cols_to_keep, value_period_col="forecast scénario modéré", don_t = False
):
if don_t:
historic["period"] = value_period_col
forecast["period"] = value_period_col
historic = historic[cols_to_keep]
forecast = forecast[cols_to_keep]
full_data = pd.concat([historic, forecast])
full_data = full_data[full_data['year']>=2025]
return full_data
historic["period"] = "historique"
forecast["period"] = value_period_col
historic = historic[cols_to_keep]
forecast = forecast[cols_to_keep]
full_data = pd.concat([historic, forecast])
return full_data
def visualize_climate(
moderate: pd.DataFrame,
historic: pd.DataFrame,
pessimist: pd.DataFrame,
x_axis="year",
column: str = "Precipitation (mm)",
cols_to_keep: List[str] = [
"Precipitation (mm)",
"Near Surface Air Temperature (°C)",
"Surface Downwelling Shortwave Radiation (W/m²)",
"Water Deficit (mm/day)",
"year",
"period",
],
):
if column == "Water Deficit (mm/day)":
concatenated_moderate = concatenate_historic_forecast(
historic, moderate, cols_to_keep,don_t=True
)
else:
concatenated_moderate = concatenate_historic_forecast(
historic, moderate, cols_to_keep
)
concatenated_moderate = concatenated_moderate.sort_values(by=x_axis) # Ensure order
fig = go.Figure()
if column == "Precipitation (mm)":
for condition_value in concatenated_moderate["period"].unique():
segment = concatenated_moderate[
concatenated_moderate["period"] == condition_value
]
avg_precipitation = segment.groupby(x_axis)[column].mean().reset_index()
fig.add_trace(
go.Bar(
x=avg_precipitation[x_axis],
y=avg_precipitation[column],
name=f"{condition_value}",
marker=dict(
color="blue" if condition_value == "historique" else "purple"
),
)
)
if column == "Water Deficit (mm/day)":
concatenated_pessimist = concatenate_historic_forecast(
historic, pessimist, cols_to_keep, "forecast scénario pessimiste",don_t=True
)
else:
concatenated_pessimist = concatenate_historic_forecast(
historic, pessimist, cols_to_keep, "forecast scénario pessimiste"
)
concatenated_pessimist = concatenated_pessimist.sort_values(by=x_axis)
concatenated_pessimist = concatenated_pessimist[
concatenated_pessimist["period"] != "historique"
]
for condition_value in concatenated_pessimist["period"].unique():
segment = concatenated_pessimist[
concatenated_pessimist["period"] == condition_value
]
avg_precipitation = segment.groupby(x_axis)[column].mean().reset_index()
fig.add_trace(
go.Bar(
x=avg_precipitation[x_axis],
y=avg_precipitation[column],
name=f"{condition_value}",
marker=dict(
color="orange" if condition_value != "historique" else "blue"
),
)
)
# Update layout for bar chart
fig.update_layout(
title=f"Moyenne de {column} par année",
xaxis_title="Année", # Set the x-axis title to Year
yaxis_title="Précipitation (mm)", # Set the y-axis title to Precipitation
barmode="group", # Group bars for different conditions
)
else:
for condition_value in concatenated_moderate["period"].unique():
segment = concatenated_moderate[
concatenated_moderate["period"] == condition_value
]
if condition_value == "historique":
fig.add_trace(
go.Scatter(
x=segment[x_axis], # Years on x-axis
y=segment[column], # Precipitation values on y-axis
mode="lines",
name=f"{condition_value}",
legendgroup="group1",
showlegend=False,
line=dict(
color=(
"blue" if condition_value == "historique" else "purple"
)
),
)
)
else:
fig.add_trace(
go.Scatter(
x=segment[x_axis], # Years on x-axis
y=segment[column], # Precipitation values on y-axis
mode="lines",
name=f"{condition_value}",
legendgroup="group2",
showlegend=False,
line=dict(
color=(
"blue" if condition_value == "historique" else "purple"
),
dash="dot",
),
)
)
# Continue with pessimistic data as in the original function...
if column == "Water Deficit (mm/day)":
concatenated_pessimist = concatenate_historic_forecast(
historic, pessimist, cols_to_keep, "forecast scénario pessimiste",don_t=True
)
else:
concatenated_pessimist = concatenate_historic_forecast(
historic, pessimist, cols_to_keep, "forecast scénario pessimiste"
)
concatenated_pessimist = concatenated_pessimist.sort_values(by=x_axis)
for condition_value in concatenated_pessimist["period"].unique():
segment = concatenated_pessimist[
concatenated_pessimist["period"] == condition_value
]
if condition_value == "historique":
fig.add_trace(
go.Scatter(
x=segment[x_axis], # Years on x-axis
y=segment[column], # Precipitation values on y-axis
mode="lines",
name=f"{condition_value}",
legendgroup="group1",
line=dict(
color=(
"blue" if condition_value == "historique" else "orange"
),
dash="dot" if condition_value != "historique" else None,
),
)
)
else:
fig.add_trace(
go.Scatter(
x=segment[x_axis], # Years on x-axis
y=segment[column], # Precipitation values on y-axis
mode="lines",
name=f"{condition_value}",
legendgroup="group3",
line=dict(
color=(
"blue" if condition_value == "historique" else "orange"
),
dash="dot" if condition_value != "historique" else None,
),
)
)
# Interpolation for the pessimistic scenario...
interpolation_pessimist = concatenated_pessimist[
concatenated_pessimist[x_axis] > 2023
]
interpolation_pessimist = interpolation_pessimist[
interpolation_pessimist[x_axis] <= 2025
]
fig.add_trace(
go.Scatter(
x=interpolation_pessimist[x_axis],
y=interpolation_pessimist[column].interpolate(),
mode="lines",
name="forecast scénario pessimiste",
legendgroup="group3",
showlegend=False,
line=dict(color="orange", dash="dot"),
),
)
interpolation_moderate = concatenated_moderate[
concatenated_moderate[x_axis] > 2023
]
interpolation_moderate = interpolation_moderate[
interpolation_moderate[x_axis] <= 2025
]
fig.add_trace(
go.Scatter(
x=interpolation_moderate[x_axis],
y=interpolation_moderate[column].interpolate(),
mode="lines",
name="forecast scénario modéré",
legendgroup="group2",
line=dict(color="purple", dash="dot"),
),
)
fig.update_layout(
title=f"Historique et Forecast pour {column}",
xaxis_title="Year", # Set the x-axis title to Year
yaxis_title=column, # Set the y-axis title to Precipitation
)
return fig
def aggregate_yearly(df, col_to_agg, operation="mean"):
df[col_to_agg] = df.groupby("year")[col_to_agg].transform(operation)
return df
def generate_plots(
moderate: pd.DataFrame,
historic: pd.DataFrame,
pessimist: pd.DataFrame,
x_axes: List[str],
cols_to_plot: List[str],
is_shaded: str = "",
):
plots = []
for i, col in enumerate(cols_to_plot):
plots.append(visualize_climate(moderate, historic, pessimist, x_axes[i], col))
return plots
def get_plots():
cols_to_plot = [
"Precipitation (mm)",
"Near Surface Air Temperature (°C)",
"Surface Downwelling Shortwave Radiation (W/m²)",
"Water Deficit (mm/day)",
]
cols_to_keep: List[str] = [
"Precipitation (mm)",
"Near Surface Air Temperature (°C)",
"Surface Downwelling Shortwave Radiation (W/m²)",
"Water Deficit (mm/day)",
"year",
"period",
]
x_axes = ["year"] * len(cols_to_plot)
latitude = 47
longitude = 5
start_year = 2000
end_year = 2025
df = download_historical_weather_data(latitude, longitude, start_year, end_year)
historic = aggregate_hourly_weather_data(df)
historic = historic.reset_index()
historic = historic.rename(
columns={
"precipitation": "Precipitation (mm)",
"air_temperature_mean": "Near Surface Air Temperature (°C)",
"irradiance": "Surface Downwelling Shortwave Radiation (W/m²)",
"index": "time",
}
)
historic["time"] = pd.to_datetime(historic["time"])
historic = historic.sort_values("time")
historic = historic[historic["time"] < "2025-01-01"]
historic = historic.rename(
columns={
"air_temperature_min": "Daily Minimum Near Surface Air Temperature (°C)",
"air_temperature_max": "Daily Maximum Near Surface Air Temperature (°C)",
"relative_humidity_min": "Relative Humidity_min",
"relative_humidity_max": "Relative Humidity_max",
"wind_speed": "Near Surface Wind Speed (m/s)",
"Precipitation (mm)": "Precipitation (kg m-2 s-1)",
}
)
historic["Precipitation (kg m-2 s-1)"] = (
historic["Precipitation (kg m-2 s-1)"] / 3600
)
historic = water_deficit(historic, latitude, longitude)
historic = historic.rename(
columns={"Precipitation (kg m-2 s-1)": "Precipitation (mm)"}
)
historic["Precipitation (mm)"] = historic["Precipitation (mm)"] * 3600
moderate = get_forecast_data(latitude, longitude, "moderate")
pessimist = get_forecast_data(latitude, longitude, "pessimist")
moderate = moderate.rename(
columns={"Precipitation (kg m-2 s-1)": "Precipitation (mm)"}
)
moderate["time"] = pd.to_datetime(moderate["time"])
moderate = moderate.sort_values("time")
moderate["year"] = moderate["time"].dt.year
moderate["Precipitation (mm)"] = moderate["Precipitation (mm)"] * 31536000
pessimist = pessimist.rename(
columns={"Precipitation (kg m-2 s-1)": "Precipitation (mm)"}
)
pessimist["time"] = pd.to_datetime(pessimist["time"])
pessimist = pessimist.sort_values("time")
pessimist["year"] = pessimist["time"].dt.year
pessimist["Precipitation (mm)"] = pessimist["Precipitation (mm)"] * 31536000
pessimist["period"] = "forecast scénario pessimiste"
historic["year"] = historic["time"].dt.year
historic["Precipitation (mm)"] = historic["Precipitation (mm)"] * 8760.0
for col in cols_to_plot:
moderate = aggregate_yearly(moderate, col)
historic = aggregate_yearly(historic, col)
pessimist = aggregate_yearly(pessimist, col)
plots = generate_plots(moderate, historic, pessimist, x_axes, cols_to_plot)
moderate = get_forecast_data(latitude, longitude, "moderate", shading_coef=0.2)
pessimist = get_forecast_data(latitude, longitude, "pessimist", shading_coef=0.2)
pessimist["year"] = pessimist["time"].dt.year
pessimist = pessimist[["year", "Water Deficit (mm/day)"]]
pessimist = aggregate_yearly(pessimist, 'Water Deficit (mm/day)')
plot_ombrage = copy.deepcopy(plots[-1])
plot_ombrage.add_trace(
go.Scatter(
x=pessimist["year"],
y=pessimist['Water Deficit (mm/day)'],
mode="lines",
name="forecast scénario pessimisste ombrage de 20%",
line=dict(
color="green",
dash="dot",
),
)
)
plots.append(plot_ombrage)
return plots