Tutorial

How to Calculate Area and Distance in GeoPandas (Correctly)

A common GIS mistake is to calculate polygon area or feature distance directly from data in a geographic CRS such as `EPSG:4326`.

Problem statement

A common GIS mistake is to calculate polygon area or feature distance directly from data in a geographic CRS such as EPSG:4326.

This usually produces wrong results because geographic coordinates are stored in degrees, not meters. GeoPandas will still return numeric values from .area, .length, or .distance(), but those values are based on the coordinate units of the geometry. If your data is in latitude/longitude, the numbers are not reliable for real-world measurement.

In practice, users are usually trying to do one of these tasks:

  • calculate polygon area
  • calculate line length
  • calculate distance between points or other features

The practical fix is to reproject the data to a suitable projected CRS first, then run the measurement.

Quick answer

To calculate area in GeoPandas or measure distance correctly:

  1. Check the current CRS with .crs
  2. Reproject to a suitable projected CRS with .to_crs()
  3. Use:
    • .area for polygon area
    • .length for line length
    • .distance() for distances between geometries
import geopandas as gpd

gdf = gpd.read_file("parcels.shp")

# Reproject to a projected CRS with suitable linear units
gdf_proj = gdf.to_crs("EPSG:32633")

# Polygon area in square meters if the CRS uses meters
gdf_proj["area_m2"] = gdf_proj.area

The output units come from the CRS units. In many projected CRSs those units are meters, but some projected CRSs use other units such as feet.

Step-by-step solution

Check the current CRS

Start by checking whether your layer is in a geographic CRS like EPSG:4326.

import geopandas as gpd

gdf = gpd.read_file("parcels.shp")
print(gdf.crs)

If you see something like EPSG:4326, your coordinates are in degrees. That is fine for storage and web mapping, but not for accurate area and distance measurements.

Choose a suitable projected CRS

You need a projected CRS that fits your study area and task.

Common practical choices:

  • Local UTM zone for city or regional data
  • National projected CRS for country-specific workflows
  • Equal-area CRS when area accuracy is the main priority

Examples:

  • EPSG:32633 — UTM zone 33N (only appropriate for data in that zone)
  • EPSG:27700 — British National Grid
  • EPSG:5070 — NAD83 / Conus Albers for US-wide area analysis

For small to medium study areas, a local UTM CRS is often a good default. For large regions, CRS choice matters more because one projected CRS may not preserve both area and distance equally well everywhere.

Reproject the GeoDataFrame

Use .to_crs() to create a projected copy.

gdf_proj = gdf.to_crs("EPSG:32633")

This keeps the original gdf unchanged and gives you a new GeoDataFrame for measurement.

Calculate polygon area

After reprojection, use .area.

gdf_proj["area_m2"] = gdf_proj.area

If the CRS uses meters, the result is square meters.

You can also convert to hectares or square kilometers:

gdf_proj["area_ha"] = gdf_proj["area_m2"] / 10_000
gdf_proj["area_km2"] = gdf_proj["area_m2"] / 1_000_000

Calculate line length

For roads, rivers, or utility lines, use .length after reprojection.

lines = gpd.read_file("roads.shp")
lines_proj = lines.to_crs("EPSG:32633")

lines_proj["length_m"] = lines_proj.length
lines_proj["length_km"] = lines_proj["length_m"] / 1000

Calculate distance between two geometries

Use .distance() when comparing geometries in the same projected CRS.

points = gpd.read_file("sites.shp").to_crs("EPSG:32633")

distance_m = points.geometry.iloc[0].distance(points.geometry.iloc[1])
print(distance_m)

For two layers, both must use the same CRS:

schools = gpd.read_file("schools.shp").to_crs("EPSG:32633")
hospitals = gpd.read_file("hospitals.shp").to_crs("EPSG:32633")

schools["dist_to_first_hospital_m"] = schools.geometry.distance(
    hospitals.geometry.iloc[0]
)

Code examples

Example 1: Calculate polygon area in square meters

import geopandas as gpd

parcels = gpd.read_file("data/parcels.shp")
print("Original CRS:", parcels.crs)

# Reproject to a projected CRS with meter units
parcels_proj = parcels.to_crs("EPSG:32633")

# Calculate area
parcels_proj["area_m2"] = parcels_proj.area

print(parcels_proj[["area_m2"]].head())

# Optional: save result
parcels_proj.to_file("output/parcels_with_area.shp")

Example 2: Convert area to hectares and square kilometers

parcels_proj["area_ha"] = parcels_proj["area_m2"] / 10_000
parcels_proj["area_km2"] = parcels_proj["area_m2"] / 1_000_000

print(parcels_proj[["area_m2", "area_ha", "area_km2"]].head())

Example 3: Calculate line length in meters

import geopandas as gpd

