Python interface to PROJ library for cartographic projections and coordinate transformations
—
Geodesic operations compute the shortest path (great circle) between points on a sphere or ellipsoid. PyProj provides comprehensive geodesic calculations including distance, azimuth, area, and intermediate point computations using the GeographicLib algorithms for high accuracy.
Create Geod objects for geodesic computations on specific ellipsoids with various initialization options.
class Geod:
def __init__(
self,
initstring: str | None = None,
a: float | None = None,
b: float | None = None,
f: float | None = None,
es: float | None = None,
rf: float | None = None,
ellps: str | None = None,
sphere: bool = False,
**kwargs
) -> None:
"""
Create a Geod object for geodesic computations.
Args:
initstring: Initialization string (e.g., 'ellps=WGS84')
a: Semi-major axis of ellipsoid in meters
b: Semi-minor axis of ellipsoid in meters
f: Flattening of ellipsoid
es: Eccentricity squared of ellipsoid
rf: Reciprocal flattening of ellipsoid
ellps: Ellipsoid name (e.g., 'WGS84', 'GRS80')
sphere: Use spherical approximation
**kwargs: Additional ellipsoid parameters
Raises:
GeodError: If ellipsoid parameters are invalid or inconsistent
"""
@property
def a(self) -> float:
"""Semi-major axis of ellipsoid in meters."""
@property
def b(self) -> float:
"""Semi-minor axis of ellipsoid in meters."""
@property
def f(self) -> float:
"""Flattening of ellipsoid."""
@property
def es(self) -> float:
"""Eccentricity squared of ellipsoid."""
@property
def initstring(self) -> str:
"""Initialization string used to create Geod object."""Compute positions and azimuths from starting points, initial bearings, and distances.
class Geod:
def fwd(
self,
lons,
lats,
az,
dist,
radians: bool = False,
return_back_azimuth: bool = False
) -> tuple:
"""
Forward geodesic computation from points, azimuths, and distances.
Args:
lons: Longitude(s) of starting point(s) in degrees
lats: Latitude(s) of starting point(s) in degrees
az: Azimuth(s) in degrees from north (0-360)
dist: Distance(s) in meters
radians: Input/output coordinates in radians
return_back_azimuth: Return back azimuth at destination
Returns:
If return_back_azimuth is False: (end_lons, end_lats)
If return_back_azimuth is True: (end_lons, end_lats, back_azimuths)
Raises:
GeodError: If computation fails or inputs are invalid
"""
def fwd_intermediate(
self,
lon1: float,
lat1: float,
azi1: float,
dist: float,
npts: int,
del_s: float | None = None,
initial_idx: int = 0,
terminus_idx: int = 0,
flags: GeodIntermediateFlag = GeodIntermediateFlag.DEFAULT,
radians: bool = False,
return_back_azimuth: bool = False
) -> GeodIntermediateReturn:
"""
Forward geodesic with intermediate points.
Args:
lon1: Starting longitude in degrees
lat1: Starting latitude in degrees
azi1: Starting azimuth in degrees
dist: Total distance in meters
npts: Number of intermediate points
del_s: Distance between points (alternative to npts)
initial_idx: Starting index for point generation
terminus_idx: Ending index for point generation
flags: Flags for intermediate calculation behavior
radians: Input/output in radians
return_back_azimuth: Return back azimuths
Returns:
GeodIntermediateReturn object with points and metadata
Raises:
GeodError: If parameters are inconsistent or calculation fails
"""Compute distances, azimuths, and paths between pairs of points.
class Geod:
def inv(
self,
lons1,
lats1,
lons2,
lats2,
radians: bool = False,
return_back_azimuth: bool = False
) -> tuple:
"""
Inverse geodesic computation between point pairs.
Args:
lons1: Longitude(s) of first point(s) in degrees
lats1: Latitude(s) of first point(s) in degrees
lons2: Longitude(s) of second point(s) in degrees
lats2: Latitude(s) of second point(s) in degrees
radians: Input coordinates in radians
return_back_azimuth: Return back azimuth from point 2 to point 1
Returns:
If return_back_azimuth is False: (forward_azimuths, distances)
If return_back_azimuth is True: (forward_azimuths, back_azimuths, distances)
Raises:
GeodError: If computation fails or coordinates are invalid
"""
def inv_intermediate(
self,
lon1: float,
lat1: float,
lon2: float,
lat2: float,
npts: int,
del_s: float | None = None,
initial_idx: int = 0,
terminus_idx: int = 0,
flags: GeodIntermediateFlag = GeodIntermediateFlag.DEFAULT,
radians: bool = False,
return_back_azimuth: bool = False
) -> GeodIntermediateReturn:
"""
Inverse geodesic with intermediate points.
Args:
lon1: First point longitude in degrees
lat1: First point latitude in degrees
lon2: Second point longitude in degrees
lat2: Second point latitude in degrees
npts: Number of intermediate points
del_s: Distance between points (alternative to npts)
initial_idx: Starting index for point generation
terminus_idx: Ending index for point generation
flags: Flags for intermediate calculation behavior
radians: Input/output in radians
return_back_azimuth: Return back azimuths
Returns:
GeodIntermediateReturn object with points and metadata
Raises:
GeodError: If points are identical or calculation fails
"""
def npts(
self,
lon1: float,
lat1: float,
lon2: float,
lat2: float,
npts: int,
radians: bool = False
) -> list[tuple[float, float]]:
"""
Compute intermediate points along geodesic.
Args:
lon1: First point longitude in degrees
lat1: First point latitude in degrees
lon2: Second point longitude in degrees
lat2: Second point latitude in degrees
npts: Number of intermediate points (excluding endpoints)
radians: Input/output coordinates in radians
Returns:
List of (longitude, latitude) tuples for intermediate points
Raises:
GeodError: If points are identical or npts is invalid
"""Compute lengths, distances, and cumulative measurements along paths defined by coordinate sequences.
class Geod:
def line_length(
self,
lons: Any,
lats: Any,
radians: bool = False
) -> float:
"""
Calculate total length of line defined by coordinate sequence.
Args:
lons: Array-like of longitude coordinates
lats: Array-like of latitude coordinates
radians: Coordinates are in radians
Returns:
Total line length in meters
Raises:
GeodError: If coordinate arrays have different lengths or < 2 points
"""
def line_lengths(
self,
lons: Any,
lats: Any,
radians: bool = False
) -> Any:
"""
Calculate segment lengths along line defined by coordinate sequence.
Args:
lons: Array-like of longitude coordinates
lats: Array-like of latitude coordinates
radians: Coordinates are in radians
Returns:
Array of segment lengths in meters (length = n_points - 1)
Raises:
GeodError: If coordinate arrays have different lengths or < 2 points
"""Compute area and perimeter of polygons defined by coordinate sequences using accurate geodesic methods.
class Geod:
def polygon_area_perimeter(
self,
lons,
lats,
radians: bool = False
) -> tuple[float, float]:
"""
Calculate area and perimeter of polygon.
Args:
lons: Array-like of polygon vertex longitudes
lats: Array-like of polygon vertex latitudes
radians: Coordinates are in radians
Returns:
Tuple of (area_square_meters, perimeter_meters)
Note:
Polygon is automatically closed if first != last point.
Positive area indicates counter-clockwise vertex order.
Negative area indicates clockwise vertex order.
Raises:
GeodError: If coordinate arrays have different lengths or < 3 points
"""Work with geometry objects (requires Shapely) for convenient geodesic calculations on geometric features.
class Geod:
def geometry_length(
self,
geometry,
radians: bool = False
) -> float:
"""
Calculate length of geometry object.
Args:
geometry: Shapely geometry object (LineString, MultiLineString, etc.)
radians: Coordinates are in radians
Returns:
Total length in meters
Note:
Requires Shapely to be installed.
Supports LineString, MultiLineString, LinearRing.
Raises:
ImportError: If Shapely is not installed
GeodError: If geometry type is not supported
"""
def geometry_area_perimeter(
self,
geometry,
radians: bool = False
) -> tuple[float, float]:
"""
Calculate area and perimeter of geometry object.
Args:
geometry: Shapely geometry object (Polygon, MultiPolygon, etc.)
radians: Coordinates are in radians
Returns:
Tuple of (area_square_meters, perimeter_meters)
Note:
Requires Shapely to be installed.
Supports Polygon, MultiPolygon.
Raises:
ImportError: If Shapely is not installed
GeodError: If geometry type is not supported
"""from pyproj import Geod
# Create Geod object for WGS84 ellipsoid
geod = Geod(ellps='WGS84')
# Forward calculation: from point + bearing + distance -> destination
lon1, lat1 = -74.0, 40.7 # New York
azimuth = 45.0 # Northeast
distance = 100000 # 100 km
lon2, lat2 = geod.fwd(lon1, lat1, azimuth, distance)
print(f"Destination: {lon2:.6f}, {lat2:.6f}")
# Inverse calculation: between two points -> azimuth + distance
lon2, lat2 = -73.0, 41.0 # Another point
azimuth, back_azimuth, distance = geod.inv(
lon1, lat1, lon2, lat2,
return_back_azimuth=True
)
print(f"Distance: {distance:.2f} m, Azimuth: {azimuth:.2f}°")from pyproj import Geod
import numpy as np
geod = Geod(ellps='WGS84')
# Define a path (e.g., flight route)
lons = np.array([-74.0, -70.0, -65.0, -60.0]) # New York to Atlantic
lats = np.array([40.7, 42.0, 43.0, 44.0])
# Calculate total path length
total_length = geod.line_length(lons, lats)
print(f"Total path length: {total_length/1000:.2f} km")
# Calculate segment lengths
segments = geod.line_lengths(lons, lats)
print(f"Segment lengths: {segments/1000}") # Convert to km
# Get intermediate points along path
intermediate = geod.npts(lons[0], lats[0], lons[-1], lats[-1], npts=10)
print(f"Intermediate points: {len(intermediate)}")from pyproj import Geod
import numpy as np
geod = Geod(ellps='WGS84')
# Define a polygon (e.g., state boundary)
# Triangle around New York area
lons = np.array([-74.0, -73.0, -75.0, -74.0]) # Close polygon
lats = np.array([40.7, 41.5, 41.0, 40.7])
# Calculate area and perimeter
area, perimeter = geod.polygon_area_perimeter(lons, lats)
print(f"Area: {abs(area)/1e6:.2f} km²") # Convert to km²
print(f"Perimeter: {perimeter/1000:.2f} km") # Convert to km
# Check if polygon is clockwise or counter-clockwise
if area > 0:
print("Counter-clockwise orientation")
else:
print("Clockwise orientation")from pyproj import Geod
# Different ellipsoids for regional accuracy
wgs84_geod = Geod(ellps='WGS84')
grs80_geod = Geod(ellps='GRS80')
clarke_geod = Geod(ellps='clrk66') # Clarke 1866
# Custom ellipsoid parameters
custom_geod = Geod(a=6378137.0, f=1/298.257223563)
# Compare distance calculations
lon1, lat1 = -100.0, 45.0
lon2, lat2 = -95.0, 50.0
distances = []
for name, geod in [('WGS84', wgs84_geod), ('GRS80', grs80_geod), ('Clarke', clarke_geod)]:
_, _, dist = geod.inv(lon1, lat1, lon2, lat2)
distances.append((name, dist))
print(f"{name}: {dist:.3f} m")from pyproj import Geod, GeodIntermediateFlag
geod = Geod(ellps='WGS84')
# Great circle route from London to Tokyo
lon1, lat1 = 0.0, 51.5 # London
lon2, lat2 = 139.7, 35.7 # Tokyo
# Generate route with specific number of points
route_points = geod.npts(lon1, lat1, lon2, lat2, npts=50)
# Get detailed intermediate information
intermediate = geod.inv_intermediate(
lon1, lat1, lon2, lat2,
npts=20,
flags=GeodIntermediateFlag.AZIS_KEEP, # Keep azimuth info
return_back_azimuth=True
)
print(f"Total points in route: {len(intermediate.lons)}")
print(f"Distance intervals: {intermediate.del_s:.2f} m")
# Forward intermediate calculation
forward_route = geod.fwd_intermediate(
lon1, lat1,
45.0, # Initial azimuth (northeast)
1000000, # 1000 km
npts=10
)from pyproj import Geod
from shapely.geometry import LineString, Polygon
geod = Geod(ellps='WGS84')
# LineString length calculation
line = LineString([(-74.0, 40.7), (-73.0, 41.0), (-72.0, 41.5)])
length = geod.geometry_length(line)
print(f"Line length: {length/1000:.2f} km")
# Polygon area calculation
coords = [(-74.0, 40.5), (-73.0, 40.5), (-73.0, 41.0), (-74.0, 41.0), (-74.0, 40.5)]
polygon = Polygon(coords)
area, perimeter = geod.geometry_area_perimeter(polygon)
print(f"Polygon area: {area/1e6:.2f} km²")
print(f"Polygon perimeter: {perimeter/1000:.2f} km")# Geodesic intermediate calculation results
class GeodIntermediateReturn:
"""Return object for intermediate geodesic calculations."""
npts: int # Number of points generated
del_s: float # Distance between points in meters
lons: list[float] # Longitude coordinates
lats: list[float] # Latitude coordinates
azis: list[float] | None # Azimuth values (if requested)
# Flags for intermediate calculations
class GeodIntermediateFlag(Enum):
"""Flags controlling intermediate point calculation behavior."""
DEFAULT = 0
NPTS_ROUND = 1 # Round number of points to nearest integer
NPTS_CEIL = 2 # Round number of points up
NPTS_TRUNC = 3 # Truncate number of points
DEL_S_RECALC = 4 # Recalculate distance between points
DEL_S_NO_RECALC = 5 # Don't recalculate distance
AZIS_DISCARD = 6 # Don't store azimuth information
AZIS_KEEP = 7 # Store azimuth information
# Global geodesic constants
geodesic_version_str: str # Version of GeographicLib
pj_ellps: dict[str, dict] # Dictionary of ellipsoid parametersInstall with Tessl CLI
npx tessl i tessl/pypi-pyproj