Coordinates and distances

PyWorldAtlas stores signed WGS84 latitude and longitude on every bundled capital and populated-place record. Exact lookup, friendly display helpers, and dependency-free great-circle calculations all work offline.

Look up coordinates

Constrain city lookups by country whenever a name may be shared:

>>> from pyworldatlas import Atlas
>>> atlas = Atlas()
>>> tokyo = atlas.city("Tokyo", country="Japan")
>>> tokyo.coordinates.as_tuple()
(35.6895, 139.69171)
>>> paris_coordinates = atlas.coordinates("Paris", country="FR")
>>> paris_coordinates.as_tuple()
(48.85341, 2.3488)

An unconstrained exact name that matches multiple stored cities raises AmbiguousPlaceError instead of choosing silently.

String inputs are resolved as bundled city names, not country names. first_country and second_country only disambiguate those city-name strings. Pass Country objects for country distance.

Distance between places

>>> paris = atlas.city("Paris", country="France")
>>> round(atlas.distance_between(tokyo, paris))
9713
>>> round(atlas.distance_between(tokyo, paris, unit="mi"))
6035
>>> round(atlas.distance_between(
...     "Tokyo", "Paris", first_country="JP", second_country="FR"
... ))
9713

unit accepts "km", "mi", or "nmi". Calculations use the standard haversine formula and the WGS84 mean Earth radius. Results represent surface great-circle distance, not road, rail, or flight-routing distance.

Country and model inputs

Country inputs use the selected primary capital. Capital and city objects use their own coordinates:

>>> japan = atlas.country("Japan")
>>> france = atlas.country("France")
>>> round(atlas.distance_between(japan, france))
9713
>>> round(atlas.distance_between(japan.capital, france.capital))
9713

An area without primary-capital coordinates raises CapitalNotFoundError when used as a country input.

Raw latitude and longitude

Use Coordinate directly or pass (latitude, longitude) tuples to the atlas helper:

>>> from pyworldatlas import Coordinate
>>> london = Coordinate(51.5074, -0.1278)
>>> paris_center = Coordinate(48.8566, 2.3522)
>>> round(london.distance_to(paris_center), 1)
343.6
>>> round(london.bearing_to(paris_center), 1)
148.1
>>> london.compass_direction_to(paris_center)
'SSE'
>>> midpoint = london.midpoint_to(paris_center)
>>> (round(midpoint.latitude, 4), round(midpoint.longitude, 4))
(50.1886, 1.1466)
>>> start = (51.5074, -0.1278)
>>> finish = (48.8566, 2.3522)
>>> round(atlas.distance_between(start, finish), 1)
343.6
>>> atlas.close()

Latitude must be from -90 through 90 and longitude from -180 through 180. Invalid coordinates and unsupported units raise ValueError. Initial bearing is undefined for coincident or antipodal coordinates, and a unique spherical midpoint is undefined for antipodal coordinates; those cases also raise ValueError.

Friendly coordinate labels

Decimal degrees are compact; degrees/minutes/seconds are useful for teaching how a coordinate is composed:

>>> tokyo_coordinates = Coordinate(35.6895, 139.6917)
>>> tokyo_coordinates.hemispheres
('N', 'E')
>>> tokyo_coordinates.format()
'35.6895° N, 139.6917° E'
>>> tokyo_coordinates.dms()
'35° 41′ 22.2″ N, 139° 41′ 30.1″ E'

compass_direction_to converts the initial bearing to a 4-, 8-, or 16-point compass label. It describes the beginning of the same great-circle path and is not a navigation instruction.

Country coordinates

country.capital_coordinates exposes the primary capital position when one is available. Passing a Country to atlas.distance_between uses that position. Country inputs therefore produce capital-to-capital distances, not centroid distances.