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:
|
def _daily_summary(rows: list[dict]) -> pd.DataFrame:
|
||||||
"""Agrega Inversión/Ingreso/Margen día a día sumando las MetricasDiarias
|
"""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
|
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:
|
if df_summary.empty:
|
||||||
st.info("Sin métricas diarias disponibles para las campañas filtradas.")
|
st.info("Sin métricas diarias disponibles para las campañas filtradas.")
|
||||||
else:
|
else:
|
||||||
df_long = df_summary.melt("Fecha", var_name="Serie", value_name="Valor")
|
_eur_line_chart(df_summary, ["Inversión", "Ingreso", "Margen (sumatorio)", "Margen (PPL)"])
|
||||||
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")
|
|
||||||
st.caption("Margen (sumatorio) = Ingreso reportado − Gasto · Margen (PPL) = Leads del día × PPL de campaña − Gasto")
|
st.caption("Margen (sumatorio) = Ingreso reportado − Gasto · Margen (PPL) = Leads del día × PPL de campaña − Gasto")
|
||||||
|
|
||||||
st.divider()
|
st.divider()
|
||||||
@ -610,14 +626,11 @@ with hist_camp_tab:
|
|||||||
df_ritmo = df_ritmo.set_index("Fecha")
|
df_ritmo = df_ritmo.set_index("Fecha")
|
||||||
st.line_chart(df_ritmo[["Leads acum.", "Objetivo"]])
|
st.line_chart(df_ritmo[["Leads acum.", "Objetivo"]])
|
||||||
|
|
||||||
# Gráfico gasto vs revenue
|
# Gráfico gasto / ingreso / margen diario
|
||||||
numeric_cols = [c for c in ["Gasto", "Revenue"] if c in df_daily.columns]
|
numeric_cols = [c for c in ["Gasto", "Revenue", "Margen"] if c in df_daily.columns]
|
||||||
if numeric_cols:
|
if numeric_cols and "Fecha" in df_daily.columns:
|
||||||
st.markdown("**Gasto vs Revenue diario**")
|
st.markdown("**Gasto, ingreso y margen diario**")
|
||||||
chart_data = df_daily[numeric_cols].copy()
|
_eur_line_chart(df_daily.rename(columns={"Revenue": "Ingreso"}), ["Gasto", "Ingreso", "Margen"])
|
||||||
if "Fecha" in df_daily.columns:
|
|
||||||
chart_data.index = df_daily["Fecha"]
|
|
||||||
st.bar_chart(chart_data)
|
|
||||||
|
|
||||||
# Tabla detalle
|
# Tabla detalle
|
||||||
st.markdown("**Detalle diario**")
|
st.markdown("**Detalle diario**")
|
||||||
@ -680,13 +693,10 @@ with hist_portfolio_tab:
|
|||||||
col_map[c] = "Fecha"
|
col_map[c] = "Fecha"
|
||||||
gdf = gdf.rename(columns=col_map)
|
gdf = gdf.rename(columns=col_map)
|
||||||
|
|
||||||
numeric_cols = [c for c in ["Gasto", "Revenue"] if c in gdf.columns]
|
numeric_cols = [c for c in ["Gasto", "Revenue", "Margen"] if c in gdf.columns]
|
||||||
if numeric_cols:
|
if numeric_cols and "Fecha" in gdf.columns:
|
||||||
st.markdown("**Portfolio: Gasto vs Revenue diario**")
|
st.markdown("**Portfolio: gasto, ingreso y margen diario**")
|
||||||
chart_data = gdf[numeric_cols].copy()
|
_eur_line_chart(gdf.rename(columns={"Revenue": "Ingreso"}), ["Gasto", "Ingreso", "Margen"])
|
||||||
if "Fecha" in gdf.columns:
|
|
||||||
chart_data.index = gdf["Fecha"]
|
|
||||||
st.bar_chart(chart_data)
|
|
||||||
else:
|
else:
|
||||||
st.info("Sin datos de portfolio para el período seleccionado.")
|
st.info("Sin datos de portfolio para el período seleccionado.")
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user