{"slug": "verify-waterfall-chart-arithmetic-from-a-csv-change-log-with-javascript", "title": "Verify waterfall chart arithmetic from a CSV change log with JavaScript", "summary": "Gixo founder Hardik published a JavaScript approach for verifying waterfall chart arithmetic from a CSV change log, converting parsed rows into start/end coordinates so each floating bar is drawn on the correct running balance. The example, executed in Node.js against synthetic data, checks intermediate balances as well as the closing total, rejecting nonfinite deltas and balance overflow, and warns that appending a derived Closing row as input would double the total to 236. It also covers negative balances, subtotal semantics, and precision policy for monetary values.", "body_md": "Disclosure: I’m Hardik, Gixo’s solo founder. AI agents drafted this article and code example. The code example was checked by executing it in Node.js. This is a standalone educational calculation using synthetic data.\n\nA waterfall chart describes how a balance changes. The height of a floating bar represents a movement; its position represents the running balance. Those are different quantities. A chart can show the right individual amounts while placing them on incorrect baselines.\n\nStart with this CSV:\n\n```\nStep,Amount\nOpening,100\nGrowth,25\nChurn,-7\n```\n\nDefine its meaning before drawing anything. Opening initializes the balance, Growth adds 25, and Churn subtracts 7. Every amount uses the same unit and reporting period. The expected closing balance is `100 + 25 - 7 = 118`.\n\nIn this example, the calculation begins at zero, so Opening is represented as an initial positive movement. A different chart API might accept an opening balance separately. Check that contract before passing it the same rows.\n\nAfter parsing the CSV, convert its rows into numeric changes. This function calculates the coordinates a renderer needs:\n\n``` js\nfunction bridge(changes) {\n  let balance = 0;\n  return changes.map(({ label, delta }) => {\n    if (!Number.isFinite(delta)) {\n      throw new TypeError('Delta must be finite');\n    }\n    const start = balance;\n    balance += delta;\n    if (!Number.isFinite(balance)) {\n      throw new RangeError('Balance overflow');\n    }\n    return { label, delta, start, end: balance };\n  });\n}\n\nconst rows = bridge([\n  { label: 'Opening', delta: 100 },\n  { label: 'Growth', delta: 25 },\n  { label: 'Churn', delta: -7 }\n]);\n\nconsole.log(rows.at(-1).end); // 118\n```\n\nThe function accepts numeric objects, not raw CSV text. Use a CSV parser that understands headers and quoted fields. Reject blank amount cells before converting them; a missing measurement should not silently become a zero.\n\nThe computed coordinates are:\n\n| Bar | Movement | Start | End | \n|---|---|---|---|\n| Opening | +100 | 0 | 100 | \n| Growth | +25 | 100 | 125 | \n| Churn | -7 | 125 | 118 | \n\nDraw Growth between 100 and 125, and Churn between 125 and 118. For each bar, map both endpoints onto the same value scale. Its top is the smaller screen coordinate, and its height is the distance between the two coordinates.\n\nA separate Total bar represents the final balance from zero to 118. It is derived output. Appending a Closing,118 input row would treat that balance as another movement and produce 236.\n\nCheck intermediate balances as well as the ending value. Two misclassified entries can cancel each other, leaving a correct total but an incorrect explanation. Sorting movements preserves their sum but changes the sequence and the intermediate balances readers see.\n\nSubtotals need explicit semantics. A Subtotal,125 row passed to this function adds 125; it does not mark a checkpoint. Keep subtotal records separate, or introduce a distinct record type that displays the current balance without changing it.\n\nNegative balances are valid arithmetic outcomes. Opening 20 followed by movements -35 and -25 produces -40. Include zero and every intermediate endpoint when choosing the scale. A negative movement does not necessarily mean a bad outcome: declining expenses may be desirable.\n\nFor monetary values, establish a precision policy. Integer minor units can avoid many decimal rounding surprises, but still need safe integer bounds. If you use decimal arithmetic or tolerances, document them and compare unformatted values before rounding labels.\n\nThe example was executed in Node.js and checked against all three expected running balances. Additional checks covered the -40 outcome, nonnumeric and nonfinite inputs, and balance overflow.\n\nArithmetic checks establish internal consistency. They cannot establish whether the source log contains every movement, uses the correct signs, or compares the same population. Keep those source checks alongside the chart rather than treating a reconciled total as proof of complete data.", "url": "https://wpnews.pro/news/verify-waterfall-chart-arithmetic-from-a-csv-change-log-with-javascript", "canonical_source": "https://dev.to/hardik_parikh_29/verify-waterfall-chart-arithmetic-from-a-csv-change-log-with-javascript-joc", "published_at": "2026-10-05 09:44:50+00:00", "updated_at": "2026-10-05 09:48:47.655146+00:00", "lang": "en", "topics": ["developer-tools"], "entities": ["Gixo", "Hardik", "Node.js"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/verify-waterfall-chart-arithmetic-from-a-csv-change-log-with-javascript", "markdown": "https://wpnews.pro/news/verify-waterfall-chart-arithmetic-from-a-csv-change-log-with-javascript.md", "text": "https://wpnews.pro/news/verify-waterfall-chart-arithmetic-from-a-csv-change-log-with-javascript.txt", "jsonld": "https://wpnews.pro/news/verify-waterfall-chart-arithmetic-from-a-csv-change-log-with-javascript.jsonld"}}