1. 程式人生 > 程式設計 >Python如何使用bokeh包和geojson資料繪製地圖

Python如何使用bokeh包和geojson資料繪製地圖

最近要繪製倫敦區地圖,查閱了很多資料後最終選擇使用bokeh包以及倫敦區的geojson資料繪製。
bokeh是基於python的繪圖工具,可以繪製各種型別的圖表,支援geojson資料的讀取及繪製地圖。

安裝bokeh

$ pip install bokeh

軟體版本

python-3.7.7bokeh-2.0.0

資料來源

倫敦地圖資料來源於Highmaps地圖資料集。下載的是英國的地圖資料united-kindom.geo.json。需要對得到的資料進行預處理才能得到只含倫敦地區的資料。這需要對geojson資料的格式有一定的瞭解。在對資料進行處理之前,先看如何繪製英國地圖。

繪製英國地圖

from bokeh.plotting import curdoc,figure
from bokeh.models import GeoJSONDataSource

# 讀入英國地圖資料並傳給GeoJSONDataSource
with open("united-kindom.geo.json",encoding="utf8") as f:
  geo_source = GeoJSONDataSource(geojson=f.read())
# 設定一張畫布
p = figure(width=500,height=500)
# 使用patches函式以及geo_source繪製地圖
p.patches(xs='xs',ys='ys',source=geo_source)

curdoc().add_root(p)

上述程式碼可以繪製出英國地圖。將上述程式碼儲存為test.py,在終端執行

$ bokeh serve --show test.py

這會自動開啟瀏覽器,並顯示英國地圖。
執行結果如圖:

Python如何使用bokeh包和geojson資料繪製地圖

獲取倫敦地區資料

獲取倫敦地區資料可以手動從united-kingdom.geo.json檔案中篩選出倫敦的資料,也可以先用python先把資料過濾一遍,然後將資料傳給bokeh。這需要對geojson檔案格式有一定的瞭解,在此不詳細介紹。

from bokeh.plotting import curdoc,figure
from bokeh.models import GeoJSONDataSource
import json

# 用json庫讀取資料
with open("united-kindom.geo.json",encoding="utf8") as f:
  data = json.loads(f.read())
# 判斷是不是倫敦地區資料
def isInLondon(district):
  if 'type' in district['properties'] and 'london borough' in district['properties']['type'].lower():
    return True
  if 'type-en' in district['properties'] and 'london borough' in district['properties']['type'].lower():
    return True
  if 'woe-name' in district['properties'] and 'city of london' in district['properties']['woe-name'].lower():
    return True
  return False
# 過濾資料
data['features'] = list(filter(isInLondon,data['features']))
#
geo_source = GeoJSONDataSource(geojson=json.dumps(data))
p = figure(width=500,height=500)
p.patches(xs='xs',source=geo_source)

curdoc().add_root(p)

執行結果如圖:

Python如何使用bokeh包和geojson資料繪製地圖

美化

上面的倫敦地圖只是一個大概的輪廓,下面對地圖新增一系列功能。

新增各區輪廓線

p.patches(xs='xs',fill_alpha=0.7,# 畫輪廓線
    line_color='white',# 線的顏色
    line_width=0.5,# 線的寬度
    source=geo_source)

現在地圖區域輪廓很清晰。

新增顏色

# 為每一個地區增加一個color屬性
for i in range(len(data['features'])):
  data['features'][i]['properties']['color'] = ['blue','red','yellow','orange','gray','purple'][i % 6]
p.patches(xs='xs',line_color='white',line_width=0.5,color="color",# 增加顏色屬性,這裡的"color"對應每個地區的color屬性
    source=geo_source)

現在地圖五顏六色。

增加圖注

import random
# 隨機產生資料用於展示
for i in range(len(data['features'])):
  data['features'][i]['properties']['number'] = random.randint(0,20_000)
p = figure(width=500,height=500,tooltips="@name,number: @number" # 使用tooltips生成圖注,@+屬性名稱,這裡的name是資料中原本有的,number是新近新增的。
  )

現在滑鼠放到區域上時,會顯示"區域名,number: 數字"。

去掉座標軸與背景線

p.axis.axis_label = None
p.axis.visible = False
p.grid.grid_line_color = None

最終程式碼

from bokeh.plotting import curdoc,figure
from bokeh.models import GeoJSONDataSource
import json
import random
with open("united-kindom.geo.json",encoding="utf8") as f:
  data = json.loads(f.read())

def isInLondon(district):
  if 'type' in district['properties'] and 'london borough' in district['properties']['type'].lower():
    return True
  if 'type-en' in district['properties'] and 'london borough' in district['properties']['type'].lower():
    return True
  if 'woe-name' in district['properties'] and 'city of london' in district['properties']['woe-name'].lower():
    return True
  return False

data['features'] = list(filter(isInLondon,data['features']))
for i in range(len(data['features'])):
  data['features'][i]['properties']['color'] = ['blue','purple'][i % 6]
  data['features'][i]['properties']['number'] = random.randint(0,20_000)

geo_source = GeoJSONDataSource(geojson=json.dumps(data))
p = figure(width=500,number: @number")
p.patches(xs='xs',source=geo_source)

p.axis.axis_label = None
p.axis.visible = False
p.grid.grid_line_color = None

curdoc().add_root(p)

倫敦地圖完成了

Python如何使用bokeh包和geojson資料繪製地圖

總結

最開始想用pyecharts做的,但是pyecharts並沒有倫敦的地圖。折騰半天,最後只好自己找geojson資料來畫地圖。

找到了很多關於地圖的資料和工具,比如上文中提到的highmap資料集,以及DataV.altas,這個工具可以視覺化地提取中國區域的地圖資料,但感覺比起自己找資料,畫中國地圖還是pyecharts來得實在。

資料最重要。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。