We would like to associate trees with street addresses when possible. When collecting tree data, we could also make note of the nearest address. Since we are collecting longitude/latitude data anyway, it would be convenient if we had a list of street addresses with associated longitude/latitude. This would allow us to auto-populate an address field based on longitude/latitude data. How does one obtain a list of all street addresses in town with longitude/latitude data? Let’s start with obtaining addresses alone. Addresses are availble commercially e.g. from the post office, but for a substantial fee. Since this is a volunteer effort, I want to see what I can get for free. Our town publishes property assessments on a regular basis, but this is hardcopy in the local paper. Though assessments are available online, it is through a query interface providing one at a time, with no obvious way to download the entire list. I was able to find our town’s street sweeping schedule which supplies a list of all streets in html format:
Street Name
Rte
Location
Aberdeen Road
16
Tanager St. to Dundee Rd.
Academy Street
25
734 Mass. Ave. to Irving St.
Acorn Park
n/a
30 Concord Tpk., 100' swly
Acton Street
20
21 Appleton St. to Appleton Pl.
Adamian Park
7
Baker Rd. to 100' S'LY OF Upland Rd.
Adams Street
32
319 Mass. Ave. to 216 Bdwy.
Addison Street
27
106 Pleasant St., 800' sely
Aerial Street
2
169 Forest St., 375' nely
Aerial Street
2
375' nely of Forest St. to Carl Rd.
Aerial Street
2
Carl Rd. to 288 Wash. St.
Albermarle Street
21
Walnut St. to Mt. Vernon St.
Alfred Road
28
97 Lake St. to Princeton Rd.
Allen Street
32
339 Mass. Ave. to 70 Warren St.
Alpine Street
15
26 Park Ave. Ext., 350' nly
Alpine Street
15
350' nly Park Ave. Ext. to 300'swly Branch Av
Alpine Street
15
300' swly of Branch Ave. to Summer St
Alpine Terrace
1
Huntington Rd., 286' swly
Alton Street
35
295 Bdwy. to 158 Warren St.
Amherst Street
11
14 River St. to Rawson Rd.
Amsden Street
34
107 Mass. Ave. to Waldo Rd.
Andrew Street
32
Foster St. to Allen St.
Apache Trail
3
Lantern Ln to 150' wly of Cntry Clb Dr
etc.
Copy paste into a text editor and with a little manipulation in R, I can get a vector of street names:
1 2 3 4 5 6 7 8 9 10 11
> rm(list=ls(all=TRUE)) > library(rjson) > library(plyr) > > con <- file("streets-modified.csv", open="rt", encoding="latin1") > all.streets <-unique( readLines(con)) > head(all.streets) [1] "street""Aberdeen Rd ""Academy St ""Acton St " [5] "Adamian Park ""Adams St " > length(all.streets) [1] 561
Looks like about 561 streets total. From my hardcopy assessment I learn that:
Most streets don’t begin with 1 as the first address
Addresses aren’t consecutive - there can be many gaps in numbering
Most streets have fewer than 200 addresses
A few of the main streets have up to 1600 addresses
Query for GPS coordinates
To obtain street addresses with lng/lat data I will use the DataScienceToolkit Google Style geocoder. To obtain coordinates I need to submit an address that looks like:
I also want to count up the street addresses beginning at 1. This will give me a lng/lat for every address depending on how the geocoder handles addresses that don’t exist. Let’s find out.
> > > prefix <- 'http://www.datasciencetoolkit.org/maps/api/geocode/json?sensor=false&address=' > suffix <- "Arlington+MA" > > arl.addresses <- data.frame( lng = numeric(), lat = numeric(), num=numeric(), street = character()) > > prefix <- 'http://www.datasciencetoolkit.org/maps/api/geocode/json?sensor=false&address=' > suffix <- "Arlington+MA" > arl.addresses <- data.frame( lng = numeric(), lat = numeric(), num=numeric(), street = character()) > > for( i in1:20){ + middle <- gsub(" ","+",all.streets[10]) + url <- paste( prefix, i, "+", middle, suffix, sep="") #replace the space with a + sign + doc <- fromJSON(file=url, method='C') + arow <- data.frame( lng=doc$results[[1]]$geometry$location$lng, + lat=doc$results[[1]]$geometry$location$lat, + num=doc$results[[1]]$address_components[[1]]$short_name, + street=doc$results[[1]]$address_components[[2]]$short_name) + + arl.addresses <- rbind(arl.addresses, arow) + + } There were 20 warnings (use warnings() to see them) > > arl.addresses lng lat num street 1 -71.1467242.411621 Allen St 2 -71.1467242.411622 Allen St 3 -71.1467242.411513 Allen St 4 -71.1468442.411604 Allen St 5 -71.1467842.411455 Allen St 6 -71.1469042.411536 Allen St 7 -71.1468342.411397 Allen St 8 -71.1469742.411468 Allen St 9 -71.1468842.411329 Allen St 10 -71.1470342.4113910 Allen St 11 -71.1469442.4112611 Allen St 12 -71.1470942.4113212 Allen St 13 -71.1469942.4112013 Allen St 14 -71.1471542.4112514 Allen St 15 -71.1470542.4111415 Allen St 16 -71.1472242.4111816 Allen St 17 -71.1471042.4110817 Allen St 18 -71.1472842.4111018 Allen St 19 -71.1471642.4110219 Allen St 20 -71.1473442.4110320 Allen St >
Allen Street addresses begin at 12 so it looks like we will assigned lng/lat to nonexisting addresses. 1 and 2 share the same lng/lat. This also happens at the high end e.g. if the highest address is 100, 1 through 100 will be assigned unique lng/lats, and then the lng/lats become constant. Modify the code to stop querying once both lng and lat aren't changing.