器→工具, 开源项目, 数据, 术→技巧

Folium绘制Choropleth分级着色图

钱魏Way · · 5,852 次浏览

上一篇Folium的文章中,针对Choropleth的使用有过简单的介绍,但是对于如何调整分级样式图等,没有进一步的阐述。这篇文章结果自己的使用经验做些简单的总结。

生成Choropleth分级着色图的方法目前主要有两种,一种是使用folium.Choropleth(),另外一种是使用folium.GeoJson()。接下来详细讲解两种方式的不同。

folium.Choropleth()

这个类可以将GeoJSON的图形覆盖到地图上。如果不绑定数据则显示单色的地图,如果绑定数据则通过值得大小显示不同颜色。具体使用方法:

class folium.features.Choropleth(geo_data, data=None, columns=None, key_on=None, bins=6, fill_color=None, nan_fill_color='black', fill_opacity=0.6, nan_fill_opacity=None, line_color='black', line_weight=1, line_opacity=1, name=None, legend_name='', overlay=True, control=True, show=True, topojson=None, smooth_factor=None, highlight=None, **kwargs)

参数说明:

  • geo_data:指定GeoJSON,可以是JsonURL、file path或其他类型 (json、dict、geopandas等)的GeoJSON几何数据
  • data:需要绑定的GeoJSON的数据,默认为空。传入的数据可以是Pandas DataFrame或Series,具体Series没有使用过,拆测如果传Series需要将index设置为匹配项。
  • columns:当数据传入的时Pandas DataFrame设定想要的值,第一列需要与GeoJSON匹配的列,第二列为具体的值
  • key_on:GeoJSON中需要绑定的列,默认为空。格式中需要以feature对象开头,如id或 feature.properties.statename
  • bins:设定对值要划分的数量,默认为6,如果传入的是数值,则传入数字时,会使用data中的最大值和最小值进行平均划分。如果传入的是一个序列,则会按序列定义边界。同时也可以传入字符串,可传入的字符串可以从histogram的文档中找到。
  • fill_color:区域需要填充的颜色,默认为blue,可以传入16进制的颜色代码或颜色名称,如果绑定了数据,则可以传入“颜色地图”,比如:‘BuGn’, ‘BuPu’, ‘GnBu’, ‘OrRd’, ‘PuBu’, ‘PuBuGn’, ‘PuRd’, ‘RdPu’, ‘YlGn’, ‘YlGnBu’, ‘YlOrBr’, and ‘YlOrRd’.
  • nan_fill_color:NaN区域填充的颜色,默认为’black’,即GeoJSON中没有匹配到的图形填充的颜色。
  • fill_opacity :填充颜色的透明度,默认为6,可选值为0-1
  • nan_fill_opacity:NaN区域填充颜色透明度,默认取fill_opacity的值。
  • line_color:区域边框颜色,默认为’black’
  • line_weight:区域边框款对,默认为1
  • line_opacity:区域边框透明度,默认为1
  • legend_name:图例标识名称
  • topojson:除了GeoJson外,同时也支持TopoJSON格式的的边界数据。 (string, default None) – If using a TopoJSON, passing “objects.yourfeature” to the topojson keyword argument will enable conversion to GeoJSON. TopoJSONs can be passed as “geo_data”, but the “topojson” keyword must also be passed with the reference to the topojson objects to convert. See the topojson.feature method in the TopoJSON API reference: https://github.com/topojson/topojson/wiki/API-Reference
  • smooth_factor:平滑因子,主要为了简化每个缩放级别的折线。数值越大表示越平滑,同时性能也更好,数值越小说明越精确,Leaflet中的默认值为0
  • highlight:当鼠标悬停在区域上时是否要突出显示,默认为False
  • name:层的名字,可选。如果设置了可以在LayerControls中出现。
  • overlay:添加层的设置,默认为True(覆盖层),如果传False则为基础层。
  • control:是否将图层包含到LayerControls中,默认为True
  • show:是否在地图打开时就显示层,默认为True

示例代码:

import folium
import pandas as pd

geo_json_data = "data/china_city.json"
df = pd.read_excel("data/orders.xlsx")

m = folium.Map(location=[32, 120], zoom_start=5)
folium.Choropleth(
    geo_data=geo_json_data,
    data=df,
    columns=["cityname", "order_count"],
    key_on="feature.properties.name",
    fill_color="BuPu",
    fill_opacity=0.7,
    line_opacity=0.2,
    legend_name="Order Count",
).add_to(m)

中间折腾的过程(个人实践):

1、生成城市级别的GeoJSON文件

