A simple reverse geocoder that resolves a location to a country

Overview

Reverse Geocoder

This repository holds a small web service that performs reverse geocoding to determine whether a user specified location is within the geographic bounds of a country. If it is then the response will contain attributes associated with the matched country such as name, iso label, etc.

I created this simple demonstrator app to learn about FastAPI and PostGIS. It is built using Python and a PostGIS database loaded with country outline polygons obtained from shape files.

API Endpoints

All endpoints are located at /v1/reverse-geocoder/ and are accessible by HTTP.

The OpenAPI specification can be read from /v1/reverse-geocoder/openapi.json.

A SwaggerUI that renders the OpenAPI specification can be found at /v1/reverse-geocoder/docs. The root / will also redirect to the SwaggerUI docs page.

Reverse Geocoder Endpoint

To access the reverse geocoder send a POST to /v1/reverse-geocoder/ with a payload containing the location of interest. See further down for examples using curl.

When the user supplied point is within a country then the response contains attributes of the country that matched. When the user supplied point is not within a country then the response indicates that no country matched.

The response will always contain a copy of the query parameters so that it provides some context for the data. When the location is within a country bounds then the response payload will look like this:

{
  "location":{
    "latitude":-42.239392,
    "longitude":146.558384,
    "altitude":null
  },
  "country":{
    "name":"Australia",
    "iso2":"AU",
    "iso3":"AUS"
  }
}

If the point is not within a country boundary then the response will look like this:

{
  "location":{
    "latitude":-35.031741,
    "longitude":138.119541,
    "altitude":null
  },
  "country":null
}

Demo

To simplify running the reverse geocoding service a Docker compose configuration example is included. However, a few set up steps need to be run first to prepare data that will go into the database - as it is not stored in this repository.

Clone Repo

Start by cloning this repo.

$ git clone https://github.com/claws/reverse-geocoder.git
$ cd reverse-geocoder

Preparation

This demonstration uses world country boundary outlines in shape file format (.shp, .dbf, .shx files) which contain encoded polygons along with other attributes. However, the files are not stored in this repo so they need to be downloaded and then converted into SQL statements.

The following steps show how to download the content from here, decompress it and then convert it into SQL statements that can later be run to insert the contents into the database.

It is important that the name of the generated SQL file is 90-shapes.sql to ensure it gets run after the builtin PostGIS initialization script (which is 10_postgis.sh). This file will be used as a volume mount in the Docker compose configuration.

shp2pgsql is a command line tool that comes with PostGIS. It converts shape files into a SQL format that can be imported into a PostGIS database. The '-G' specifies the use of the geography data type. The '-I' option creates a spatial index after the table is created. This is strongly recommended for improved performance. To run the last command you may need to install PostGIS on your host machine to get the shp2pgsql tool - there may even be a Docker container that has it too.

$ cd database
$ wget http://thematicmapping.org/downloads/TM_WORLD_BORDERS-0.3.zip
$ unzip TM_WORLD_BORDERS-0.3.zip
$ shp2pgsql -G -I TM_WORLD_BORDERS-0.3.shp countries > 90-shapes.sql
$ cd ..

The shape file produces columns containing the following structures:

COLUMN TYPE DESCRIPTION
fips String(2) FIPS 10-4 Country Code
iso2 String(2) ISO 3166-1 Alpha-2 Country Code
iso3 String(3) ISO 3166-1 Alpha-3 Country Code
un Short Integer(3) ISO 3166-1 Numeric-3 Country Code
name String(50) Name of country/area
area Long Integer(7) Land area, FAO Statistics (2002)
pop2005 Double(10,0) Population, World Population Prospects (2005)
region Short Integer(3) Macro geographical (continental region), UN Statistics
subregion Short Integer(3) Geographical sub-region, UN Statistics
lon FLOAT (7,3) Longitude
lat FLOAT (6,3) Latitude
geog Polygon Country/area border as polygon(s)

Start services

Start the database and web server using Docker compose. As part of the startup steps the database runs initialisation script - which will run SQL file created in the setup steps above.

$ docker-compose up --build

The FastAPI framework is built upon OpenAPI and it supports a builtin viewer for the interface specification. These allow developers to perform manual tests.

Once the services start up you should be able to access the SwaggerUI web user interface here which should redirect you to the docs site.

screenshot

