#!/usr/bin/env python # coding: utf-8 # Let's try to build a chloropleth map using Bokeh, inspired by [this example](http://bokeh.pydata.org/en/0.10.0/docs/gallery/choropleth.html). Let's get our imports going: # In[1]: from bokeh.sampledata import us_states, us_counties, unemployment from bokeh.plotting import figure, show, output_file, output_notebook # In[2]: output_notebook() # It should be noted we're only importing three things from bokeh.plotting: figure, show and output_file. # In[3]: help(figure) # In[4]: help(show) # In[5]: help(output_file) # We can now go through the example steps: first, let's load the data. # In[6]: us_states = us_states.data.copy() us_counties = us_counties.data.copy() unemployment = unemployment.data # In[7]: type(us_states) # In[8]: type(us_counties) # In[9]: type(unemployment) # We now delete Alaska and Hawai from the data and load the coordinates for each state in separate variables. # In[10]: del us_states["HI"] del us_states["AK"] state_xs = [us_states[code]["lons"] for code in us_states] state_ys = [us_states[code]["lats"] for code in us_states] county_xs=[us_counties[code]["lons"] for code in us_counties if us_counties[code]["state"] not in ["ak", "hi", "pr", "gu", "vi", "mp", "as"]] county_ys=[us_counties[code]["lats"] for code in us_counties if us_counties[code]["state"] not in ["ak", "hi", "pr", "gu", "vi", "mp", "as"]] # To have a better look at what we're manipulating, we can just plot the coordinates using matplotlib. # In[11]: import matplotlib.pyplot as plt get_ipython().run_line_magic('matplotlib', 'inline') # In[12]: plt.plot(county_xs[0], county_ys[0]) # We now go over the data for each county and assign it a color, depending on the numerical value of the unemployment. # In[13]: colors = ["#F1EEF6", "#D4B9DA", "#C994C7", "#DF65B0", "#DD1C77", "#980043"] county_colors = [] for county_id in us_counties: if us_counties[county_id]["state"] in ["ak", "hi", "pr", "gu", "vi", "mp", "as"]: continue try: rate = unemployment[county_id] idx = min(int(rate/2), 5) county_colors.append(colors[idx]) except KeyError: county_colors.append("black") # Finally, a figure is created and patches are added to the map. Filled patches are used, as well as simpler patches that only map the contour of the states. # In[14]: p = figure(title="US Unemployment 2009", toolbar_location="left", plot_width=1100, plot_height=700) p.patches(county_xs, county_ys, fill_color=county_colors, fill_alpha=0.7, line_color="white", line_width=0.5) p.patches(state_xs, state_ys, fill_alpha=0.0, line_color="#884444", line_width=2) show(p) # With this knowledge in our hands, can we create a similar looking map of France? # # The raw data can be found here: [http://bl.ocks.org/rveciana/02eb5b83848e0b06fa8e](http://bl.ocks.org/rveciana/02eb5b83848e0b06fa8e). # # The instructions for using geopandas here: [https://michelleful.github.io/code-blog/2015/04/27/osm-data/](https://michelleful.github.io/code-blog/2015/04/27/osm-data/). # In[15]: import pandas as pd # In[16]: import geopandas as gpd # In[17]: import urllib # In[18]: json_file = urllib.request.urlopen("https://cdn.rawgit.com/rveciana/5919944/raw/b1f826319231c3e06d6e8548bc947ca2c29dc9e8/france.json").readlines() # In[20]: import tempfile # In[38]: f = tempfile.NamedTemporaryFile(dir='files/', delete=False) try: f.write(json_file[0]) f.close() df = gpd.read_file(f.name) finally: os.remove(f.name) # In[39]: df.columns # In[40]: df.ix[0]['geometry'] # In[41]: df['centroids_lon'] = [g.centroid.coords.xy[0][0] for g in df.geometry] df['centroids_lat'] = [g.centroid.coords.xy[1][0] for g in df.geometry] # In[42]: df # Let's filter the map items based on the centroid coordinates. # In[46]: metropolitan_france = (df.centroids_lat > 40) & (df.centroids_lon > -10) df[metropolitan_france].plot() # Nice! Let's try to do the same thing using bokeh! What we need is a way to extract the polygon coordinates from the geopandas dataframe and plot them using Bokeh. # In[65]: s = df[metropolitan_france].geometry # In[79]: from ipywidgets import interact from IPython.display import display @interact def disp_geom(ind=(0, s.shape[0] - 1)): display(s.iloc[ind]) print(s.iloc[ind].type) # In[80]: o = s.iloc[43] # In[81]: o # Reading the [shapely documentation](http://toblerity.org/shapely/manual.html#polygons), I found out that the coordinates of a polygon can be accessed in the following way: # In[84]: len(o.geoms) # In[82]: plt.plot(o.exterior.coords.xy[0], o.exterior.coords.xy[1]) # In[87]: plt.plot(o.convex_hull.exterior.coords.xy[0], o.convex_hull.exterior.coords.xy[1]) # We are now set: let's build a Bokeh figure using this! # In[95]: import numpy as np # In[97]: dept_xs = [np.array(row.convex_hull.exterior.coords.xy[0]) for row in df[metropolitan_france].geometry] dept_ys = [np.array(row.convex_hull.exterior.coords.xy[1]) for row in df[metropolitan_france].geometry] # In[98]: p = figure(title="France map from geojson data", toolbar_location="left", plot_width=1100, plot_height=700) p.patches(dept_xs, dept_ys, fill_color="#F1EEF6", fill_alpha=0.7, line_color="white", line_width=0.5) show(p) # In[ ]: