Skip to content

fix(Sankey): prevent NaN node positions when link values sum to zero#7185

Merged
ckifer merged 2 commits into
recharts:mainfrom
Mridul012:fix/sankey-zero-division
Apr 3, 2026
Merged

fix(Sankey): prevent NaN node positions when link values sum to zero#7185
ckifer merged 2 commits into
recharts:mainfrom
Mridul012:fix/sankey-zero-division

Conversation

@Mridul012

@Mridul012 Mridul012 commented Mar 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes a division-by-zero issue in Sankey layout that can produce NaN node positions when link values sum to 0.

Problem

In relaxLeftToRight and relaxRightToLeft, node positions are computed using:

weightedSum / sourceSum
weightedSum / targetSum

When sourceSum or targetSum is 0, this results in NaN, which propagates and breaks the layout.

Fix

Added guards to handle zero sums:

  • Fallback to centerY(node) when sourceSum === 0
  • Fallback to centerY(node) when targetSum === 0

Tests

Added a regression test to ensure:

  • No NaN node positions are produced when link values are zero

Impact

  • Prevents layout corruption in edge cases
  • No impact on normal datasets

Summary by CodeRabbit

  • Bug Fixes

    • Improved Sankey chart handling of zero-value links to prevent invalid layout values and ensure stable rendering (nodes with no flow are omitted while links remain valid).
  • Tests

    • Added tests covering zero-value link scenarios, asserting node rendering rules and that generated path data contains no invalid numbers.

@coderabbitai

coderabbitai Bot commented Mar 29, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0937d614-bdc1-4e7d-aa75-3cb291553568

📥 Commits

Reviewing files that changed from the base of the PR and between a0fe1bb and eab9311.

📒 Files selected for processing (2)
  • src/chart/Sankey.tsx
  • test/chart/Sankey.spec.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • test/chart/Sankey.spec.tsx
  • src/chart/Sankey.tsx

Walkthrough

Guard against division-by-zero in Sankey layout: three methods in src/chart/Sankey.tsx now fallback to centerY(node) or clamp yRatio when depth-level sums are zero. Tests added to validate rendering with zero-valued links.

Changes

Cohort / File(s) Summary
Sankey layout calculation guards
src/chart/Sankey.tsx
Added zero-sum checks in updateYOfTree, relaxLeftToRight, and relaxRightToLeft; use Infinity/clamp semantics for yRatio and centerY(node) as fallback when sums are zero to avoid Infinity/NaN.
Sankey zero-value tests
test/chart/Sankey.spec.tsx
Added tests covering all-zero links[].value and mixed zero/positive scenarios; assert node/link rendering behavior and that link path d and stroke-width are finite and contain no NaN.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • PavelVanecek
  • ckifer
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description covers the problem, fix, and tests, but is missing several required template sections: Related Issue link, detailed testing methodology, Screenshots section, Types of changes checkboxes, and completion of the Checklist items. Add the missing template sections: link the related issue, describe testing environment and test execution details, complete the Types of changes and Checklist sections with appropriate checkmarks.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the primary change: fixing NaN node positions in Sankey when link values sum to zero, matching the code modifications in updateYOfTree, relaxLeftToRight, and relaxRightToLeft.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
test/chart/Sankey.spec.tsx (1)

741-767: Good regression test for the all-zero case.

The test correctly validates that NaN values don't appear in link paths when all link values are zero.

Consider adding a companion test with mixed link values (e.g., { source: 0, target: 1, value: 100 }, { source: 1, target: 2, value: 0 }) to ensure nodes with positive values still render correctly. This would guard against regressions in the yRatio calculation for datasets where only some links have zero values.

,

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/chart/Sankey.spec.tsx` around lines 741 - 767, Add a companion test to
Sankey.spec.tsx that renders the Sankey component with mixed link values (e.g.,
links [{ source: 0, target: 1, value: 100 }, { source: 1, target: 2, value: 0
}]) and assert that nodes with positive aggregated value render (query
'.recharts-sankey-node' and expect length > 0), links render without NaN in
their path 'd' attribute and have finite 'stroke-width', so we validate the
yRatio/layout logic handles mixed zero/non-zero link values correctly when using
the Sankey component.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/chart/Sankey.tsx`:
- Around line 207-212: The current yRatio calculation returns 0 for any depth
with sum===0 which makes Math.min pick 0 and collapse positive-valued nodes;
instead, when mapping depthTree use Infinity as the fallback for sum===0 so
Math.min correctly ignores empty depths (use sumBy, getValue, nodePadding,
height in that mapping), then after computing yRatio = Math.min(...candidates)
add a special case: if yRatio === Infinity set yRatio = 0 (handles the all-zero
case). This preserves previous behavior for mixed and all-zero scenarios.

---

Nitpick comments:
In `@test/chart/Sankey.spec.tsx`:
- Around line 741-767: Add a companion test to Sankey.spec.tsx that renders the
Sankey component with mixed link values (e.g., links [{ source: 0, target: 1,
value: 100 }, { source: 1, target: 2, value: 0 }]) and assert that nodes with
positive aggregated value render (query '.recharts-sankey-node' and expect
length > 0), links render without NaN in their path 'd' attribute and have
finite 'stroke-width', so we validate the yRatio/layout logic handles mixed
zero/non-zero link values correctly when using the Sankey component.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3b81251a-15a3-4d1c-bb0e-e3ab3aa4eb92

📥 Commits

Reviewing files that changed from the base of the PR and between fc96239 and a0fe1bb.

📒 Files selected for processing (2)
  • src/chart/Sankey.tsx
  • test/chart/Sankey.spec.tsx

Comment thread src/chart/Sankey.tsx Outdated
@codecov

codecov Bot commented Mar 30, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 89.06%. Comparing base (fc96239) to head (eab9311).
⚠️ Report is 15 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #7185   +/-   ##
=======================================
  Coverage   89.06%   89.06%           
=======================================
  Files         539      539           
  Lines       41011    41017    +6     
  Branches     5553     5557    +4     
=======================================
+ Hits        36527    36533    +6     
  Misses       4476     4476           
  Partials        8        8           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@codecov

codecov Bot commented Mar 30, 2026

Copy link
Copy Markdown

Bundle Report

Changes will increase total bundle size by 432 bytes (0.01%) ⬆️. This is within the configured threshold ✅

Detailed changes
Bundle name Size Change
recharts/bundle-cjs 1.3MB 177 bytes (0.01%) ⬆️
recharts/bundle-es6 1.13MB 177 bytes (0.02%) ⬆️
recharts/bundle-umd 547.98kB 78 bytes (0.01%) ⬆️

Affected Assets, Files, and Routes:

view changes for bundle: recharts/bundle-umd

Assets Changed:

Asset Name Size Change Total Size Change (%)
Recharts.js 78 bytes 547.98kB 0.01%
view changes for bundle: recharts/bundle-cjs

Assets Changed:

Asset Name Size Change Total Size Change (%)
chart/Sankey.js 177 bytes 32.24kB 0.55%
view changes for bundle: recharts/bundle-es6

Assets Changed:

Asset Name Size Change Total Size Change (%)
chart/Sankey.js 177 bytes 30.48kB 0.58%

@Mridul012

Copy link
Copy Markdown
Contributor Author

Thanks for the review, Please let me know if any further changes are needed.

@ckifer
ckifer merged commit 0f5689c into recharts:main Apr 3, 2026
52 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants