Introduction

Eryk Walczak

2019-08-23

PostcodesioR is an API wrapper for postcodes.io. It allows acquiring geographic information about the UK postcodes and geographic coordinates.

Installation

if (!require("devtools")) install.packages("devtools")
devtools::install_github("erzk/PostcodesioR")

Lookup postcodes and outcodes

Single postcode

Provide a postcode to obtain all available information

## 'data.frame':    1 obs. of  31 variables:
##  $ postcode                       : chr "EC1Y 8LX"
##  $ quality                        : int 1
##  $ eastings                       : int 532544
##  $ northings                      : int 182128
##  $ country                        : chr "England"
##  $ nhs_ha                         : chr "London"
##  $ longitude                      : num -0.0909
##  $ latitude                       : num 51.5
##  $ european_electoral_region      : chr "London"
##  $ primary_care_trust             : chr "Islington"
##  $ region                         : chr "London"
##  $ lsoa                           : chr "Islington 023D"
##  $ msoa                           : chr "Islington 023"
##  $ incode                         : chr "8LX"
##  $ outcode                        : chr "EC1Y"
##  $ parliamentary_constituency     : chr "Islington South and Finsbury"
##  $ admin_district                 : chr "Islington"
##  $ parish                         : chr "Islington, unparished area"
##  $ admin_county                   : logi NA
##  $ admin_ward                     : chr "Bunhill"
##  $ ced                            : logi NA
##  $ ccg                            : chr "NHS Islington"
##  $ nuts                           : chr "Haringey and Islington"
##  $ admin_district_code            : chr "E09000019"
##  $ admin_county_code              : chr "E99999999"
##  $ admin_ward_code                : chr "E05000367"
##  $ parish_code                    : chr "E43000209"
##  $ parliamentary_constituency_code: chr "E14000764"
##  $ ccg_code                       : chr "E38000088"
##  $ ced_code                       : chr "E99999999"
##  $ nuts_code                      : chr "UKI43"

There is another function that returns the same data points but returns a list and allows optional parameters

## List of 1
##  $ :List of 24
##   ..$ postcode                  : chr "EC1Y 8LX"
##   ..$ quality                   : int 1
##   ..$ eastings                  : int 532544
##   ..$ northings                 : int 182128
##   ..$ country                   : chr "England"
##   ..$ nhs_ha                    : chr "London"
##   ..$ longitude                 : num -0.0909
##   ..$ latitude                  : num 51.5
##   ..$ european_electoral_region : chr "London"
##   ..$ primary_care_trust        : chr "Islington"
##   ..$ region                    : chr "London"
##   ..$ lsoa                      : chr "Islington 023D"
##   ..$ msoa                      : chr "Islington 023"
##   ..$ incode                    : chr "8LX"
##   ..$ outcode                   : chr "EC1Y"
##   ..$ parliamentary_constituency: chr "Islington South and Finsbury"
##   ..$ admin_district            : chr "Islington"
##   ..$ parish                    : chr "Islington, unparished area"
##   ..$ admin_county              : NULL
##   ..$ admin_ward                : chr "Bunhill"
##   ..$ ced                       : NULL
##   ..$ ccg                       : chr "NHS Islington"
##   ..$ nuts                      : chr "Haringey and Islington"
##   ..$ codes                     :List of 8
##   .. ..$ admin_district            : chr "E09000019"
##   .. ..$ admin_county              : chr "E99999999"
##   .. ..$ admin_ward                : chr "E05000367"
##   .. ..$ parish                    : chr "E43000209"
##   .. ..$ parliamentary_constituency: chr "E14000764"
##   .. ..$ ccg                       : chr "E38000088"
##   .. ..$ ced                       : chr "E99999999"
##   .. ..$ nuts                      : chr "UKI43"

This function creates a nested list with the codes for administrative district, county, ward, parish, parliamentary constituency, CCG, and NUTS.

Multiple postcodes

To query two or more postcodes, use bulk_ functions.

