Calculate distance between a coordinate and a county in GeoPandas

One of the packages that Geopandas depends on is Shapely. Shapely uses 2D Cartesian coordinates (x, y) and calculations are performed in 2D plane.

If you use "projected coordinate system", no problem. The distance that you get is the distance on the map (not on the spherical earth). When using "geographic coordinate system - GCS", the distance that you get will be the shortest distance in 3D space.

So you should use a formula to calculate distance on the sphere, and that is Haversine formula. But it calculates great-circle distance between two points on a sphere given their longitudes and latitudes. However, you have a point and a polygon. So you need a point on the polygon which has nearest distance to the point.

enter image description here

I assume that the coordinates of county polygon are on GCS, not projected. If projected, you need to transform to GCS using .to_crs() method. Then use that code to find nearest point coordinates on the polygon. (Code Reference: Find Coordinate of Closest Point on Polygon Shapely)

from shapely.geometry import LinearRing

pol_ext = LinearRing(county.geometry.exterior.coords)
d = pol_ext.project(point.geometry)
p = pol_ext.interpolate(d)
closest_point_coords = list(p.coords)[0]

And then, use the function below to calculate spherical distance that you need. (Code Reference: Haversine Formula in Python)

from math import radians, cos, sin, asin, sqrt

def haversine(lon1, lat1, lon2, lat2):
    """
    Calculate the great circle distance between two points 
    on the earth (specified in decimal degrees)
    """
    # convert decimal degrees to radians 
    lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2])

    # haversine formula 
    dlon = lon2 - lon1 
    dlat = lat2 - lat1 
    a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
    c = 2 * asin(sqrt(a)) 
    r = 3956 # Radius of earth in miles. Use 6371 for kilometers
    return c * r

You need to reproject your geodataframes into a CRS that adequately preserves distances; UTM is a common choice, and the results would be in meters. You must determine which UTM zone to use, find the appropriate EPSG, then use the .to_crs(epsg=XXXX) method on your geodataframes to convert them.

Choosing the correct CRS in many cases is nontrivial; I have just provided a starting point that may work for you. UTM projections do not preserve distances, but over small areas, the distortion is often acceptable. The Plate Caree apparently preserves distances (epsg 32662).