如何用 PYTHON 绘制漂亮的地图?— FOLIUM 作图工具介绍
Folium 简介
作为 Python 的一个可视化工具包 Folium,它通过 Leaflet 的地图服务,可以在 Jupyter Notebook 上实现可视化的地理位置作图,制作各种各样精美的地图信息。它不仅可以针对某个经纬度进行地理位置的可视化操作,还能够根据实时的人群地理位置信息来构建静态与动态热力图,甚至还能够针对经纬度的数量来进行必要的聚类可视化。本文将会基于新加坡的地图,对 Folium 的一些功能做简要的介绍,对此工具有兴趣的读者可以参阅 Folium 的官方文档。
创建地图
通过 Folium 工具,可以直接作出一张世界地图,其代码也十分地简洁明了。
import folium
%matplotlib inline
import webbrowser
print(folium.__version__)
# define the world map
world_map = folium.Map()
# display world map
world_map
除了能够作出一张完整的世界地图之外,通常程序员最常见的需求是针对某个或者某一些经纬度,来作出一张局部地图。地图中不仅需要包括经纬度信息,也需要有街道信息等必要的内容,甚至需要对经纬度的标记做一些必要的定制化工作。
在初始化一张地图的时候,需要指定它的经纬度信息,也就是 location 的位置。也需要根据需要放大的尺寸来指定相应的 zoom_start 值。另外,tiles 是 str 型,用于控制绘图调用的地图样式,默认为'OpenStreetMap',也有一些其他的内建地图样式,如'Stamen Terrain','Stamen Toner'。
有的时候需要在地图上标识出相应的经纬度,此时需要使用 folium.Marker 函数。其使用方法就是直接输入相应的经纬度信息,以及 icon 的形状(例如 'cloud', 'info-sign' 等);除此之外,还可以对其颜色进行标记,一般是对参数 color 进行调整即可。
另外,在某些经纬度上,还可以使用“点击-弹出“的控件 tooltip 和 popup,一旦鼠标指向该位置,就会呈现出相应的弹出信息。
# latitude and longitude in Singapore city
coordinate_sentosa = [1.248946, 103.834306]
coordinate_orchard_road = [1.304247, 103.833264]
coordinate_changi_airport = [1.357557, 103.98847]
coordinate_nus = [1.296202,103.776899]
coordinate_ntu = [1.34841, 103.682933]
coordinate_zoo = [1.403717, 103.793974]
coordinate_ang_mo_kio = [1.37008, 103.849523]
coordinate_yi_shun = [1.429384, 103.835028]
# icon
icon_cloud = "cloud"
icon_sign = "info-sign"
# define the city map
# tiles in {'OpenStreetMap', 'Stamen Terrain', 'Stamen Toner', 'Mapbox Bright'}
city_map = folium.Map(
location=coordinate_orchard_road,
zoom_start=11,
tiles='OpenStreetMap')
# add marker in the city map
folium.Marker(
coordinate_sentosa,
icon=folium.Icon(color='blue')
).add_to(city_map)
folium.Marker(
coordinate_orchard_road,
icon=folium.Icon(color='green', icon=icon_cloud)
).add_to(city_map)
# add popup
folium.Marker(
coordinate_changi_airport,
popup='Changi Airport',
icon=folium.Icon(color='red', icon=icon_sign)
).add_to(city_map)
# add tooltips and popup
tooltip = "Click me!"
folium.Marker(
coordinate_nus,
popup="<i>National University of Singapore</i>",
tooltip=tooltip
).add_to(city_map)
folium.Marker(
coordinate_ntu,
popup="<b>Nanyang Technological University</b>",
tooltip=tooltip
).add_to(city_map)
# display city map
city_map
有的时候,我们只知道某个地点,但是并不知道相应的经纬度数据,此时,只需要使用 folium.LatLngPopup() 就可以在鼠标指向位置上呈现相应的经纬度值,可以方便的查阅和使用。
# define the city map
city_map = folium.Map(location=coordinate_orchard_road, zoom_start=11)
# 在地图中添加经纬度, add latitude and longitude in the map when click
city_map.add_child(folium.LatLngPopup())
city_map
几何形状
在作出关键的经纬度点之后,有的时候我们需要作出相应的几何图形将其显示得更加清楚。Folium 提供线段相连,多边形,圆形,矩形等诸多图形,只需要使用相应的函数即可。
# define the city map
city_map = folium.Map(location=coordinate_orchard_road, zoom_start=11)
# 在地图中如何添加形状
# 多条边
points_1 = [
coordinate_ntu,
coordinate_nus,
coordinate_zoo
# 在 city_map 中添加多条边,第一种添加方式
city_map.add_child(folium.PolyLine(
locations=points_1, # 坐标列表
weight=3, # 线条宽度
color='gray'))
# 在 city_map 中添加多条边,第二种添加方式
folium.PolyLine(
locations=points_1, # 坐标列表
weight=3, # 线条宽度
color='gray').add_to(city_map)
# 多边形
points_2 = [
coordinate_orchard_road,
coordinate_sentosa,
coordinate_changi_airport
city_map.add_child(folium.Polygon(
locations=points_2, # 坐标列表
weight=3, # 线条宽度
color='yellow'))
bounds = [
coordinate_ang_mo_kio,
coordinate_yi_shun
city_map.add_child(folium.Rectangle(
bounds=bounds, # 坐标列表, Latitude and Longitude of line (Northing, Easting)
weight=2, # 线条宽度
color='blue'))
# 圆形, circle, radius units meters
folium.Circle(
radius=1000,
location=coordinate_nus,
popup="National University of Singapore",
color="crimson",
fill=False,
).add_to(city_map)
# 圆形, circle, radius units pixels
folium.CircleMarker(
location=coordinate_ntu,
radius=30,
popup="Nanyang Technological University",
color="#3186cc",
fill=True,
fill_opacity=0.3, # 透明度
fill_color="#3186cc",
).add_to(city_map)
city_map
热力图
在实际使用经纬度信息的时候,通常来说会针对某个 APP 或者多款 APP 的实时经纬度信息来获取路况的拥挤程度,景区的人流量等信息,在这种情况下,就可以做出热力图。通过实时的热力图信息,我们可以获得相应的人流量信息进行必要的数据分析工作。
import numpy as np
from folium.plugins import HeatMap
# define the city map
city_map = folium.Map(location=coordinate_orchard_road, zoom_start=11)
# 构建随机数据
data = (
np.random.normal(
size=(10, 3)) * 0.03 * np.array([[1, 1, 1]]) +
np.array([[coordinate_orchard_road[0], coordinate_orchard_road[1], 1]])
).tolist()
city_map.add_child(HeatMap(data=data))
city_map
除了单张图的热力图之外,Folium 还能够计算一段时间的连续热力图信息。
import numpy as np
from folium.plugins import HeatMapWithTime
# define the city map
city_map = folium.Map(location=coordinate_orchard_road, zoom_start=11)
# 使用 numpy 建立初始数据
initial_data = (np.random.normal(size=(200, 2)) *
np.array([[0.02, 0.02]]) +
np.array([coordinate_orchard_road]))
# 建立连续的数据
data = [initial_data.tolist()]
for i in range(20):
data.append((data[i] + np.random.normal(size=(200, 2)) * 0.001).tolist())
# 显示连续的热力图
city_map.add_child(HeatMapWithTime(data))
city_map
经纬度点的聚类
除了热力图能反映人流量的信息,基于地理位置的聚类算法同样能够反映一个地区的拥挤程度,Folium 的 MarkerCluster() 函数可以对一个区域中的点来做聚类,在地图中可以放大和缩小,从而知道局部最拥挤的点在哪里了,最稀疏的区域是哪里。
from folium.plugins import MarkerCluster
# define the city map
city_map = folium.Map(location=coordinate_orchard_road, zoom_start=11)
# 经纬度的聚类
# 在 NUS 的经纬度附近随机生成 100 个点;
data = (
np.random.normal(size=(100, 2))
* np.array([[0.001, 0.001]]) +
np.array([coordinate_nus]))
# create a mark cluster object
marker_cluster = MarkerCluster().add_to(city_map)
# 将这些经纬度数据加入聚类
for element in data:
folium.Marker(location=[element[0], element[1]],icon=None).add_to(marker_cluster)