Data Visualization For GIS Info With Python

This post breifly records my learning on how to visualiza the GIS info on the map by python. I attempted different ways to visualize my gis data by python. I was very luck to find two powerful package to deal with data visualization:

The two package offers different ways to visualize gis info on the map. And most importantly, it is easy to get started!

what is folium

folium is a package aimed at making beautiful maps with Leaflet.js & Python. Just with a few codes, you can generate a beautiful map to visualize your data and help you doing analysis. folium supports python2 and python3. If you install the anaconda IDE environment, you won’t face any trouble to install it. the installation is simple and easy with pip:

pip install folium

get started to create the first simple map

with a few code, we can get the traditional map immediately:

1
2
3
4
5
import folium
map_osm = folium.Map(location=[45.5236, -122.6750])

## output to a html file
map_osm.create_map(path='osm.html')

Different types of map

As far as I know, folium has at least three types of map form (tiles), which are “default”,”Stamen Toner”,”Stamen Terrain”. In the following are the examples:

1
2
3
4
5
map_demo1 = folium.Map(location=[45.5236, -122.6750])
map_demo2 = folium.Map(location=[45.5236, -122.6750], tiles='Stamen Toner',
zoom_start=13)
map_demo3 = folium.Map(location=[45.372, -121.6972], tiles='Stamen Terrain',
zoom_start=12)

custom tiles:

tiles: str, default 'OpenStreetMap'
    Map tileset to use. Can choose from this list of built-in tiles:
        - "OpenStreetMap"
        - "MapQuest Open"
        - "MapQuest Open Aerial"
        - "Mapbox Bright" (Limited levels of zoom for free tiles)
        - "Mapbox Control Room" (Limited levels of zoom for free tiles)
        - "Stamen" (Terrain, Toner, and Watercolor)
        - "Cloudmade" (Must pass API key)
        - "Mapbox" (Must pass API key)
        - "CartoDB" (positron and dark_matter)

Of course, you can use mapbox and Leaflet.js to design and create many other types of map style (tile)
Of course, you can use mapbox and Leaflet.js to design and create many other types of map style (tile)
For Mapbox, it is very simple : all you need to do is set the tiles as ‘Mapbox’, and include API_key.(I don not know it quite well)

Mapbox is an open source mapping platform for custom designed maps. it is very easy to use and can help designers and gis professionars to create beautiful maps instantly

1
2
3
4
5
6
7
custom = folium.Map(location=[45.5236, -122.6750], tiles='Mapbox',
API_key='wrobstory.map-12345678')

tileset = r'https://api.mapbox.com/v4/xiaofeima.p37fkfk1/{z}/{x}/{y}.png?access_token=pk.eyJ1IjoieGlhb2ZlaW1hIiwiYSI6ImNpa2I2dTRudDBtNnV2dWtwbXh6Njg2NmcifQ.7E2eCTrl2aY5dCtTJJwXtw'

custom2 = folium.Map(location=[45.372, -121.6972], zoom_start=2,
tiles=tileset, attr='My Data Attribution')

and with the above style, we get the following map style

map

markers and popups

When we create the map style, the next thing we want to do is to mark the information on the map, folium offers us multiple methods to make marker icon and popups:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
map_demo2 = folium.Map(location=[45.5236, -122.6750], tiles='Stamen Toner',
zoom_start=13)

# custom simple
map_demo2.simple_marker(location=[45.5244, -122.6699], popup='The Waterfront')
# draw a circle
map_demo2.circle_marker(location=[45.5215, -122.6261], radius=500,
popup='Laurelhurst Park', line_color='#3186cc',
fill_color='#3186cc')
# Polygon marker

map_demo4 = folium.Map(location=[45.5236, -122.6750], zoom_start=13)
map_demo4.polygon_marker(location=[45.5012, -122.6655], popup='Ross Island Bridge',
fill_color='#132b5e', num_sides=3, radius=10)
map_demo4.polygon_marker(location=[45.5132, -122.6708], popup='Hawthorne Bridge',
fill_color='#45647d', num_sides=4, radius=10)
map_demo4.polygon_marker(location=[45.5275, -122.6692], popup='Steel Bridge',
fill_color='#769d96', num_sides=6, radius=10)
map_demo4.polygon_marker(location=[45.5318, -122.6745], popup='Broadway Bridge',
fill_color='#769d96', num_sides=8, radius=10)

# lively icon
map_demo1.simple_marker([45.3288, -121.6625], popup='Mt. Hood Meadows',marker_icon='cloud')
map_demo1.simple_marker([45.3311, -121.7113], popup='Timberline Lodge',marker_color='green')
map_demo1.simple_marker([45.3300, -121.6823], popup='Some Other Location',marker_color='red',marker_icon='info-sign')

Moreover, folium support the Vincent/Vega markers, which means we can put data and graphs into the marker

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

import vincent, json
import numpy as np

scatter_points = {
'x' : np.random.uniform(size=(100,)),
'y' : np.random.uniform(size=(100,)),
}

# Let's create the vincent chart.
scatter_chart = vincent.Scatter(scatter_points,
iter_idx='x',
width=600,
height=300)

# Let's convert it to JSON.
scatter_json = scatter_chart.to_json()

# Let's convert it to dict.
scatter_dict = json.loads(scatter_json)


map_vin = folium.Map([43,-100], zoom_start=4)

# Let's create a Vega popup based on scatter_chart.
popup = folium.Popup(max_width=800)
folium.Vega(scatter_chart, height=350, width=650).add_to(popup)
folium.Marker([30,-120], popup=popup).add_to(map_vin)

# Let's create a Vega popup based on scatter_json.
popup = folium.Popup(max_width=800)
folium.Vega(scatter_json, height=350, width=650).add_to(popup)
folium.Marker([30,-100], popup=popup).add_to(map_vin)

# Let's create a Vega popup based on scatter_dict.
popup = folium.Popup(max_width=800)
folium.Vega(scatter_dict, height=350, width=650).add_to(popup)
folium.Marker([30,-80], popup=popup).add_to(map_vin)

map_vin

In more general case, we can put html in to the popup so that we can represet anything we want :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

m = folium.Map([43,-100], zoom_start=4)

html="""
<h1> This is a big popup</h1><br>
With a few lines of code...
<p>
<code>
from numpy import *<br>
exp(-2*pi)
</code>
</p>
"""
iframe = folium.element.IFrame(html=html, width=500, height=300)
popup = folium.Popup(iframe, max_width=2650)

folium.Marker([30,-100], popup=popup).add_to(m)

m

the folium also supports the Choropleth Maps. But we need to offer the Geojson files to draw the map. The folium command is simple, but how to get Geojson is difficult. we need to find GIS info and switch it into geojson format. Fortunately,We find ways to get geoJson format file: source

  • Install the Quantum GIS framework http://www.qgis.org/e/qgis.
    • If you are on Mac OS X, you can use this version http://www.kyngchaos.com/software
    • This will give you the ogr2ogr utility used for converting shapefiles to geoJSON
  • Download the shapefiles for your country from here http://www.gadm.org/country and unzip
    • For Canada, and possibly other countries, the shapefile with suffix 0 is for the country boundary and the suffix 1 is for the internal regions. Not sure if this naming is consistent across countries.
  • Upload the region level shapefile to MapShaper http://mapshaper.com/test/MapShaper.swf or http://www.mapshaper.org.
    • You can skip this step if you don’t care to optimize the size of your resulting geoJSON
    • Set the ‘simplification level’ slider in MapShaper to the desired level and export the simplified shapefile as ‘Shapefile - Polygons’
  • Download .shp and .shx file to the local directory where you unzipped the original shapefiiles, replace the original files with the simplified ones.
  • Navigate to the local directory and run the command below, replacing with the actual name of the shapefile you want to convert.
    ogr2ogr -f geoJSON regions.json <shapefile>.shp
  • You should now have the regions for your country in geoJSON format. Check to make sure there are paths defined in regions.json and that property fields were maintained (ex. region name).

Then we should have the Choropleth maps:

1
2
3
4
5
6
7
8
9
10
11
12
13

china_geo=r'geojson/chn_adm1_2.json'

csv_data = r'data/CN-gdp-2014.csv'
state_data = pd.read_csv(csv_data,encoding='gbk')
map_ch = folium.Map(location=[50, 120], zoom_start=3)
map_ch.geo_json(geo_path=china_geo, data=state_data,
columns=['province', 'GDP-2014'],
#threshold_scale=[6, 7, 8, 9, 10,11,12,13],
key_on='feature.properties.HASC_1',
fill_color='BuPu', fill_opacity=0.7, line_opacity=0.5,
legend_name='GDP Rate (%)',reset=True)
map_ch.create_map('cn_states.html')

download the source code

word_cloud
ipynb to md