{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Folium - Mapas de coropletas" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Importación de módulos de Python" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import folium\n", "import pandas as pd\n", "\n", "import json" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.11.0\n" ] } ], "source": [ "# Impresión de la versión de Folium\n", "print(folium.__version__)" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1.1.3\n" ] } ], "source": [ "# Impresión de la versión de Pandas\n", "print(pd.__version__)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Clase [Choropleth](https://python-visualization.github.io/folium/modules.html#folium.features.Choropleth)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Esta clase de Folium crea un [mapa de coropletas](https://en.wikipedia.org/wiki/Choropleth_map) y lo colorea de acuerdo al valor de un campo de datos.\n", "\n", "El método constructor de Choropleth recibe como parámetros la ubicación de los datos geoespaciales en formato GeoJSON (ej. en un archivo) y puede recibir también un conjunto de datos tabulares en un dataframe de [pandas](https://pandas.pydata.org/). Otros parámetros se utilizan para especificar los campos de datos según los que se colorea el mapa, así como los campos que se utilizan para enlazar los datos espaciales y tabulares.\n", "\n", "En el siguiente ejemplo, se crea un mapa de coropletas que refleja la cantidad de casos positivos de COVID-19 en los cantones de Costa Rica, de acuerdo con los [datos publicados por el Ministerio de Salud](http://geovision.uned.ac.cr/oges/). El archivo GeoJSON de cantones proviene de la capa publicada por el Instituto Geográfico Nacional (IGN) en el [Sistema Nacional de Información Territorial (SNIT)](https://www.snitcr.go.cr/)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "La función [read_csv()](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.read_csv.html) carga un archivo CSV en un [dataframe](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html) de pandas." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "# Carga de datos tabulares de casos positivos de COVID-19 en un dataframe\n", "df_positivos = pd.read_csv('datos/10_07_CSV_POSITIVOS_ULTIMA_FECHA.csv', sep=',')" ] }, { "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", "
Unnamed: 0cod_cantonpositivos
01112490
121103943
231061149
341182078
451036111
............
7879705389
79807021234
8081703830
8182704602
8283999532
\n", "

83 rows × 3 columns

\n", "
" ], "text/plain": [ " Unnamed: 0 cod_canton positivos\n", "0 1 112 490\n", "1 2 110 3943\n", "2 3 106 1149\n", "3 4 118 2078\n", "4 5 103 6111\n", ".. ... ... ...\n", "78 79 705 389\n", "79 80 702 1234\n", "80 81 703 830\n", "81 82 704 602\n", "82 83 999 532\n", "\n", "[83 rows x 3 columns]" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df_positivos" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "La función [rename()](https://pandas.pydata.org/pandas-docs/version/0.23.4/generated/pandas.DataFrame.rename.html) renombra una columna de un dataframe." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "# Renombramiento de la primera columna\n", "df_positivos.rename(columns = {'Unnamed: 0': 'id'}, inplace=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "La función [head()](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.head.html) despliega las primeras filas de un dataframe." ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "scrolled": true }, "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", "
idcod_cantonpositivos
7374609126
74756012017
7576606328
7677706440
77787011843
7879705389
79807021234
8081703830
8182704602
8283999532
\n", "
" ], "text/plain": [ " id cod_canton positivos\n", "73 74 609 126\n", "74 75 601 2017\n", "75 76 606 328\n", "76 77 706 440\n", "77 78 701 1843\n", "78 79 705 389\n", "79 80 702 1234\n", "80 81 703 830\n", "81 82 704 602\n", "82 83 999 532" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Despliegue de las primeras filas, para observación de los datos\n", "df_positivos.tail(10)" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "C:\\Users\\mfvargas\\anaconda3\\envs\\leccion-10\\lib\\site-packages\\folium\\folium.py:415: FutureWarning: The choropleth method has been deprecated. Instead use the new Choropleth class, which has the same arguments. See the example notebook 'GeoJSON_and_choropleth' for how to do this.\n", " FutureWarning\n" ] }, { "data": { "text/html": [ "
Make this Notebook Trusted to load map: File -> Trust Notebook
" ], "text/plain": [ "" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# GeoJSON de cantones\n", "# geo_cantones = r'datos/cr_cantones_wgs84.geojson'\n", "geo_cantones = r'datos/cr_limite_cantonal_ign_wgs84.geojson'\n", "\n", "# Mapa base\n", "m = folium.Map(\n", " location=[10, -84], \n", " zoom_start=7, \n", " tiles='openstreetmap')\n", "\n", "\n", "# Capa de coropletas coloreada de acuerdo con el campo de casos positivos.\n", "# El enlace entre los datos geoespaciales y tabulares se realiza a través del campo \"cod_canton\" del dataframe\n", "# y el campo del mismo nombre en el archivo GeoJSON.\n", "m.choropleth(\n", " geo_data=geo_cantones,\n", " data=df_positivos,\n", " columns=['cod_canton', 'positivos'],\n", " bins=8,\n", " key_on='feature.properties.cod_canton',\n", " fill_color='Reds', \n", " fill_opacity=1, \n", " line_opacity=1,\n", " legend_name='Casos positivos',\n", " smooth_factor=0)\n", "\n", "\n", "# Despliegue del mapa\n", "m" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "m.save('index.html')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Ventana emergente con datos de un polígono" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "# GeoJSON de cantones\n", "geo_cantones = r'datos/cr_limite_cantonal_ign_wgs84.geojson'\n", "\n", "# Mapa base\n", "m = folium.Map(\n", " location=[10, -84], \n", " zoom_start=7, \n", " tiles='openstreetmap')\n", "\n", "# Capa de coropletas coloreada de acuerdo con el campo de casos positivos.\n", "choropleth = folium.Choropleth(\n", " geo_data=geo_cantones,\n", " data=df_positivos,\n", " columns=['cod_canton', 'positivos'],\n", " bins=8,\n", " key_on='feature.properties.cod_canton',\n", " fill_color='Reds', \n", " fill_opacity=1, \n", " line_opacity=1,\n", " legend_name='Casos positivos',\n", " name='Casos positivos',\n", " smooth_factor=0).add_to(m)" ] }, { "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": [ "# Se crea un campo adicional en la estructura de la capa GeoJSON para almacenar el texto de la ventana emergente\n", "for feature in choropleth.geojson.data['features']:\n", " # print(type(feature['properties']))\n", " canton_filtrado_df = df_positivos[df_positivos['cod_canton'] == feature['properties']['cod_canton']]\n", " feature['properties']['texto_emergente'] = feature['properties']['canton'] + \"
\" + str(canton_filtrado_df.iloc[0]['positivos'])\n", "\n", "# Se especifica el nuevo campo como el contenido de la ventana emergente\n", "choropleth.geojson.add_child(folium.features.GeoJsonTooltip(['texto_emergente'], labels=False))\n", "\n", "# Otra opción para explorar\n", "# choropleth.add_child(folium.Popup('Texto emergente'))\n", "\n", "# Despliegue del mapa\n", "m " ] }, { "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.7.9" } }, "nbformat": 4, "nbformat_minor": 4 }