{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Analyse de l’épidémie de choléra à Soho (1854) — Reproduction de la carte de John Snow - Victor GERENTON\n",
"\n",
"Ce notebook a pour objectif de reproduire la célèbre carte de John Snow montrant la répartition des décès dus au choléra à Soho en 1854. À l'aide de données géographiques historiques et d'outils modernes de visualisation, nous allons :\n",
"\n",
"1. Visualiser les lieux de décès et les pompes à eau sur une carte interactive.\n",
"2. Explorer des méthodes d'analyse spatiale pour mettre en évidence le rôle central de la pompe de Broad Street.\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Installation des biliothèques\n",
"\n",
"L'ensembles des biliothèques et leur version respective se trouvent dans le fichier 'requirements.txt'"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"!pip install -r requirements.txt\n",
"\n",
"print((\"----------------------------------------\"))\n",
"print(\"Toutes les bibliothèques sont installées !\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Importation des biliothèques"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Importation des bibliothèques nécessaires à notre analyse\n",
"import geopandas as gpd\n",
"import folium\n",
"import matplotlib.pyplot as plt\n",
"from shapely.geometry import Point\n",
"\n",
"print(\"Toutes les bibliothèques sont importées !\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Étape 1 — Chargement des données\n",
"\n",
"Nous utilisons ici les fichiers Shapefile fournis dans l’archive `SnowGIS_SHP` provenant de ce site :\n",
"\n",
"https://blog.rtwilson.com/john-snows-cholera-data-in-more-formats/\n",
"\n",
"\n",
"Ces fichiers contiennent les données géographiques suivantes :\n",
"\n",
"- `Cholera_Deaths.shp` : emplacements des décès dus au choléra, avec le nombre de morts par adresse.\n",
"- `Pumps.shp` : emplacements des pompes à eau publiques dans le quartier de Soho.\n",
"\n",
"Nous utilisons la bibliothèque `GeoPandas` pour lire ces fichiers et vérifier que les données sont bien chargées avec le bon système de coordonnées.\n"
]
},
{
"cell_type": "code",
"execution_count": 35,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" Id | \n",
" Count | \n",
" geometry | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
" 0 | \n",
" 3 | \n",
" POINT (529308.741 181031.352) | \n",
"
\n",
" \n",
" 1 | \n",
" 0 | \n",
" 2 | \n",
" POINT (529312.164 181025.172) | \n",
"
\n",
" \n",
" 2 | \n",
" 0 | \n",
" 1 | \n",
" POINT (529314.382 181020.294) | \n",
"
\n",
" \n",
" 3 | \n",
" 0 | \n",
" 1 | \n",
" POINT (529317.380 181014.259) | \n",
"
\n",
" \n",
" 4 | \n",
" 0 | \n",
" 4 | \n",
" POINT (529320.675 181007.872) | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" Id Count geometry\n",
"0 0 3 POINT (529308.741 181031.352)\n",
"1 0 2 POINT (529312.164 181025.172)\n",
"2 0 1 POINT (529314.382 181020.294)\n",
"3 0 1 POINT (529317.380 181014.259)\n",
"4 0 4 POINT (529320.675 181007.872)"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" Id | \n",
" geometry | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
" 0 | \n",
" POINT (529396.539 181025.063) | \n",
"
\n",
" \n",
" 1 | \n",
" 0 | \n",
" POINT (529192.538 181079.391) | \n",
"
\n",
" \n",
" 2 | \n",
" 0 | \n",
" POINT (529183.740 181193.735) | \n",
"
\n",
" \n",
" 3 | \n",
" 0 | \n",
" POINT (529748.911 180924.207) | \n",
"
\n",
" \n",
" 4 | \n",
" 0 | \n",
" POINT (529613.205 180896.804) | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" Id geometry\n",
"0 0 POINT (529396.539 181025.063)\n",
"1 0 POINT (529192.538 181079.391)\n",
"2 0 POINT (529183.740 181193.735)\n",
"3 0 POINT (529748.911 180924.207)\n",
"4 0 POINT (529613.205 180896.804)"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"CRS des décès : epsg:27700\n",
"CRS des pompes : epsg:27700\n"
]
}
],
"source": [
"# Chargement des shapefiles avec GeoPandas\n",
"deaths = gpd.read_file(\"Cholera_Deaths.shp\")\n",
"pumps = gpd.read_file(\"Pumps.shp\")\n",
"\n",
"# Aperçu des données\n",
"display(deaths.head())\n",
"display(pumps.head())\n",
"\n",
"# Vérification du système de coordonnées (CRS)\n",
"print(\"CRS des décès :\", deaths.crs)\n",
"print(\"CRS des pompes :\", pumps.crs)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Étape 2 — Conversion des coordonnées pour Folium\n",
"\n",
"Folium utilise sur le système de coordonnées **WGS 84** (latitude/longitude), qui est utilisé par défaut dans les cartes web comme OpenStreetMap. \n",
"Cependant, nos fichiers shapefile utilisent actuellement le système **British National Grid** (EPSG:27700), qui fonctionne avec des coordonnées en mètres, propres au Royaume-Uni.\n",
"\n",
"Afin de pouvoir afficher correctement nos données sur une carte interactive avec Folium, il est nécessaire de les convertir vers le système de projection WGS 84 (**EPSG:4326**). \n",
"Cette opération est appelée une **reprojection**. Elle permet à nos points d'apparaître au bon endroit sur la carte.\n",
"\n",
"Nous réalisons cette conversion avec la méthode .to_crs(epsg=4326) de GeoPandas, qui transforme les coordonnées de chaque géométrie."
]
},
{
"cell_type": "code",
"execution_count": 36,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" Id | \n",
" Count | \n",
" geometry | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
" 0 | \n",
" 3 | \n",
" POINT (-0.13793 51.51342) | \n",
"
\n",
" \n",
" 1 | \n",
" 0 | \n",
" 2 | \n",
" POINT (-0.13788 51.51336) | \n",
"
\n",
" \n",
" 2 | \n",
" 0 | \n",
" 1 | \n",
" POINT (-0.13785 51.51332) | \n",
"
\n",
" \n",
" 3 | \n",
" 0 | \n",
" 1 | \n",
" POINT (-0.13781 51.51326) | \n",
"
\n",
" \n",
" 4 | \n",
" 0 | \n",
" 4 | \n",
" POINT (-0.13777 51.51320) | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" Id Count geometry\n",
"0 0 3 POINT (-0.13793 51.51342)\n",
"1 0 2 POINT (-0.13788 51.51336)\n",
"2 0 1 POINT (-0.13785 51.51332)\n",
"3 0 1 POINT (-0.13781 51.51326)\n",
"4 0 4 POINT (-0.13777 51.51320)"
]
},
"execution_count": 36,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Reprojection en EPSG:4326 (latitude/longitude)\n",
"deaths_wgs84 = deaths.to_crs(epsg=4326)\n",
"pumps_wgs84 = pumps.to_crs(epsg=4326)\n",
"\n",
"# Aperçu pour vérification\n",
"deaths_wgs84.head()\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Étape 3 — Création de la carte interactive\n",
"\n",
"Nous utilisons la bibliothèque `folium` pour créer une carte interactive centrée sur le quartier de Soho.\n",
"\n",
"- Les **cercles rouges** représentent les décès dus au choléra. Leur taille est proportionnelle au nombre de morts enregistrés à cette adresse (`Count`).\n",
"- Les **marqueurs bleus** représentent les pompes à eau publiques.\n",
"\n",
"Cette visualisation permet de retrouver la logique de la carte originale de John Snow, en montrant la concentration des décès autour de certaines pompes.\n"
]
},
{
"cell_type": "code",
"execution_count": 37,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"Make this Notebook Trusted to load map: File -> Trust Notebook
"
],
"text/plain": [
""
]
},
"execution_count": 37,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Obtenir le centre de la carte en prenant le centre des décès\n",
"map_center = [deaths_wgs84.geometry.y.mean(), deaths_wgs84.geometry.x.mean()]\n",
"\n",
"# Créer la carte Folium centrée sur Soho\n",
"m = folium.Map(location=map_center, zoom_start=17, tiles='cartodbpositron')\n",
"\n",
"# Ajouter les décès avec des cercles proportionnels à Count\n",
"for _, row in deaths_wgs84.iterrows():\n",
" folium.CircleMarker(\n",
" location=[row.geometry.y, row.geometry.x],\n",
" radius=row['Count'] * 1.5, # multiplier pour avoir une taille visible\n",
" color='red',\n",
" fill=True,\n",
" fill_color='red',\n",
" fill_opacity=0.6,\n",
" popup=f\"{row['Count']} décès\"\n",
" ).add_to(m)\n",
"\n",
"# Ajouter les pompes avec une icône bleue\n",
"for _, row in pumps_wgs84.iterrows():\n",
" folium.Marker(\n",
" location=[row.geometry.y, row.geometry.x],\n",
" icon=folium.Icon(color='blue', icon='tint', prefix='fa'),\n",
" popup=\"Pompe à eau\"\n",
" ).add_to(m)\n",
"\n",
"# Afficher la carte\n",
"m\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Étape 4 — Visualisation de la densité des décès avec une Heatmap\n",
"\n",
"Pour identifier visuellement les zones les plus touchées par l’épidémie, nous utilisons une **carte de chaleur** (heatmap). \n",
"Chaque point de décès est pondéré par le nombre de morts (`Count`). On observe ainsi une zone de concentration très nette autour d'une certaine pompe.\n",
"On voyait déjà cela avec les cercles mais je trouve la heat map plus parlante.\n"
]
},
{
"cell_type": "code",
"execution_count": 38,
"metadata": {
"scrolled": true
},
"outputs": [
{
"data": {
"text/html": [
"Make this Notebook Trusted to load map: File -> Trust Notebook
"
],
"text/plain": [
""
]
},
"execution_count": 38,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from folium.plugins import HeatMap\n",
"\n",
"# Extraire les points avec leur pondération\n",
"heat_data = [[row.geometry.y, row.geometry.x, row['Count']] for _, row in deaths_wgs84.iterrows()]\n",
"\n",
"# Nouvelle carte centrée sur Soho\n",
"m_heat = folium.Map(location=map_center, zoom_start=17, tiles='cartodbpositron')\n",
"\n",
"# Ajouter la heatmap des décès\n",
"HeatMap(heat_data, radius=15, blur=10, max_zoom=18).add_to(m_heat)\n",
"\n",
"# Ajouter les pompes pour référence\n",
"for _, row in pumps_wgs84.iterrows():\n",
" folium.Marker(\n",
" location=[row.geometry.y, row.geometry.x],\n",
" icon=folium.Icon(color='blue', icon='tint', prefix='fa'),\n",
" popup=\"Pompe à eau\"\n",
" ).add_to(m_heat)\n",
"\n",
"# Afficher la heatmap\n",
"m_heat\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Conclusion\n",
"\n",
"Grâce à nos outils de visualisation de données géospatiales, nous avons pu reproduire et enrichir l’analyse historique de John Snow sur l’épidémie de choléra de 1854 à Soho.\n",
"\n",
"- Nous avons visualisé les lieux de décès avec des cercles proportionnels au nombre de morts.\n",
"- Nous avons localisé les pompes à eau sur la même carte.\n",
"- La carte de chaleur a clairement mis en évidence une forte concentration de décès autour d'une pompe spécifique, celle de Broad Street.\n",
"\n",
"\n",
"Victor Gérenton\n",
"---\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.4"
}
},
"nbformat": 4,
"nbformat_minor": 5
}