Skip to content

Add global-projection templates to from_template (web_mercator, wgs84/latlon, equal_earth)#3550

Merged
brendancol merged 4 commits into
mainfrom
issue-3549
Jun 27, 2026
Merged

Add global-projection templates to from_template (web_mercator, wgs84/latlon, equal_earth)#3550
brendancol merged 4 commits into
mainfrom
issue-3549

Conversation

@brendancol

Copy link
Copy Markdown
Contributor

Closes #3549

Adds whole-world templates to from_template, each resolving to a real EPSG code:

  • web_mercator -> EPSG:3857 (WGS 84 / Pseudo-Mercator)
  • equal_earth -> EPSG:8857 (Equal Earth, the equal-area option)
  • wgs84 and latlon -> aliases for the existing EPSG:4326 world grid (single source of truth via a small _REGION_ALIASES map)

Robinson, Gall-Peters, and Mollweide were requested but only have ESRI codes, not EPSG. Storing those as a bare int would be ambiguous with EPSG and would break the CF metadata path, so they are left out; equal_earth covers the equal-area case with a real EPSG code. The reasoning is written up in the issue.

The new names go through the same backend dispatch as the rest of from_template, so numpy, cupy, dask+numpy, and dask+cupy all work with no new backend-specific code. The dask path stays lazy (da.full).

Test plan

  • pytest xrspatial/tests/test_templates.py (80 passed, including the cupy and dask backends that run on this box)
  • Contract checks for all four names (dims, all-NaN, float32, crs int, north-up coords)
  • wgs84/latlon produce the same grid and attrs as world
  • Case-insensitive lookup, exact-resolution honoring, metre coords within bounds
  • CF grid-mapping: 3857 and 8857 have no grid_mapping_name, so crs_wkt carries the name
  • Verified the web_mercator dask grid stays lazy

Add web_mercator (EPSG:3857), equal_earth (EPSG:8857), and wgs84/latlon
aliases for the EPSG:4326 world grid. All resolve to real EPSG codes so
attrs['crs'] stays an int. Reuses the existing backend dispatch, so all
four backends work.

@brendancol brendancol left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

PR Review: Add global-projection templates to from_template

Blockers (must fix before merge)

None.

Suggestions (should fix, not blocking)

  • xrspatial/_template_data.py: the web_mercator and equal_earth entries carry area_epsg=8857 / shape_epsg=3395, so from_template('web_mercator', preserve='shape') will reproject a global template into yet another projection. That combination works but is odd, and nothing tests it. Either add a one-line build test or drop the keys if preserve-on-global is out of scope.

Nits (optional improvements)

  • xrspatial/_template_data.py: the Web Mercator latitude limit is written as 85.051129, but the exact value is 85.0511287798. It only matters on the rarely-used preserve path, so it is cosmetic. The nearby comment cites the precise definition, which makes the rounded literal look slightly off.

What looks good

  • wgs84/latlon reuse the world grid through _REGION_ALIASES rather than copying the bounds, so there is one source of truth.
  • All four projections resolve to real EPSG ints, matching the project convention. The ESRI-only projections (Robinson, Gall-Peters, Mollweide) are documented as deliberately left out.
  • No new backend code: coverage comes from the existing _make_data dispatch, and the dask path stays lazy via da.full.
  • Tests cover the array contract, the alias-equals-world check, case-insensitive lookup, exact resolution, bounds containment, and the CF grid-mapping behavior for 3857/8857.

Checklist

  • Algorithm matches reference (EPSG codes and projected bounds verified with pyproj)
  • All implemented backends produce consistent results (shared dispatch)
  • NaN handling is correct (NaN-filled, asserted)
  • Edge cases covered (case-insensitive, exact resolution, bounds)
  • Dask chunk boundaries handled (lazy da.full, no overlap needed)
  • No premature materialization
  • Benchmark not needed (no compute kernel)
  • README feature matrix updated
  • Docstrings present and accurate

@brendancol brendancol left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Follow-up review (after commit b1719cb)

Both items from the first pass are resolved.

  • Suggestion (preserve on global templates): kept the area_epsg/shape_epsg hints, since they match the world entry and steer preserve='shape' to World Mercator (EPSG:3395) instead of a stray UTM zone for the (0, 0) centroid. Added test_global_preserve_picks_world_projection to lock that in for both web_mercator and equal_earth.
  • Nit (latitude limit): the Web Mercator lonlat band now uses the exact 85.0511287798, matching the comment.

No new findings. Tests: 82 passed locally (numpy, cupy, dask backends).

@brendancol brendancol merged commit d9516e9 into main Jun 27, 2026
12 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.

Add global-projection templates to from_template (web_mercator, wgs84/latlon, equal_earth)

1 participant