Photo by GeoJango Maps on Unsplash
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?