germain.vallverdu@gmail.com
¶This notebook shows how to build a choropleth plot using geopandas in order to read a shapefile and bokeh in order to draw the choropleth plot.
U.S. states and councils are available from core packages of bokeh. In the case of France you have to download the data from a government website. In this example, I used the data from IGN website. I downloaded only metropolitan france departments.
The main strategy is the following :
import used pacakges :
import pandas as pd
import geopandas as gpd
from bokeh.io import show, output_notebook
from bokeh.plotting import figure
import bokeh.models as bm
import bokeh.palettes
# set up bokeh for jupyter notebook
output_notebook()
First, read the data from a csv file. Here I did the following :
df = pd.read_csv("membres_par_pays_dep.csv", sep=";")
df = df[df["Pays"] == "FR"]
df.rename(columns={df.columns[2]: "Departement"}, inplace=True)
df.index = df.Departement.apply(lambda x: "%02d" % x)
df.index.name = "CODE_DEPT"
df.head()
Nombre de membres | Pays | Departement | |
---|---|---|---|
CODE_DEPT | |||
01 | 8 | FR | 1.0 |
02 | 1 | FR | 2.0 |
03 | 1 | FR | 3.0 |
04 | 3 | FR | 4.0 |
05 | 1 | FR | 5.0 |
Now we read a shape file and set up the same index with the department number.
The last column of a GeoDataFrame
is a geometry object, here a polygon.
gdf = gpd.GeoDataFrame.from_file("DEPARTEMENT/DEPARTEMENT.shp")
gdf = gdf[["CODE_DEPT", "NOM_CHF", "NOM_DEPT", "geometry"]]
gdf.set_index("CODE_DEPT", inplace=True)
gdf.sort_index(inplace=True)
gdf.head()
NOM_CHF | NOM_DEPT | geometry | |
---|---|---|---|
CODE_DEPT | |||
01 | BOURG-EN-BRESSE | AIN | POLYGON ((838243.5999999591 6564210.300001801,... |
02 | LAON | AISNE | POLYGON ((708718.999999999 6956305.000000671, ... |
03 | MOULINS | ALLIER | POLYGON ((664479.2000000098 6602292.300001685,... |
04 | DIGNE-LES-BAINS | ALPES-DE-HAUTE-PROVENCE | POLYGON ((910437.2999999194 6342569.70000242, ... |
05 | GAP | HAUTES-ALPES | POLYGON ((933489.9999999163 6411083.800002239,... |
Now we merge the data frames. As they have the same index, you only need to call the join
method.
We only keep the column with the number of members and set NaN
values to zero.
gdf2 = gdf.join(df["Nombre de membres"])
gdf2.rename(columns={"Nombre de membres": "membres"}, inplace=True)
gdf2.fillna(value=0., inplace=True)
gdf2.head()
NOM_CHF | NOM_DEPT | geometry | membres | |
---|---|---|---|---|
CODE_DEPT | ||||
01 | BOURG-EN-BRESSE | AIN | POLYGON ((838243.5999999591 6564210.300001801,... | 8.0 |
02 | LAON | AISNE | POLYGON ((708718.999999999 6956305.000000671, ... | 1.0 |
03 | MOULINS | ALLIER | POLYGON ((664479.2000000098 6602292.300001685,... | 1.0 |
04 | DIGNE-LES-BAINS | ALPES-DE-HAUTE-PROVENCE | POLYGON ((910437.2999999194 6342569.70000242, ... | 3.0 |
05 | GAP | HAUTES-ALPES | POLYGON ((933489.9999999163 6411083.800002239,... | 1.0 |
First we convert the GeoDataFrame
in a GeoJSONDataSource
bokeh model.
geo_src = bm.GeoJSONDataSource(geojson=gdf2.to_json())
Now we set up a show the plot.
# set up a log colormap
cmap = bm.LogColorMapper(
palette=bokeh.palettes.BuGn9[::-1], # reverse the palette
low=0,
high=gdf2.membres.max()
)
# define web tools
TOOLS = "pan,wheel_zoom,box_zoom,reset,hover,save"
# set up bokeh figure
p = figure(
title="Membres de l'AFPY en 2016",
tools=TOOLS,
toolbar_location="below",
x_axis_location=None,
y_axis_location=None,
width=500,
height=500
)
# remove the grid
p.grid.grid_line_color = None
# core part !
# * add a patch for each polygon in the geo data frame
# * fill color from column 'membres' using the color map defined above
p.patches(
'xs', 'ys',
fill_alpha=0.7,
fill_color={'field': 'membres', 'transform': cmap},
line_color='black',
line_width=0.5,
source=geo_src
)
# set up mouse hover informations
hover = p.select_one(bm.HoverTool)
hover.point_policy = 'follow_mouse'
hover.tooltips = [
('Département:', '@NOM_DEPT'),
("Membres:", "@membres"),
("Contact:", "??"),
("Afpyro:", "True/False")
]
# add a color bar
color_bar = bm.ColorBar(
color_mapper=cmap,
ticker=bm.LogTicker(),
title_text_align="left",
location=(0, 0),
border_line_color=None,
title="Membres"
)
p.add_layout(color_bar, 'right')
# show plot
show(p)
from bokeh.plotting import output_file
output_file("afpy_france.html")