• Stars
    star
    231
  • Rank 172,452 (Top 4 %)
  • Language
    Python
  • License
    Apache License 2.0
  • Created about 4 years ago
  • Updated almost 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Geocode rows in a SQLite database table

geocode-sqlite

PyPI Changelog Tests License

Geocode rows from a SQLite table

Installation

Install this tool using pip or pipx:

# install inside a virtualenv
pip install geocode-sqlite

# install globally
pipx install geocode-sqlite

Usage

Let's say you have a spreadsheet with addresses in it, and you'd like to map those locations. First, create a SQLite database and insert rows from that spreadsheet using sqlite-utils.

sqlite-utils insert data.db data data.csv --csv

Now, geocode it using OpenStreetMap's Nominatim geocoder.

geocode-sqlite nominatim data.db data \
 --location="{address}, {city}, {state} {zip}" \
 --delay=1 \
 --user-agent="this-is-me"

In the command above, you're using Nominatim, which is free and only asks for a unique user agent (--user-agent).

This will connect to a database (data.db) and read all rows from the table data (skipping any that already have both a latitude and longitude column filled).

You're also telling the geocoder how to extract a location query (--location) from a row of data, using Python's built-in string formatting, and setting a rate limit (--delay) of one request per second.

For each row where geocoding succeeds, latitude and longitude will be populated. If you hit an error, or a rate limit, run the same query and pick up where you left off.

The resulting table layout can be visualized with datasette-cluster-map.

Under the hood, this package uses the excellent geopy library, which is stable and thoroughly road-tested. If you need help understanding a particular geocoder's options, consult geopy's documentation.

Supported Geocoders

The CLI currently supports these geocoders:

  • bing
  • googlev3
  • mapquest (and open-mapquest)
  • mapbox
  • nominatim
  • opencage

Adding new geocoders

  1. Open an issue with the name of the geocoding service as the ticket title (example). Put any noteworthy implementation details in the ticket body, like where to get an API key if one is required.
  2. Fork the repo and add a geocoder.
  3. Add an example to the Makefile. Add tests if there's new shared functionality.

Common arguments and options

Each geocoder needs to know where to find the data it's working with. These are the first two arguments:

  • database: a path to a SQLite file, which must already exist
  • table: the name of a table, in that database, which exists and has data to geocode

From there, we have a set of options passed to every geocoder:

  • location: a string format that will be expanded with each row to build a full query, to be geocoded
  • delay: a delay between each call (some services require this)
  • latitude: latitude column name
  • longitude: longitude column name
  • geojson: store results as GeoJSON, instead of in latitude and longitude columns
  • spatialite: store results in a SpatiaLite geometry column, instead of in latitude and longitude columns
  • raw: store raw geocoding results in a JSON column

Each geocoder takes additional, specific arguments beyond these, such as API keys. Again, geopy's documentation is an excellent resource.

Using SpatiaLite

The --spatialite flag will store results in a geometry column, instead of latitude and longitude columns. This is useful if you're doing other GIS operations, such as using a spatial index. See the SpatiaLite cookbook and functions list for more of what's possible.

Capturing additional geocoding data

Geocoding services typically return more data than just coordinates. This might include accuracy, normalized addresses or other context. This can be captured using the --raw flag. By default, this will add a raw column and store the full geocoding response as JSON. If you want to rename that column, pass a value, like --raw custom_raw.

The shape of this response object will vary between services. You can query specific values using SQLite's built-in JSON functions. For example, this will work with Google's geocoder:

select
  json_extract(raw, '$.formatted_address') as address,
  json_extract(raw, '$.geometry.location_type') as location_type
from
  innout_test

Check each geocoding service's documentation for what's included in the response.

Python API

The command line interface aims to support the most common options for each geocoder. For more fine-grained control, use the Python API.

As with the CLI, this assumes you already have a SQLite database and a table of location data.

from geocode_sqlite import geocode_table
from geopy.geocoders import Nominatim

# create a geocoder instance, with some extra options
nominatim = Nominatim(user_agent="this-is-me", domain="nominatim.local.dev", scheme="http")

# assuming our database is in the same directory
count = geocode_table("data.db", "data", query_template="{address}, {city}, {state} {zip}")

# when it's done
print(f"Geocoded {count} rows")

Any geopy geocoder can be used with the Python API.

Development

To contribute to this tool, first checkout the code. Then create a new virtual environment:

cd geocode-sqlite
python -m venv .venv
source .venv/bin/activate

Or if you are using pipenv:

pipenv shell

Now install the dependencies and tests:

pip install -e '.[test]'

To run the tests:

pytest

Please remember that this library is mainly glue code between other well-tested projects, specifically: click, geopy and sqlite-utils. Tests should focus on making sure those parts fit together correctly. We can assume the parts themselves already work.

To that end, there is a test geocoder included: geocode_sqlite.testing.DummyGeocoder. That geocoder works with an included dataset of In-N-Out Burger locations provided by AllThePlaces. It works like a normal GeoPy geocoder, except it will only return results for In-N-Out locations using the included database.

More Repositories

1

python-frontmatter

Parse and manage posts with YAML (or other) frontmatter
Python
321
star
2

python-tablefu

A Python version (almost a port) of ProPublica's TableFu
Python
231
star
3

awesome-journalism

A collection of awesome tools for journalism
96
star
4

propublica-congress

