Inspired by Mike Bostock's Let's Make a Map, we want to make a map too using matta. We will display the communes of Santiago, Chile. To do that we will perform the following steps:
In [2]:
from __future__ import print_function, unicode_literals
In [1]:
import matta
import json
import unicodedata
# we do this to load the required libraries when viewing on NBViewer
matta.init_javascript(path='https://rawgit.com/carnby/matta/master/matta/libs')
Out[1]:
In [4]:
!rm -fr data
!mkdir data
!wget http://siit2.bcn.cl/obtienearchivo?id=repositorio/10221/10396/1/division_comunal.zip -O data/division_comunal.zip
In [5]:
!unzip data/division_comunal.zip -d data/
In [6]:
!ogrinfo data/division_comunal.shp 'division_comunal' | head -n 30
Now we use ogr2ogr to convert the shapefile into GeoJSON. We will build a file for Santiago (its capital) only.
Notes:
santiago-comunas-geo.json in case it exists (that is, when we re-run the notebook :) ).-clipdst option to specify a bounding box obtained in this site. We need it because some populated locations are much bigger in administrative terms than in population terms.-t_srs EPSG:4326 option to convert the data coordinates to (longitude,latitude) pairs.
In [7]:
!ogr2ogr -where "NOM_PROV IN ('Santiago', 'Maipo', 'Cordillera', 'Chacabuco', 'Talagante')" -f GeoJSON \
-clipdst -70.828155 -33.635036 -70.452573 -33.302953 -t_srs EPSG:4326 \
data/santiago-comunas-geo.json data/division_comunal.shp
In [8]:
!topojson -p --id-property NOM_COM -s 0 -o data/santiago-comunas-topo.json data/santiago-comunas-geo.json
In [9]:
!ls -lh data/*.json
In [10]:
def strip_accents(s):
return ''.join(c for c in unicodedata.normalize('NFD', s) if unicodedata.category(c) != 'Mn')
with open('data/santiago-comunas-topo.json', 'r') as f:
stgo = json.load(f)
for g in stgo['objects']['santiago-comunas-geo']['geometries']:
g['id'] = strip_accents(g['id'].title())
g['properties']['id'] = g['id']
Here is an example feature:
In [11]:
stgo['objects']['santiago-comunas-geo']['geometries'][0]
Out[11]:
In [12]:
matta.cartography(geometry=stgo, leaflet=False, label='NOM_COM',
fill_color={'value': 'id', 'palette': str('husl'), 'scale': 'ordinal', 'n_colors': 40})
Now that we can load a map and giving some colors to areas, let's try to visualize some data. The easiest way to do so would be to get a Wikipedia page with data for Santiago. From it, we will get the Human Development Index (IDH in Spanish) score for each municipality of the city.
In [13]:
import pandas as pd
df = pd.read_html('https://es.wikipedia.org/wiki/Anexo:Comunas_de_Santiago_de_Chile',
attrs={'class': 'sortable'}, header=0)[0]
df.head()
Out[13]:
Data is not clean due to locale settings. Fortunately, we just want the HDI column, which should be easy to convert to a meaningful float. Let's fix the HDI and Population columns.
In [14]:
df['Comuna'] = [strip_accents(c).replace('?', '').title() for c in df['Comuna']]
df['HDI'] = [float(c.split()[0].replace(',', '.')) for c in df['IDH (2003)?']]
del df['IDH (2003)?']
df.head()
Out[14]:
In [15]:
df['Population'] = df['Población (2002)?'] * 1000
df = df.loc[:,('Comuna', 'HDI', 'Population')]
df.head()
Out[15]:
Much better!
In [16]:
df.describe()
Out[16]:
Now let's visualize HDI for each municipality.
In [17]:
matta.cartography(geometry=stgo, label='NOM_COM', width=700,
area_dataframe=df, area_feature_name='Comuna',
area_color={'value': 'HDI', 'scale': 'threshold', 'palette': 'coolwarm', 'n_colors': 7, 'legend': True},
leaflet=False)
What happened there? We bound a DataFrame (area_dataframe) to the geometry by using the area_feature_name column in the DataFrame. Using this, our code was able to match a feature from the TopoJSON structure with a row from the DataFrame. Note that some areas are not drawn - they were not available in the DataFrame.
We can also visualize this information using a cartogram. According to Wikipedia:
A cartogram is a map in which some thematic mapping variable – such as travel time, population, or Gross National Product – is substituted for land area or distance. The geometry or space of the map is distorted in order to convey the information of this alternate variable.
For instance, we observe that the areas that have a high HDI are, indeed, big. But how much people inhabit them?
In [38]:
matta.cartogram(geometry=stgo, width=700,
area_dataframe=df, area_feature_name='Comuna', area_opacity=1.0,
area_color={'value': 'HDI', 'scale': 'threshold', 'palette': 'coolwarm', 'n_colors': 7},
area_value='Population', na_value=df['Population'].min() * 0.75)
As we can see, the shape of each area is different now! The differences are not very dramatic, but this is just an example.
In [ ]: