Skip to content

Prevent overlapping PolarAngleAxis ticks#6611

Merged
ckifer merged 2 commits intomainfrom
polarangleaxis-duplicate-ticks
Nov 12, 2025
Merged

Prevent overlapping PolarAngleAxis ticks#6611
ckifer merged 2 commits intomainfrom
polarangleaxis-duplicate-ticks

Conversation

@PavelVanecek
Copy link
Collaborator

@PavelVanecek PavelVanecek commented Nov 12, 2025

Description

Recharts sometimes renders duplicated ticks on angles 0 and 360, depending on how many ticks d3 decides to render. So let's add a condition to protect against that.

Related Issue

I couldn't find anyone complaining about it but we had plenty of examples in our own storybook.

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

    • Fixed polar angle axis rendering to prevent duplicate ticks at the 0/360-degree boundary, improving chart clarity.
  • Tests

    • Updated polar angle axis test suite to validate corrected tick deduplication.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 12, 2025

Walkthrough

The PR introduces a specialized tick selector for polar angle axes that deduplicates ticks mapped to the same circular position (0/360 degrees), updates component and test references to use this new selector, removes a console warning ignore pattern from test helpers, and adjusts test expectations to remove 360-degree tick assertions.

Changes

Cohort / File(s) Summary
Test Infrastructure Updates
omnidoc/omnidoc.spec.ts, test/helper/consoleWarningToError.ts
Added vitest test import to omnidoc tests. Removed the 'Encountered two children with the same key' warning from the ignore list in console warning handler.
Polar Angle Axis Selector & Component
src/state/selectors/polarScaleSelectors.ts, src/polar/PolarAngleAxis.tsx
Introduced new selectPolarAngleAxisTicks selector that deduplicates ticks at 0/360-degree positions by normalizing coordinates to 0–359.999 range and retaining first occurrence. Updated PolarAngleAxis.tsx to use this new selector instead of generic selectPolarAxisTicks.
Test Expectations Update
test/polar/PolarAngleAxis.spec.tsx
Removed assertions for 360-degree tick and corresponding label from two test blocks, reflecting expected output change after tick deduplication.

Sequence Diagram

sequenceDiagram
    participant Component as PolarAngleAxis Component
    participant Selector as selectPolarAngleAxisTicks
    participant CoreSelector as selectPolarAxisTicks
    participant Store as Redux State

    Component->>Selector: Request angle axis ticks
    Selector->>CoreSelector: Get all ticks for angleAxis
    CoreSelector->>Store: Query ticks from state
    Store-->>CoreSelector: Return raw ticks array
    CoreSelector-->>Selector: Return ticks
    Selector->>Selector: Normalize tick angles to 0–359.999
    Selector->>Selector: Deduplicate by position (keep first)
    Selector-->>Component: Return deduplicated ticks
    Note over Selector: Removes 360° duplicates of 0°
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • The new selectPolarAngleAxisTicks selector introduces deduplication logic for circular coordinates—verify the normalization and deduplication algorithm correctly handles edge cases at 0/360 boundary.
  • Test expectation removals in PolarAngleAxis.spec.tsx must align with the intended behavior change and shouldn't mask unrelated rendering issues.
  • Confirm the selector import reorganization in PolarAngleAxis.tsx maintains correct module resolution.

Possibly related PRs

Suggested reviewers

  • ckifer

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely describes the main change: preventing duplicate/overlapping ticks at 0 and 360 degrees on polar angle axes.
Description check ✅ Passed The PR description covers key sections including description of the problem, types of changes, and completed checklist items. However, the 'Related Issue' and 'Motivation and Context' sections lack detail, and 'How Has This Been Tested' is not explicitly addressed.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch polarangleaxis-duplicate-ticks

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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/state/selectors/polarScaleSelectors.ts (1)

99-122: Consider floating-point precision when comparing coordinates.

The deduplication logic correctly normalizes circular coordinates and removes duplicates. However, using floating-point tick.coordinate values directly as Map keys could lead to near-duplicate angles being treated as distinct (e.g., 0.0000001 and 0.0000002).

If coordinates are always integers or have controlled precision, this is fine. Otherwise, consider rounding to a fixed precision before using as a Map key:

  const uniqueTicksMap = new Map<number, CartesianTickItem>();
  ticks.forEach(tick => {
-   const normalizedCoordinate = (tick.coordinate + 360) % 360;
+   const normalizedCoordinate = Math.round(((tick.coordinate + 360) % 360) * 1e10) / 1e10;
    if (!uniqueTicksMap.has(normalizedCoordinate)) {
      uniqueTicksMap.set(normalizedCoordinate, tick);
    }
  });

Verify whether tick coordinates can have floating-point precision issues by checking how D3 generates these values:

#!/bin/bash
# Description: Check how tick coordinates are generated and if they're integers or floats