## List of 1
##  $ :List of 2
##   ..$ query : chr "PR3 0SG"
##   ..$ result:List of 24
##   .. ..$ postcode                  : chr "PR3 0SG"
##   .. ..$ quality                   : int 1
##   .. ..$ eastings                  : int 351012
##   .. ..$ northings                 : int 440302
##   .. ..$ country                   : chr "England"
##   .. ..$ nhs_ha                    : chr "North West"
##   .. ..$ longitude                 : num -2.75
##   .. ..$ latitude                  : num 53.9
##   .. ..$ european_electoral_region : chr "North West"
##   .. ..$ primary_care_trust        : chr "North Lancashire Teaching"
##   .. ..$ region                    : chr "North West"
##   .. ..$ lsoa                      : chr "Wyre 006A"
##   .. ..$ msoa                      : chr "Wyre 006"
##   .. ..$ incode                    : chr "0SG"
##   .. ..$ outcode                   : chr "PR3"
##   .. ..$ parliamentary_constituency: chr "Wyre and Preston North"
##   .. ..$ admin_district            : chr "Wyre"
##   .. ..$ parish                    : chr "Myerscough and Bilsborrow"
##   .. ..$ admin_county              : chr "Lancashire"
##   .. ..$ admin_ward                : chr "Brock with Catterall"
##   .. ..$ ced                       : chr "Wyre Rural East"
##   .. ..$ ccg                       : chr "NHS Fylde and Wyre"
##   .. ..$ nuts                      : chr "Lancaster and Wyre"
##   .. ..$ codes                     :List of 8
##   .. .. ..$ admin_district            : chr "E07000128"
##   .. .. ..$ admin_county              : chr "E10000017"
##   .. .. ..$ admin_ward                : chr "E05009934"
##   .. .. ..$ parish                    : chr "E04005340"
##   .. .. ..$ parliamentary_constituency: chr "E14001057"
##   .. .. ..$ ccg                       : chr "E38000226"
##   .. .. ..$ ced                       : chr "E58000832"
##   .. .. ..$ nuts                      : chr "UKD44"

Outward code lookup

Provide an outcode to obtain geolocation data for the centroid of the specified outcode:

## List of 10
##  $ outcode       : chr "E1"
##  $ longitude     : num -0.0595
##  $ latitude      : num 51.5
##  $ northings     : int 181614
##  $ eastings      : int 534738
##  $ admin_district:List of 3
##   ..$ : chr "Hackney"
##   ..$ : chr "City of London"
##   ..$ : chr "Tower Hamlets"
##  $ parish        :List of 3
##   ..$ : chr "Hackney, unparished area"
##   ..$ : chr "City of London, unparished area"
##   ..$ : chr "Tower Hamlets, unparished area"
##  $ admin_county  : list()
##  $ admin_ward    :List of 13
##   ..$ : chr "Shadwell"
##   ..$ : chr "Spitalfields & Banglatown"
##   ..$ : chr "St Dunstan's"
##   ..$ : chr "Portsoken"
##   ..$ : chr "Stepney Green"
##   ..$ : chr "Weavers"
##   ..$ : chr "Whitechapel"
##   ..$ : chr "Bethnal Green"
##   ..$ : chr "Bishopsgate"
##   ..$ : chr "Hoxton East & Shoreditch"
##   ..$ : chr "Tower"
##   ..$ : chr "Aldgate"
##   ..$ : chr "St Peter's"
##  $ country       :List of 1
##   ..$ : chr "England"

Reverse geocoding

Provide latitude and longitude to obtain geographic information. Different levels of aggregation are available, i.e. postcode or outcode.

Single postcode

## List of 1
##  $ :List of 25
##   ..$ postcode                  : chr "SE28 8NH"
##   ..$ quality                   : int 1
##   ..$ eastings                  : int 547715
##   ..$ northings                 : int 180780
##   ..$ country                   : chr "England"
##   ..$ nhs_ha                    : chr "London"
##   ..$ longitude                 : num 0.127
##   ..$ latitude                  : num 51.5
##   ..$ european_electoral_region : chr "London"
##   ..$ primary_care_trust        : chr "Bexley"
##   ..$ region                    : chr "London"
##   ..$ lsoa                      : chr "Bexley 001D"
##   ..$ msoa                      : chr "Bexley 001"
##   ..$ incode                    : chr "8NH"
##   ..$ outcode                   : chr "SE28"
##   ..$ distance                  : num 38.9
##   ..$ parliamentary_constituency: chr "Erith and Thamesmead"
##   ..$ admin_district            : chr "Bexley"
##   ..$ parish                    : chr "Bexley, unparished area"
##   ..$ admin_county              : NULL
##   ..$ admin_ward                : chr "Thamesmead East"
##   ..$ ced                       : NULL
##   ..$ ccg                       : chr "NHS Bexley"
##   ..$ nuts                      : chr "Bexley and Greenwich"
##   ..$ codes                     :List of 8
##   .. ..$ admin_district            : chr "E09000004"
##   .. ..$ admin_county              : chr "E99999999"
##   .. ..$ admin_ward                : chr "E05011232"
##   .. ..$ parish                    : chr "E43000194"
##   .. ..$ parliamentary_constituency: chr "E14000696"
##   .. ..$ ccg                       : chr "E38000011"
##   .. ..$ ced                       : chr "E99999999"
##   .. ..$ nuts                      : chr "UKI51"

