{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Sujet 3 : L'épidémie de choléra à Londres en 1854" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "À partir des données numériques, réalisez une carte dans l'esprit de celle de John Snow. Montrez les lieux de décès avec des symboles dont la taille indique le nombre de décès. Indiquez sur la même carte la localisation des pompes en utilisant une autre couleur et/ou un autre symbole. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Installation les packages nécessaires \n", "- package folium pour afficager la carte\n", "- package geopandas pour lire les données \n", "\n", "Ce processus d'installation prendra certain minutes." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Collecting folium\n", " Downloading folium-0.12.1-py2.py3-none-any.whl (94 kB)\n", "\u001b[K |████████████████████████████████| 94 kB 6.6 MB/s eta 0:00:01\n", "\u001b[?25hRequirement already satisfied: jinja2>=2.9 in /opt/conda/lib/python3.6/site-packages (from folium) (2.11.0)\n", "Collecting branca>=0.3.0\n", " Downloading branca-0.4.2-py3-none-any.whl (24 kB)\n", "Requirement already satisfied: numpy in /opt/conda/lib/python3.6/site-packages (from folium) (1.15.2)\n", "Requirement already satisfied: requests in /opt/conda/lib/python3.6/site-packages (from folium) (2.23.0)\n", "Requirement already satisfied: MarkupSafe>=0.23 in /opt/conda/lib/python3.6/site-packages (from jinja2>=2.9->folium) (1.1.1)\n", "Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in /opt/conda/lib/python3.6/site-packages (from requests->folium) (1.25.7)\n", "Requirement already satisfied: idna<3,>=2.5 in /opt/conda/lib/python3.6/site-packages (from requests->folium) (2.9)\n", "Requirement already satisfied: chardet<4,>=3.0.2 in /opt/conda/lib/python3.6/site-packages (from requests->folium) (3.0.4)\n", "Requirement already satisfied: certifi>=2017.4.17 in /opt/conda/lib/python3.6/site-packages (from requests->folium) (2020.4.5.1)\n", "Installing collected packages: branca, folium\n", "Successfully installed branca-0.4.2 folium-0.12.1\n", "Collecting geopandas\n", " Downloading geopandas-0.9.0-py2.py3-none-any.whl (994 kB)\n", "\u001b[K |████████████████████████████████| 994 kB 6.0 MB/s eta 0:00:01\n", "\u001b[?25hCollecting fiona>=1.8\n", " Downloading Fiona-1.8.20-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl (15.4 MB)\n", "\u001b[K |████████████████████████████████| 15.4 MB 18.6 MB/s eta 0:00:01\n", "\u001b[?25hCollecting pyproj>=2.2.0\n", " Downloading pyproj-3.0.1-cp36-cp36m-manylinux2010_x86_64.whl (6.5 MB)\n", "\u001b[K |████████████████████████████████| 6.5 MB 24.1 MB/s eta 0:00:01\n", "\u001b[?25hCollecting pandas>=0.24.0\n", " Downloading pandas-1.1.5-cp36-cp36m-manylinux1_x86_64.whl (9.5 MB)\n", "\u001b[K |████████████████████████████████| 9.5 MB 62.1 MB/s eta 0:00:01\n", "\u001b[?25hCollecting shapely>=1.6\n", " Downloading Shapely-1.7.1-cp36-cp36m-manylinux1_x86_64.whl (1.0 MB)\n", "\u001b[K |████████████████████████████████| 1.0 MB 29.2 MB/s eta 0:00:01\n", "\u001b[?25hCollecting munch\n", " Downloading munch-2.5.0-py2.py3-none-any.whl (10 kB)\n", "Collecting click>=4.0\n", " Downloading click-8.0.1-py3-none-any.whl (97 kB)\n", "\u001b[K |████████████████████████████████| 97 kB 8.7 MB/s eta 0:00:01\n", "\u001b[?25hRequirement already satisfied: six>=1.7 in /opt/conda/lib/python3.6/site-packages (from fiona>=1.8->geopandas) (1.14.0)\n", "Requirement already satisfied: setuptools in /opt/conda/lib/python3.6/site-packages (from fiona>=1.8->geopandas) (45.2.0.post20200209)\n", "Collecting click-plugins>=1.0\n", " Downloading click_plugins-1.1.1-py2.py3-none-any.whl (7.5 kB)\n", "Collecting cligj>=0.5\n", " Downloading cligj-0.7.2-py3-none-any.whl (7.1 kB)\n", "Requirement already satisfied: certifi in /opt/conda/lib/python3.6/site-packages (from fiona>=1.8->geopandas) (2020.4.5.1)\n", "Requirement already satisfied: attrs>=17 in /opt/conda/lib/python3.6/site-packages (from fiona>=1.8->geopandas) (19.3.0)\n", "Collecting numpy>=1.15.4\n", " Downloading numpy-1.19.5-cp36-cp36m-manylinux2010_x86_64.whl (14.8 MB)\n", "\u001b[K |████████████████████████████████| 14.8 MB 59.1 MB/s eta 0:00:01\n", "\u001b[?25hRequirement already satisfied: python-dateutil>=2.7.3 in /opt/conda/lib/python3.6/site-packages (from pandas>=0.24.0->geopandas) (2.8.1)\n", "Requirement already satisfied: pytz>=2017.2 in /opt/conda/lib/python3.6/site-packages (from pandas>=0.24.0->geopandas) (2019.3)\n", "Collecting importlib-metadata; python_version < \"3.8\"\n", " Downloading importlib_metadata-4.4.0-py3-none-any.whl (17 kB)\n", "Collecting typing-extensions>=3.6.4; python_version < \"3.8\"\n", " Downloading typing_extensions-3.10.0.0-py3-none-any.whl (26 kB)\n", "Requirement already satisfied: zipp>=0.5 in /opt/conda/lib/python3.6/site-packages (from importlib-metadata; python_version < \"3.8\"->click>=4.0->fiona>=1.8->geopandas) (2.1.0)\n", "Installing collected packages: munch, typing-extensions, importlib-metadata, click, click-plugins, cligj, fiona, pyproj, numpy, pandas, shapely, geopandas\n", " Attempting uninstall: numpy\n", " Found existing installation: numpy 1.15.2\n", " Uninstalling numpy-1.15.2:\n", " Successfully uninstalled numpy-1.15.2\n", " Attempting uninstall: pandas\n", " Found existing installation: pandas 0.22.0\n", " Uninstalling pandas-0.22.0:\n", " Successfully uninstalled pandas-0.22.0\n", "Successfully installed click-8.0.1 click-plugins-1.1.1 cligj-0.7.2 fiona-1.8.20 geopandas-0.9.0 importlib-metadata-4.4.0 munch-2.5.0 numpy-1.19.5 pandas-1.1.5 pyproj-3.0.1 shapely-1.7.1 typing-extensions-3.10.0.0\n" ] } ], "source": [ "import sys\n", "!{sys.executable} -m pip install folium\n", "!{sys.executable} -m pip install geopandas " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1 Récupérer des données\n", "Récupérer les données de [Snow](https://johnsnowsociety.org/) dans le webset [ici](http://blog.rtwilson.com/john-snows-cholera-data-in-more-formats/), les données incluent l'information de pompes et les détails des morts. \n", " - fichier 'cholera_deaths.kml' inclut la position des morts et le nombre correspondant\n", " - fichier 'pumps.kml' inclut la position des pompes" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "import requests\n", "import zipfile\n", "import io" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [], "source": [ "# Télécharge les données\n", "# données de la format KML\n", "zip_url = 'http://rtwilson.com/downloads/SnowGIS_KML.zip'\n", "\n", "r = requests.get(zip_url)\n", "z = zipfile.ZipFile(io.BytesIO(r.content))\n", "z.extractall(path='./')" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "import geopandas as gpd\n", "import fiona\n", "\n", "#Extraire les données des morts et le nombre correspondant\n", "gpd.io.file.fiona.drvsupport.supported_drivers['KML'] = 'rw'\n", "df = gpd.read_file('SnowGIS_KML/cholera_deaths.kml', driver='KML')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "le nombre de mort peut être trouvé dans l'information 'Description' " ] }, { "cell_type": "code", "execution_count": 5, "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", " \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", "
NameDescriptiongeometry
0<div class=\"googft-info-window\" style=\"font-fa...POINT (-0.13793 51.51342)
1<div class=\"googft-info-window\" style=\"font-fa...POINT (-0.13788 51.51336)
2<div class=\"googft-info-window\" style=\"font-fa...POINT (-0.13785 51.51332)
3<div class=\"googft-info-window\" style=\"font-fa...POINT (-0.13781 51.51326)
4<div class=\"googft-info-window\" style=\"font-fa...POINT (-0.13777 51.51320)
............
245<div class=\"googft-info-window\" style=\"font-fa...POINT (-0.13711 51.51453)
246<div class=\"googft-info-window\" style=\"font-fa...POINT (-0.13706 51.51471)
247<div class=\"googft-info-window\" style=\"font-fa...POINT (-0.13847 51.51231)
248<div class=\"googft-info-window\" style=\"font-fa...POINT (-0.13812 51.51200)
249<div class=\"googft-info-window\" style=\"font-fa...POINT (-0.13776 51.51186)
\n", "

250 rows × 3 columns

\n", "
" ], "text/plain": [ " Name Description \\\n", "0
\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", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
NameDescriptiongeometry
0<div class=\"googft-info-window\" style=\"font-fa...POINT (-0.13667 51.51334)
1<div class=\"googft-info-window\" style=\"font-fa...POINT (-0.13959 51.51388)
2<div class=\"googft-info-window\" style=\"font-fa...POINT (-0.13967 51.51491)
3<div class=\"googft-info-window\" style=\"font-fa...POINT (-0.13163 51.51235)
4<div class=\"googft-info-window\" style=\"font-fa...POINT (-0.13359 51.51214)
5<div class=\"googft-info-window\" style=\"font-fa...POINT (-0.13592 51.51154)
6<div class=\"googft-info-window\" style=\"font-fa...POINT (-0.13396 51.51002)
7<div class=\"googft-info-window\" style=\"font-fa...POINT (-0.13820 51.51129)
\n", "
" ], "text/plain": [ " Name Description \\\n", "0
')+10:row['Description'].rfind('
')]),\n", " popup='Count:' + row['Description'][row['Description'].rfind('count:')+10:row['Description'].rfind('')],\n", " color= 'red',\n", " weight = 2,\n", " fill=True,\n", " fill_color='red',\n", " fillOpacity=0,\n", " ).add_to(m)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " - la taille de la cercle rouge indique le nombre de décès, cliquez sur la zone du cercle rouge avec la souris pour afficher le nombre spécifique de décès à cet endroit.\n", "\n", " - Mark blue avec l'icône de gouttte d'eau indique la position des pompes." ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/html": [ "
Make this Notebook Trusted to load map: File -> Trust Notebook
" ], "text/plain": [ "" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m.save(\"mapBroadStreet1.html\")\n", "m" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Résultat:\n", "\n", "La carte nous montre que la distribution du cercle rouge est concentrée autour de la position de pomp de 'Broadwick Street', et la position qui a le plus grand nombre de morts de 15 personnes est proche de la position de pomp de 'Broadwick Street' aussi." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 3 Méthode de densité des décès \n", "l'autres façons pour montrer que la pompe de Broad Street est au centre de l'épidémie. \n", "\n", "Calculer la densité des décès dans le quartier et l'afficher sur la carte. D'ici on calcul le nombre de morts à moins de 100 mètres de chaque pomp, et les affichons sur la carte.\n", "\n", "La couleur rouge indique le nombre de morts est grand, par contre la couleur blue indique le nombre de morts est petit." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "import math\n", "\n", "#La fonction pour calcul la distance avec le coordonnées de la carte\n", "# code source reference \n", "#https://instrovate.com/2019/07/01/tagging-two-locations-on-map-using-python-and-finding-distance-between-two-tagged-location-in-python/\n", "\n", "def find_distance(origin, destination):\n", " lat1, lon1 = origin\n", " lat2, lon2 = destination\n", " radius = 6371 # km\n", "\n", " dlat = math.radians(lat2-lat1)\n", " dlon = math.radians(lon2-lon1)\n", " a = math.sin(dlat/2) * math.sin(dlat/2) + math.cos(math.radians(lat1)) \\\n", " * math.cos(math.radians(lat2)) * math.sin(dlon/2) * math.sin(dlon/2)\n", " c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))\n", " distance_bw_ori_desti = radius * c\n", " return distance_bw_ori_desti\n" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": [ "import folium\n", "from folium.plugins import HeatMap\n", "\n", "m = folium.Map(location=[51.51323855699922, -0.13695845651105376], zoom_start=16) \n", "\n", "countList = []\n", "for index, row in pumpsdf.iterrows():\n", " count = 0\n", " for i, dfrow in df.iterrows():\n", " dis = find_distance((dfrow['geometry'].coords[0][1],dfrow['geometry'].coords[0][0]),(row['geometry'].coords[0][1],row['geometry'].coords[0][0]))\n", " \n", " if dis*1000 < 100:\n", " count = count + int(dfrow['Description'][dfrow['Description'].rfind('count:')+10:dfrow['Description'].rfind('')])\n", " countList.append((row['geometry'].coords[0][1], row['geometry'].coords[0][0], count))\n", " '''\n", " folium.Circle(\n", " location=[row['geometry'].coords[0][1], row['geometry'].coords[0][0]],\n", " radius=100,\n", " popup=str(count),\n", " title=str(count),\n", " color= 'blue',\n", " weight = 6,\n", " opacity = count/100,\n", " fill=True,\n", " #fill_color='blue',\n", " fillOpacity=0,\n", " ).add_to(m)\n", " '''\n", " folium.Marker(\n", " location=[row['geometry'].coords[0][1], row['geometry'].coords[0][0]],\n", " popup=str(count),\n", " icon=folium.Icon(color='blue', icon='tint', prefix='glyphicon'),\n", " ).add_to(m)\n", "\n", " m.add_child(HeatMap(countList, radius=100))" ] }, { "cell_type": "code", "execution_count": 22, "metadata": { "scrolled": false }, "outputs": [ { "data": { "text/html": [ "
Make this Notebook Trusted to load map: File -> Trust Notebook
" ], "text/plain": [ "" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m.save(\"mapBroadStreet2.html\")\n", "m" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Résultat:\n", "\n", "La carte nous montre que à côte de la position de pomp de 'Broadwick Street', la couleur de la région est plus rouge qu'il indique le nombre de morts est plus grand.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "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": 2 }