如何使用Bokeh在Google地图上绘制大规模经纬度点位?
900万量级经纬度点位Google地图绘制方案
你当前使用的Bokeh直接绘制散点的逻辑,会把全量点位坐标全部序列化后传到前端渲染层,每个点位都是独立的渲染单元,内存、渲染开销随点位数量线性上涨,超过10万点就很容易触发Jupyter内核/浏览器内存溢出冻结,靠调整现有代码参数无法解决这个量级的渲染问题,可行方案如下:
- 方案1:后端栅格化渲染(性能最高,适配千万级以上点位)
不要把单点传到前端,直接在Python后端把全量点位渲染成和画布尺寸一致的栅格图层,再叠加到Google地图上,渲染开销只和画布分辨率有关,和点位总量无关,1亿级点位也能流畅运行。
先安装依赖:pip install datashader bokeh pandas
参考实现代码:
import datashader as ds
import pandas as pd
from bokeh.models import GMapOptions
from bokeh.io import show, export_png
from bokeh.plotting import gmap
import bokeh
基础配置
bokeh_width, bokeh_height = 1200, 900
api_key = "替换为你的Google地图API密钥"
替换为你的900万点位DataFrame,需包含lat、lon两个数值列
point_df = smr_lat_lon
def plot_mass_points(center_lat, center_lng, zoom=10, map_type='roadmap'):
gmap_options = GMapOptions(lat=center_lat, lng=center_lng, map_type=map_type, zoom=zoom)
p = gmap(api_key, gmap_options, title='大规模点位分布图', width=bokeh_width, height=bokeh_height)
# 后端聚合渲染全量点位 canvas = ds.Canvas(plot_width=bokeh_width, plot_height=bokeh_height) agg_result = canvas.points(point_df, x='lon', y='lat') # 生成红色半透明点图层 point_layer = ds.tf.shade(agg_result, cmap=["#ff0000"], alpha=180) # 将渲染好的栅格图层叠加到地图 p.image_rgba( image=[ds.tf.to_rgba(point_layer)], x=p.x_range.start, y=p.y_range.start, dw=p.x_range.end - p.x_range.start, dh=p.y_range.end - p.y_range.start ) show(p) export_png(p, filename="mass_point_map.png") return p
p = plot_mass_points(lat, lon, zoom=10)
如果需要缩放、平移交互,只需要给地图绑定视口变化回调,每次操作后重新渲染对应视口范围的栅格图层即可,响应速度和原生Google地图无明显差异。 - **方案2:视口抽稀加载(需要单点交互场景用)** 如果需要点击查看单点属性、做单点筛选这类交互,不要一次性加载全量点: 1. 用Rtree库给全量点位构建空间索引 2. 初始加载时只查询当前地图视口范围内的点位,按当前缩放等级的像素分辨率做抽稀:同一像素位置存在多个点时仅保留1个,保证前端同时渲染的点量始终在5万阈值以内 3. 绑定地图的平移、缩放事件,视口变化时重新查询、抽稀点位,更新ColumnDataSource的数据源即可 - **方案3:纯静态出图(无交互需求用)** 如果不需要交互操作,仅需要导出带点位的地图图片,完全跳过前端渲染流程:先下载对应范围、缩放等级的Google地图静态底图,再用Matplotlib/Pillow在后端把全量点位直接绘制到底图上导出即可,全程不会触发前端内存溢出。 > 注意:不要尝试直接把900万点位传入ColumnDataSource,仅全量数据的JSON序列化过程就会占用数GB内存,必然触发Jupyter/浏览器冻结,没有参数调优空间。 内容的提问来源于stack exchange,提问作者AM8564
相关产品推荐
相关产品推荐

