A&E Driving Distances in Ireland

TL:DR Check out « this map » to see how far you are from a 🏥 hospital emergency department New Tab.

Update: As featured in Galway Beo



Mayo A&E Map Example shot of distances from Mayo University Hospital

Introduction

The data and map generated highlight the investment towards certain parts of the country and where hospital services are lacking. Particularly the west coast is faced with longer travel times that could make all the difference in an emergency.

If you wanted to find out how far your house was from the 🏥 A&E incase anything cropped up you’d have to go to Google Maps and check manually. What if you wanted to see how far every house in the entirety of Ireland is from an 🏥 A&E? Well this map computes every possible route down every possible road in Ireland and compiles it into one scrollable interactive map.

The full county map is available here

Figures

See the table for the entire list of 🏥 A&E coverages per county. Most countries have a distance coverage percentage for most of the population. Some counties such as Westmeath, Tyrone, Kilkenny, etc. have 100% coverage under 60 minutes meaning everyone in these counties can reach an A&E department in under 1 hour. Meanwhile Kerry has the lowest with only 78.5 of area in Kerry able to reach an 🏥 A&E department in under 1 hour.

county name 10 min percentage 20 min percentage 30 min percentage 40 min percentage 50 min percentage 60 min percentage 100 min percentage total area (m^2)
Louth 10.58 64.92 98.04 99.25 99.47 99.8 99.98 824697424.38
Sligo 5.38 28.75 61.49 87.48 98.65 99.18 99.59 1832320861.46
Westmeath 3.86 44.62 87.5 98.14 100.0 100.0 100.0 1835094872.09
Tyrone 0.41 12.05 49.78 87.03 99.54 100.0 100.0 3258041212.65
Limerick 3.12 20.81 51.48 86.07 96.65 97.49 98.11 2750581255.19
Waterford 5.18 19.5 43.2 61.95 94.83 99.49 99.84 1858789078.95
Kilkenny 2.86 42.79 90.56 100.0 100.0 100.0 100.0 2067787314.53
Carlow 0.0 0.61 28.81 80.51 97.5 100.0 100.0 894867772.0
Cork 2.04 10.55 28.27 57.44 76.72 86.4 98.3 7492154677.75
Derry 8.8 38.23 78.01 93.27 99.36 99.69 99.85 2116426989.94
Leitrim 0.11 6.84 30.99 66.25 99.58 100.0 100.0 1585155409.84
Clare 0.03 4.0 15.19 33.68 58.02 84.11 94.83 3443295248.39
Kildare 7.11 51.2 89.95 100.0 100.0 100.0 100.0 1691176098.19
Monaghan 0.0 1.28 28.38 93.04 100.0 100.0 100.0 1291778233.81
Fermanagh 7.96 46.42 94.17 100.0 100.0 100.0 100.0 1846868979.96
Galway 1.46 12.28 36.32 59.32 76.93 88.06 97.58 6157406937.9
Mayo 1.94 15.09 31.56 59.84 78.72 84.36 94.95 5585170772.02
Laois 6.78 47.52 83.35 99.87 100.0 100.0 100.0 1716199480.56
Longford 0.0 0.29 37.8 82.56 98.69 100.0 100.0 1089403518.68
Donegal 2.69 17.78 35.54 65.54 86.55 92.84 97.68 4848038019.81
Roscommon 0.44 7.24 21.73 48.82 86.46 100.0 100.0 2543058640.37
Offaly 4.23 28.56 71.24 97.15 100.0 100.0 100.0 1997178392.14
Kerry 1.87 12.55 33.86 49.74 60.54 78.5 96.43 4799098649.65
Meath 7.67 56.42 89.88 99.98 99.98 100.0 100.0 2337675154.57
Dublin 30.54 87.02 98.88 99.24 99.27 99.43 99.58 927222522.91
Armagh 15.99 62.67 91.08 95.73 100.0 100.0 100.0 1322897039.7
Antrim 7.98 47.67 75.71 86.92 98.45 99.41 99.5 3088251938.77
Down 5.44 43.86 74.25 95.69 99.25 99.61 99.67 2492890657.18
Tipperary 1.4 11.89 37.89 75.99 97.37 99.07 100.0 4297626758.73
Wicklow 0.0 5.34 26.95 55.18 89.03 99.75 99.94 2020001614.15
Cavan 1.95 29.92 76.31 96.71 100.0 100.0 100.0 1927778805.91
Wexford 3.78 32.94 72.11 95.04 98.48 99.38 99.66 2372348207.48

