Capítulo 6 - Explicación
  
Previamente… Módulo 3 - Tarea 5
GeoJSON y coropletas
GeoJSON es un formato basado en JSON para representar simples elementos geográficos junto con atributos no espaciales. Este formato es ampliamente usado en entornos web porque es ligero y fácil de procesar.
{
     "type": "FeatureCollection",
     "features": [
         {
             "type": "Feature",
             "geometry": {
                 "type": "Point",
                 "coordinates": [102.0, 0.5]
             },
             "properties": {
                 "prop0": "value0"
             }
         }
     ]
 }
La función siguiente convierte un ESRI shapefile a un GeoJSON
Input[1]:
import shapefile
 from json import dumps
 
 def shape2json(fname, outfile):
     reader = shapefile.Reader(fname)
     fields = reader.fields[1:]
     field_names = [field[0] for field in fields]
     data = []
     for sr in reader.shapeRecords():
         atr = dict(zip(field_names, sr.record))
         geom = sr.shape.__geo_interface__
         data.append(dict(type="Feature", geometry=geom, properties=atr))
     keys = ['NUTS_NAME']
     for b in data:
         b['properties']['NUTS_NAME'] = b['properties']['NUTS_NAME'].strip('\u0000')
     with open(outfile, "w") as geojson:
         geojson.write(dumps({"type": "FeatureCollection",
                              "features": data}, indent=2) + "\n")
Para usarla, solo necesitas introducir el directorio del archivo de entrada y salida
Input[3]:
input_data = "datos/nuts2/NUTS_RG_01M_2016_4326_LEVL_2.shp"
 output_data = "datos/nuts2.json"
 
 shape2json(input_data, output_data)
GeoJSON en mapas
Folium tiene un buen soporte para crear mapas con GeoJSON.
Solo necesitamos la localización del archivo
Input[4]:
import folium
 mapa = folium.Map(zoom_start=3,location=[41.6563,-0.8811])
 folium.GeoJson("datos/nuts2.json").add_to(mapa)
Output[4]:
<folium.features.GeoJson at 0x234bea71608>
Folium crea un archive HTML con todo el código de JavaScript necesario y los datos en GeoJSON.
De esta manera podemos resusar los mapas.
La siguiente función guarda este HTML y lo visualiza en Jupyter.
Input[5]:
def embed_map(m, name):
     from IPython.display import IFrame
     file_name = 'datos/'+name + '.html'
     m.save(file_name)
     return IFrame(file_name, width=900,height=350)
Solo necesitamos usarlo
Input[6]:
embed_map(mapa, "nuts2")
Output[6]:

 
Folium te permite crear mapas de coropletas en una manera muy flexible.
Primero necesitamos los datos.
Input[3]:
import pandas as pd
 file = 'datos/animalEurostatNuts2_corrected.xlsx'
 data = pd.read_excel(file, sheet_name='Data', index_col=0)
 data.head(5)
Output[3]:

Después necesitamos una rampa de color.
Asumamos que los datos están entre 0 y 4000.
Input[4]:
from branca.colormap import linear
 
 colormap = linear.YlGn_09.scale(0, 4000)
 colormap
Output[4]:
![]()
Y ahora usamos la rampa de color para asociar cada NUTS con un color.
Input[5]:
color_dict = data['1991'].map(colormap)
 color_dict.get('ES11')
Output[5]:
'#e1f4a9ff'
Y para asegurar que dependiendo de cada geometría del NUTS_IS se les da el color correcto.
Usaremos el color rojo para indicar la ausencia de datos.
Input[6]:
def computar_color(feature):
     return  {
         'fillColor' : color_dict.get(feature["properties"]["NUTS_ID"], '#ff0000'),
         'fillOpacity': 1
     }   
Ahora visualizaremos la información aplicando el color.
Input[7]:
import folium
 mapa = folium.Map(zoom_start=3)
 folium.GeoJson(
     "datos/nuts2.json",
     name = "Datos 1991",        
     style_function = computar_color
 ).add_to(mapa)
 folium.LayerControl().add_to(mapa)
 colormap.caption = "Miles"
 mapa.add_child(colormap)
 mapa.fit_bounds([[43.7483377142, 3.03948408368], 
                  [35.946850084, -9.39288367353]])
Input[8]:
def embed_map(m, name):
     from IPython.display import IFrame
     file_name = 'datos/'+name + '.html'
     m.save(file_name)
     return IFrame(file_name, width=900,height=350)
 embed_map(mapa, "choropleth1")
Output[8]:

Podemos visualizar en capas datos de diferentes años.
Para hacer esto tienes que cambiar el código.
Input[9]:
def computar_color_columna(mapColor):
     def computar(feature):
         return  {
             'fillColor' : mapColor.get(feature["properties"]["NUTS_ID"], '#ff0000'),
             'fillOpacity': 1
         }
     return computar
Ahora creamos múltiples capas.
Input[10]:
mapa = folium.Map(zoom_start=3)
 for column in ['1991', '2001', '2011', '2019']:
     folium.GeoJson("datos/nuts2.json",
         name = "Datos " + column,        
         style_function = computar_color_columna(data[column].map(colormap))
     ).add_to(mapa)
 folium.LayerControl().add_to(mapa)
 colormap.caption = "Miles"
 mapa.add_child(colormap)
 mapa.fit_bounds([[43.7483377142, 3.03948408368], 
                  [35.946850084, -9.39288367353]])
Input[11]:
embed_map(mapa, "choropleth2")
Output[11]:
