Finding distance between two latitudes and longitudes in Python | by Zolzaya Luvsandorj | Towards Data Science

When preparing data for a model, there may be a time where it’s useful to find distances between two locations. This post shows how to find the shortest spherical and travel distance between two locations from their latitude and longitude in Python.
We can locate any place on earth from its geographic coordinates. Geographic coordinates of a location consist of its latitude and longitude position.
Latitude is a measurement of the vertical position between North Pole and South Pole. Imaginary horizontal latitude lines are called parallels. Equator is a special parallel that is at 0° latitude and lies halfway between and North Pole and South Pole.
Longitude is a measurement of the horizontal position. Imaginary vertical longitude lines are called meridians. The Prime Meridian is a special meridian that is at 0° longitude. Longitudes are also important when it comes to time zones.
Parallels are like a ring whereas meridians are like a half a ring.
We will import the libraries and set two sample location coordinates in Melbourne, Australia:
import numpy as npimport pandas as pdfrom math import radians, cos, sin, asin, acos, sqrt, pifrom geopy import distancefrom geopy.geocoders import Nominatimimport osmnx as oximport networkx as nxlat1, lon1 = -37.82120, 144.96441 # location 1lat2, lon2 = -37.88465,  145.08727 # location 2
Installing osmnx can be fiddly. One easy way to setup the environment to follow this tutorial would be to use Google Colaboratory: First, create a new notebook; second, install the library with !pip install osmnx; third, restart: go to Runtime from menu on top > Restart Runtime > Environment is ready!
Earth’s equatorial radius is 6378 km and polar radius is 6356 km so earth is not a perfect sphere. However, assuming spherical earth enables us to easily find approximate distances which is satisfactory in some applications. In this section, we will use the haversine formula to find the spherical distance between two locations from their geographic coordinates. Let’s first familiarise with the haversine function.
The haversine function is as follows:
Haversine of a central angle, which equals the spherical distance divided by the radius of the sphere, can be calculated using the haversine formula:
We can transform this formula using the first definition of the haversine function and rearrange it such that d is on the left side:
Now, it’s time to translate this into Python code. There are two things to highlight: First, the latitudes and longitudes are in degrees so we will have to convert them to radians before we plug them into the formula. Second, we will use globally average value of 6371 km as the radius of the spherical earth.
def calculate_spherical_distance(lat1, lon1, lat2, lon2, r=6371):    # Convert degrees to radians    coordinates = lat1, lon1, lat2, lon2    # radians(c) is same as c*pi/180    phi1, lambda1, phi2, lambda2 = [        radians(c) for c in coordinates    ]          # Apply the haversine formula    a = (np.square(sin((phi2-phi1)/2)) + cos(phi1) * cos(phi2) *          np.square(sin((lambda2-lambda1)/2)))    d = 2*r*asin(np.sqrt(a))    return dprint(f"{calculate_spherical_distance(lat1, lon1, lat2, lon2):.4f} km")
Alternatively, we can use the second definition of the haversine function with cosine and rearrange the equation to express d:
This can be expressed in Python as follows:
def calculate_spherical_distance(lat1, lon1, lat2, lon2, r=6371):    # Convert degrees to radians    coordinates = lat1, lon1, lat2, lon2    phi1, lambda1, phi2, lambda2 = [        radians(c) for c in coordinates    ]        # Apply the haversine formula    d = r*acos(cos(phi2-phi1) - cos(phi1) * cos(phi2) *              (1-cos(lambda2-lambda1)))    return dprint(f"{calculate_spherical_distance(lat1, lon1, lat2, lon2):.4f} km")
More practically, we can use geopy package to get the spherical distance in a single line of code:
print(f"{distance.great_circle((lat1, lon1), (lat2, lon2)).km:.4f} km")
In addition, it’s easy to find other distances with geopy package. For instance, we can get distance based on ellipsoid earth assumption like this: distance.distance((lat1, lon1), (lat2, lon2)).km. There are different ellipsoid models available, the previous function uses the WGS-84 model and here’s an alternative syntax: distance.geodesic((lat1, lon1), (lat2, lon2), ellipsoid=’WGS-84').km. If you want to learn more about the library, check out its resource on calculating distance.
In this section, we will look at how to find shortest travel distance using OpenStreetMap with OSMnx package. We will start by pulling the graph of the network of the city:
mel_graph = ox.graph_from_place(    'Melbourne, Australia', network_type='drive', simplify=True)ox.plot_graph(mel_graph)
This code is likely to take a while to run. We used network_type='drive' to get driving distance. Other network types are also available. For instance, if we are after walking distance, then we tweak the code to network_type='walk'.
Now, we can find the driving distance using the graph:
orig_node = ox.distance.nearest_nodes(mel_graph, lon1, lat1)target_node = ox.distance.nearest_nodes(mel_graph, lon2, lat2)nx.shortest_path_length(G=mel_graph, source=orig_node, target=target_node, weight='length')
The shortest driving distance from location 1 to location 2 is 15,086.094 meters. It’s worth noting that distance from location 2 to location 1 may not necessarily be the same as the distance from location 1 to location 2.
We can create a function that calculates the distance:
def calculate_driving_distance(lat1, lon1, lat2, lon2):    # Get city and country name    geolocator = Nominatim(user_agent="geoapiExercises")    location = geolocator.reverse(f"{lat1}, {lon1}")    address = location.raw['address']    area = f"{address['city']}, {address['country']}"    # Get graph for the city    graph = ox.graph_from_place(area, network_type='drive',                                 simplify=True)    # Find shortest driving distance    orig_node = ox.distance.nearest_nodes(graph, lon1, lat1)    target_node = ox.distance.nearest_nodes(graph, lon2, lat2)    length = nx.shortest_path_length(G=graph, source=orig_node,                                      target=target_node, weight='length')    return length / 1000 # convert from m to kmsprint(f"{calculate_driving_distance(lat1, lon1, lat2, lon2):.2f} km")
That was it! If you want to learn more about the library, check out OSMnx user reference and OSMnx examples.
Would you like to access more content like this? Medium members get unlimited access to any articles on Medium. If you become a member using my referral link, a portion of your membership fee will directly go to support me.
Thank you for reading my post. If you are interested, here are links to some of my posts:◼️ Enrich your Jupyter Notebook with these tips◼️ Organise your Jupyter Notebook with these tips◼️ Useful IPython magic commands◼️ Introduction to Python Virtual Environment for Data Science◼️ Introduction to Git for Data Science◼️ Simple data visualisations in Python that you will find useful◼️ 6 simple tips for prettier and customised plots in Seaborn (Python)◼️️ 5 tips for pandas users◼️️ Writing 5 common SQL queries in pandas
Bye for now 🏃💨