Learn R Programming

⚠️There's a newer version (0.9.1) of this package.Take me there.

cholera: amend, augment and aid analysis of John Snow's 1854 cholera data

John Snow's map of the 1854 cholera outbreak in London is one of the best known examples of data visualization and information design.

By plotting the number and location of fatalities on a map, Snow was able to do something that is easily taken for granted today: the ability to create and disseminate a visualization of a spatial distribution. To our modern eye, the pattern is unmistakable. It seems self-evident that the map elegantly supports Snow's claims: cholera is a waterborne disease and the pump on Broad Street is the source of the outbreak. And yet, despite its virtues, the map failed to convince both the authorities and Snow's colleagues in the medical and scientific communities.

Beyond considerations of time and place, there are "scientific" reasons for this failure. The map shows a concentration of cases around the Broad Street pump, but that alone should not convince us that Snow is right. The map doesn't refute Snow's primary rival, miasma theory. The pattern we see is not unlike what airborne transmission might look like. And while the presence of a pump near or at the epicenter of the distribution of fatalities is strong circumstantial evidence, it is still circumstantial. There are a host of rival explanations that the map doesn't consider and cannot rule out: location of sewer grates, elevation, weather patterns, etc..

Arguably, this may be one reason why Snow added a graphical annotation in a second, lesser-known version of the map that was published in the official report on the outbreak (Report On The Cholera Outbreak In The Parish Of St. James, Westminster, During The Autumn Of 1854):

pump neighborhoods

The annotation outlines what we might call the Broad Street pump neighborhood: the set of addresses that are, according to Snow, within "close" walking distance to the pump. The notion of a pump neighborhood is important because it provides a prediction about where we should and should not expect to find cases. If water is cholera's mode of transmission and if water pumps are the primary source of drinking water, then most, if not all, fatalities should be found within the pump neighborhood. The disease should stop at the neighborhood's borders.

Creating this annotation is not a trivial matter. To identify the neighborhood of the Broad Street pump, you actually need to identify the neighborhoods of surrounding pumps. Snow writes: "The inner dotted line on the map shews [sic] the various points which have been found by careful measurement to be at an equal distance by the nearest road from the pump in Broad Street and the surrounding pumps ..." (Ibid., p. 109.).

I build on Snow's efforts by writing functions that allow you to compute pump neighborhoods. There are two flavors. The first is based on Voronoi tessellation. It works by computing the Euclidean distances between pumps. It's easy to compute and has been a popular choice for analysts of Snow's map. However, it has two drawbacks: 1) roads and buildings play no role. It assumes that people can walk directly to their preferred pump; and 2) it's not what Snow has in mind. For that, you'll need to consider the second flavor.

plot(neighborhoodVoronoi())
addLandmarks()

The second flavor is based on the walking distance along the roads on the map. While more accurate, it's computationally more demanding. To compute these distances, I transform the roads on the map into a network graph and turn the computation of walking distance into a graph theory problem. For each case (observed or simulated), I compute the shortest path, weighted by the length of roads, to the nearest pump. Then, applying the "rinse and repeat" principle, the different pump neighborhoods emerge:

plot(neighborhoodWalking())
addLandmarks()

To explore the data, you can consider a variety of scenarios by computing neighborhoods using any desired subset of pumps. Here's the result excluding the Broad Street pump.

plot(neighborhoodWalking(-7))

You can also explore "expected" neighborhoods:

plot(neighborhoodWalking(case.set = "expected"))

Or highlight the area of "expected" neighborhoods:

plot(neighborhoodWalking(case.set = "expected"), area = TRUE)

other package features

  • Fixes three apparent coding errors in Dodson and Tobler's 1992 digitization of Snow's map.
  • "Unstacks" the data in two ways to improve analysis and visualization.
  • Adds the ability to overlay graphical features like kernel density, Voronoi diagrams, Snow's annotation, and notable landmarks (John Snow's residence, the Lion Brewery, etc.).
  • Includes a variety of functions to highlight specific cases, roads, pumps and walking paths.
  • Appends street names to the roads data set.
  • Includes the revised pump data used in the second version of Snow's map from the Vestry report. This includes the corrected location of the Broad Street pump.
  • Adds two different aggregate time series fatalities data sets, taken from the Vestry report.

getting started

To install 'cholera' from CRAN:

install.packages("cholera")

To install the current/development version of 'cholera' from GitHub:

# Note that you may need to install the 'devtools' package:
# install.packages("devtools")
devtools::install_github("lindbrook/cholera", build_vignettes = TRUE)

Read the package's vignettes. They include detailed discussions about the data, the functions and the methods used to "fix" the data and to compute walking distances and neighborhoods.

note