Click the POST /v1/reverse-geocoder/ row to expose details about the endpoint. This endpoint is implemented to accept a payload, rather than URL parameters, as it can then rely on the specification and Pydantic to simplify the interface between the API endpoint and the database layer.

Click the Try it out button. This changes the form to allow user input. Leave the default payload structure then click Execute. The Responses section should get populated with the data returned from the web service - which in this case indicates that the point was in Australia.

Try changing the location to some of those in the table below. The last two should return 'null' for the country as they are located in a sea.

Rough Location Position
Tasmania 146.558384 -42.239392
New Zealand 167.930127 -47.033240
Hawaii -157.935416 21.460822
Iceland -21.478138 64.113670
Cypress 34.321495 35.556301
St Vincent Gulf 138.119541 -35.031741
Black Sea 34.402367 43.400157

The Swagger UI also shows the equivalent curl command to use too.

Check using curl

The Reverse Geocoder Service REST API can be used from curl too.

When the location is within a country bounds then the response payload will contain country attributes.

$ curl -X POST "http://localhost:8000/v1/reverse-geocoder/" \
  -H "accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{\"location\":{\"longitude\":146.558384,\"latitude\":-42.239392}}"
{
  "location":{
    "latitude":-42.239392,
    "longitude":146.558384,
    "altitude":null
  },
  "country":{
    "name":"Australia",
    "iso2":"AU",
    "iso3":"AUS"
  }
}

When the user supplied point is not within a country then the response indicates that no country matched.

$ curl -X POST "http://localhost:8000/v1/reverse-geocoder/" \
  -H "accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{\"location\":{\"longitude\":138.119541,\"latitude\":-35.031741}}"
{
  "location":{
    "latitude":-35.031741,
    "longitude":138.119541,
    "altitude":null
  },
  "country":null
}

Developer Notes

Data Server

It can be useful during development to run the Python web server locally. The instructions below show how to do that.

Create a Python virtual environment.

$ cd web-service
$ python3.8 -m venv venv --prompt fast
$ source venv/bin/activate
(fast) $ pip install pip -U
(fast) $ pip install -r requirements.dev.txt
(fast) $ pip install -r requirements.txt

Apply code style

$ black app

Run the data server. Use --reload to enable automatic reloads on code changes.

(fast) $ uvicorn app.main:app --reload --log-level info
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [2617]
INFO:     Started server process [2619]
INFO:     Waiting for application startup.
INFO:     Connected to database postgresql://postgres:********@localhost:54321/postgres
INFO:     Application startup complete.

Database Inspection

It can be useful to attach to the database directly to test out queries. Use docker-compose to connect to the running database by attaching to the container. Once attached the psql tool can be used to execute a query identical to that done by the web service to check if a point lies within a polygon.

The PostGIS ST_Covers function which returns TRUE if A covers B (i.e. no points of B are outside A).

$ docker-compose run database bash
[email protected]:/$
[email protected]:/$ psql --host database -U postgres postgres
Password for user postgres:
postgres=#
postgres=# SELECT name,fips,iso2,iso3 FROM countries WHERE ST_Covers(countries.geog, ST_GeographyFromText('POINT(146.558384 -42.239392)'));
   name    | fips | iso2 | iso3
-----------+------+------+------
 Australia | AS   | AU   | AUS
(1 row)
postgres=#
postgres=# SELECT name,fips,iso2,iso3 FROM countries WHERE ST_Covers(countries.geog, ST_GeographyFromText('POINT(138.119541 -35.031741)'));
 name | fips | iso2 | iso3
------+------+------+------
(0 rows)
postgres=# \q
[email protected]:/$ exit
Geocoding library for Python.

geopy geopy is a Python client for several popular geocoding web services. geopy makes it easy for Python developers to locate the coordinates of addr

geopy 3.8k Dec 30, 2022
PyTorch implementation of ''Background Activation Suppression for Weakly Supervised Object Localization''.

Background Activation Suppression for Weakly Supervised Object Localization PyTorch implementation of ''Background Activation Suppression for Weakly S

34 Dec 27, 2022
h3-js provides a JavaScript version of H3, a hexagon-based geospatial indexing system.

h3-js The h3-js library provides a pure-JavaScript version of the H3 Core Library, a hexagon-based geographic grid system. It can be used either in No

Uber Open Source 648 Jan 07, 2023
A package to fetch sentinel 2 Satellite data from Google.

