3

Using the Office for National Statistics website I can get a census summary for a UK postcode.

https://neighbourhood.statistics.gov.uk/dissemination/

I expected that I should be able to do the same thing using the API.

https://neighbourhood.statistics.gov.uk/HTMLDocs/downloads/QuickStart-Guide-V2.1.pdf

But it isn't clear to me how to get from the postcode to the neighbourhood (or Lower Layer Super Output Area as the Office for National Statistics calls them). It seems that I need to use the Delivery endpoint like this.

http://neighbourhood.statistics.gov.uk/NDE2/Deli/getChildAreaTables?ParentAreaId=276980&LevelTypeId=141&Datasets=67

But how do I find out which parameters to use for a specific postcode?

Joe
  • 91
  • 7

2 Answers2

1

It looks like three calls are required to get a dataset.

import xml.etree.ElementTree as ElementTree
import json
import requests
API_KEY = "YOUR_API_KEY"

def get_area_id(level_type, postcode):
    """ Get the area id for the pos

    :param level_type: The resolution you are interested in. 14 = ward level data.
    :param postcode: A UK postcode
    :return: string area identifier
    """
    base_url = "http://neighbourhood.statistics.gov.uk/NDE2/Disco/FindAreas"
    payload = {'HierarchyId': '27', 'Postcode': postcode}
    response = requests.get(base_url, params=payload)
    xml = ElementTree.fromstring(response.content)
    namespaces = {'ns1': 'http://neighbourhood.statistics.gov.uk/nde/v1-0/discoverystructs'}
    xpath_for_area = './/ns1:Area'
    areas = xml.findall(xpath_for_area, namespaces)
    ward_area_id = ''
    for area in areas:
        level_type_id = area.find('ns1:LevelTypeId', namespaces).text
        if level_type_id == str(level_type):  # find the Ward (=14)
            ward_area_id = area.find('ns1:AreaId', namespaces).text
    return ward_area_id

def get_ext_code(area_id):
    """ Get the ext code (whatever that is) from an area id

    :param area_id: the area id for a postcode
    :return: the ext code for an area (I think is the GSS code)
    """
    base_url = "http://neighbourhood.statistics.gov.uk/NDE2/Disco/GetAreaDetail"
    payload = {'AreaId': area_id}
    response = requests.get(base_url, params=payload)
    xml = ElementTree.fromstring(response.content)
    namespaces = {'ns1': 'http://neighbourhood.statistics.gov.uk/nde/v1-0/discoverystructs',
              'structure': 'http://www.SDMX.org/resources/SDMXML/schemas/v2_0/structure'}
    xpath_for_ext_code = './/ns1:ExtCode'
    ext_code = xml.find(xpath_for_ext_code, namespaces).text
    return ext_code

def get_data(data_set, geog_code):
    """ Get the data for a geographical code

    :param data_set: string identifier from http://www.nomisweb.co.uk/census/2011 /quick_statistics
    :param geog_code: the ext code for the geographical area
    :return: a json object with the data
    """
    base_url = "http://data.ons.gov.uk/ons/api/data/dataset/"
    payload = {'apikey': API_KEY, 'context': 'Census', 'geog': '2011WARDH', 'dm/2011WARDH': geog_code,
               'totals': 'false', 'jsontype': 'json-stat'}
    r = requests.get(base_url + "/" + data_set + ".json", params=payload)
    obj = json.loads(r.text)
    return obj

def process(json_object, data_set):
    data = {}
    values = json_object[data_set]['value']
    index = json_object[data_set]['dimension'][json_object[data_set]['dimension']['id'][1]]['category']['index']
    labels = json_object[data_set]['dimension'][json_object[data_set]['dimension']['id'][1]]['category']['label']
    for l in labels:
        num = index[l]
        count = values[str(num)]
        data[labels[l]] = count
    return data

area_id = get_area_id(14, "SW1A 0AA")
gss_code = get_ext_code(area_id)
data_returned = get_data("QS208EW", gss_code)  # QS208EW = religion

print(process(data_returned, "QS208EW"))
Joe
  • 91
  • 7
0

Have you tried looking at the code in the VBA example?

Function RunAreas()
    Dim txtResponse
    Dim postcode As String
    Dim extCode
    Set rootSheet = GetSheet("Query")
    Set areaSheet = GetSheet("Areas")
    endPoint = "http://neighbourhood.statistics.gov.uk/NDE2/Disco/FindAreas?HierarchyId=27&Postcode="
    postcode = rootSheet.Range("A2").Value
    Application.StatusBar = "Getting areas for " + postcode
    txtResponse = GetAreas(postcode)
    delim = "<delim>"
    data = GetElements(txtResponse, "Area")

    If UBound(data) < 0 Then
        Application.StatusBar = False
        MsgBox "Postcode " + postcode + " not found", vbExclamation
        Exit Function
    End If

    For i = 0 To UBound(data)
        curLevelType = GetValue(data(i), "LevelTypeId")
        curHierarchy = GetValue(data(i), "HierarchyId")
        curId = GetValue(data(i), "AreaId")
        curName = GetValue(data(i), "Name")

        Select Case curLevelType
        Case 15
            extCode = UpdateArea("Output Area", 2, curId, curName, curHierarchy)
        Case 14
            extCode = UpdateArea("Ward", 3, curId, curName, curHierarchy)
        Case 13
            extCode = UpdateArea("LA", 4, curId, curName, curHierarchy)
        Case 11
            extCode = UpdateArea("Region", 5, curId, curName, curHierarchy)
        Case 10
            extCode = UpdateArea("Country", 6, curId, curName, curHierarchy)
        End Select

    Next

    MsgBox ("Areas Found")
    Application.StatusBar = "Get Areas completed"

End Function
TZHX
  • 5,291
  • 15
  • 47
  • 56
citydreams
  • 303
  • 1
  • 3
  • 5