feat: add GenesysCX study and fix Streamlit chart key collisions
- Add 202512_GenesysCX TEI study (config, seed data, notebooks, README) with NPV $10.8M / ROI 266% including AI-token cost line - Add explicit `key` parameter to all chart wrappers in app/components to prevent StreamlitDuplicateElementId errors when the same figure type renders across Summary/Benefits/Costs tabs - Render benefits bar and cost pie charts on their respective tabs - Add benefits_vs_costs_by_year chart wrapper
This commit is contained in:
@@ -1,4 +1,9 @@
|
||||
"""Streamlit-friendly chart wrappers (delegate to core.notebook_helpers.charts)."""
|
||||
"""Streamlit-friendly chart wrappers (delegate to core.notebook_helpers.charts).
|
||||
|
||||
Every wrapper takes a ``key`` — the same figure type renders on multiple
|
||||
tabs (Summary, Benefits, Costs) within one script run, so Streamlit needs
|
||||
explicit element IDs to avoid StreamlitDuplicateElementId errors.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -7,26 +12,31 @@ import streamlit as st
|
||||
from core.notebook_helpers import charts as core_charts
|
||||
|
||||
|
||||
def cashflow(yearly_breakdown, *, initial_cost: float = 0.0) -> None:
|
||||
def cashflow(yearly_breakdown, *, initial_cost: float = 0.0, key: str = "cashflow") -> None:
|
||||
fig = core_charts.cashflow_chart(yearly_breakdown, initial_cost=initial_cost)
|
||||
st.plotly_chart(fig, width="stretch")
|
||||
st.plotly_chart(fig, width="stretch", key=key)
|
||||
|
||||
|
||||
def benefits_bar(items) -> None:
|
||||
def benefits_bar(items, *, key: str = "benefits_bar") -> None:
|
||||
fig = core_charts.benefits_bar(items)
|
||||
st.plotly_chart(fig, width="stretch")
|
||||
st.plotly_chart(fig, width="stretch", key=key)
|
||||
|
||||
|
||||
def cost_pie(items) -> None:
|
||||
def cost_pie(items, *, key: str = "cost_pie") -> None:
|
||||
fig = core_charts.cost_breakdown_pie(items)
|
||||
st.plotly_chart(fig, width="stretch")
|
||||
st.plotly_chart(fig, width="stretch", key=key)
|
||||
|
||||
|
||||
def scenario_bars(scenarios) -> None:
|
||||
def benefits_vs_costs_by_year(benefit_items, cost_items, *, key: str = "by_year") -> None:
|
||||
fig = core_charts.benefits_vs_costs_by_year(benefit_items, cost_items)
|
||||
st.plotly_chart(fig, width="stretch", key=key)
|
||||
|
||||
|
||||
def scenario_bars(scenarios, *, key: str = "scenario_bars") -> None:
|
||||
fig = core_charts.scenario_comparison(scenarios)
|
||||
st.plotly_chart(fig, width="stretch")
|
||||
st.plotly_chart(fig, width="stretch", key=key)
|
||||
|
||||
|
||||
def waterfall(values) -> None:
|
||||
def waterfall(values, *, key: str = "waterfall") -> None:
|
||||
fig = core_charts.waterfall(values)
|
||||
st.plotly_chart(fig, width="stretch")
|
||||
st.plotly_chart(fig, width="stretch", key=key)
|
||||
|
||||
Reference in New Issue
Block a user