Extracting by location

Up to this point, we have only looked at the summary data from each model run. There is a lot more that can be explored, as metawards models the outbreak in every ward in the model (e.g. every electoral ward in the UK).

Metadata about those wards is loaded into info() object, which is of class WardInfos. This class can be queried to get the index of wards according to their name, their official ID code, or the local authority or region in which it belongs.

Searching using WardInfo

For example, we can find all of the wards that match the name “Clifton” using the below code. Open up ipython or a Jupyter notebook and type;

>>> from metawards import Network, Parameters
>>> params = Parameters.load()
>>> params.set_input_files("2011Data")
>>> params.set_disease("lurgy")
>>> network = Network.build(params)

This has now built a network object that you can query, e.g.

>>> clifton = network.info.find("Clifton")
>>> print(clifton)
[154, 403, 829, 3612, 3662, 3670, 3703, 3766, 3974, 3975, 8134, 8327, 8328]
>>> for ward in clifton:
...     print(network.info[ward])
WardInfo(name='Clifton-with-Maidenway', alternate_names=['Clifton-with-Maidenway'], code='E05002101', alternate_codes=['E36000654'], authority='Torbay', authority_code='E06000027', region='', region_code='')
WardInfo(name='Clifton', alternate_names=['Clifton'], code='E05003119', alternate_codes=['E36001870'], authority='Allerdale', authority_code='E07000026', region='', region_code='')
WardInfo(name='Clifton and Bradley', alternate_names=['Clifton and Bradley'], code='E05003350', alternate_codes=['E36002100'], authority='Derbyshire Dales', authority_code='E07000035', region='', region_code='')
WardInfo(name='Skelton, Rawcliffe and Clifton Without', alternate_names=['Skelton, Rawcliffe and Clifton Without'], code='E05001763', alternate_codes=['E36000299'], authority='York', authority_code='E06000014', region='', region_code='')
WardInfo(name='Clifton', alternate_names=['Clifton'], code='E05001980', alternate_codes=['E36000533'], authority='Bristol, City of', authority_code='E06000023', region='', region_code='')
WardInfo(name='Clifton East', alternate_names=['Clifton East'], code='E05001981', alternate_codes=['E36000534'], authority='Bristol, City of', authority_code='E06000023', region='', region_code='')
WardInfo(name='Clifton', alternate_names=['Clifton'], code='E05001747', alternate_codes=['E36000283'], authority='York', authority_code='E06000014', region='', region_code='')
WardInfo(name='Clifton', alternate_names=['Clifton'], code='E05001648', alternate_codes=['E36000184'], authority='Blackpool', authority_code='E06000009', region='', region_code='')
WardInfo(name='Clifton North', alternate_names=['Clifton North'], code='E05001831', alternate_codes=['E36000367'], authority='Nottingham', authority_code='E06000018', region='', region_code='')
WardInfo(name='Clifton South', alternate_names=['Clifton South'], code='E05001832', alternate_codes=['E36000368'], authority='Nottingham', authority_code='E06000018', region='', region_code='')
WardInfo(name='Clifton', alternate_names=['Clifton'], code='E05005188', alternate_codes=['E36003801'], authority='Fylde', authority_code='E07000119', region='', region_code='')
WardInfo(name='Cliftonville East', alternate_names=['Cliftonville East'], code='E05005087', alternate_codes=['E36003700'], authority='Thanet', authority_code='E07000114', region='', region_code='')
WardInfo(name='Cliftonville West', alternate_names=['Cliftonville West'], code='E05005088', alternate_codes=['E36003701'], authority='Thanet', authority_code='E07000114', region='', region_code='')

This has returned all wards that have “Clifton” in the name. The search is actually performed as a regular expression, and is case-insensitive. You can pass a regular expression string directly, e.g. `r"^(Clifton)$"` would match “Clifton” at the beginning (`^`) and end (`$`) of the string, i.e. it only matches wards that exactly match “Clifton”. Try this by typing;

>>> clifton = network.info.find(r"^(Clifton)$")
>>> for ward in clifton:
...    print(network.info[ward])
WardInfo(name='Clifton', alternate_names=['Clifton'], code='E05003119', alternate_codes=['E36001870'], authority='Allerdale', authority_code='E07000026', region='', region_code='')
WardInfo(name='Clifton', alternate_names=['Clifton'], code='E05001980', alternate_codes=['E36000533'], authority='Bristol, City of', authority_code='E06000023', region='', region_code='')
WardInfo(name='Clifton', alternate_names=['Clifton'], code='E05001747', alternate_codes=['E36000283'], authority='York', authority_code='E06000014', region='', region_code='')
WardInfo(name='Clifton', alternate_names=['Clifton'], code='E05001648', alternate_codes=['E36000184'], authority='Blackpool', authority_code='E06000009', region='', region_code='')
WardInfo(name='Clifton', alternate_names=['Clifton'], code='E05005188', alternate_codes=['E36003801'], authority='Fylde', authority_code='E07000119', region='', region_code='')

Searching by local authority

