healthcare access analysis in madagascar

In the case of a disaster (natural or man made), a country is not only affected by the intensity of the disaster but also by it’s own vulnerability to it. Countries have different kind of opportunities to prepare for such catastrophes, to respond finally to start the recovery. Many less developed countries, e.g. Madagascar, are in particular prone to disasters, not only because of the higher probability of occurence, but also due to a potentially lower ability to cope up during and after the event.

Analysis of Access to Health Care using OpenRouteService

Abstract

In the case of a disaster (natural or man made), a country is not only affected by the intensity of the disaster but also by it's own vulnerability to it. Countries have different kind of opportunities to prepare for such catastrophes, to respond finally to start the recovery. Many less developed countries, e.g. Madagascar, are in particular prone to disasters, not only because of the higher probability of occurence, but also due to a potentially lower ability to cope up during and after the event.

In this example we will focus on vulnerability in terms of access to health care. The access to health facilities can be highly unequal within a country. Consequently, some areas and communities are more vulnerable to disasters effects than others. Quantifying and visualizing such inequalities is the aim of this notebook.

The notebook gives an overview on health sites distribution and the amount of population with access to those by foot and by car for Madagascar. Open source data from OpenStreetMap and tools (such as the OpenRouteService) were used to create accessibility isochrones for each hospital and to derive analysis results about the population percentage with access to health facilities per district. The findings show that the inhabitants of 69 of 119 (58%) districts don't have any access to hospitals in an one hour foot walking range and those of 43 of 119 (36%) districts in an one hour car driving range.

Workflow:

  • Preprocessing: Get data for districts, health facilities, population density, population count per disctrict.
  • Analysis:
    • Compute accessibility to health care facilities using OpenRouteService API
    • Derive the percentage of people with access to health care per district.
  • Result: Visualize results as choropleth maps.

Datasets and Tools:

Python Workflow

In [1]:
import os

from IPython.display import *
from IPython.display import HTML, display

import folium
from folium import Map, Marker, FeatureGroup, LayerControl
from folium.plugins import MarkerCluster

from openrouteservice import client

import time 
import pandas as pd 
import fiona as fn
from shapely.geometry import shape, Polygon, mapping
from shapely.ops import cascaded_union

# import zonal stats function from python file, get it here: https://gist.github.com/perrygeo/5667173
from zonal_stats import *

Preprocessing

For this study different kind of data were used. First of all a map were created with folium, a python package. The boundaries of the districts as well as the healtsites were given as shapefiles, which were printed on the map. The dataset about the health sites is from 2018.

In [2]:
# inserte your ORS api key
api_key = '{your-ors-api-key}'
clnt = client.Client(key=api_key)

# make sure to provide the right filenames
districts_filename = 'data/mdg_polbnda_adm2_Distritcts_BNGRC_OCHA.shp'
health_facilities_filename = 'data/healthsites.shp'
population_raster_filename = 'data/MDG_ppp_2020_adj_v2.tif'

# these files will be generated during processing
isochrones_car_filename = 'data/iso_union_car.shp'
isochrones_car_per_district_filename = 'data/iso_car_per_district.shp'
isochrones_foot_filename = 'data/iso_union_foot.shp'
isochrones_foot_per_district_filename = 'data/iso_foot_per_district.shp'

# final file with all generated information
output_file = 'data/districts_final.geojson'

Create district dictionary and facilities dictionary

In [3]:
districts_dictionary = {}
with fn.open(districts_filename, 'r') as districts:
    for feature in districts:
        district_id = int(feature['id'])
        districts_dictionary[district_id] = {
            'District Code': feature['properties']['DIST_PCODE'],
            'District Name': feature['properties']['DISTRICT_N'],
            'Population Count': 0,
            'Car: Pop. with access': 0,
            'Car: Pop. with access [%]': 0.0,
            'Foot: Pop. with access': 0,
            'Foot: Pop. with access [%]': 0.0,
            'geometry': feature['geometry']       
        }
print('created dictionary for %s districts' % len(districts_dictionary))

facilities_dictionary = {}
with fn.open(health_facilities_filename, 'r') as facilities:
    for feature in facilities:
        facility_id = int(feature['id'])
        facilities_dictionary[facility_id] = {
            'geometry': feature['geometry'] 
        }
print('created dictionary for %s facilities' % len(facilities_dictionary))
created dictionary for 119 districts
created dictionary for 121 facilities

Let's get an overview and look at a map of the districts and health facilities

In [48]:
map_outline = folium.Map(tiles='Stamen Toner', location=([-18.812718, 46.713867]), zoom_start=5)

# Import health facilities
cluster = MarkerCluster().add_to(map_outline) # To cluster hospitals

for facility_id in facilities_dictionary:
    folium.Marker(list(reversed(facilities_dictionary[facility_id]['geometry']['coordinates']))).add_to(cluster)

# Import district boundaries
district_simp = []
for district_id in districts_dictionary:
    geom = shape(districts_dictionary[district_id]['geometry'])
    # we simplify the geometry just for the purpose of visualisation
    # be aware that some browsers e.g. chrome might fail to render the entire map if there are to many coordinates
    simp_geom = geom.simplify(0.005, preserve_topology=False)
    simp_coord = mapping(simp_geom)    
    folium.GeoJson(simp_coord).add_to(map_outline)
    district_simp.append(simp_coord)

map_outline.save(os.path.join('results', '1_health_facilities_overview.html'))
map_outline
Out[48]: