Discover Nearby Towns, Cities, and Villages Using Python and OpenStreetMap

Introduction

One fine day, I found myself wondering about the various towns and villages that were around me. As a Python Developer and Sustainability enthusiast, I'm always thinking about how I can expand my impact in the fields of sustainability and technology. What better way to do it than know my neighbours, right? I decided to write a Python script to dynamically fetch information about all the places that surround me, within a certain radius.

The Pre-Requisites

Before I could dive into the fun part, which is coding, I needed to install a couple of Python packages that would make my life easier:

pip install requests geopy

Most people use pip, but I would recommend Poetry.

Fetching Data from OpenStreetMap

The first step was to gather the data. I opted for OpenStreetMap's API. Here's how I did it:

import requests

# Function to fetch data from OpenStreetMap
def fetch_osm_data(lat, lon, radius_km):
    radius_meters = radius_km * 1000  # Convert the radius from kilometers to meters
    overpass_url = "http://overpass-api.de/api/interpreter"

    # Constructing the API query
    overpass_query = f"""
    [out:json];
    (
      node["place"="town"](around:{radius_meters},{lat},{lon});
      node["place"="city"](around:{radius_meters},{lat},{lon});
      node["place"="village"](around:{radius_meters},{lat},{lon});
    );
    out;
    """
    response = requests.get(overpass_url, params={'data': overpass_query})
    if response.status_code != 200:
        return None
    data = response.json()
    return data['elements']

This function, fetch_osm_data, takes in the latitude, longitude, and radius (in kilometers) and returns a JSON object containing the nearby places.

Calculating Distances

After obtaining the data, I wanted to know exactly how far each place was from my coordinates. For this, I employed the geopy library to calculate the geodesic distance:

from geopy.distance import geodesic

# Looping through the fetched data to calculate the distances
for element in osm_data:
    place_name = element.get('tags', {}).get('name', 'Unknown')  # Get the name of the place
    place_coord = (element['lat'], element['lon'])  # Get the coordinates of the place
    distance = geodesic((lat, lon), place_coord).kilometers  # Calculate the distance
    print(f"{place_name} ({distance:.2f} km)")

I looped through each element in the fetched data, calculated the distance from my location to the place, and printed it out.

The Complete Script

After combining the data fetching and distance calculation steps, here's the full script I ended up with:

import requests
from geopy.distance import geodesic

def fetch_osm_data(lat, lon, radius_km):
    radius_meters = radius_km * 1000
    overpass_url = "http://overpass-api.de/api/interpreter"
    overpass_query = f"""
    [out:json];
    (
      node["place"="town"](around:{radius_meters},{lat},{lon});
      node["place"="city"](around:{radius_meters},{lat},{lon});
      node["place"="village"](around:{radius_meters},{lat},{lon});
    );
    out;
    """
    response = requests.get(overpass_url, params={'data': overpass_query})
    if response.status_code != 200:
        return None
    data = response.json()
    return data['elements']

if __name__ == "__main__":
    lat = float(input("Enter latitude: "))
    lon = float(input("Enter longitude: "))
    radius_km = float(input("Enter radius in kilometers: "))

    osm_data = fetch_osm_data(lat, lon, radius_km)

    if not osm_data:
        print("Failed to fetch data or no places found.")
    else:
        print(f"Places within {radius_km} km:")
        for element in osm_data:
            place_name = element.get('tags', {}).get('name', 'Unknown')
            place_coord = (element['lat'], element['lon'])
            distance = geodesic((lat, lon), place_coord).kilometers
            print(f"{place_name} ({distance:.2f} km)")

Conclusion

And there it is! That's how I successfully created a Python script that could tell me about all the towns, cities, and villages around any location. The joy of seeing those place names pop up on my screen was priceless.

Why not give it a try yourself and discover the places around you?

Did you find this article valuable?

Support Theo van der Sluijs by becoming a sponsor. Any amount is appreciated!