国内的GeoJSON数据时我从阿里的DataV.GeoAtlas上抓取下来的,国家文件内包含了省份,省份文件下包含了城市。如果要在国家下直接包含城市,则需要自己处理数据:

import json
import glob

file_path = r'geojson_city\*.json'
file_list = glob.glob(file_path)
features = []
for file_name in file_list:
    with open(file_name, 'r') as f:
        data = json.load(f)
        for feature in data['features']:
            features.append(feature)
china = {'type': 'FeatureCollection', 'features': features}

with open('china_city.json', 'w') as fp:
    json.dump(china, fp)

2、城市名称的匹配

在使用过程中遇到的第二个问题是,公司数据库中的城市名称与GeoJSON中的城市名是不匹配的,有些带“市”,有些“不带”。另外还包含县级市即直辖市等问题。解决方案是人工进行匹配。具体以GeoJSON中的城市名为准:

with open('china_city.json', 'r') as f:
    data = json.load(f)
    for feature in data['features']:
        print(feature['properties']['name'])

3、对GeoJSON中的区域边界数据进行简化

默认情况下,从阿里抓取过来的GeoJSON的精度非常的的细,实际使用过程中造成绘制图形时非常的慢,且实际使用时并不需要这么详细。解决方案:使用https://mapshaper.org/ 进行抽稀。如下图将18994个线段抽稀到5%(1318个线段)视觉上没有什么区别。

4、填充颜色的选择

文档说颜色是由color brewer(http://colorbrewer2.org/ )顺序调色板生成的。 默认情况下,在值的最小值和最大值之间使用线性划分。

正确传达信息的一个关键点是为您的设计选择一个合适的配色方案。 配色方案主要有三种类型: (1)顺序配色,(2)发散配色,(3)定性配色。

  • 顺序的颜色方案按照从低到高的逻辑顺序排列,非常适合表示不包含临界中点或有序类别数据(低/中/高)的数值数据

  • 发散的颜色方案突出显示高于或低于一个有趣的中点值(例如平均值)的值。 发散格式用于可以有意义地用中点进行划分的数据

  • 定性配色方案用于名义范畴数据(即数据没有固有的顺序)。 类别之间的差异以不同的色调表现出来,明度和饱和度是相似的

ColorBrewer提供的Color Groups:

  • sequential
    • multihue
      • YlGn
      • YlGnBu
      • GnBu
      • BuGn
      • PuBuGn
      • PuBu
      • BuPu
      • RdPu
      • PuRd
      • OrRd
      • YlOrRd
      • YlOrBr
    • singlehue
      • Purples
      • Blues
      • Greens
      • Oranges
      • Reds
      • Greys
    • diverging
      • PuOr
      • BrBG
      • PRGn
      • PiYG
      • RdBu
      • RdGy
      • RdYlBu
      • Spectral
      • RdYlGn
    • qualitative
      • Pastel1
      • Pastel2
      • Dark2
      • Accent
      • Paired
      • Set1
      • Set2
      • Set3

具体颜色代表的如下:

folium.GeoJson()

folium.GeoJson()类相对来所较为底层,可以在定义更多的样式,但操作更麻烦些。

class folium.features.GeoJson(data, style_function=None, highlight_function=None, name=None, overlay=True, control=True, show=True, smooth_factor=None, tooltip=None, embed=True, popup=None)

参数说明:

  • data:GeoJSON数据
  • style_function:样式函数
  • highlight_function:高亮函数
  • name:层的名称
  • overlay:同上
  • control:同上
  • show:同上
  • smooth_factor:同上
  • tooltip:在地图上显示tooltip,更多详情可以看GeoJsonTooltip
  • embed:是否将数据嵌入到html文件中,默认为True

使用示例:

import json
import folium
import pandas as pd
from branca.colormap import linear

with open("china_city.json") as f:
    geo_json_data = json.load(f)
df = pd.read_excel("data/orders.xlsx")

colormap = linear.RdYlGn_09.scale(df["order_number"].min(), df["order_number"].max())
incr_dict = df.set_index("cityname")["order_number"]

m = folium.Map(location=[32, 120], zoom_start=5)
folium.GeoJson(
    geo_json_data,
    style_function=lambda feature: {
        "fillColor": colormap(incr_dict.get(feature["properties"]["name"], 0)),
        "color": colormap(incr_dict.get(feature["properties"]["name"], 0)),
        "weight": 2,
        "fill_opacity": 0.7,
        "line_opacity": 0.2,
    },
).add_to(m)

参考链接:

One Reply to “Folium绘制Choropleth分级着色图”

  1. 你好,请问下使用folium.Choropleth 办法能做到类似folium.GeoJson 中 tooltip 的功能吗

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注