Cartographie intéractive avec Bokeh

Visualiser mes 4 ans de missions dans le conseil

Détails des missions réalisés chez Horwath HTL

Tutorial

import pandas as pd
import numpy as np

from bokeh.plotting import figure
from bokeh.tile_providers import get_provider, Vendors
from bokeh.transform import factor_cmap
from bokeh.models.tools import WheelZoomTool
from bokeh.models import ColumnDataSource
from bokeh.io import show

Introductrion

Bokeh est une librairie de visualisation interactive pour python très puissante. La majorité des types de visualisation de données auquel ont peu penser peut se faire avec Bokeh. Ce tutorial explique comme réaliser une carte interactive avec affichage d’information au passage de la souris.

Les données

Pour réaliser la carte, on utilise un dataframe issu d’un fichier csv. Il contient les coordonnées GPS des points que l’on souhaite afficher d’autres attributs (du texte ici).

df_mission = pd.read_csv("missionsHTL.csv", sep=';', decimal=',')
df_mission.drop(columns=['type_business','année','loc_codegeo','loc_cp','pays'], inplace = True)
df.head()

type_etudenomclientlatitudelongitude
0Etude stratégiqueEtude sur les opportunités di'nvestissement to...BATIPART47.10239111.290570
1Etude stratégiqueAssistance pour le projet de mise en concessio...BOAD6.1356696.135669
2Audit de Société et potentiel de développementExpertise de la société API&YOUBPI France46.8378215.709352
3Audit de Société et potentiel de développementExpertise de la société LoungeUpBPI France48.8804102.350979
4Audit de Société et potentiel de développementAnalyse du marché des solutions de conciergeri...BPI France48.8792122.352816

La carte

Choisir le CRS (coordinate reference system)

Le système de coordonnées des données est le WGS 84. Il s’agit du référentiel standard que l’on retrouve sur service de cartographie en ligne.

Les fonds de cartes utilisés par Bokeh utilisent la projection Mercator. Il faut donc modifier le csr avant de faire la carte. On utilise la projection suivante:

k = 6378137
df_mission["x"] = df_mission['longitude'] * (k * np.pi / 180.0)
df_mission["y"] = np.log(np.tan((90 + df_mission['latitude']) * np.pi / 360.0)) * k

Chargement du fond de carte : Bokeh propose plusieurs types de fond de cartes, disponibles ici

tile_provider = get_provider(Vendors.CARTODBPOSITRON)

L’affichage intéractif est activé pour les colonnes ‘Client’ et ‘Missions’

TOOLTIPS = [
    ('Client', '@client'),
    ('Mission', '@name')]

Bokeh permet d’utiliser de nombreux outils pour les figures, par défaut la plupart sont présents, pour notre carte on choisit d’utiliser les suivants uniquement:

tools = "pan,wheel_zoom,box_zoom,reset"

Création de la figure

p = figure(x_range=(-2000000, 6000000), y_range=(-1000000, 7000000),
           x_axis_type="mercator", y_axis_type="mercator",
           tooltips=TOOLTIPS,
           tools=tools,
           plot_width=800,
           plot_height=600
           )

p.add_tile(tile_provider)
TileRenderer(
id = '1042', …)

Afficher les points

Chaque ligne des données représente une mission, on souhaite afficher de la même couleur les missions qui ont le même type. Pour cela on filtre les données et utilise la fonction scatter plusieurs fois, pour chaque type de missions

La couleur des points en fonction du type de mission est définie grâce à factor_cmap et à la palette de couleur ‘Category10’

cat_unique = df_mission['type_etude'].unique()
for cat in cat_unique:

    df_mission_f = df_mission[df_mission['type_etude']==cat]

    geo_source = ColumnDataSource(data={
        'cat': df_mission_f['type_etude'],
        'name': df_mission_f['nom'],
        'client': df_mission_f['client'],
        'lat': df_mission_f['y'],
        'long': df_mission_f['x']
    })
    
    p.scatter(x='long', y='lat', size=12, alpha=0.5, source=geo_source,
                  color=factor_cmap('cat', 'Category10_6', df_mission['type_etude'].unique()),
                  legend_group='cat')

Parametrer le rendu de la figure

Cosmétique pour masquer l’affichage des axes dont on ne se sert pas.

p.legend.click_policy = "hide" permet de rendre la légende interactive et de masquer les missions par types.

p.toolbar.active_scroll = p.select_one(WheelZoomTool) permet d’activer la fonction de zoom avec la souris.

p.xgrid.grid_line_color = None
p.ygrid.grid_line_color = None
p.xaxis.major_label_text_color = None
p.yaxis.major_label_text_color = None
p.xaxis.major_tick_line_color = None  
p.xaxis.minor_tick_line_color = None  
p.yaxis.major_tick_line_color = None  
p.yaxis.minor_tick_line_color = None  
p.yaxis.axis_line_color = None
p.xaxis.axis_line_color = None
p.legend.label_text_font_size = "9pt"
p.legend.click_policy = "hide" 
p.toolbar.active_scroll = p.select_one(WheelZoomTool)
show(p) #afficher la carte

Enregistrer le HTML de la carte

from bokeh.plotting import  output_file, save
output_file('carte_bokeh.html')
save(p)

Sur le même sujet