from_template: use CF Conventions metadata instead of crs_units/crs_name#3532
Merged
Conversation
Replace the ad-hoc crs_units/crs_name attrs with CF grid-mapping keys grid_mapping_name + crs_wkt (via pyproj.CRS.to_cf, best-effort) and move units onto the x/y coordinates with CF standard_names. EPSG:4326 axes use degrees_east/degrees_north; projected axes use metres.
brendancol
commented
Jun 26, 2026
brendancol
left a comment
Contributor
Author
There was a problem hiding this comment.
PR Review: from_template — CF Conventions metadata
Blockers
None.
Suggestions
- Flat attrs vs. a real CF grid mapping (
templates.py:325,:338-345). Strict CF putsgrid_mapping_nameon a separate scalar grid-mapping variable that the data variable points to via agrid_mappingattribute; here bothgrid_mapping_nameand the coordinatestandard_names sit directly on the data variable. That matches how this library already models CRS (flat attrs,crs/crs_wkt), so it's a reasonable call — but a strict CF reader like cf_xarray won't auto-detect it as a grid mapping. Worth a one-line docstring caveat, or a follow-up if fuller CF encoding is ever wanted. Not blocking. - Narrower exception catch than before (
templates.py:194-200)._cf_crs_attrscatches onlyImportError; the old_crs_namealso swallowedValueError/TypeError. Every caller passes a curated/queried EPSG int, sofrom_epsg().to_cf()won't fail in practice — but if an unknown code ever reached here it would now raise instead of degrading to "no CF keys." Low risk given current call sites; flagging for awareness.
Nits
- Inconsistent wrapping (
templates.py:339-345). The 4326 branch keeps.attrs.update(...)on one line (83 chars) while the projected branch wraps onto two. Both fit the 100-char limit; pick one style for symmetry.
What looks good
- Clean swap: no code outside the tests still reads
crs_units/crs_namefrom a template, so nothing downstream breaks. crs_wktlines up with the geotiff layer, which already documentscrs/crs_wktas the canonical, additive CRS keys.- Test coverage is solid — both coordinate flavors, both grid-mapping branches, plus the two real edge cases (Equal Earth has no CF mapping, and the pyproj-absent fallback).
brendancol
commented
Jun 26, 2026
brendancol
left a comment
Contributor
Author
There was a problem hiding this comment.
Follow-up review (after fixes)
Re-reviewed the two follow-up commits. Disposition of the first-pass findings:
- Nit — inconsistent wrapping: fixed. Both branches of the coordinate-units block now use single-line
.attrs.update(...)(all within the 100-char limit). - Suggestion — flat attrs vs. CF grid-mapping variable: addressed by docstring. The
Returnssection now states the keys sit onattrs(the library's flat CRS convention), not a separate CF grid-mapping variable, so a strict CF reader won't auto-detect them. - Suggestion — narrower exception catch in
_cf_crs_attrs: dismissed. Every call site passes a curated or pyproj-queried EPSG int, sofrom_epsg().to_cf()can't fail in practice. CLAUDE.md asks for no error handling on unreachable paths, so I left the catch scoped toImportError(the only real branch — the dependency-free fallback).
flake8 clean; test_templates.py green (51 passed). No blockers outstanding.
brendancol
added a commit
that referenced
this pull request
Jun 26, 2026
7 tasks
brendancol
added a commit
that referenced
this pull request
Jun 26, 2026
) * Add world-city bounding-box templates to from_template (#3533) 519 cities (national capitals + metros >=1.2M pop) from Natural Earth, each in its UTM zone (EPSG:326xx/327xx). Wired into _resolve between the curated regions and country codes; preserve='area'/'shape' work as for nyc. * Add city tests and flake8/isort-clean formatting (#3533) - 5 tests: registry integrity over all 519 cities, sample builds, UTM spot-checks, case-insensitivity, name-collision disambiguation. - Reformat generated _CITIES entries to a hanging indent (flake8 max-line 100) and apply isort to the touched imports. * Document world-city templates: rst, README, user-guide notebook (#3533) * Address review nit: exercise southern-hemisphere city build path (#3533) Add sao_paulo/sydney (327xx) to test_city_sample_builds so the southern build is explicit, not only implied by the UTM spot-checks. Discoverability suggestion deferred to follow-up #3535 (new public listing API needs its own design). * Reconcile city templates with CF-metadata switch from main #3532 (#3533) main replaced crs_units/crs_name with CF grid-mapping attrs. Update the city sample test to assert CF coord units (x.units=='m', standard_name) and the notebook to print grid_mapping_name instead of crs_name. * Add recognizable US secondary cities to from_template (#3533) Natural Earth's POP_MAX/SCALERANK underrate US metros (Las Vegas listed at 17k, scalerank 8), so a population cutoff misses Austin, New Orleans, Las Vegas, Portland, etc. Add a curated US name list (top match per name) run through the same UTM-zone + metro-buffer machinery. 519 -> 558 cities.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #3531.
from_templatewas tagging its output with two non-standard attrs,crs_unitsandcrs_name. This swaps them for CF (Climate and Forecast) Conventions metadata, the standard xarray and the geoscience stack already use.Changes
crs_units. Units now live on thex/ycoordinates where they belong. EPSG:4326 axes getdegrees_east/degrees_north(was a non-CF'degree'); projected axes getm, each with the matching CFstandard_name(longitude/latitude,projection_x_coordinate/projection_y_coordinate).crs_namewith the CF grid-mapping keysgrid_mapping_name(e.g.albers_conical_equal_area) andcrs_wkt(full WKT, which carries the human-readable name). This lines up with the rest of the library, which keys offcrs/crs_wkt.pyproj.CRS.to_cf(), kept best-effort: without pyproj the default path stays dependency-free and the keys are omitted, same ascrs_namebefore. Equal Earth has no CF grid mapping, sogrid_mapping_nameis left off there andcrs_wktstands alone.Backends
Metadata-only change; behaviour is identical across numpy / cupy / dask+numpy / dask+cupy.
Test plan
test_cf_coordinate_units— CF units +standard_nameon x/y, nocrs_unitstest_cf_grid_mapping_attrs—grid_mapping_name+crs_wkt, nocrs_nametest_cf_grid_mapping_preserve_path— preserve path keys presenttest_grid_mapping_omitted_for_equal_earth—crs_wktonly for 8857test_cf_attrs_omitted_without_pyproj— graceful dependency-free fallbacktest_templates.pysuite green (51 passed)