Replace ambiguous cost-vs-revenue bar charts with clearer line charts
Stacked/grouped bars made it hard to compare gasto vs ingreso when the two values are close, and margen barely visible against that scale. Extract a shared _eur_line_chart helper (single €-axis, fixed categorical colors, tooltip) and reuse it for the per-campaign, portfolio, and resumen daily views instead of duplicating Altair boilerplate per chart.
This commit is contained in:
parent
8cb5832f8b
commit
ea201ef565
76
dashboard.py
76
dashboard.py
@ -197,6 +197,39 @@ def _compute_analysis(row: dict, dia_actual: int, dias_mes: int) -> dict:
|
||||
}
|
||||
|
||||
|
||||
_SERIE_COLORS = {
|
||||
"Inversión": "#2a78d6",
|
||||
"Gasto": "#2a78d6",
|
||||
"Ingreso": "#1baf7a",
|
||||
"Revenue": "#1baf7a",
|
||||
"Margen": "#4a3aa7",
|
||||
"Margen (sumatorio)": "#4a3aa7",
|
||||
"Margen (PPL)": "#eb6834",
|
||||
}
|
||||
|
||||
|
||||
def _eur_line_chart(df: pd.DataFrame, series: list[str], height: int = 320):
|
||||
"""Gráfico de líneas en € para comparar varias series por día. Un solo eje
|
||||
(todas las series están en €), colores categóricos fijos y tooltip — evita
|
||||
la ambigüedad de un gráfico de barras apiladas/agrupadas para comparar
|
||||
magnitudes que pueden ser muy parecidas entre sí (p.ej. gasto vs ingreso)."""
|
||||
series = [s for s in series if s in df.columns]
|
||||
df_long = df.melt("Fecha", value_vars=series, var_name="Serie", value_name="Valor")
|
||||
color_scale = alt.Scale(domain=series, range=[_SERIE_COLORS[s] for s in series])
|
||||
chart = (
|
||||
alt.Chart(df_long)
|
||||
.mark_line(point=True, strokeWidth=2)
|
||||
.encode(
|
||||
x=alt.X("Fecha:O", title=None),
|
||||
y=alt.Y("Valor:Q", title="€"),
|
||||
color=alt.Color("Serie:N", scale=color_scale, sort=series, legend=alt.Legend(title=None)),
|
||||
tooltip=["Fecha", "Serie", alt.Tooltip("Valor:Q", format=",.2f")],
|
||||
)
|
||||
.properties(height=height)
|
||||
)
|
||||
st.altair_chart(chart, width="stretch")
|
||||
|
||||
|
||||
def _daily_summary(rows: list[dict]) -> pd.DataFrame:
|
||||
"""Agrega Inversión/Ingreso/Margen día a día sumando las MetricasDiarias
|
||||
de todas las campañas dadas, más un margen alternativo calculado con el
|
||||
@ -340,24 +373,7 @@ with tab_resumen:
|
||||
if df_summary.empty:
|
||||
st.info("Sin métricas diarias disponibles para las campañas filtradas.")
|
||||
else:
|
||||
df_long = df_summary.melt("Fecha", var_name="Serie", value_name="Valor")
|
||||
serie_order = ["Inversión", "Ingreso", "Margen (sumatorio)", "Margen (PPL)"]
|
||||
color_scale = alt.Scale(
|
||||
domain=serie_order,
|
||||
range=["#2a78d6", "#1baf7a", "#4a3aa7", "#eb6834"],
|
||||
)
|
||||
chart = (
|
||||
alt.Chart(df_long)
|
||||
.mark_line(point=True, strokeWidth=2)
|
||||
.encode(
|
||||
x=alt.X("Fecha:O", title=None),
|
||||
y=alt.Y("Valor:Q", title="€"),
|
||||
color=alt.Color("Serie:N", scale=color_scale, sort=serie_order, legend=alt.Legend(title=None)),
|
||||
tooltip=["Fecha", "Serie", alt.Tooltip("Valor:Q", format=",.2f")],
|
||||
)
|
||||
.properties(height=320)
|
||||
)
|
||||
st.altair_chart(chart, width="stretch")
|
||||
_eur_line_chart(df_summary, ["Inversión", "Ingreso", "Margen (sumatorio)", "Margen (PPL)"])
|
||||
st.caption("Margen (sumatorio) = Ingreso reportado − Gasto · Margen (PPL) = Leads del día × PPL de campaña − Gasto")
|
||||
|
||||
st.divider()
|
||||
@ -610,14 +626,11 @@ with hist_camp_tab:
|
||||
df_ritmo = df_ritmo.set_index("Fecha")
|
||||
st.line_chart(df_ritmo[["Leads acum.", "Objetivo"]])
|
||||
|
||||
# Gráfico gasto vs revenue
|
||||
numeric_cols = [c for c in ["Gasto", "Revenue"] if c in df_daily.columns]
|
||||
if numeric_cols:
|
||||
st.markdown("**Gasto vs Revenue diario**")
|
||||
chart_data = df_daily[numeric_cols].copy()
|
||||
if "Fecha" in df_daily.columns:
|
||||
chart_data.index = df_daily["Fecha"]
|
||||
st.bar_chart(chart_data)
|
||||
# Gráfico gasto / ingreso / margen diario
|
||||
numeric_cols = [c for c in ["Gasto", "Revenue", "Margen"] if c in df_daily.columns]
|
||||
if numeric_cols and "Fecha" in df_daily.columns:
|
||||
st.markdown("**Gasto, ingreso y margen diario**")
|
||||
_eur_line_chart(df_daily.rename(columns={"Revenue": "Ingreso"}), ["Gasto", "Ingreso", "Margen"])
|
||||
|
||||
# Tabla detalle
|
||||
st.markdown("**Detalle diario**")
|
||||
@ -680,13 +693,10 @@ with hist_portfolio_tab:
|
||||
col_map[c] = "Fecha"
|
||||
gdf = gdf.rename(columns=col_map)
|
||||
|
||||
numeric_cols = [c for c in ["Gasto", "Revenue"] if c in gdf.columns]
|
||||
if numeric_cols:
|
||||
st.markdown("**Portfolio: Gasto vs Revenue diario**")
|
||||
chart_data = gdf[numeric_cols].copy()
|
||||
if "Fecha" in gdf.columns:
|
||||
chart_data.index = gdf["Fecha"]
|
||||
st.bar_chart(chart_data)
|
||||
numeric_cols = [c for c in ["Gasto", "Revenue", "Margen"] if c in gdf.columns]
|
||||
if numeric_cols and "Fecha" in gdf.columns:
|
||||
st.markdown("**Portfolio: gasto, ingreso y margen diario**")
|
||||
_eur_line_chart(gdf.rename(columns={"Revenue": "Ingreso"}), ["Gasto", "Ingreso", "Margen"])
|
||||
else:
|
||||
st.info("Sin datos de portfolio para el período seleccionado.")
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user