roads = gpd.read_file("data/roads.shp")
roads_proj = roads.to_crs("EPSG:32633")

roads_proj["length_m"] = roads_proj.length

print(roads_proj[["length_m"]].head())

Example 4: Calculate distance between points

import geopandas as gpd

origins = gpd.read_file("data/origins.shp").to_crs("EPSG:32633")
destinations = gpd.read_file("data/destinations.shp").to_crs("EPSG:32633")

origins["distance_to_first_dest_m"] = origins.geometry.distance(
    destinations.geometry.iloc[0]
)

print(origins[["distance_to_first_dest_m"]].head())

Example 5: Calculate nearest-feature distance

A practical pattern is to find the nearest feature in another layer, then measure the distance.

import geopandas as gpd

buildings = gpd.read_file("data/buildings.shp").to_crs("EPSG:32633")
bus_stops = gpd.read_file("data/bus_stops.shp").to_crs("EPSG:32633")

nearest = gpd.sjoin_nearest(
    buildings,
    bus_stops,
    how="left",
    distance_col="nearest_dist_m"
)

print(nearest[["nearest_dist_m"]].head())

Note: gpd.sjoin_nearest() requires a recent GeoPandas version and a working spatial index backend in your environment.

Explanation

The key issue is the difference between a geographic CRS and a projected CRS.

A geographic CRS stores coordinates on the earth using angular units such as latitude and longitude. EPSG:4326 is the most common example. In this CRS, coordinates are in degrees, so geometry calculations based on raw coordinate values do not represent meters or square meters.

A projected CRS transforms the curved earth surface into a flat coordinate system. Its units are often meters or feet. That makes it suitable for planar measurements such as area, line length, and distance between features.

GeoPandas does not automatically decide whether your CRS is appropriate for measurement. It simply uses the geometry coordinates as they are:

  • .area returns area in CRS units squared
  • .length returns length in CRS units
  • .distance() returns distance in CRS units

So if your data is in degrees, your output is also degree-based, which is usually not what you want.

For accurate GeoPandas area calculation and distance measurement, reproject first, then measure.

Edge cases and notes

Data in EPSG:4326 gives misleading results

You can run .area or .distance() on data in EPSG:4326, but the results are not suitable for real-world measurement. The values may look valid because they are numeric, but they are based on degrees.

Missing CRS metadata

If gdf.crs is None, do not use .to_crs() yet. First assign the correct existing CRS with .set_crs(), then reproject if needed.

gdf = gdf.set_crs("EPSG:4326")
gdf_proj = gdf.to_crs("EPSG:32633")

Both layers must use the same CRS for distance calculations

If you calculate distance between two layers, align both to the same projected CRS first.

layer1 = layer1.to_crs("EPSG:32633")
layer2 = layer2.to_crs("EPSG:32633")

Multipolygon and multiline geometries

Multipart geometries still work with .area and .length. The result is the total area or total length of the full geometry.

Large study areas need careful CRS selection

A single local projected CRS may work well for one city or region but perform poorly across a continent. If you are measuring over large areas, choose a CRS designed for that extent and purpose. For some large-extent workflows, a geodesic approach may be more appropriate than using one projected CRS for everything.

Geometry validity can affect results

Invalid polygons can produce unreliable area values. If results look wrong, check geometry validity.

invalid = ~gdf.geometry.is_valid
print(gdf[invalid])

If needed, repair invalid geometries before measurement.

Internal links

For the CRS background behind this workflow, see Geographic vs Projected CRS in GeoPandas.

If you need the reprojection step itself, read How to Reproject Spatial Data in Python (GeoPandas).

For line-specific measurement workflows, see How to Calculate Line Length in GeoPandas.

If your numbers still look incorrect, check Why GeoPandas Area or Distance Values Are Wrong.

FAQ

How do I calculate area in GeoPandas in square meters?

Reproject your polygon layer to a projected CRS that uses meters, then use .area.

gdf_proj = gdf.to_crs("EPSG:32633")
gdf_proj["area_m2"] = gdf_proj.area

Why is GeoPandas giving incorrect area or distance values?

The most common reason is that your data is in a geographic CRS such as EPSG:4326. In that case, coordinates are in degrees, so area and distance calculations are not in meters.

What CRS should I use to calculate distance in GeoPandas?

Use a projected CRS appropriate for your study area. For regional work, a local UTM zone is often a practical choice. For country-scale or area-focused analysis, a national or equal-area CRS may be better.

Do both GeoDataFrames need the same CRS for .distance()?

Yes. Both layers should be in the same projected CRS before running .distance() or nearest-distance workflows.

Can I calculate area directly in EPSG:4326?

You can, but the result will not be a reliable real-world area measurement. For correct values, reproject first.

Keep exploring with more guides in this category.