Skip to content

fix(Sankey): avoid exponential depth traversal on dense graphs#7479

Merged
PavelVanecek merged 3 commits into
recharts:mainfrom
dm-gthb:fix/sankey-layout-performance
Jul 4, 2026
Merged

fix(Sankey): avoid exponential depth traversal on dense graphs#7479
PavelVanecek merged 3 commits into
recharts:mainfrom
dm-gthb:fix/sankey-layout-performance

Conversation

@dm-gthb

@dm-gthb dm-gthb commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Description

Fix Sankey layout freezing on dense, heavily branching graphs by pruning depth assignment in updateDepthOfTargets.

When computing node depth (longest path from a source), the layout recurses into every target even when depth does not grow. On graphs where many paths share nodes, that re-walks every distinct path combinatorially. The freeze is not limited to very large datasets — it can happen with modest node/link counts when the graph branches heavily.

The fix only recurses when curNode.depth + 1 exceeds the target's current depth. Once depth stops increasing, the subtree is already correct.

Also exports computeData from Sankey.tsx for unit tests (same pattern as Treemap's computeNode). It is not added to src/index.ts, so the public API is unchanged. New test coverage is described below.

Related Issue

#7478

Motivation and Context

Sankey layout can freeze the browser when depth assignment must follow the longest path to each node. Without pruning, the layout walks every distinct path combinatorially.

Starting from relatively small graphs, this is already a problem — not only at “big data” scale. For example, the issue reproducer uses only 85 nodes and 112 links (makeBranchingChainData(28)).

The cost is driven by path count (how many distinct routes exist through shared nodes), not by raw node/link totals alone. Modest node/link counts can still hang when the graph branches heavily.

The fix is a small guard in updateDepthOfTargets. Existing Sankey tests that pin exact coordinates still pass, so layout geometry for typical graphs is unchanged.

How Has This Been Tested?

Added unit tests in test/chart/Sankey.spec.tsx covering the Sankey layout for large, heavily branching graphs:

  • Depth correctness: verifies a node's depth is the longest path from a source, even when links skip layers (e.g. a 0 -> 1 -> 2 chain plus a 0 -> 2 shortcut resolves node 2 to depth 2, not 1).
  • Performance regression guard: builds a chain of 28 branching segments (small node/link count but 2 ** 28 distinct paths) and asserts computeData returns all nodes with the expected max depth, completing well within vitest's default timeout — the previous, unfixed implementation would time out on this input.
  • Rendering: renders with the same branching graph and checks all node and link elements are present.

Screenshots (if appropriate):

N/A — performance fix with no visual change for existing graphs.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have added tests to cover my changes.
  • I have added a storybook story or VR test, or extended an existing story or VR test to show my changes

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Improved Sankey layout depth propagation to avoid redundant recalculations and better handle complex branching graphs, resulting in more reliable node positioning.
  • Tests

    • Added new Sankey tests using large, heavily branching datasets to verify depth assignment and expected rendered node/link counts.

@coderabbitai

coderabbitai Bot commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

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: b6143c89-7749-40e6-8375-f53a88cc22d1

📥 Commits

Reviewing files that changed from the base of the PR and between 0714cb1 and c749a48.

📒 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)
  • src/chart/Sankey.tsx
  • test/chart/Sankey.spec.tsx

Walkthrough

updateDepthOfTargets in Sankey.tsx now only recurses when a target depth increases, computeData is exported as a named API, and tests cover large branching Sankey layouts with depth and render-count assertions.

Changes

Sankey depth recursion guard and layout tests

Layer / File(s) Summary
Depth recursion guard and computeData export
src/chart/Sankey.tsx
updateDepthOfTargets now skips depth updates and recursion unless newDepth exceeds the current target depth, and computeData is exported.
Branching graph layout tests
test/chart/Sankey.spec.tsx
Imports computeData and adds a branching-graph suite that checks longest-path depth assignment, depth scaling, and rendered node/link counts.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related issues

Possibly related PRs

  • recharts/recharts#7471: Both PRs change the Sankey layout pipeline in src/chart/Sankey.tsx, including computeData-adjacent behavior.
  • Suggested reviewers: PavelVanecek
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the Sankey performance fix on dense graphs.
Description check ✅ Passed The description follows the template and includes the issue, motivation, testing, screenshots, change type, and checklist.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ 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.

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/chart/Sankey.spec.tsx`:
- Around line 860-866: In the test "renders a heavily branching graph without
freezing the main thread", add a call to advance pending timers (such as
jest.runAllTimers() or the appropriate timer advancement utility from the test
setup) immediately after the render call for the Sankey component and before the
expect assertions. This ensures all pending timers are flushed to prevent test
flakiness according to the project's coding guidelines.
🪄 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: 3ac562be-f752-4725-a557-9976b3c7b747

📥 Commits

Reviewing files that changed from the base of the PR and between 410cf5c and 0714cb1.

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

Comment thread test/chart/Sankey.spec.tsx
@codecov

codecov Bot commented Jun 20, 2026

Copy link
Copy Markdown

Bundle Report

Changes will increase total bundle size by 1.43kB (0.03%) ⬆️. This is within the configured threshold ✅

Detailed changes
Bundle name Size Change
recharts/bundle-cjs 1.44MB 3.08kB (0.21%) ⬆️
recharts/bundle-es6 1.27MB 2.9kB (0.23%) ⬆️
recharts/bundle-umd 584.99kB -4.9kB (-0.83%) ⬇️
recharts/bundle-treeshaking-sankey 382.0kB 355 bytes (0.09%) ⬆️

Affected Assets, Files, and Routes:

view changes for bundle: recharts/bundle-umd

Assets Changed:

Asset Name Size Change Total Size Change (%)
Recharts.js -4.9kB 584.99kB -0.83%
view changes for bundle: recharts/bundle-treeshaking-sankey

Assets Changed:

Asset Name Size Change Total Size Change (%)
bundle.js 355 bytes 382.0kB 0.09%
view changes for bundle: recharts/bundle-es6

Assets Changed:

Asset Name Size Change Total Size Change (%)
chart/Sankey.js 362 bytes 37.99kB 0.96%
theme/graphicalItemIdentity.js (New) 2.54kB 2.54kB 100.0% 🚀
view changes for bundle: recharts/bundle-cjs

Assets Changed:

Asset Name Size Change Total Size Change (%)
chart/Sankey.js 412 bytes 39.8kB 1.05%
theme/graphicalItemIdentity.js (New) 2.67kB 2.67kB 100.0% 🚀

@codecov

codecov Bot commented Jun 20, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 88.15%. Comparing base (0ed5fba) to head (c749a48).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #7479      +/-   ##
==========================================
+ Coverage   88.14%   88.15%   +0.01%     
==========================================
  Files         608      609       +1     
  Lines       14211    14229      +18     
  Branches     3567     3569       +2     
==========================================
+ Hits        12526    12544      +18     
  Misses       1495     1495              
  Partials      190      190              

☔ View full report in Codecov by Harness.
📢 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.

@dm-gthb

dm-gthb commented Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

@ckifer @PavelVanecek would appreciate a review when you have a moment - this fixes a freeze on dense branching graphs (#7478).

@PavelVanecek

Copy link
Copy Markdown
Collaborator

@dm-gthb may I ask you to resolve the merge conflicts please? (Sorry if this is posted multiple times, GitHub is showing me errors when I send)

@dm-gthb

dm-gthb commented Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

@PavelVanecek done, resolved the conflicts and merged latest main

@PavelVanecek
PavelVanecek merged commit 52a2a89 into recharts:main Jul 4, 2026
58 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