Sentinel 2 Data Fetcher Installation Create a Virtual Environment and activate it. python3 -m venv venv . venv/bin/activate Install the Package via pi

1 Nov 18, 2021
r.cfdtools 7 Dec 28, 2022
Calculate & view the trajectory and live position of any earth-orbiting satellite

satellite-visualization A cross-platform application to calculate & view the trajectory and live position of any earth-orbiting satellite in 3D. This

Space Technology and Astronomy Cell - Open Source Society 3 Jan 08, 2022
Creates 3D geometries from 2D vector graphics, for use in geodynamic models

geomIO - creating 3D geometries from 2D input This is the Julia and Python version of geomIO, a free open source software to generate 3D volumes and s

3 Feb 01, 2022
Python 台灣行政區地圖 (2021)

Python 台灣行政區地圖 (2021) 以 python 讀取政府開放平台的 ShapeFile 地圖資訊。歡迎引用或是協作 另有縣市資訊、村里資訊與各種行政地圖資訊 例如: 直轄市、縣市界線(TWD97經緯度) 鄉鎮市區界線(TWD97經緯度) | 政府資料開放平臺: https://data

WeselyOng 12 Sep 27, 2022
Bacon - Band-limited Coordinate Networks for Multiscale Scene Representation

BACON: Band-limited Coordinate Networks for Multiscale Scene Representation Project Page | Video | Paper Official PyTorch implementation of BACON. BAC

Stanford Computational Imaging Lab 144 Dec 29, 2022
gjf: A tool for fixing invalid GeoJSON objects

gjf: A tool for fixing invalid GeoJSON objects The goal of this tool is to make it as easy as possible to fix invalid GeoJSON objects through Python o

Yazeed Almuqwishi 91 Dec 06, 2022
Search and download Copernicus Sentinel satellite images

sentinelsat Sentinelsat makes searching, downloading and retrieving the metadata of Sentinel satellite images from the Copernicus Open Access Hub easy

837 Dec 28, 2022
Evaluation of file formats in the context of geo-referenced 3D geometries.

Geo-referenced Geometry File Formats Classic geometry file formats as .obj, .off, .ply, .stl or .dae do not support the utilization of coordinate syst

Advanced Information Systems and Technology 11 Mar 02, 2022
Enable geospatial data mining through Google Earth Engine in Grasshopper 3D, via its most recent Hops component.

AALU_Geo Mining This repository is produced for a masterclass at the Architectural Association Landscape Urbanism programme. Requirements Rhinoceros (

4 Nov 16, 2022
Python interface to PROJ (cartographic projections and coordinate transformations library)

pyproj Python interface to PROJ (cartographic projections and coordinate transformations library). Documentation Stable: http://pyproj4.github.io/pypr

832 Dec 31, 2022
Deal with Bing Maps Tiles and Pixels / WGS 84 coordinates conversions, and generate grid Shapefiles

PyBingTiles This is a small toolkit in order to deal with Bing Tiles, used i.e. by Facebook for their Data for Good datasets. Install Clone this repos

Shoichi 1 Dec 08, 2021
A Django application that provides country choices for use with forms, flag icons static files, and a country field for models.

Django Countries A Django application that provides country choices for use with forms, flag icons static files, and a country field for models. Insta

Chris Beaven 1.2k Jan 03, 2023
GebPy is a Python-based, open source tool for the generation of geological data of minerals, rocks and complete lithological sequences.

GebPy is a Python-based, open source tool for the generation of geological data of minerals, rocks and complete lithological sequences. The data can be generated randomly or with respect to user-defi

Maximilian Beeskow 16 Nov 29, 2022
Python Data. Leaflet.js Maps.

folium Python Data, Leaflet.js Maps folium builds on the data wrangling strengths of the Python ecosystem and the mapping strengths of the Leaflet.js

6k Jan 02, 2023
A Jupyter - Leaflet.js bridge

ipyleaflet A Jupyter / Leaflet bridge enabling interactive maps in the Jupyter notebook. Usage Selecting a basemap for a leaflet map: Loading a geojso

Jupyter Widgets 1.3k Dec 27, 2022
iNaturalist observations along hiking trails

This tool reads the route of a hike and generates a table of iNaturalist observations along the trails. It also shows the observations and the route of the hike on a map. Moreover, it saves waypoints

7 Nov 11, 2022