Multiple postcodes

To reverse geocode multiple values use the function underneath. The result is a nested list, which might be a bit intimidating, but it allows storing unequal number of elements.

## $postcode
## [1] "CF24 2BT"
## 
## $quality
## [1] 1
## 
## $eastings
## [1] 319675
## 
## $northings
## [1] 176305
## 
## $country
## [1] "Wales"
## 
## $nhs_ha
## [1] "Cardiff and Vale University Health Board"
## 
## $longitude
## [1] -3.158076
## 
## $latitude
## [1] 51.47998
## 
## $european_electoral_region
## [1] "Wales"
## 
## $primary_care_trust
## [1] "Cardiff and Vale University Health Board"
## 
## $region
## NULL
## 
## $lsoa
## [1] "Cardiff 038D"
## 
## $msoa
## [1] "Cardiff 038"
## 
## $incode
## [1] "2BT"
## 
## $outcode
## [1] "CF24"
## 
## $distance
## [1] 1.567236
## 
## $parliamentary_constituency
## [1] "Cardiff South and Penarth"
## 
## $admin_district
## [1] "Cardiff"
## 
## $parish
## [1] "Splott"
## 
## $admin_county
## NULL
## 
## $admin_ward
## [1] "Splott"
## 
## $ced
## NULL
## 
## $ccg
## [1] "Cardiff and Vale University Health Board"
## 
## $nuts
## [1] "Cardiff and Vale of Glamorgan"
## 
## $codes
## $codes$admin_district
## [1] "W06000015"
## 
## $codes$admin_county
## [1] "W99999999"
## 
## $codes$admin_ward
## [1] "W05000879"
## 
## $codes$parish
## [1] "W04001005"
## 
## $codes$parliamentary_constituency
## [1] "W07000080"
## 
## $codes$ccg
## [1] "W11000029"
## 
## $codes$ced
## [1] "W99999999"
## 
## $codes$nuts
## [1] "UKL22"

The list above is not the most common way of storing files. It’s more likely that a data frame will be used to store the geodata. In that case, it has to be turned into a list of a specific format required by the API:

##   longitude latitude limit radius
## 1 -3.158077 51.47999    NA     NA
## 2 -1.129358 50.71864   100    500
## $geolocations
##   longitude latitude limit radius
## 1 -3.158077 51.47999    NA     NA
## 2 -1.129358 50.71864   100    500

Common usage of this function might be extracting particular variables. You can extract one variable like this:

## [1] "CF24 2AL"

But more likely you will want more than one result. After all, that’s the point of using a bulk function:

##    postcode  latitude longitude
## 1  CF24 2BT 51.479976 -3.158076
## 2  CF24 2ED 51.479691 -3.158688
## 3  CF24 2AA 51.480209 -3.159062
## 4  CF24 5NW  51.47936 -3.158478
## 5  CF24 2AJ 51.480682 -3.158526
## 6  CF24 2AH 51.480552 -3.158912
## 7  CF24 2DZ 51.480105 -3.156798
## 8  CF24 2AL  51.48083 -3.158141
## 9  PO33 1PS 50.718813 -1.129298
## 10 PO33 1PT 50.718573 -1.128467
## 11 PO33 1PX 50.717878 -1.127136
## 12 PO33 1QB 50.717046 -1.129826
## 13 PO33 1QD 50.717191 -1.127843
## 14 PO33 1PU 50.718465 -1.126032
## 15 PO33 1PZ 50.716247 -1.127932
## 16 PO33 1QR  50.71574 -1.125998
## 17 PO33 1PB 50.721022 -1.133719
## 18 PO33 1PR 50.721486 -1.133187
## 19 PO33 1FS 50.717205 -1.123735
## 20 PO33 1PY 50.715159 -1.126734
## 21 PO33 1QP 50.715694 -1.124911
## 22 PO34 5AP 50.721464 -1.124234

