CoolFace
Apppublic

BPR17/EDMproject

sourceHugging Faceupdated 3mo agoView on Hugging Face
0likes
app.py204 linesDownload Raw Back to root
1from pathlib import Path2import pandas as pd3import numpy as np4import streamlit as st5import plotly.express as px6import warnings7 8warnings.filterwarnings("ignore")9 10COL_STATION = "Numero"11DIAS_SEMANA = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]12MESES_VERANO = {6: "June", 7: "July", 8: "August"}13 14 15@st.cache_data16def cargar_predicciones_2026() -> pd.DataFrame:17    base_dir = Path(__file__).resolve().parent18    pred_path = base_dir / "predicciones_2026.parquet"19 20    if not pred_path.exists():21        st.error(22            "No se ha encontrado `predicciones_2026.parquet`.\n\n"23            "Ejecuta primero `python predecir_2026.py` para generar las predicciones."24        )25        st.stop()26 27    df = pd.read_parquet(pred_path)28    df["fecha_prediccion"] = pd.to_datetime(df["fecha_prediccion"])29    df[COL_STATION] = pd.to_numeric(df[COL_STATION], errors="coerce").astype(int)30 31    return df32 33 34def clasificar_ocupacion(pct):35    if pct < 25:36        return "Low occupancy"37    elif pct < 60:38        return "Medium occupancy"39    else:40        return "High occupancy"41 42 43st.set_page_config(44    page_title="Valenbisi 2026",45    page_icon="🚲",46    layout="wide"47)48 49st.title("🚲 Valenbisi Smart Forecast")50st.caption("Interactive app to predict Valenbisi occupancy during the summer of 2026")51 52with st.spinner("Cargando predicciones 2026..."):53    df_predicciones = cargar_predicciones_2026()54 55st.header("Availability forecast by station and date")56 57estaciones_disponibles = sorted(df_predicciones[COL_STATION].dropna().unique())58ano_pred = 202659 60col_a, col_b, col_c = st.columns(3)61 62with col_a:63    estacion_pred = st.selectbox("Station", estaciones_disponibles, key="estacion_pred")64    st.text_input("Year", value="2026", disabled=True)65 66with col_b:67    mes_pred = st.selectbox(68        "Month",69        list(MESES_VERANO.keys()),70        format_func=lambda x: MESES_VERANO[x],71        key="mes_pred"72    )73    dia_pred = st.slider("Day of the month", 1, 31, 15, key="dia_pred")74 75with col_c:76    hora_pred = st.slider("Hour of the day", 0, 23, 12, key="hora_pred")77    minuto_pred = st.selectbox("Minute", [0, 15, 30, 45], key="minuto_pred")78 79 80try:81    fecha_elegida = pd.Timestamp(82        year=int(ano_pred),83        month=int(mes_pred),84        day=int(dia_pred),85        hour=int(hora_pred),86        minute=int(minuto_pred)87    )88except ValueError:89    st.warning("Esa combinación de día y mes no es válida. Por ejemplo, el 31 de junio no existe.")90    st.stop()91 92 93df_instante = df_predicciones[df_predicciones["fecha_prediccion"] == fecha_elegida]94 95if df_instante.empty:96    st.error("No hay predicciones guardadas para esa fecha y hora.")97    st.stop()98 99 100resultado_individual = df_instante[df_instante[COL_STATION] == estacion_pred]101 102if resultado_individual.empty:103    st.error("No hay predicción guardada para esa estación en esa fecha y hora.")104    st.stop()105 106resultado_individual = resultado_individual.iloc[0]107 108bicis_pred = int(resultado_individual["Bicis_predichas"])109huecos_pred = int(resultado_individual["Huecos_predichos"])110capacidad_estacion = int(resultado_individual["Capacidad"])111 112dia_semana_pred = fecha_elegida.dayofweek113 114st.caption(115    f"{fecha_elegida.strftime('%d/%m/%Y')} ({DIAS_SEMANA[dia_semana_pred]}) · "116    f"{hora_pred:02d}:{minuto_pred:02d}h · Station Nº {estacion_pred}"117)118 119res1, res2, res3 = st.columns(3)120res1.metric("Estimated bikes available", f"{bicis_pred} bikes")121res2.metric("Estimated free docks", f"{huecos_pred} docks")122res3.metric("Station capacity", f"{capacidad_estacion} docks")123 124 125st.header("Estimated station occupancy map")126st.write("The map displays all stations for the selected date and time.")127 128columnas_necesarias = {"Latitud", "Longitud", "Bicis_predichas", "Huecos_predichos", "Capacidad"}129 130if not columnas_necesarias.issubset(df_instante.columns):131    st.warning(132        "El archivo `predicciones_2026.parquet` no contiene todas las columnas necesarias "133        "para dibujar el mapa. Debe incluir Latitud y Longitud."134    )135else:136    df_mapa = df_instante.dropna(subset=["Latitud", "Longitud"]).copy()137 138    df_mapa["Ocupación (%)"] = np.where(139        df_mapa["Capacidad"] > 0,140        df_mapa["Bicis_predichas"] / df_mapa["Capacidad"] * 100,141        0142    )143 144    df_mapa["Occupancy level"] = df_mapa["Ocupación (%)"].apply(clasificar_ocupacion)145 146    df_mapa = df_mapa.rename(columns={147        "Bicis_predichas": "Bicis estimadas",148        "Huecos_predichos": "Huecos estimados"149    })150 151    fig_mapa = px.scatter_mapbox(152        df_mapa,153        lat="Latitud",154        lon="Longitud",155        color="Occupancy level",156        color_discrete_map={157 158            "Low occupancy":"#2ECC71",159            "Medium occupancy":"#F1C40F",160            "High occupancy":"#E74C3C"161        },162        hover_name=COL_STATION,163        hover_data={164            "Bicis estimadas": True,165            "Huecos estimados": True,166            "Capacidad": True,167            "Ocupación (%)": ":.1f",168            "Latitud": False,169            "Longitud": False170        },171        zoom=12,172        height=650,173        mapbox_style="open-street-map",174        title="Estimated station occupancy map"175    )176    fig_mapa.update_traces(177            marker=dict(size=18)178    )179 180    fig_mapa.update_layout(181            legend_title_text="Nivel de ocupación"182    )183 184    st.plotly_chart(fig_mapa, use_container_width=True)185 186 187with st.expander("Ver tabla de predicciones para la fecha y hora seleccionadas"):188    columnas_tabla = [189        COL_STATION,190        "fecha_prediccion",191        "Bicis_predichas",192        "Huecos_predichos",193        "Capacidad",194        "Latitud",195        "Longitud"196    ]197 198    columnas_tabla = [col for col in columnas_tabla if col in df_instante.columns]199 200    st.dataframe(201        df_instante[columnas_tabla].sort_values(COL_STATION),202        use_container_width=True203    )204