A Python client for the ProPublica Congress API
Python
54
star
5

feed-to-sqlite

Save an RSS or ATOM feed to a SQLite database
Python
44
star
6

python-wordpress

A really simple Python client for WordPress JSON API
Python
35
star
7

ulysses-js

A tool for telling stories with maps.
JavaScript
24
star
8

datasette-geojson-map

Render a map for any query with a geometry column
Python
23
star
9

visible-data

Cultural learnings of dataviz to make benefit glorious profession of journalism.
JavaScript
21
star
10

spatial-data-cooking-show

A demo project and template repository showing how I use SpatiaLite with Datasette for quick spatial analysis.
Makefile
16
star
11

self-hosted-maps-codespace

An example self-hosted map with all dependencies included
Makefile
16
star
12

datasette-query-files

Write Datasette canned queries as plain SQL files
Python
12
star
13

datasette-geojson

Add GeoJSON output to Datasette queries
Python
12
star
14

geocoder-comparison

A test of various geocoders available on the web
Python
11
star
15

python-nytcongress

Another Python client for the NY Times' Congress API
Python
10
star
16

alltheplaces-datasette

AllThePlaces in Datasette
Makefile
9
star
17

python-publish2

Publish2 is a tool for collaborative journalism, letting users create and distribute feeds of topical news links. This is the beginnings of a Python wrapper around Publish2's JSON feeds.
Python
7
star
18

simple-sunlight

A simpler wrapper for Sunlight's Congress API
Python
7
star
19

flask-docviewer

A really simple DocumentCloud viewer built on Python and Flask
Python
5
star
20

climate-change

The heat is on for the planet as a whole, but what has been happening where you live?
JavaScript
5
star
21

things-i-use

An opinionated list of what I reach for first on new projects
5
star
22

django-newsutils

A suite of simple, reusible tools for news sites
Python
5
star
23

data-loading-kit

A starter kit for loading data
Python
4
star
24

flask-tablesetter

A Python version of ProPublica's TableSetter, using Flask
JavaScript
4
star
25

tweetbill

Find legislators. Track bills. Take action.
Python
4
star
26

sqlite-colorbrewer

A custom function to use ColorBrewer scales in SQLite queries
Python
4
star
27

python-metalsmyth

A file processor, maybe a static site generator, inspired by Metalsmith.io
Python
4
star
28

chrisamico.com

My personal site. May include a blog.
Python
3
star
29

tennis-rankings

Scrapers for professional tennis rankings (ATP and WTA)
JavaScript
3
star
30

newsbot

A better news aggregator for DC
Python
3
star
31

walldrawings

Sol LeWitt's wall drawings, as implemented for the internet
CSS
3
star
32

dorchester

A toolkit for making dot-density maps in Python
Jupyter Notebook
3
star
33

til

Today I Learned
3
star
34

django-scrivo

Building myself a better, simpler blog engine
Python
3
star
35

nicar24-self-hosted-maps

Slides for my NICAR2024 talk
JavaScript
3
star
36

fedblogger

FedBlogger is an aggregator for federal government blogs
Python
3
star
37

bank-failures

Give me a heads up if there's a new bank failure
2
star
38

hello-congress

A demo app using the New York Times' Congress API and Flask
JavaScript
2
star
39

largest-fires-2018

The 10 largest fires in 2018
Makefile
2
star
40

ft-builder

A prototype Fusion Tables layer builder
JavaScript
2
star
41

jquery-winerlinks

Paragraph-level permalinks in one step
JavaScript
2
star
42

scorekeeper

A little app to keep score in games
HTML
2
star
43

nameparse

A little web service to parse names
Python
2
star
44

hw-maps

Homicide Watch mapping framework built on an open stack
JavaScript
2
star
45

boston-trees

Trees in Boston
Makefile
2
star
46

price-of-things

The prices of things in the news
JavaScript
2
star
47

baltimore-trees

A demo project for NICAR24 in Baltimore
Python
2
star
48

talks

Slides for talks, all in one repo
HTML
1
star
49

wildfires

1
star
50

wumb-to-sqlite

Scrape WUMB playlists to SQLite
HTML
1
star
51

wedding

I'm getting married next year. This is where I'm putting the code for a simple site we're using. It's not very reusable, but we only plan to use it once.
Python
1
star
52

mustachio

An excuse to stay up late playing with mustache templates
JavaScript
1
star
53

guess-mass

A game to learn Massachusetts towns
HTML
1
star
54

hw-partners

JavaScript
1
star
55

geojson-speed-test

What's the fastest way to load GeoJSON into SQLite?
Shell
1
star
56

python-alchemy

A really basic wrapper for Alchemy's text extraction API
Python
1
star
57

politicsinquotes

Python
1
star
58

classroulette

Spin the wheel. Maybe you'll learn something.
JavaScript
1
star
59

beijing_air

Keeping tabs on the air in Beijing
Python
1
star
60

backbone-opened-captions

A set of Backbone base classes for use with OpenedCaptions.
JavaScript
1
star
61

responsive-dataviz

Slides from my panel at #nicar14
JavaScript
1
star
62

ma-redistricting-2022

Let's play with redistricting data
Makefile
1
star
63

nicar-2020-three-kinds-of-code

The three kinds of code you'll write in the newsroom. My NICAR20 lightning talk.
HTML
1
star
64

dc-gis-data

DC Boundary Service Data
Python
1
star