neighborhoodWalking() is computationally intensive. Using the current/development version on a single core of a 2.3 GHz Intel i7, plotting observed paths takes about 8 seconds while expected paths takes about 35 seconds. When using the function's parallel implementation, these times fall to approximately 6 and 15 seconds using 4 physical or 8 logical cores.

Note that the parallelized version is currently only available on Linux and Mac. Also, note that the developers of the 'parallel' package strongly discourage against using parallelization within a GUI or embedded environment.

Copy Link

Version

Install

install.packages('cholera')

Monthly Downloads

261

Version

0.3.0

License

GPL (>= 2)

Issues

Pull Requests

Stars

Forks

Maintainer

Peter Li

Last Published

January 26th, 2018

Functions in cholera (0.3.0)

addWhitehead

Add Rev. Henry Whitehead's Broad Street pump neighborhood.
anchor.case

Anchor or base case of each stack of fatalities.
addIndexCase

Highlight index case at 40 Broad Street.
addKernelDensity

Add 2D kernel density contours.
fatalities.address

"Unstacked" amended cholera data with address as unit of observation.
fatalities.unstacked

"Unstacked" amended cholera fatalities data with fatality as unit of observation.
fixFatalities

Fix apparent coding errors in Dodson and Tobler's digitization of Snow's map.
nearestPath

Compute shortest walking paths from case to pump.
ortho.proj.pump.vestry

Orthogonal projection of the 14 pumps from the Vestry Report.
plague.pit

Plague pit coordinates.
print.time_series

Print summary data for timeSeries().
print.voronoi

Print method for neighborhoodVoronoi().
addSnow

Adds Snow's graphical annotation of the Broad Street pump walking neighborhood.
addVoronoi

Add Voronoi cells.
pump.case

List of the observed fatality "addresses" grouped by walking-distance pump neighborhood.
pumpCase

Numeric case IDs by pump neighborhood.
segmentLength

Compute length of road segment.
segmentLocator

Locate road segment by ID.
neighborhoodWalking

Compute walking path pump neighborhoods.
nodeData

Compute network graph of roads, cases and pumps.
regular.cases

"Expected" cases.
road.segments

Dodson and Tobler's street data transformed into road segments.
border

Numeric IDs of line segments that create the map's border frame.
caseLocator

Locate case by numerical ID.
euclideanDistance

Compute the Euclidean distance between cases and/or pumps.
cholera-package

cholera: amend, augment and aid analysis of John Snow's cholera data
classifierAudit

Test if case is orthogonal to segment.
plot.time_series

Plot aggregate time series data from Vestry report.
plot.voronoi

Plot Voronoi neighborhoods.
print.walking

Print method for neighborhoodWalking().
print.walking_distance

Print method for walkingDistance().
addLandmarks

Add landmarks.
addPlaguePit

Add plague pit (Marshall Street).
nearestPump

Compute shortest walking path distance from case to pump.
neighborhoodVoronoi

Compute Voronoi pump neighborhoods.
ortho.proj

Orthogonal projection of observed cases onto road network.
ortho.proj.pump

Orthogonal projection of 13 original pumps.
plot.walking

Plot method for neighborhoodWalking().
unstackFatalities

Unstack "stacks" in Snow's cholera map.
walkingDistance

Compute the shortest walking distance between cases and/or pumps.
pumpData

Compute pump coordinates.
pumpLocator

Locate water pump by numerical ID.
sim.ortho.proj

Orthogonal projection of simulated "expected" cases onto road network.
sim.pump.case

List of "simulated" fatalities grouped by walking-distance pump neighborhood.
fatalities

Amended Dodson and Tobler's cholera data.
plot.classifier_audit

Plot result of classifierAudit().
plot.euclidean_distance

Plot the Euclidean distance between cases and/or pumps.
print.classifier_audit

Return result of classifierAudit().
print.euclidean_distance

Summary of euclideanDistance().
pumps

Dodson and Tobler's pump data with street name.
pumps.vestry

Vestry report pump data.
simulateFatalities

Generate simulated fatalities and their orthogonal projections.
snow.neighborhood

Snow neighborhood fatalities.
plot.walking_distance

Plot the walking distance between cases and/or pumps.
roadSegments

Reshape 'roads' data frame into 'road.segments' data frame.
roads

Dodson and Tobler's street data with appended road names.
streetNameLocator

Locate road by name.
streetLength

Compute length of selected street.
streetNumberLocator

Locate road by numerical ID.
snowNeighborhood

Plotting data for Snow's graphical annotation of the Broad Street pump neighborhood.
snowColors

Create a set of colors for pump neighborhoods.
snowMap

Plot John Snow's cholera map.
timeSeries

Aggregate time series fatality data from the Vestry report.
unitMeter

Convert nominal map distance to yards or meters.