Measuring Areas and Distances#
Understanding how to measure areas and distances is a key part of working with spatial data — and it’s no coincidence that this section comes right after the blocks on coordinate systems.
That’s because accurate calculations of distance, area, and even buffer zones all depend heavily on the coordinate reference system (CRS) you’re using.
If your data is in a geographic CRS (like WGS 84), coordinates are expressed in degrees, which are not suitable for direct distance or area calculations.
To get correct results in meters or square meters, your data needs to be projected into an appropriate projected CRS, like UTM.
In this section, we’ll explore how to measure distances and areas correctly — and why choosing the right projection is essential.
Import libraries#
import geopandas as gpd
import pandas as pd
import osmnx as ox
Export City Boundary#
admin_border = ox.geocode_to_gdf('Vienna, Austria')
admin_border.explore(tiles='cartodbpositron')
In GeoPandas, every GeoDataFrame has a special attribute called .geometry
, which stores the geometric shapes of the spatial features — for example, points, lines, or polygons.
This attribute gives you direct access to the geometry of each object in your dataset.
Once you have access to the geometry, you can perform various spatial operations.
One particularly useful method is .area
, which calculates the area of each polygon feature.
But here’s an important note: the .area
method returns correct values only if your data is in a projected CRS (like UTM), where coordinates are in meters.
If your data is still in degrees (e.g., EPSG:4326), the area values will be meaningless.
Now that we’ve reprojected our dataset into a suitable UTM zone, we can safely use the .area
method to calculate the area of each polygon.
Let’s create a new column called "area"
in our admin_okrug
GeoDataFrame and store the calculated area values there:
admin_okrug["area"] = admin_okrug.geometry.area
admin_border['area'] = admin_border.geometry.area
admin_border.head()
/var/folders/ry/9bb7wrz54vq_kn2ytlj6ynzm0000gn/T/ipykernel_49378/1924210537.py:1: UserWarning: Geometry is in a geographic CRS. Results from 'area' are likely incorrect. Use 'GeoSeries.to_crs()' to re-project geometries to a projected CRS before this operation.
admin_border['area'] = admin_border.geometry.area
geometry | bbox_west | bbox_south | bbox_east | bbox_north | place_id | osm_type | osm_id | lat | lon | class | type | place_rank | importance | addresstype | name | display_name | area | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | POLYGON ((16.18183 48.17112, 16.1819 48.17103,... | 16.181831 | 48.117907 | 16.577513 | 48.322668 | 408340724 | relation | 109166 | 48.208354 | 16.372504 | boundary | administrative | 7 | 0.818783 | city | Vienna | Vienna, Austria | 0.050199 |
And here’s the problem — the area values look strange and way too small. What’s going on?
Let’s think back to the coordinate system of this layer… it’s geographic, which means the units are in degrees, not meters.
As a result, all area calculations are also in degrees² — which isn’t meaningful for real-world measurements.
🛑 Always pay attention to the “UserWarning” you might see when calculating areas (like we did above). It often points out that the results are likely incorrect because the data is still in a geographic CRS. It also reminds you that you need to reproject your data to a suitable projected CRS to get accurate results.
admin_border_utm = admin_border.to_crs(admin_border.estimate_utm_crs())
admin_border_utm['area_utm'] = admin_border_utm.geometry.area
admin_border_utm.head()
geometry | bbox_west | bbox_south | bbox_east | bbox_north | place_id | osm_type | osm_id | lat | lon | class | type | place_rank | importance | addresstype | name | display_name | area | area_utm | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | POLYGON ((587866.661 5335995.06, 587872.091 53... | 16.181831 | 48.117907 | 16.577513 | 48.322668 | 408340724 | relation | 109166 | 48.208354 | 16.372504 | boundary | administrative | 7 | 0.818783 | city | Vienna | Vienna, Austria | 0.050199 | 4.146378e+08 |
Now that looks more realistic — and yes, the values are in square meters!
This kind of notation might not be familiar to everyone, so let’s break it down with an example:
4.146378e+08
means 4.146378 × 108, i.e., 414,637,800 square meters, which is 414.6378 square kilometers (≈ 414.6 km²).
Summary#
In this section, we covered how to measure areas and distances correctly in GeoPandas.
We learned to:
Recognize that geographic CRS (e.g., EPSG:4326) stores coordinates in degrees, which aren’t suitable for measurements.
Reproject data to an appropriate projected CRS (e.g., UTM) using to get results in meters and square meters.
With the right CRS, distance, area, and buffer calculations become accurate and reliable.