This guide is part of CRS Normalization Across Mixed Datasets, within the broader Automated Vector & Raster Cleaning Workflows reference.

Choosing a Projected CRS for Area and Distance

Every projection distorts something. Choosing one is choosing which distortion the pipeline can live with, and the choice is determined by what is being measured rather than by what looks familiar.

Why the Default Choice Is Usually Wrong

  • Degrees are not a length unit. A buffer of 0.001 in EPSG:4326 is 111 metres at the equator and 43 in Norway.
  • Web Mercator is a display projection. Its area error is over 400% at 65 degrees latitude, and it is the most common CRS in a spatial stack.
  • A single UTM zone does not cover a country. Distortion at the zone edge is around one part in a thousand and grows quickly beyond it.
  • The measurement CRS is rarely recorded. An area column with no accompanying CRS cannot be checked, only trusted.

Version and Environment Compatibility

Component Version Note
pyproj >=3.6 CRS.area_of_use, estimate_utm_crs, geodesic calculations
GeoPandas >=1.0 estimate_utm_crs on a frame; to_crs round trip
PROJ >=9.0 Modern equal-area definitions and grid transforms
pip install "geopandas>=1.0" "pyproj>=3.6"

Matching the Projection to the Quantity

What to project into, by what you are measuring A matrix of measured quantity against extent. Area over a country or continent takes an equal-area projection such as Albers or Lambert Azimuthal. Area or distance within one or two UTM zones takes UTM or the relevant national grid. Point-to-point distance over any extent is best computed geodesically on the ellipsoid rather than in any projection at all. measuring extent use area country or continent equal-area: Albers, Lambert Azimuthal, EPSG:6933 area or distance ≤ 2 UTM zones UTM zone, or the national grid where one exists point distance any geodesic on the ellipsoid — no projection at all nothing web display EPSG:3857 — and never measure anything in it

The measurement_crs Recipe

from __future__ import annotations

import logging

import geopandas as gpd
from pyproj import CRS, Geod

logger = logging.getLogger(__name__)
GEOD = Geod(ellps="WGS84")

# Continental equal-area systems, keyed by a rough extent test.
EQUAL_AREA = {
    "world": 6933,      # WGS 84 / NSIDC EASE-Grid 2.0 Global
    "europe": 3035,     # ETRS89-extended / LAEA Europe
    "north_america": 5070,  # NAD83 / Conus Albers
}


def measurement_crs(gdf: gpd.GeoDataFrame, quantity: str = "area") -> CRS:
    """Return a CRS whose distortion is acceptable for the quantity being measured."""
    if gdf.crs is None:
        raise ValueError("cannot choose a measurement CRS for a frame with no CRS")

    west, south, east, north = gdf.to_crs(4326).total_bounds
    span_deg = max(east - west, north - south)

    if quantity == "area" and span_deg > 12:
        # Wider than about two UTM zones: an equal-area projection is required.
        key = "europe" if (-25 < west < 45 and 34 < south < 72) else "world"
        chosen = CRS.from_epsg(EQUAL_AREA[key])
        logger.info("extent spans %.1f° — using equal-area %s", span_deg, chosen.name)
        return chosen

    chosen = gdf.estimate_utm_crs()
    logger.info("extent spans %.1f° — using local %s", span_deg, chosen.name)
    return chosen


def true_area_m2(gdf: gpd.GeoDataFrame) -> gpd.GeoSeries:
    """Area in square metres, measured in a CRS appropriate to the extent."""
    return gdf.to_crs(measurement_crs(gdf, "area")).geometry.area


def geodesic_length_m(gdf: gpd.GeoDataFrame) -> list[float]:
    """Length on the ellipsoid — exact, and independent of any projection."""
    wgs84 = gdf.to_crs(4326)
    return [GEOD.geometry_length(geom) for geom in wgs84.geometry]

