/sf-locate

Offline geolocation for the rest of us

Primary LanguageJavaScript

sf-locate

Geolocating street addresses in SF

the goal

You have an address (or an array of addresses) in San Francisco and you want to know:

  • what election precinct is in it?
  • what neighborhood?
  • which census tract?
  • supervisor district?
  • ...?

Only... you don't know PostGIS. You don't want to upload sensitive information to Carto. You don't have the time to learn spacial joins.

Have no fear. This will (hopefully) make your life easier.

Use the code here to run your analysis offline and locally. The tradeoff is it's not super efficient, so you'll probably have to do some manually and in batches.

data sources

Data comes from DataSF

geographic lineshapes

setup

Run once

  1. $ npm run downloads
  2. $ npm run prep-data This creates a lookup table of addresses in San Francisco which gets reused. It will take a long time (like, 0.5-2hr or more, depending) to process all the addresses, because it is inefficient.

Optional

  1. put additional (non-official) addresses into additional-addresses.csv
  2. run additional-munge.js
  3. copy those addresses into ./data/addressesProcessed.csv

tests

Oh snap! I actually wrote tests?

  • $npm test

use

  const SFLocator = require('locator.js')
  let locator = new SFLocator()

  let mainLibrary = locator.findOne({address: '100 Larkin St.', zipcode: '94102'})
  // mainLibrary now contains properties:
  // {
  //   address: '100 LARKIN ST',
  //   zipcode: '94102',
  //   assemdist: '17',
  //   bartdist: '9',
  //   congdist: '12',
  //   nhood: 'Tenderloin',
  //   prec_2010: '3621',
  //   prec_2012: '7617',
  //   supdist: '6',
  //   tractce10: '012402'
  // }

  let someLibraries = locator.findMany([
    {address: '100 Larkin St.', zipcode: '94102'},
    {address: '550 37th Avenue', zipcode: '94121'},
    {address: '123 Main Street', zipcode: '12345'}
  ])
  // someLibraries now looks like:
  // {
  //   result: [
  //     {address: '100 LARKIN ST', assemdist: '17', ...},
  //     {address: '550 37TH AVE', nhood: 'Outer Richmond', ...},
  //     'Not an SF zip code'
  //   ],
  //   unmatched: [
  //     {address: '123 Main Street', zipcode: '12345', reason: 'Not an SF zip code'}
  //   ]}

see example.js for more (now with streams!)

improvements

  • use the Addresses-with-Units dataset (dxjs-vqsy) to get parcel/blocklot numbers
  • make the code more efficient
  • make sure this is reusable for other municipalities
  • use any geojson files to do geocoding for whatever boundaries desired
  • do this in Python, R, whatever
  • write some more tests

sqlite settings

setup:

.mode csv
.import data/addressesProcessed.csv sanfrancisco
delete from sanfrancisco where street = 'UNKNOWN';
delete from sanfrancisco where longitude = 0;