Single outcode

## List of 1
##  $ :List of 11
##   ..$ outcode       : chr "CF99"
##   ..$ longitude     : num -3.16
##   ..$ latitude      : num 51.5
##   ..$ northings     : int 174588
##   ..$ eastings      : int 319421
##   ..$ admin_district:List of 1
##   .. ..$ : chr "Cardiff"
##   ..$ parish        :List of 1
##   .. ..$ : chr "Butetown"
##   ..$ admin_county  : list()
##   ..$ admin_ward    :List of 1
##   .. ..$ : chr "Butetown"
##   ..$ country       :List of 1
##   .. ..$ : chr "Wales"
##   ..$ distance      : num 997

Generate random entries

Postcodes

Generates a list with a random UK postcode and corresponding geographic information:

## $postcode
## [1] "ME18 6AB"
## 
## $quality
## [1] 1
## 
## $eastings
## [1] 569435
## 
## $northings
## [1] 152031
## 
## $country
## [1] "England"
## 
## $nhs_ha
## [1] "South East Coast"
## 
## $longitude
## [1] 0.426016
## 
## $latitude
## [1] 51.24229
## 
## $european_electoral_region
## [1] "South East"
## 
## $primary_care_trust
## [1] "West Kent"
## 
## $region
## [1] "South East"
## 
## $lsoa
## [1] "Maidstone 014B"
## 
## $msoa
## [1] "Maidstone 014"
## 
## $incode
## [1] "6AB"
## 
## $outcode
## [1] "ME18"
## 
## $parliamentary_constituency
## [1] "Maidstone and The Weald"
## 
## $admin_district
## [1] "Maidstone"
## 
## $parish
## [1] "West Farleigh"
## 
## $admin_county
## [1] "Kent"
## 
## $admin_ward
## [1] "Coxheath and Hunton"
## 
## $ced
## [1] "Maidstone Rural West"
## 
## $ccg
## [1] "NHS West Kent"
## 
## $nuts
## [1] "Mid Kent"
## 
## $codes
## $codes$admin_district
## [1] "E07000110"
## 
## $codes$admin_county
## [1] "E10000016"
## 
## $codes$admin_ward
## [1] "E05008553"
## 
## $codes$parish
## [1] "E04004977"
## 
## $codes$parliamentary_constituency
## [1] "E14000804"
## 
## $codes$ccg
## [1] "E38000199"
## 
## $codes$ced
## [1] "E58000716"
## 
## $codes$nuts
## [1] "UKJ45"

A randomly generated postcode can also belong to a particular outcode:

## $postcode
## [1] "N1 4JE"
## 
## $quality
## [1] 1
## 
## $eastings
## [1] 533077
## 
## $northings
## [1] 184654
## 
## $country
## [1] "England"
## 
## $nhs_ha
## [1] "London"
## 
## $longitude
## [1] -0.082291
## 
## $latitude
## [1] 51.5451
## 
## $european_electoral_region
## [1] "London"
## 
## $primary_care_trust
## [1] "City and Hackney Teaching"
## 
## $region
## [1] "London"
## 
## $lsoa
## [1] "Hackney 021D"
## 
## $msoa
## [1] "Hackney 021"
## 
## $incode
## [1] "4JE"
## 
## $outcode
## [1] "N1"
## 
## $parliamentary_constituency
## [1] "Hackney South and Shoreditch"
## 
## $admin_district
## [1] "Hackney"
## 
## $parish
## [1] "Hackney, unparished area"
## 
## $admin_county
## NULL
## 
## $admin_ward
## [1] "De Beauvoir"
## 
## $ced
## NULL
## 
## $ccg
## [1] "NHS City and Hackney"
## 
## $nuts
## [1] "Hackney and Newham"
## 
## $codes
## $codes$admin_district
## [1] "E09000012"
## 
## $codes$admin_county
## [1] "E99999999"
## 
## $codes$admin_ward
## [1] "E05009371"
## 
## $codes$parish
## [1] "E43000202"
## 
## $codes$parliamentary_constituency
## [1] "E14000721"
## 
## $codes$ccg
## [1] "E38000035"
## 
## $codes$ced
## [1] "E99999999"
## 
## $codes$nuts
## [1] "UKI41"

