How US Presidents Died According to Wikidata
Wikidata is a free linked database that serves as a central storage for the structured data in Wikipedia and other Wikimedia projects. Yesterday, the project announced on Twitter that their query service is officially live.
The Wikidata Query service is now officially live and in production! https://t.co/D5bypZ8ZmS
— Wikidata (@wikidata) September 8, 2015
This service allows you to execute SPARQL queries for answering questions like Whose birthday is today? or the more morbid How US presidents died? I address the latter question in this notebook and show how you can query the service and process the response in Python. For more query examples see this page.
Setup
Load the necessary libraries, set the styling and some meta information for the chart.
%load_ext signature
%matplotlib inline
import requests
import helpers
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
mpl.style.use('ramiro')
chartinfo = 'Author: Ramiro Gómez - ramiro.org • Data: Wikidata - wikidata.org'
infosize = 12
Define the SPARQL query
SPARQL is a declarative language to query RDF stores. I don't have much experience with SPARQL myself, but I'll try to explain the query you see below. First we define prefixes, which serve as shortcuts to resolve resources. The names following the SELECT keyword are variables, which are indicated by a ? prefix.
What these variables mean is defined by the triple patterns that follow in the WHERE clause. The first triple basically says that ?pid stands for the Wikidata entity Q11696, i. e. "President of the United States of America". The following triples define ?cid, ?dob and ?dod as properties cause of death (P509), date of birth (P569), and date of birth (P570) of a president ID respectively.
The following 2 optional patterns assign English language labels to the variables ?president and ?cause. By making them optional we make sure to get a result triple, even if the label is not defined in English, in which case the label value would be empty.
As said I'm by no means a SPARQL expert, so if you can improve my explanation feel to edit the notebook on GitHub and submit a pull-request.
query = '''PREFIX wikibase:
PREFIX wd:
PREFIX wdt:
PREFIX rdfs:
SELECT ?president ?cause ?dob ?dod WHERE {
?pid wdt:P39 wd:Q11696 .
?pid wdt:P509 ?cid .
?pid wdt:P569 ?dob .
?pid wdt:P570 ?dod .
OPTIONAL {
?pid rdfs:label ?president filter (lang(?president) = "en") .
}
OPTIONAL {
?cid rdfs:label ?cause filter (lang(?cause) = "en") .
}
}'''
Get and process the data
Next we send an HTTP request to the SPARQL endpoint providing the query as a URL parameter, we also specify that we want the result encoded as JSON rather than the default XML. Thanks to the requests library this is practically self-explaining code.
url = 'https://query.wikidata.org/bigdata/namespace/wdq/sparql'
data = requests.get(url, params={'query': query, 'format': 'json'}).json()
Now we iterate through the result, creating a list of dictionaries, each of which contains values for the query variables defined above. Then we create a Pandas DataFrame from this list, print its length and the first few rows.
presidents = []
for item in data['results']['bindings']:
presidents.append({
'name': item['president']['value'],
'cause of death': item['cause']['value'],
'date of birth': item['dob']['value'],
'date of death': item['dod']['value']})
df = pd.DataFrame(presidents)
print(len(df))
df.head()
47
| cause of death | date of birth | date of death | name | |
|---|---|---|---|---|
| 0 | cholera | 1795-11-02T00:00:00Z | 1849-06-15T00:00:00Z | James K. Polk |
| 1 | heart attack | 1872-07-04T00:00:00Z | 1933-01-05T00:00:00Z | Calvin Coolidge |
| 2 | heart attack | 1822-10-04T00:00:00Z | 1893-01-17T00:00:00Z | Rutherford B. Hayes |
| 3 | heart attack | 1865-11-02T00:00:00Z | 1923-08-02T00:00:00Z | Warren G. Harding |
| 4 | heart attack | 1837-03-18T00:00:00Z | 1908-06-24T00:00:00Z | Grover Cleveland |
Let's also see the data types of the columns.
df.dtypes
cause of death object
date of birth object
date of death object
name object
dtype: object
We have 47 records in the dataset, but Barack Obama is US president number 44 and some former presidents are still alive, so there must be more than one record for some presidents. To learn why this number is higher we'll sort the DataFrame by date of birth and date of death. To do so we convert the corresponding column values to datetime objects and then perform the sort operation and print out the complete result.
df['date of birth'] = pd.to_datetime(df['date of birth'])
df['date of death'] = pd.to_datetime(df['date of death'])
df.sort(['date of birth', 'date of death'])
| cause of death | date of birth | date of death | name | |
|---|---|---|---|---|
| 33 | acute laryngitis | 1732-07-04 | 1799-12-14 | George Washington |
| 35 | bloodletting | 1732-07-04 | 1799-12-14 | George Washington |
| 20 | diarrhea | 1743-04-02 | 1826-07-04 | Thomas Jefferson |
| 30 | uremia | 1743-04-02 | 1826-07-04 | Thomas Jefferson |
| 36 | bacteremia | 1743-04-02 | 1826-07-04 | Thomas Jefferson |
| 21 | diarrhea | 1743-04-13 | 1826-07-04 | Thomas Jefferson |
| 31 | uremia | 1743-04-13 | 1826-07-04 | Thomas Jefferson |
| 37 | bacteremia | 1743-04-13 | 1826-07-04 | Thomas Jefferson |
| 19 | tuberculosis | 1767-03-15 | 1845-06-08 | Andrew Jackson |
| 28 | sepsis | 1773-02-09 | 1841-04-04 | William Henry Harrison |
| 9 | pneumonia | 1782-12-05 | 1862-07-24 | Martin Van Buren |
| 25 | heart failure | 1782-12-05 | 1862-07-24 | Martin Van Buren |
| 23 | Gastroenteritis Viral | 1784-11-24 | 1850-07-09 | Zachary Taylor |
| 15 | stroke | 1790-03-29 | 1862-01-18 | John Tyler |
| 40 | respiratory failure | 1791-04-23 | 1868-06-01 | James Buchanan |
| 0 | cholera | 1795-11-02 | 1849-06-15 | James K. Polk |
| 14 | stroke | 1800-01-07 | 1874-03-08 | Millard Fillmore |
| 22 | cirrhosis | 1804-11-23 | 1869-10-08 | Franklin Pierce |
| 17 | stroke | 1808-12-29 | 1875-07-31 | Andrew Johnson |
| 45 | gunshot wound | 1809-02-12 | 1865-04-15 | Abraham Lincoln |
| 32 | throat cancer | 1822-04-27 | 1885-07-23 | Ulysses S. Grant |
| 2 | heart attack | 1822-10-04 | 1893-01-17 | Rutherford B. Hayes |
| 12 | stroke | 1829-10-05 | 1886-11-18 | Chester A. Arthur |
| 5 | heart attack | 1831-11-19 | 1881-09-19 | James A. Garfield |
| 8 | pneumonia | 1831-11-19 | 1881-09-19 | James A. Garfield |
| 27 | sepsis | 1831-11-19 | 1881-09-19 | James A. Garfield |
| 34 | aneurysm | 1831-11-19 | 1881-09-19 | James A. Garfield |
| 43 | gunshot wound | 1831-11-19 | 1881-09-19 | James A. Garfield |
| 7 | pneumonia | 1833-08-20 | 1901-03-13 | Benjamin Harrison |
| 4 | heart attack | 1837-03-18 | 1908-06-24 | Grover Cleveland |
| 42 | gunshot wound | 1843-01-29 | 1901-09-14 | William McKinley |
| 13 | stroke | 1856-12-28 | 1924-02-03 | Woodrow Wilson |
| 39 | coronary thrombosis | 1858-10-27 | 1919-01-06 | Theodore Roosevelt |
| 3 | heart attack | 1865-11-02 | 1923-08-02 | Warren G. Harding |
| 24 | heart failure | 1865-11-02 | 1923-08-02 | Warren G. Harding |
| 1 | heart attack | 1872-07-04 | 1933-01-05 | Calvin Coolidge |
| 38 | coronary thrombosis | 1872-07-04 | 1933-01-05 | Calvin Coolidge |
| 46 | internal bleeding | 1874-08-10 | 1964-10-20 | Herbert Hoover |
| 18 | stroke | 1882-01-30 | 1945-04-12 | Franklin Delano Roosevelt |
| 10 | pneumonia | 1884-05-08 | 1972-12-26 | Harry S. Truman |
| 41 | multiple organ dysfunction syndrome | 1884-05-08 | 1972-12-26 | Harry S. Truman |
| 26 | heart failure | 1890-10-14 | 1969-03-28 | Dwight D. Eisenhower |
| 6 | heart attack | 1908-08-27 | 1973-01-22 | Lyndon B. Johnson |
| 11 | pneumonia | 1911-02-06 | 2004-06-05 | Ronald Reagan |
| 16 | stroke | 1913-01-09 | 1994-04-22 | Richard Nixon |
| 29 | arteriosclerosis | 1913-07-14 | 2006-12-26 | Gerald Ford |
| 44 | gunshot wound | 1917-05-29 | 1963-11-22 | John F. Kennedy |
For several presidents there are multiple causes of death listed, apparently in some cases it is not possible to determine a single cause of death with certainty. James A. Garfield for example was shot by Charles Guiteau, but did not immediately die and consequently developed several health issues and even starvation may have played a role, see the corresponding Wikipedia article section for more details.
There are 6 records for Thomas Jefferson. The exact cause of his death also has never been conclusively determined. Moreover, his date of birth is given in both Old Style and New Style dates. While it is not appropriate to just decide for a single cause of death we can filter out these 3 dispensable records with the following statement.
df = df[df['date of birth'] != '1743-04-02']
Ranking the causes of death
Finally, let's create a simple bar chart that ranks the causes of death of US presidents adding a note at the bottom so it is clear why there is no 1-to-1 correspondence of causes of death and past US presidents who died.
title = 'US Presidents Causes of Death According to Wikidata'
footer = '''Wikidata lists multiple causes of death for several presidents, that are all included. Thus the total count of causes is
higher than the number of US presidents who died. ''' + chartinfo
df['cause of death'] = df['cause of death'].apply(lambda x: x.capitalize())
s = df.groupby('cause of death').agg('count')['name'].order()
ax = s.plot(kind='barh', figsize=(10, 8), title=title)
ax.yaxis.set_label_text('')
ax.xaxis.set_label_text('Cause of death count')
ax.annotate(footer, xy=(0, -1.16), xycoords='axes fraction', fontsize=infosize)
plt.savefig('img/' + helpers.slug(title), bbox_inches='tight')

Summary
This notebook showed a simple example of how you can query the Wikidata query service from Python. Moreover, we saw that even a very small dataset cannot just be taken for granted, but may need to be cleaned and require further research to meaningfully interpret the results.
%signature
Author: Ramiro Gómez • Last edited: September 09, 2015
Published: September 09, 2015 by Ramiro Gómez.
If you want to be notified about new content, click here to subscribe to the newsletter or RSS feed.
Disclosure: External links on this page may contain affiliate IDs, which means that I earn a commission if you make a purchase via such a link. This allows me to operate this site and offer hopefully valuable content that is freely accessible. More information about affiliate programs.