Population Coverage

By taking existing census data in Ireland we can roughly work out how much of the population each of these areas cover.

Taking the Deprivation Index dataset which has an expansive list of small areas (over 14,000 across 26 counties) with corresponding population counts. Taking Laois as an example we can find the intersection for each timed area and the small areas from the deprivation index. Calculating rough figures we get:

county name 10 min population 20 min population 30 min population 40 min population 50 min population 60 min population 100 min population
Laois 39706 78070 91448 91877 91877 91877 91877

Seeing how 99.87% of the county area wise is able to get to an A&E department in less than 40 minutes it seems reasonable that our population count tops out at 91,877, close to the estimated 2023 count of 91,657 people. We can also see that 39706/91877 x 100 = 43.22% of the population of Laois can reach an A&E department in less than 10 mintues!

Conclusion

The technology behind the map is easy to update for future hospital plans while being very low cost to run. Data science is a necessary tool that can be leveraged to promote a more equitable society in Ireland that provides equally of access to health services throughout the Ireland North and South.


Technial Details

Here’s the technical details for how I made it work

Routing

The first step of creating the map was compiling a list of A&E departments combining these two lists:

Packaging it as a csv file:

name type lat lon
Mayo University Hospital hospital 53.8586987 -9.3057666
Sligo University Hospital hospital 54.2742179 -8.46534
University Hospital Galway hospital 53.2768492 -9.0686869
Portiuncula University Hospital hospital 53.3267853 -8.2354909
Beaumont Hospital hospital 53.3886228 -6.2298697
Cavan General Hospital hospital 54.001614 -7.3721102
Connolly Hospital Blanchardstown hospital 53.3883035 -6.3733538
Cork University Hospital hospital 51.8828831 -8.5123853
Letterkenny University Hospital hospital 54.9599749 -7.7341944
Mater Misericordiae University Hospital hospital 53.3601096 -6.265246
Mercy Hospital hospital 51.9016319 -8.5023249
Midland Regional Hospital Portlaoise hospital 53.0382084 -7.2760839
Midland Regional Hospital Tullamore hospital 53.2830682 -7.4884664
Naas General Hospital hospital 53.2113718 -6.6610156
Our Lady of Lourdes Hospital Drogheda hospital 53.7222147 -6.354332
Our Lady’s Hospital Navan hospital 53.6509365 -6.6965478
Regional Hospital Mullingar hospital 53.5339849 -7.3488692
St James’ Hospital hospital 53.339302 -6.3010192
St Luke’s General Hospital hospital 52.6665445 -7.2622519
St Vincent’s University Hospital hospital 53.3168588 -6.2145806
Tallaght University Hospital hospital 53.2825903 -6.6420337
Tipperary University Hospital hospital 52.3552083 -7.7136177
University Hospital Kerry hospital 52.2652569 -9.6886432
University Hospital Limerick hospital 52.6351824 -8.6538597
University Hospital Waterford hospital 52.2485059 -7.0784959
Wexford General Hospital hospital 52.3430674 -6.4827788
Royal Victoria Hospital hospital 54.5944794 -5.9568094
Causeway Area Hospital hospital 55.1242238 -6.6537714
Craigavon Area Hospital hospital 54.4343794 -6.4135847
Daisy Hill Hospital hospital 54.1789493 -6.3527515
Mater Hospital Crumlin Road hospital 54.6085403 -5.9430679
Antrim Area Hospital hospital 54.7332802 -6.191414
Altnagelvin Area Hospital hospital 54.9861244 -7.2933306
South West Acute Hospital hospital 54.366971 -7.636536

I was able to use a routing engine to find the distances you can travel from given locations. There are various online options but for server intensive operations I chose to use an open-source alternative that can be run on a local machine. I installed Valhalla locally, and created a short python script to interface with the routing engine and produce the geojson data