Key Implementation Notes

  • The extent decides, not the country. A twelve-degree span is roughly two UTM zones, beyond which zone distortion exceeds what most area work tolerates.
  • estimate_utm_crs uses the frame’s centroid. It is the right default for local work and silently wrong for a dataset that straddles a zone boundary — hence the span check first.
  • Geodesic length needs no projection. Geod.geometry_length computes on the ellipsoid and is more accurate than any projected length, at the cost of being slower per feature.
  • The chosen CRS is logged, not just used. A measurement whose CRS is unrecorded cannot be reproduced or audited, which is the same argument made for area_crs in the metrics guidance.
  • Equal-area systems are listed explicitly. A lookup table of a few continental systems is more honest than a formula, because the right choice genuinely depends on the region’s conventions.
  • A missing CRS raises. Guessing a measurement system for an unreferenced frame produces numbers that look authoritative and are not.
The same parcel measured four ways A one square kilometre parcel at fifty-five degrees north measured in four coordinate systems. The equal-area projection and the UTM zone both return one square kilometre. The national grid returns the same to within a fraction of a percent. Web Mercator returns just over three square kilometres, because its area scale factor at that latitude is roughly three. true area 1.000 km² · parcel at 55° N EPSG:3035 equal-area 1.000 UTM zone 30N 1.000 national grid 1.001 EPSG:3857 web mercator 3.038 — not an area at all The Web Mercator figure is not noise: it is the correct answer to a different question, which is why it never announces itself as wrong.

Verifying the Choice

A projection choice is a hypothesis, and it is cheap to test. Take a feature whose true size is published — an administrative unit with a gazetted area, a survey parcel, a national park — measure it in the candidate CRS, and compare.

Checking a projection against a published area An administrative unit with a gazetted area of 412.6 square kilometres measured in three systems. The equal-area projection returns 412.6. A UTM zone covering the centre of the dataset returns 412.9. The same UTM zone applied at the dataset's eastern edge returns 414.8, which is the distortion growing away from the central meridian. gazetted area 412.6 km² · measured three ways equal-area projection · 412.6 km² exact across the whole dataset UTM, feature near the central meridian · 412.9 km² +0.07% UTM, same feature at the zone edge · 414.8 km² +0.53% Measure at the corners of the extent, not only at its centre — that is where a projection choice fails first.

Two checks are worth running as assertions rather than as a one-off. Measure the same feature in the chosen CRS and in a geodesic computation on the ellipsoid; agreement within a fraction of a percent confirms the projection is behaving over that extent. And measure a feature at each corner of the dataset’s extent, because distortion grows away from the projection’s centre and the corner cases are where it becomes visible.

Where the pipeline serves published figures, record both the measurement and its CRS in the output. The column costs nothing and it converts “these areas look wrong” from a dispute into a lookup.

Troubleshooting Measurement CRS Choices

Symptom Likely cause Fix
Areas inflated by 2–5× Measured in Web Mercator Reproject to an equal-area system first
Areas drift across a country Single UTM zone over too wide an extent Use an equal-area or national system
Buffers vary in size by latitude Buffering in degrees Project to metres before buffering
Lengths slightly short Projected length over a long feature Compute geodesically on the ellipsoid
Values changed after a library upgrade Different transform path selected Pin the CRS and the PROJ grids explicitly
Two teams report different areas Different measurement CRSs, both unrecorded Record the measurement CRS with the value

Integration Note

Measurement CRS selection belongs in the transform stage, not at ingestion: the storage CRS and the measurement CRS are different decisions, and conflating them forces every consumer to accept one projection’s distortions. Store geometry in the CRS the pipeline standardises on — usually the one described in CRS normalization across mixed datasets — and project transiently for each measurement, recording which system produced each figure.

Distance Is Three Different Questions

“How far apart are these?” hides three computations that differ by enough to matter.

Geodesic distance is the shortest path across the ellipsoid’s surface. It is what a navigator means, it needs no projection, and it is exact to millimetres over any distance. Use it for point-to-point separations and for anything crossing a projection boundary.

Projected distance is the straight line in a plane, which is what a spatial index, a buffer and a nearest-neighbour join all actually compute. It is exact only where the projection’s scale factor is one and close enough within a well-chosen local system. Use it for anything involving geometry operations, because those operations are planar regardless.

Network distance — along roads, rivers or pipes — is unrelated to both and usually the one a stakeholder means. No CRS choice produces it; it needs a routing engine, and confusing it with either of the above is a category error rather than a precision problem.

Stating which of the three a column holds, in its name or its metadata, prevents the most common misinterpretation in spatial analysis: a straight-line proximity figure being read as travel distance.