Places

You can also generate a random place, specified by an OSGB code, with corresponding geographic information:

random_place()
##                   code name_1 name_1_lang name_2 name_2_lang local_type
## 1 osgb4000000074334496 Chapel        NULL   NULL        NULL     Hamlet
##   outcode    county_unitary county_unitary_type district_borough
## 1     ML2 North Lanarkshire    UnitaryAuthority             NULL
##   district_borough_type   region  country longitude latitude eastings
## 1                  NULL Scotland Scotland  -3.85938 55.77092   283452
##   northings min_eastings min_northings max_eastings max_northings
## 1    654630       283204        654337       283704        654837

Postcode validation

This function can validate a UK postcode:

postcode_validation("EC1Y 8LX") # actual UK postcode
## [1] TRUE
postcode_validation("XYZ") # incorrect UK postcode
## [1] FALSE

Autocomplete postcodes

Find the potential candidates for a postcode if you only know the beginning characters

postcode_autocomplete("EC1")
##    postcode
## 1  EC1A 1AA
## 2  EC1A 1AH
## 3  EC1A 1AZ
## 4  EC1A 1BB
## 5  EC1A 1DN
## 6  EC1A 1DU
## 7  EC1A 1HQ
## 8  EC1A 1TA
## 9  EC1A 1TB
## 10 EC1A 1TF

It defaults to 10 candidates, but can be changed by specifying the limit argument.

Find nearest postcodes or outcodes

Provide a postcode to get a list of the nearest postcodes:

near_pc <- nearest_postcode("EC1Y 8LX")

#overview
str(near_pc[1])
## List of 1
##  $ :List of 25
##   ..$ postcode                  : chr "EC1Y 8LX"
##   ..$ quality                   : int 1
##   ..$ eastings                  : int 532544
##   ..$ northings                 : int 182128
##   ..$ country                   : chr "England"
##   ..$ nhs_ha                    : chr "London"
##   ..$ longitude                 : num -0.0909
##   ..$ latitude                  : num 51.5
##   ..$ european_electoral_region : chr "London"
##   ..$ primary_care_trust        : chr "Islington"
##   ..$ region                    : chr "London"
##   ..$ lsoa                      : chr "Islington 023D"
##   ..$ msoa                      : chr "Islington 023"
##   ..$ incode                    : chr "8LX"
##   ..$ outcode                   : chr "EC1Y"
##   ..$ distance                  : int 0
##   ..$ parliamentary_constituency: chr "Islington South and Finsbury"
##   ..$ admin_district            : chr "Islington"
##   ..$ parish                    : chr "Islington, unparished area"
##   ..$ admin_county              : NULL
##   ..$ admin_ward                : chr "Bunhill"
##   ..$ ced                       : NULL
##   ..$ ccg                       : chr "NHS Islington"
##   ..$ nuts                      : chr "Haringey and Islington"
##   ..$ codes                     :List of 8
##   .. ..$ admin_district            : chr "E09000019"
##   .. ..$ admin_county              : chr "E99999999"
##   .. ..$ admin_ward                : chr "E05000367"
##   .. ..$ parish                    : chr "E43000209"
##   .. ..$ parliamentary_constituency: chr "E14000764"
##   .. ..$ ccg                       : chr "E38000088"
##   .. ..$ ced                       : chr "E99999999"
##   .. ..$ nuts                      : chr "UKI43"

You can also use outcodes:

near_outcode <- nearest_outcode("EC1Y")

