GeoJSON to a map: valid numbers do not prove coordinate order
The short answer
Validate the selected format and name the coordinates. A range check cannot prove which location the source intended.
A number pair is not location evidence
A map adapter can draw a point in the wrong place without an error. A pair whose two values both lie within the latitude range provides no convenient numeric alarm. The useful goal is therefore not to guess the right place automatically, but to expose the interpretation and demonstrate the check’s boundary.
RFC 7946 places longitude before latitude and permits an additional altitude component.[4] Our example adapter deliberately accepts only two-dimensional Point objects. Rejecting altitude is therefore our limited adapter scope, not a claim that valid GeoJSON points can never include altitude.
Define the boundary between source and map
- Source shape: a GeoJSON Point with coordinates as a list.
- Adapter output: separate longitude and latitude keys.
- Map input: then check the documented convention of the chosen map library; it is not assumed here.
- Unknown provenance or another coordinate system: hold the handoff instead of swapping values until the picture looks plausible.
Demonstrate what the validator cannot know
The invented coordinates [4.3, 52.1] below are labeled, not geographically looked up. Reversed input [52.1, 4.3] also passes. That counterexample is the main test: a tidy output mapping does not automatically reveal mistaken source intent. Never substitute a plausible map image for the source agreement.
Use Copy code to copy the complete code exactly. Manual selection may omit the final newline.
import json
import math
from operator import le
def point_to_named(point):
if type(point) is not dict or point.get("type") != "Point":
raise ValueError("expected Point")
c = point.get("coordinates")
if type(c) is not list or len(c) != 2:
raise ValueError("this adapter accepts two dimensions only")
if any(type(x) not in (int, float) or not math.isfinite(x) for x in c):
raise ValueError("expected finite numbers, not booleans")
lon, lat = c
if not (le(abs(lon), 180) and le(abs(lat), 90)):
raise ValueError("outside this adapter's range")
return {"longitude": lon, "latitude": lat}
# Invented coordinates; not a location lookup or surveyed point.
normal = point_to_named({"type": "Point", "coordinates": [4.3, 52.1]})
swapped = point_to_named({"type": "Point", "coordinates": [52.1, 4.3]})
assert normal["longitude"] == 4.3 and normal["latitude"] == 52.1
assert swapped["longitude"] == 52.1 # Still in range: cannot detect intent.
bad = [[True, 52], [4, float("nan")], [4, 91], [4, 52, 3], [181, 52]]
for c in bad:
try:
point_to_named({"type": "Point", "coordinates": c})
except ValueError:
pass
else:
raise AssertionError("invalid coordinates accepted")
print(json.dumps({"named": normal, "swapped_also_passes": swapped, "rejected": len(bad)}, sort_keys=True))
{"named": {"latitude": 52.1, "longitude": 4.3}, "rejected": 5, "swapped_also_passes": {"latitude": 4.3, "longitude": 52.1}}
The five negative fixtures reject a boolean, NaN, a latitude outside the chosen range, a third dimension, and a longitude outside the chosen range. The type check explicitly excludes True even though Python treats booleans as numbers in some numeric contexts. The output is an actual local result over invented input, not a geolocation or provider observation.
Carry uncertainty through to the user
A useful handoff card retains format, source field, order, unit, known conversion, and the party confirming the meaning. If an upstream system already supplies named latitude and longitude fields, convert them through an explicit adapter rather than blindly reusing an array function. Swapping values to move a marker nearer the expected city is not a validation method.
This exercise does not check FeatureCollection, geometry collections, bbox, the antimeridian, projection conversion, accuracy, or map rendering. It neither validates an address nor selects an administrative candidate. A real integration needs representative permitted source data and tests against the chosen map. Only the documented format reading and local fixtures were executed; rights and independent review remain open.
Sources & evidence
- Original source title: RFC 7946 — The GeoJSON Format
Accessed: 2026-10-18T22:58:30.816185+00:00