{ "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": 9, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
IdCountgeometry
003POINT (529308.741 181031.352)
102POINT (529312.164 181025.172)
201POINT (529314.382 181020.294)
301POINT (529317.380 181014.259)
404POINT (529320.675 181007.872)
\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", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Idgeometry
00POINT (529396.539 181025.063)
10POINT (529192.538 181079.391)
20POINT (529183.740 181193.735)
30POINT (529748.911 180924.207)
40POINT (529613.205 180896.804)
\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(\"data/Cholera_Deaths.shp\")\n", "pumps = gpd.read_file(\"data/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": 10, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
IdCountgeometry
003POINT (-0.13793 51.51342)
102POINT (-0.13788 51.51336)
201POINT (-0.13785 51.51332)
301POINT (-0.13781 51.51326)
404POINT (-0.13777 51.51320)
\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": 10, "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": 11, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
Make this Notebook Trusted to load map: File -> Trust Notebook
" ], "text/plain": [ "" ] }, "execution_count": 11, "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": 12, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/html": [ "
Make this Notebook Trusted to load map: File -> Trust Notebook
" ], "text/plain": [ "" ] }, "execution_count": 12, "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 }