# overview
str(near_outcode[2])
## List of 1
##  $ :List of 11
##   ..$ outcode       : chr "EC2Y"
##   ..$ longitude     : num -0.0937
##   ..$ latitude      : num 51.5
##   ..$ northings     : int 181784
##   ..$ eastings      : int 532361
##   ..$ admin_district:List of 2
##   .. ..$ : chr "Islington"
##   .. ..$ : chr "City of London"
##   ..$ parish        :List of 2
##   .. ..$ : chr "Islington, unparished area"
##   .. ..$ : chr "City of London, unparished area"
##   ..$ admin_county  : list()
##   ..$ admin_ward    :List of 6
##   .. ..$ : chr "Coleman Street"
##   .. ..$ : chr "Aldersgate"
##   .. ..$ : chr "Bunhill"
##   .. ..$ : chr "Bassishaw"
##   .. ..$ : chr "Clerkenwell"
##   .. ..$ : chr "Cripplegate"
##   ..$ country       :List of 1
##   .. ..$ : chr "England"
##   ..$ distance      : num 405

Or longitude and latitude

near_ll <- nearest_outcode_lonlat(0.127, 51.507)

#overview
str(near_ll[1])
## List of 1
##  $ :List of 11
##   ..$ outcode       : chr "DA18"
##   ..$ longitude     : num 0.136
##   ..$ latitude      : num 51.5
##   ..$ northings     : int 179425
##   ..$ eastings      : int 548403
##   ..$ admin_district:List of 1
##   .. ..$ : chr "Bexley"
##   ..$ parish        :List of 1
##   .. ..$ : chr "Bexley, unparished area"
##   ..$ admin_county  : list()
##   ..$ admin_ward    :List of 2
##   .. ..$ : chr "Slade Green & Northend"
##   .. ..$ : chr "Thamesmead East"
##   ..$ country       :List of 1
##   .. ..$ : chr "England"
##   ..$ distance      : num 1556

Find places

Provide a name of a place of interest. You can specify the number of results (default is 10):

place_query_result <- place_query("Hills", limit = 11)

# overview
str(place_query_result[1])
## List of 1
##  $ :List of 21
##   ..$ code                 : chr "osgb4000000074547803"
##   ..$ name_1               : chr "Red Hills"
##   ..$ name_1_lang          : NULL
##   ..$ name_2               : NULL
##   ..$ name_2_lang          : NULL
##   ..$ local_type           : chr "Hamlet"
##   ..$ outcode              : chr "CA11"
##   ..$ county_unitary       : chr "Cumbria"
##   ..$ county_unitary_type  : chr "County"
##   ..$ district_borough     : chr "Eden"
##   ..$ district_borough_type: chr "District"
##   ..$ region               : chr "North West"
##   ..$ country              : chr "England"
##   ..$ longitude            : num -2.77
##   ..$ latitude             : num 54.7
##   ..$ eastings             : int 350463
##   ..$ northings            : int 528605
##   ..$ min_eastings         : int 349916
##   ..$ min_northings        : int 528349
##   ..$ max_eastings         : int 350584
##   ..$ max_northings        : int 528849

You can also find a place using an OSGB code:

place_lookup_result <- place_lookup("osgb4000000074544700")

# overview
str(place_lookup_result)
## List of 21
##  $ code                 : chr "osgb4000000074544700"
##  $ name_1               : chr "Cutler Heights"
##  $ name_1_lang          : NULL
##  $ name_2               : NULL
##  $ name_2_lang          : NULL
##  $ local_type           : chr "Suburban Area"
##  $ outcode              : chr "BD4"
##  $ county_unitary       : NULL
##  $ county_unitary_type  : NULL
##  $ district_borough     : chr "Bradford"
##  $ district_borough_type: chr "MetropolitanDistrict"
##  $ region               : chr "Yorkshire and the Humber"
##  $ country              : chr "England"
##  $ longitude            : num -1.72
##  $ latitude             : num 53.8
##  $ eastings             : int 418830
##  $ northings            : int 431785
##  $ min_eastings         : int 418487
##  $ min_northings        : int 431541
##  $ max_eastings         : int 419040
##  $ max_northings        : int 432041

Terminated postcodes

You might end up having terminated postcodes in your data set. These are postcodes that are no longer active. UK postcodes can change so it’s worth checking whether used postcodes are still active. If you need more information about when a particular postcode was terminated use:

terminated_postcode("E1W 1UU")
##   postcode year_terminated month_terminated longitude latitude
## 1  E1W 1UU            2015                2 -0.073732 51.50801