# Search for where CartesianTickItem coordinates are assigned
ast-grep --pattern 'coordinate: $_'

# Look for D3 tick generation
rg -n -C3 'ticks\(\)' --type=ts --type=tsx
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8964e36 and fcbb429.

⛔ Files ignored due to path filters (30)
  • test-vr/__snapshots__/tests/RadialBarChart.spec-vr.tsx-snapshots/Reversed-Angle-Axis-1-chromium-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/RadialBarChart.spec-vr.tsx-snapshots/Reversed-Angle-Axis-1-firefox-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/RadialBarChart.spec-vr.tsx-snapshots/Reversed-Angle-Axis-1-webkit-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/RadialBarChart.spec-vr.tsx-snapshots/Reversed-Both-Axes-1-chromium-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/RadialBarChart.spec-vr.tsx-snapshots/Reversed-Both-Axes-1-firefox-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/RadialBarChart.spec-vr.tsx-snapshots/Reversed-Both-Axes-1-webkit-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/RadialBarChart.spec-vr.tsx-snapshots/Reversed-Radius-Axis-1-chromium-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/RadialBarChart.spec-vr.tsx-snapshots/Reversed-Radius-Axis-1-firefox-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/RadialBarChart.spec-vr.tsx-snapshots/Reversed-Radius-Axis-1-webkit-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/RadialBarChart.spec-vr.tsx-snapshots/Rings-With-Custom-Domain-1-chromium-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/RadialBarChart.spec-vr.tsx-snapshots/Rings-With-Custom-Domain-1-firefox-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/RadialBarChart.spec-vr.tsx-snapshots/Rings-With-Custom-Domain-1-webkit-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/RadialBarChart.spec-vr.tsx-snapshots/Rings-With-Data-Keys-1-chromium-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/RadialBarChart.spec-vr.tsx-snapshots/Rings-With-Data-Keys-1-firefox-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/RadialBarChart.spec-vr.tsx-snapshots/Rings-With-Data-Keys-1-webkit-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/RadialBarChart.spec-vr.tsx-snapshots/Rings-With-Data-Keys-And-Types-1-chromium-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/RadialBarChart.spec-vr.tsx-snapshots/Rings-With-Data-Keys-And-Types-1-firefox-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/RadialBarChart.spec-vr.tsx-snapshots/Rings-With-Data-Keys-And-Types-1-webkit-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/RadialBarChart.spec-vr.tsx-snapshots/Rings-With-Default-Axes-1-chromium-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/RadialBarChart.spec-vr.tsx-snapshots/Rings-With-Default-Axes-1-firefox-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/RadialBarChart.spec-vr.tsx-snapshots/Rings-With-Default-Axes-1-webkit-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/RadialBarChart.spec-vr.tsx-snapshots/Rings-With-Radius-Axis-Vertically-1-chromium-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/RadialBarChart.spec-vr.tsx-snapshots/Rings-With-Radius-Axis-Vertically-1-firefox-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/RadialBarChart.spec-vr.tsx-snapshots/Rings-With-Radius-Axis-Vertically-1-webkit-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/RadialBarChart.spec-vr.tsx-snapshots/Rings-With-Types-1-chromium-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/RadialBarChart.spec-vr.tsx-snapshots/Rings-With-Types-1-firefox-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/RadialBarChart.spec-vr.tsx-snapshots/Rings-With-Types-1-webkit-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/RadialBarChart.spec-vr.tsx-snapshots/Stacked-RadialBar-Chart-1-chromium-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/RadialBarChart.spec-vr.tsx-snapshots/Stacked-RadialBar-Chart-1-firefox-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/RadialBarChart.spec-vr.tsx-snapshots/Stacked-RadialBar-Chart-1-webkit-linux.png is excluded by !**/*.png
📒 Files selected for processing (5)
  • omnidoc/omnidoc.spec.ts (1 hunks)
  • src/polar/PolarAngleAxis.tsx (2 hunks)
  • src/state/selectors/polarScaleSelectors.ts (1 hunks)
  • test/helper/consoleWarningToError.ts (0 hunks)
  • test/polar/PolarAngleAxis.spec.tsx (0 hunks)
💤 Files with no reviewable changes (2)
  • test/polar/PolarAngleAxis.spec.tsx
  • test/helper/consoleWarningToError.ts
🧰 Additional context used
📓 Path-based instructions (1)
src/**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Do not hardcode any user-facing strings or formatting choices in the library code; leave internationalization to library users

Files:

  • src/polar/PolarAngleAxis.tsx
  • src/state/selectors/polarScaleSelectors.ts
🧠 Learnings (7)
📚 Learning: 2025-10-25T07:35:46.188Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-10-25T07:35:46.188Z
Learning: Applies to test/**/vitest.setup.ts : Ensure vi.useFakeTimers() is configured in the Vitest setup file