{
  "Mayo University Hospital": {
    "features": [
      {
        "properties": {
          "fill-opacity": 0.33,
          "fill": "##D53F4F",
          "fillColor": "##D53F4F",
          "color": "##D53F4F",
          "fillOpacity": 0.33,
          "opacity": 0.33,
          "contour": 10,
          "metric": "time"
        },
        "geometry": {
          "coordinates": [
            [
              -9.226767,
              53.943009
            ],
            [
              -9.227811,
              53.942699
            ],
...

Creating the map

Here is the full set of helpful python libraries I used for this project

import csv
import json

import branca
import folium
import selenium

import geopandas as gpd
import matplotlib.pyplot as plt
import pandas as pd

from area import area
from shapely import to_geojson
from shapely.geometry import Polygon
from shapely.ops import unary_union

We that set we can load in the hospital data

with open("valhalla_county_routing_data.json", "r") as json_file:
  valhalla_data = json.load(json_file)

We need to take all the 10 minute, 20 minute, etc. sections on the map and join the polygons together

# Split into groups of NUMBER_OF_BUCKETS
v_isochrone_coords = [[] for _ in range(NUMBER_OF_BUCKETS)]
for loc in valhalla_data.keys():
  for index, buc in enumerate(valhalla_data[loc]["features"]):
      v_isochrone_coords[index % NUMBER_OF_BUCKETS].append(Polygon(buc["geometry"]["coordinates"]))

# Merge polygons
v_merged_isochrones = [[] for _ in range(NUMBER_OF_BUCKETS)]
for index, iso in enumerate(v_isochrone_coords):
  v_merged_isochrones[index] = unary_union(iso)

County Outlines

To break it down for each county I had to get the GeoJSON data for the area covered. There was plenty of files online for council districts but not many for county boundaries. Most only included 26 counties, I was able to find a 32 county file here thanks to Martin Peters. I updated the Irish Language names due to some name corruption because of the fadas and made the whole file accessible here.

Folium was used for creating the maps from all the collected data

gdf_bucket = gpd.GeoDataFrame(geometry=v_merged_isochrones,
                              crs='EPSG:4326')
counties_gdf = gpd.GeoDataFrame(geometry=list(counties.values()), crs='EPSG:4326')

county_map = folium.Map(location=map_center,
                        zoom_start=7, 
                        zoom_control=True,
                        tiles='OpenStreetMap')

folium.GeoJson(gdf_bucket, style_function=colouring).add_to(county_map)
folium.GeoJson(counties_gdf, style_function=county_outline).add_to(county_map)

Branca is used for the colour map legend at the top

branca.colormap.StepColormap(
    new_colour_map[::-1], vmin=0, vmax=100, index=[0, 10, 20, 30, 40, 50, 60, 100], caption='Minutes driving distance from A&E Department'
).add_to(county_map)

County Coverage

Now that we have the routing distances areas and the area for each county we can find the intersection for each distance bucket (10 minutes, 20 minutes, etc.) and compute the area out of the total.

county_areas = {}
for bucket in merged_isochrones:
  for county in counties.keys():
    intersection = counties[county].intersection(bucket)
    if county in county_areas:
      county_areas[county].append(area(intersection))
    else:
      county_areas[county] = [area(intersection)]

Population Estimates

I was able to join the Deprivation Index dataset with the existing county areas and the CSO Small Areas dataset on the small area id ED_ID_STR. By checking for an intersection in the Polygons and simply adding up the populations I was able to roughly esimate the counts for the population for each time bucket for each county.

For example:

bucket_pops = []
for bucket in merged_isochrones:
  b_pop = 0
  seen = set([])
  for loc in laois_coord_data:
    if loc['ED_ID_STR'] in deprivation_data and loc['ED_ID_STR'] not in seen and intersects(Polygon(loc['coordinates'][0][0]), bucket):
      b_pop += int(Decimal(deprivation_data[loc['ED_ID_STR']]['population'].replace(',', '')))
      seen.add(loc['ED_ID_STR'])
  bucket_pops.append(b_pop)