Creating a Custom Network

While the default networks supplied in MetaWardsData model the UK, there is nothing to stop you creating your own network to model any country or region. Indeed, you can use the concepts of wards, workers and players in a more generic way to model lots of different environments, e.g.

  • Using wards to represent different university buildings, and then track disease spread between buildings as staff and students move around.

  • Using wards to represent care homes, hospitals and homes in a single region, and then model the motion of staff, patients and the general population between these different environments.

Network file formats

A lot of data needs to be loaded to define the network. There are two file formats for specifying this data;

  1. A set of fixed-format files that contain the data in a set of files that are contained in a single directory. This is an older format that is used predominantly for older model networks.

  2. A JSON-format file that contains all of the data needed to describe the network in a single file. This file should only be manipulated or edited using the Python API described below.

Creating and editing Networks in Python

The best way to create a new network is to use the Python API. A Network is edited or created via the Wards class. This represents an editable collection of individual Ward objects, each of which represents a ward. The Ward provides functions for setting the name and metadata for a ward, plus adding work and play connections to other wards.

For example, we can interactively create a new Network using the Ward and Wards classes in, e.g. ipython or a jupyter notebook;

First, we will import the necessary classes and create our Wards object, which we will call wards;

>>> from metawards import Ward, Wards, Network
>>> wards = Wards()

Next, we will create a Ward object to represent Bristol (which we will call bristol). We will add 500 workers who will work in Bristol, and 750 players.

>>> bristol = Ward(name="Bristol")
>>> bristol.add_workers(500)
>>> bristol.set_num_players(750)

Next, we will create a Ward object to represent London (which we will call london). We will add 8600 workers and 10000 players.

>>> london = Ward(name="London")
>>> london.add_workers(8500)
>>> london.set_num_players(10000)

Now, we will add some commuters. We will have 500 Bristolians commute each day to London, while 100 Londoners will commute each day to Bristol.

>>> bristol.add_workers(500, destination=london)
>>> london.add_workers(100, destination=bristol)

We can confirm that the information is correct by printing, e.g.

>>> print(bristol)
Ward( name=Bristol, num_workers=1000, num_players=750 )

>>> print(london)
Ward( name=London, num_workers=8600, num_players=10000 )

Next, we add the two Ward objects to our Wards object that represents the entire model.

>>> wards.add(bristol)
>>> wards.add(london)
>>> print(wards)
[ Ward( info=Bristol, id=1, num_workers=1000, num_players=750 ), Ward( info=London, id=2, num_workers=8600, num_players=10000 ) ]

Note

Note that each Ward in the Wards collection has been automatically assigned an ID number (1 for Bristol and 2 for London). You can refer to the wards by their ID number, but should, in general, leave metawards to automatically generate and manage these IDs.

We can now save this set of Wards to a file by converting this to a data dictionary, and then serialising that dictionary to JSON, which we will stream to the file custom_network.json.bz2.

>>> wards.to_json("custom_network.json", indent=2)

The resulting JSON file will look something like this;

[
  {
    "id": 1,
    "info": {
      "name": "Bristol"
    },
    "num_workers": 1000,
    "num_players": 750,
    "workers": {
      "destination": [
        1,
        2
      ],
      "population": [
        500,
        500
      ]
    }
  },
  {
    "id": 2,
    "info": {
      "name": "London"
    },
    "num_workers": 8600,
    "num_players": 10000,
    "workers": {
      "destination": [
        1,
        2
      ],
      "population": [
        100,
        8500
      ]
    }
  }
]

Note

Note that the exact format of the JSON will change as metawards evolves. We will retain backwards compatibility, meaning that newer versions of metawards will be able to read old files, but older versions may not be able to read new files.

Note that the file will be automatically compressed using bzip2. You can disable this by setting auto_bzip=False.

Note also that indent=2 just sets the indentation used for printing. You can set whatever indentation you want, including not setting any. It won’t affect the included information - just its human-readability.

You can load this JSON file into a Wards object using;

>>> wards = Wards.from_json("custom_network.json.bz2")
>>> print(wards)
[ Ward( id=1, name=Bristol, num_workers=1000, num_players=750 ), Ward( id=2, name=London, num_workers=8600, num_players=10000 ) ]