{"spec_id":"waterfall-basic","library":"plotly","language":"python","code":"\"\"\" anyplot.ai\nwaterfall-basic: Basic Waterfall Chart\nLibrary: plotly 6.9.0 | Python 3.13.14\nQuality: 91/100 | Updated: 2026-08-04\n\"\"\"\n\nimport os\nimport sys\n\n\n_orig_path = sys.path[:]\nsys.path = [p for p in sys.path if p != os.path.dirname(__file__) and p != os.getcwd()]\nimport plotly.graph_objects as go\n\n\nsys.path = _orig_path\n\n# Theme colors\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\nGRID = \"rgba(26,26,23,0.10)\" if THEME == \"light\" else \"rgba(240,239,232,0.10)\"\n\n# Imprint palette\nCOLOR_POSITIVE = \"#009E73\"  # brand green (first series) — increases\nCOLOR_NEGATIVE = \"#AE3030\"  # matte red — decreases (semantic loss anchor)\nCOLOR_TOTAL = \"#4467A3\"  # blue — start/end totals\n\n# Data - Quarterly financial breakdown from revenue to net income\ncategories = [\"Revenue\", \"Product Costs\", \"Operating Expenses\", \"Marketing\", \"Other Income\", \"Taxes\", \"Net Income\"]\n\n# Values: positive for increases, negative for decreases\n# Revenue is the starting total, Net Income is the ending total\nvalues = [500000, -180000, -95000, -45000, 25000, -51250, 153750]\n\n# Define measure types: absolute for start, relative for changes, total for end\nmeasures = [\"absolute\", \"relative\", \"relative\", \"relative\", \"relative\", \"relative\", \"total\"]\n\n# Running/cumulative total after each step, so intermediate bars can display it\nrunning_totals = []\ncumulative = 0\nfor value, measure in zip(values, measures, strict=True):\n    cumulative = value if measure != \"relative\" else cumulative + value\n    running_totals.append(cumulative)\n\n# Bar labels: delta amount for relative steps (with the running total below it),\n# and the total itself for the absolute/total anchor bars\nbar_labels = [\n    f\"${value:,.0f}\"\n    if measure != \"relative\"\n    else f\"{'+' if value >= 0 else '-'}${abs(value):,.0f}<br>(${running_total:,.0f})\"\n    for value, measure, running_total in zip(values, measures, running_totals, strict=True)\n]\n\n# Create waterfall chart using Plotly's native Waterfall trace\nfig = go.Figure(\n    go.Waterfall(\n        name=\"Financial Breakdown\",\n        orientation=\"v\",\n        measure=measures,\n        x=categories,\n        y=values,\n        textposition=\"outside\",\n        text=bar_labels,\n        textfont={\"size\": 13, \"color\": INK},\n        connector={\"line\": {\"color\": INK_SOFT, \"width\": 1.5, \"dash\": \"dot\"}},\n        decreasing={\"marker\": {\"color\": COLOR_NEGATIVE}},\n        increasing={\"marker\": {\"color\": COLOR_POSITIVE}},\n        totals={\"marker\": {\"color\": COLOR_TOTAL}},\n        showlegend=False,\n    )\n)\n\n# Add dummy traces for legend (to explain colors)\nfig.add_trace(\n    go.Scatter(\n        x=[None],\n        y=[None],\n        mode=\"markers\",\n        marker={\"size\": 10, \"color\": COLOR_POSITIVE},\n        name=\"Increases\",\n        showlegend=True,\n        legendgroup=\"colors\",\n        hoverinfo=\"skip\",\n    )\n)\n\nfig.add_trace(\n    go.Scatter(\n        x=[None],\n        y=[None],\n        mode=\"markers\",\n        marker={\"size\": 10, \"color\": COLOR_NEGATIVE},\n        name=\"Decreases\",\n        showlegend=True,\n        legendgroup=\"colors\",\n        hoverinfo=\"skip\",\n    )\n)\n\nfig.add_trace(\n    go.Scatter(\n        x=[None],\n        y=[None],\n        mode=\"markers\",\n        marker={\"size\": 10, \"color\": COLOR_TOTAL},\n        name=\"Totals\",\n        showlegend=True,\n        legendgroup=\"colors\",\n        hoverinfo=\"skip\",\n    )\n)\n\n# Update layout for 3200x1800 px canvas with theme colors\nfig.update_layout(\n    autosize=False,\n    title={\n        \"text\": \"waterfall-basic · python · plotly · anyplot.ai\",\n        \"font\": {\"size\": 19, \"color\": INK},\n        \"x\": 0.5,\n        \"xanchor\": \"center\",\n    },\n    xaxis={\n        \"title\": {\"text\": \"Category\", \"font\": {\"size\": 12, \"color\": INK}},\n        \"tickfont\": {\"size\": 10, \"color\": INK_SOFT},\n        \"linecolor\": INK_SOFT,\n        \"showgrid\": False,\n    },\n    yaxis={\n        \"title\": {\"text\": \"Amount ($)\", \"font\": {\"size\": 12, \"color\": INK}},\n        \"tickfont\": {\"size\": 10, \"color\": INK_SOFT},\n        \"tickformat\": \"$,.0f\",\n        \"showgrid\": True,\n        \"gridwidth\": 1,\n        \"gridcolor\": GRID,\n        \"linecolor\": INK_SOFT,\n    },\n    paper_bgcolor=PAGE_BG,\n    plot_bgcolor=PAGE_BG,\n    font={\"color\": INK},\n    template=\"plotly_white\",\n    showlegend=True,\n    legend={\n        \"x\": 0.98,\n        \"y\": 0.98,\n        \"xanchor\": \"right\",\n        \"yanchor\": \"top\",\n        \"bgcolor\": \"rgba(0,0,0,0)\" if THEME == \"light\" else \"rgba(255,255,255,0)\",\n        \"borderwidth\": 0,\n        \"font\": {\"size\": 10, \"color\": INK_SOFT},\n    },\n    margin={\"t\": 90, \"b\": 70, \"l\": 100, \"r\": 40},\n)\n\n# Save as PNG and HTML with theme-suffixed filenames\nfig.write_image(f\"plot-{THEME}.png\", width=800, height=450, scale=4)\nfig.write_html(f\"plot-{THEME}.html\", include_plotlyjs=\"cdn\")\n"}