Skip to content

Fix geo projections losing their D3 default rotation - #7976

Open
CAOShurong wants to merge 6 commits into
plotly:masterfrom
CAOShurong:codex/geo-d3-default-rotation
Open

Fix geo projections losing their D3 default rotation#7976
CAOShurong wants to merge 6 commits into
plotly:masterfrom
CAOShurong:codex/geo-d3-default-rotation

Conversation

@CAOShurong

Copy link
Copy Markdown
Contributor

Problem

Geo.updateProjection sets projection.rotate([-rotation.lon, -rotation.lat, rotation.roll]) unconditionally. Since projection.rotation defaults to [0, 0, 0], the rotation the d3 projection factory ships with is discarded for the six projections that carry a non-identity default (albers [96, 0, 0], bertin1953, gringorten and peirce quincuncial [-90, -90, 45], sinu mollweide, wiechel) — #7949.

Fix

Capture the factory rotation when the projection wrapper is created (projection.defaultRotation) and compose the user rotation on top of it:

.rotate([
    -rotation.lon + projection.defaultRotation[0],
    -rotation.lat + projection.defaultRotation[1],
    rotation.roll + projection.defaultRotation[2]
])
  • projections whose d3 default is the identity (the large majority) produce exactly the same rotation as before in every case;
  • at default projection.rotation, the six affected projections now keep their canonical orientation (the reported bug);
  • an explicit user rotation now composes relative to the canonical orientation rather than replacing it — for the six projections this changes the meaning of explicit values that were previously compensating for the wiped default; for all other projections explicit behavior is unchanged. The composition semantics are the natural reading of projection.rotation as additional rotation on top of the projection's own orientation, and are what makes both defaults and explicit values consistent without tracking whether each attribute was user-set.

Test

Adds a regression spec asserting albers keeps [96, 0, 0] at defaults, composes (96 - 10) when rotation.lon: 10 is set, and that mercator stays exactly [0, 0, 0].

Fixes #7949

CAOShurong and others added 6 commits August 23, 2026 02:42
Geo.updateProjection unconditionally called
projection.rotate([-rotation.lon, -rotation.lat, rotation.roll]), so the
default projection.rotation attributes ([0, 0, 0]) discarded the rotation
the d3 projection factory ships with. Six projections are affected
(albers, bertin1953, gringorten and peirce quincuncial, sinu mollweide,
wiechel).

Capture the factory rotation when the projection wrapper is created and
compose the user rotation on top of it. Projections whose d3 default is
the identity are bit-for-bit unchanged; an explicit rotation now rotates
relative to the projection's canonical orientation instead of replacing
it.

Fixes plotly#7949
The composed d3 factory rotation can carry float64 dust depending on
platform math (e.g. 96.00000000000001 on linux runners), so exact
toEqual/toBe assertions are environment-dependent. Assert each axis
with a tight 1e-9 tolerance instead.
Regenerated from the exact CI environment (kaleido 1.2 / plotly 6.6.0,
linux render): the three sheets containing the six affected projections
change because their default orientation now follows the d3-geo factory
rotation instead of forcing [0,0,0]. Verified deterministic across two
independent CI runs (byte-identical PNGs); all other mocks unchanged.
The previous commit regenerated baselines in a local Windows kaleido
environment; the committed bytes were the local render, not the CI
render, so test-baselines still failed. Replace with the artifacts
produced by the CI make-baselines jobs themselves (verified sha256-
identical to the CI uploads).
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.

[BUG]: geo projections lose their D3 default rotation

1 participant