This tool helps answer a simple but important question: for any given London postcode, which is the nearest neonatal (newborn baby) hospital unit?
When a baby is born prematurely or becomes seriously ill, they may need specialist care in a Neonatal Unit. These units are graded into three levels:
| Level | Name | What it provides |
|---|---|---|
| Level 1 | Special Care | Short-term support for babies who need extra monitoring |
| Level 2 | High Dependency | More intensive support, including help with breathing |
| Level 3 | Neonatal Intensive Care (NICU) | The highest level of care for the most critically ill babies |
Not every hospital has every level of unit, so knowing which is closest — and at which level — matters.
The script takes two input files:
hospitals_refined.csv— A list of ~31 neonatal hospitals across London, including their location (latitude/longitude), care level (1–3), and which side of the Thames they serve (North, South, or Both).postcodes_master.csv— A list of ~326,000 London-area postcodes with their geographic coordinates.
It then runs through three steps:
London's neonatal care is broadly organised around the River Thames. The script classifies each postcode as being on the North or South side based on its area code (the letters at the start of the postcode).
The outcode is extracted by stripping the last 3 characters (the incode) from the postcode, which correctly handles postcodes with or without spaces.
SW postcodes are handled specially — districts SW1, SW3, SW5, SW6, SW7 and SW10 are classified as North, while the rest are South. A small number of individual postcodes within those North districts are manually overridden as South (see TECHNICAL.md for the full list).
Some hospitals near the river serve both sides (e.g. West Middlesex), so they are available to postcodes on either side.
For each postcode, the script finds the closest neonatal hospital on the same side of the river, using accurate geographic distance calculations (Haversine formula). It does this four times:
- Closest unit at any level
- Closest Level 1 (Special Care)
- Closest Level 2 (High Dependency)
- Closest Level 3 (NICU)
Results are saved to the output/ folder in two formats:
Individual hospital files — one CSV per hospital (e.g. output/West_Middlesex.csv), containing all postcodes where that hospital is the nearest at any level.
Combined file — output/All_Postcodes.csv with one row per postcode:
| Column | Example |
|---|---|
| Postcode | TW7 6QT |
| Latitude | 51.4729 |
| Longitude | -0.3317 |
| Side | South |
| Closest_Any | West Middlesex |
| Distance_Any_km | 0.48 |
| Closest_L1 | West Middlesex |
| Distance_L1_km | 0.48 |
| Closest_L2 | Kingston Hospital |
| Distance_L2_km | 7.32 |
| Closest_L3 | St. Georges Hospital |
| Distance_L3_km | 12.0 |
A separate script (generate_map.py) generates an interactive HTML map showing each hospital's catchment area as colour-coded dots. Hover over any dot to see its postcode. Hospital markers can be clicked for name, level and side. Use the layer control (top-right) to toggle individual hospitals on/off. A Deselect All / Select All button at the bottom of the control panel lets you quickly clear or restore all layers.
A Flask-based frontend (app.py) provides a local web interface at http://127.0.0.1:5001 with:
- Postcode search — enter any London postcode to see the nearest neonatal unit at each level, with distances and an interactive map.
- Embedded catchment map — the generated map is viewable directly within the app.
- Hospital API — a
/hospitalsendpoint returning all hospitals as JSON.
A fully client-side version lives in the docs/ folder and is published via GitHub Pages at https://drhammadkhan.github.io/postcode-lookup/.
The script build_static.py compresses the output into two compact JSON files (docs/postcodes.json and docs/hospitals.json) which docs/index.html loads and searches entirely in the browser — no server required.
- Make sure you have Python 3 installed (use
python3on macOS) - Install the required packages:
pip install pandas numpy scipy folium flask - Confirm the input files are present in the project root:
hospitals_refined.csvpostcodes_master.csv
-
Generate postcode lookups (main pipeline)
python3 postcode_lookup.py- Outputs:
output/All_Postcodes.csv- One CSV per hospital in
output/
- Outputs:
-
Generate the interactive catchment map
python3 generate_map.py- Output:
neonatal_catchment_map.html
- Output:
-
Build the static JSON for the GitHub Pages / Netlify site
python3 build_static.py- Outputs:
docs/postcodes.jsondocs/hospitals.json
- Outputs:
-
Run the local Flask web app
python3 app.py- Then visit
http://127.0.0.1:5001in your browser
- Then visit
-
Open the map directly (optional)
- Open
neonatal_catchment_map.htmlin your browser
- Open
If you want a small local frontend with buttons to run each script (or the full pipeline), start the runner:
python3 script_runner_app.py
Then open http://127.0.0.1:5002 in your browser and use the buttons to run:
postcode_lookup.pygenerate_map.pybuild_static.py- or the full pipeline in order