There are many “Clifton”s in the UK. We can limit to the “Clifton” in Bristol by specifying the local authority. Again, this can be a regular expression, although in this case just searching for “Bristol” will be enough.

>>> clifton = network.info.find(r"^(Clifton)$", authority="Bristol")
>>> for ward in clifton:
...     print(ward)
WardInfo(name='Clifton', alternate_names=['Clifton'], code='E05001980', alternate_codes=['E36000533'], authority='Bristol, City of', authority_code='E06000023', region='', region_code='')

Note

In this case the dataset does not include regional data (the `region` is empty). If regional data was available you could search by region using `network.info.find("Clifton", region="South West").

This searching is very powerful. For example, we can now search for all wards that are in the same local authority as “Clifton, Bristol”, e.g.

>>> clifton = network.info.find(r"^(Clifton)$", authority="Bristol")[0]
>>> clifton = newwork.info[clifton]
>>> authority_code = clifton.authority_code
>>> wards = network.info.find(authority=authority_code)
>>> for ward in wards:
...     print(ward)
WardInfo(name='Brislington West', alternate_names=['Brislington West'], code='E05001978', alternate_codes=['E36000531'], authority='Bristol, City of', authority_code='E06000023', region='', region_code='')
WardInfo(name='Cabot', alternate_names=['Cabot'], code='E05001979', alternate_codes=['E36000532'], authority='Bristol, City of', authority_code='E06000023', region='', region_code='')
WardInfo(name='Clifton', alternate_names=['Clifton'], code='E05001980', alternate_codes=['E36000533'], authority='Bristol, City of', authority_code='E06000023', region='', region_code='')
WardInfo(name='Clifton East', alternate_names=['Clifton East'], code='E05001981', alternate_codes=['E36000534'], authority='Bristol, City of', authority_code='E06000023', region='', region_code='')
WardInfo(name='Cotham', alternate_names=['Cotham'], code='E05001982', alternate_codes=['E36000535'], authority='Bristol, City of', authority_code='E06000023', region='', region_code='')
WardInfo(name='Easton', alternate_names=['Easton'], code='E05001983', alternate_codes=['E36000536'], authority='Bristol, City of', authority_code='E06000023', region='', region_code='')
WardInfo(name='Eastville', alternate_names=['Eastville'], code='E05001984', alternate_codes=['E36000537'], authority='Bristol, City of', authority_code='E06000023', region='', region_code='')
WardInfo(name='Filwood', alternate_names=['Filwood'], code='E05001985', alternate_codes=['E36000538'], authority='Bristol, City of', authority_code='E06000023', region='', region_code='')
WardInfo(name='Frome Vale', alternate_names=['Frome Vale'], code='E05001986', alternate_codes=['E36000539'], authority='Bristol, City of', authority_code='E06000023', region='', region_code='')
WardInfo(name='Hartcliffe', alternate_names=['Hartcliffe'], code='E05001987', alternate_codes=['E36000540'], authority='Bristol, City of', authority_code='E06000023', region='', region_code='')
WardInfo(name='Henbury', alternate_names=['Henbury'], code='E05001988', alternate_codes=['E36000541'], authority='Bristol, City of', authority_code='E06000023', region='', region_code='')
WardInfo(name='Hengrove', alternate_names=['Hengrove'], code='E05001989', alternate_codes=['E36000542'], authority='Bristol, City of', authority_code='E06000023', region='', region_code='')
WardInfo(name='Henleaze', alternate_names=['Henleaze'], code='E05001990', alternate_codes=['E36000543'], authority='Bristol, City of', authority_code='E06000023', region='', region_code='')
WardInfo(name='Hillfields', alternate_names=['Hillfields'], code='E05001991', alternate_codes=['E36000544'], authority='Bristol, City of', authority_code='E06000023', region='', region_code='')
WardInfo(name='Horfield', alternate_names=['Horfield'], code='E05001992', alternate_codes=['E36000545'], authority='Bristol, City of', authority_code='E06000023', region='', region_code='')
WardInfo(name='Kingsweston', alternate_names=['Kingsweston'], code='E05001993', alternate_codes=['E36000546'], authority='Bristol, City of', authority_code='E06000023', region='', region_code='')
WardInfo(name='Ashley', alternate_names=['Ashley'], code='E05001972', alternate_codes=['E36000525'], authority='Bristol, City of', authority_code='E06000023', region='', region_code='')
WardInfo(name='Avonmouth', alternate_names=['Avonmouth'], code='E05001973', alternate_codes=['E36000526'], authority='Bristol, City of', authority_code='E06000023', region='', region_code='')
WardInfo(name='Bedminster', alternate_names=['Bedminster'], code='E05001974', alternate_codes=['E36000527'], authority='Bristol, City of', authority_code='E06000023', region='', region_code='')
WardInfo(name='Bishopston', alternate_names=['Bishopston'], code='E05001975', alternate_codes=['E36000528'], authority='Bristol, City of', authority_code='E06000023', region='', region_code='')
WardInfo(name='Bishopsworth', alternate_names=['Bishopsworth'], code='E05001976', alternate_codes=['E36000529'], authority='Bristol, City of', authority_code='E06000023', region='', region_code='')
WardInfo(name='Brislington East', alternate_names=['Brislington East'], code='E05001977', alternate_codes=['E36000530'], authority='Bristol, City of', authority_code='E06000023', region='', region_code='')
WardInfo(name='Knowle', alternate_names=['Knowle'], code='E05001994', alternate_codes=['E36000547'], authority='Bristol, City of', authority_code='E06000023', region='', region_code='')
WardInfo(name='Lawrence Hill', alternate_names=['Lawrence Hill'], code='E05001995', alternate_codes=['E36000548'], authority='Bristol, City of', authority_code='E06000023', region='', region_code='')
WardInfo(name='Lockleaze', alternate_names=['Lockleaze'], code='E05001996', alternate_codes=['E36000549'], authority='Bristol, City of', authority_code='E06000023', region='', region_code='')
WardInfo(name='Redland', alternate_names=['Redland'], code='E05001997', alternate_codes=['E36000550'], authority='Bristol, City of', authority_code='E06000023', region='', region_code='')
WardInfo(name='St George East', alternate_names=['St George East'], code='E05001998', alternate_codes=['E36000553'], authority='Bristol, City of', authority_code='E06000023', region='', region_code='')
WardInfo(name='St George West', alternate_names=['St George West'], code='E05001999', alternate_codes=['E36000554'], authority='Bristol, City of', authority_code='E06000023', region='', region_code='')
WardInfo(name='Southmead', alternate_names=['Southmead'], code='E05002000', alternate_codes=['E36000551'], authority='Bristol, City of', authority_code='E06000023', region='', region_code='')
WardInfo(name='Southville', alternate_names=['Southville'], code='E05002001', alternate_codes=['E36000552'], authority='Bristol, City of', authority_code='E06000023', region='', region_code='')
WardInfo(name='Stockwood', alternate_names=['Stockwood'], code='E05002002', alternate_codes=['E36000555'], authority='Bristol, City of', authority_code='E06000023', region='', region_code='')
WardInfo(name='Stoke Bishop', alternate_names=['Stoke Bishop'], code='E05002003', alternate_codes=['E36000556'], authority='Bristol, City of', authority_code='E06000023', region='', region_code='')
WardInfo(name='Westbury-on-Trym', alternate_names=['Westbury-on-Trym'], code='E05002004', alternate_codes=['E36000557'], authority='Bristol, City of', authority_code='E06000023', region='', region_code='')
WardInfo(name='Whitchurch Park', alternate_names=['Whitchurch Park'], code='E05002005', alternate_codes=['E36000558'], authority='Bristol, City of', authority_code='E06000023', region='', region_code='')
WardInfo(name='Windmill Hill', alternate_names=['Windmill Hill'], code='E05002006', alternate_codes=['E36000559'], authority='Bristol, City of', authority_code='E06000023', region='', region_code='')

Note

It is true that we could have achieved this by just searching for Bristol alone. However, this method of searching for ward+authority is more robust against multiple authorities having similar names. For example, searching for the authority “Newcastle” returns both “Newcastle upon Tyne” and “Newcastle-under-Lyme”.

Using location in an extractor

We can use the above search to track the total number of infections in each of the wards in Bristol. Create a new python file called location.py and copy in the below;

matched_wards = None
headers = []

def output_location(network, population, workspace, output_dir, **kwargs):
    ward = "clifton"
    authority = "bristol"

    global matched_wards, headers

    if matched_wards is None:
        # This is performed only once, when this function is first called
        ward = network.info.find(name=ward, authority=authority)[0]
        ward = network.info[ward]
        authority_code = ward.authority_code
        matched_wards = network.info.find(authority=authority_code)

        headers = []
        headers.append("day")

        for ward in matched_wards:
            headers.append(f"'{network.info[ward].name}'")

    # open the file called "authority.dat", e.g. "bristol.dat"
    # Note we are using comma separators and have put the ward
    # names in single quotes to make the output easier to parse
    locfile = output_dir.open(f"{authority}.dat", headers=headers, sep=",")

    locfile.write(str(population.day))

    for ward in matched_wards:
        total = workspace.total_inf_ward[ward]
        locfile.write("," + str(total))

    locfile.write("\n")

def extract_location(**kwargs):
    from metawards.extractors import extract_default

    return extract_default(**kwargs) + [output_location]

Save the file and run metawards using this extractor via

metawards --extractor location

You should see that a new output file called bristol.dat.bz2 was created. Loading this up into pandas should show;

>>> import pandas as pd
>>> df = pd.read_csv("output/bristol.dat.bz2", index_col="day")
>>> print(df)
      'Brislington West'  'Cabot'  ...  'Whitchurch Park'  'Windmill Hill'
 day                               ...
 0                     0        0  ...                  0                0
 1                     0        0  ...                  0                0
 2                     0        0  ...                  0                0
 3                     0        0  ...                  0                0
 4                     0        0  ...                  0                0

 [5 rows x 35 columns]