Geopy Geographic Programming in Practice: Implementing Address Resolution and Distance Calculation in Python

Do you remember that time we worked on the food delivery system project? The product manager confidently said, “It’s just a simple distance calculation.” But what happened?

When a user inputs “Sanlitun, Chaoyang District, Beijing,” we need to calculate the delivery distance. Initially, we used a simple latitude and longitude calculation, which resulted in a huge error. Later, we realized that this involves a whole set of geographic information processing, including address resolution, coordinate transformation, and distance calculation.

That’s when I learned how complex geographic programming can be.

01

Let’s start with the Geopy library. It’s like a Swiss Army knife for Python geographic programming, capable of handling almost all geographic-related operations.

Installation is straightforward:

pip install geopy

The most basic function is address resolution, which converts textual addresses into latitude and longitude coordinates:

from geopy.geocoders import Nominatim

# Create a geocoder instance
geolocator = Nominatim(user_agent="my_app")

# Address resolution
location = geolocator.geocode("Tiananmen Square, Beijing")
print(f"Latitude: {location.latitude}")  # Latitude: 39.9042004
print(f"Longitude: {location.longitude}")  # Longitude: 116.407526
print(f"Full address: {location.address}")  # Get standardized address

Here’s a pitfall: the user_agent parameter must be set; otherwise, many services will reject the request.

02

Reverse geocoding is also very common, which converts coordinates back into addresses:

# Get address information based on coordinates
location = geolocator.reverse("39.9042004, 116.407526")
print(location.address)

In actual projects, I found that the accuracy of different geocoding services varies significantly. Nominatim is free but has limited support for domestic addresses, while the APIs from Amap and Baidu are paid but more accurate.

You can switch between different services like this:

# Using Amap API (requires an API key)
from geopy.geocoders import AMap
amap_geocoder = AMap(api_key='your_api_key')

# Or use Google Maps API
from geopy.geocoders import GoogleV3  
google_geocoder = GoogleV3(api_key='your_api_key')

Which one to choose? It depends on your needs and budget.

03

Distance calculation is a core function of geographic programming. Geopy provides various methods for distance calculation:

from geopy.distance import geodesic, great_circle
from geopy import Point

# Define two locations
point1 = Point("39.9042004, 116.407526")  # Tiananmen
point2 = Point("31.2304, 121.4737")       # Bund in Shanghai

# Great-circle distance calculation (spherical geometry)
distance1 = great_circle(point1, point2).kilometers
print(f"Great-circle distance: {distance1:.2f} km")

# Geodesic distance calculation (ellipsoidal geometry, more accurate)
distance2 = geodesic(point1, point2).kilometers  
print(f"Geodesic distance: {distance2:.2f} km")

# You can also use miles, meters, etc.
print(f"Distance (miles): {distance2.miles:.2f}")
print(f"Distance (meters): {distance2.meters:.0f}")

The geodesic method is more accurate than the great_circle method because it takes into account the Earth’s ellipsoidal shape. The difference is significant for long-distance calculations.

This is really useful.

04

When building the delivery system, we needed to calculate distances between multiple locations in bulk. I wrote a small tool:

def calculate_delivery_routes(origin, destinations):
    """
    Calculate delivery routes and distances
    origin: Starting address
    destinations: List of target addresses
    """
    geolocator = Nominatim(user_agent="delivery_app")
    
    # Parse starting point coordinates
    origin_location = geolocator.geocode(origin)
    if not origin_location:
        return None
    
    origin_point = Point(origin_location.latitude, origin_location.longitude)
    routes = []
    
    for dest in destinations:
        # Parse target address
        dest_location = geolocator.geocode(dest)
        if dest_location:
            dest_point = Point(dest_location.latitude, dest_location.longitude)
            distance = geodesic(origin_point, dest_point).kilometers
            
            routes.append({
                'destination': dest,
                'distance': round(distance, 2),
                'coordinates': (dest_location.latitude, dest_location.longitude)
            })
    
    # Sort by distance
    routes.sort(key=lambda x: x['distance'])
    return routes

# Example usage
origin = "Sanlitun, Chaoyang District, Beijing"
destinations = ["Zhongguancun, Haidian District, Beijing", "Xidan, Xicheng District, Beijing", "Wangfujing, Dongcheng District, Beijing"]

routes = calculate_delivery_routes(origin, destinations)
for route in routes:
    print(f"Destination: {route['destination']}, Distance: {route['distance']} km")

This function helped us optimize delivery routes and significantly reduce operational costs.

05

Let me mention a few practical considerations.

Geocoding services all have request frequency limits, so when processing in bulk, you need to add delays:

import time

def batch_geocode(addresses):
    results = []
    for addr in addresses:
        location = geolocator.geocode(addr)
        results.append(location)
        time.sleep(1)  # Avoid too frequent requests
    return results

Also, error handling is important. Network issues and address recognition failures are common:

from geopy.exc import GeocoderTimedOut, GeocoderServiceError

try:
    location = geolocator.geocode("Ambiguous address description", timeout=10)
    if location is None:
        print("Address cannot be recognized")
    else:
        print(f"Found location: {location.address}")
except GeocoderTimedOut:
    print("Request timed out")
except GeocoderServiceError as e:
    print(f"Service error: {e}")

Overall, Geopy is indeed a fantastic geographic programming tool. It can handle everything from simple address resolution to complex geographic information systems. Combined with mapping visualization libraries, you can create some really cool applications.

Looking back, that food delivery project, despite the many pitfalls, gave me a deep understanding of geographic programming.

Leave a Comment