Applied to files:

  • omnidoc/omnidoc.spec.ts
📚 Learning: 2025-10-25T07:35:46.188Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-10-25T07:35:46.188Z
Learning: Write unit tests using Vitest and React Testing Library

Applied to files:

  • omnidoc/omnidoc.spec.ts
📚 Learning: 2025-10-25T07:36:02.229Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-25T07:36:02.229Z
Learning: When running unit tests, prefer running a single test file via: npm run test -- path/to/TestFile.spec.tsx

Applied to files:

  • omnidoc/omnidoc.spec.ts
📚 Learning: 2025-10-25T07:35:46.188Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-10-25T07:35:46.188Z
Learning: Applies to test/**/*.test.{ts,tsx} : Prefer using the createSelectorTestCase helper when writing or modifying tests

Applied to files:

  • omnidoc/omnidoc.spec.ts
📚 Learning: 2025-10-25T07:35:46.188Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-10-25T07:35:46.188Z
Learning: Applies to test/**/*.test.{ts,tsx} : When using user-event, initialize with userEvent.setup({ advanceTimers: vi.runOnlyPendingTimers }) or use test/helper/userEventSetup.ts

Applied to files:

  • omnidoc/omnidoc.spec.ts
📚 Learning: 2025-10-25T07:35:46.188Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-10-25T07:35:46.188Z
Learning: Applies to test/**/*.test.{ts,tsx} : Avoid vi.runAllTimers() in tests to prevent infinite loops caused by chained scheduled timers

Applied to files:

  • omnidoc/omnidoc.spec.ts
📚 Learning: 2025-10-25T07:36:02.229Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-25T07:36:02.229Z
Learning: Recharts aims for simple, declarative, and composable charts; prioritize consistency, usability, performance, and accessibility

Applied to files:

  • src/polar/PolarAngleAxis.tsx
🧬 Code graph analysis (2)
src/polar/PolarAngleAxis.tsx (2)
src/state/hooks.ts (1)
  • useAppSelector (40-50)
src/state/selectors/polarScaleSelectors.ts (1)
  • selectPolarAngleAxisTicks (99-122)
src/state/selectors/polarScaleSelectors.ts (3)
src/state/store.ts (1)
  • RechartsRootState (94-94)
src/state/cartesianAxisSlice.ts (1)
  • AxisId (8-8)
src/util/types.ts (1)
  • CartesianTickItem (769-773)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Build, Test, Pack
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (3)
omnidoc/omnidoc.spec.ts (1)

1-1: LGTM!

The addition of the test import is correct and necessary for the test.each usage on lines 139 and 160.

src/polar/PolarAngleAxis.tsx (2)

20-20: LGTM!

The import change correctly updates to use the specialized angle axis tick selector.


260-260: LGTM!

The selector usage is correct and properly integrates the new deduplication logic for angle axis ticks. The parameters match the expected signature, and the return type is compatible with the existing code flow.

@codecov
Copy link

codecov bot commented Nov 12, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.16%. Comparing base (8964e36) to head (fcbb429).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #6611   +/-   ##
=======================================
  Coverage   94.16%   94.16%           
=======================================
  Files         493      493           
  Lines       41067    41081   +14     
  Branches     4773     4778    +5     
=======================================
+ Hits        38671    38685   +14     
  Misses       2391     2391           
  Partials        5        5           

☔ 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
Copy link

codecov bot commented Nov 12, 2025

Bundle Report

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

Detailed changes
Bundle name Size Change
recharts/bundle-cjs 1.12MB 682 bytes (0.06%) ⬆️
recharts/bundle-es6 967.33kB 607 bytes (0.06%) ⬆️
recharts/bundle-umd 509.5kB 138 bytes (0.03%) ⬆️

Affected Assets, Files, and Routes:

view changes for bundle: recharts/bundle-cjs

Assets Changed:

Asset Name Size Change Total Size Change (%)
polar/PolarAngleAxis.js 5 bytes 11.88kB 0.04%
state/selectors/polarScaleSelectors.js 677 bytes 3.48kB 24.14% ⚠️
view changes for bundle: recharts/bundle-umd

Assets Changed:

Asset Name Size Change Total Size Change (%)
Recharts.js 138 bytes 509.5kB 0.03%
view changes for bundle: recharts/bundle-es6

Assets Changed:

Asset Name Size Change Total Size Change (%)
polar/PolarAngleAxis.js 10 bytes 10.55kB 0.09%
state/selectors/polarScaleSelectors.js 597 bytes 2.85kB 26.51% ⚠️

@ckifer ckifer merged commit b086656 into main Nov 12, 2025
28 of 29 checks passed
@ckifer ckifer deleted the polarangleaxis-duplicate-ticks branch November 12, 2025 17:22
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