You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Bokeh中为Tile Provider使用额外坐标轴(extra_x_ranges/extra_y_ranges)以直接显示EPSG:4326坐标的地图

刚好遇到过类似的问题,我来帮你梳理清楚问题所在,以及可行的解决方案:

问题分析:为什么你的原始代码没显示地图?

你尝试用额外坐标轴兼容EPSG:4326和EPSG:3857的思路方向没错,但忽略了一个核心点:Web墨卡托(EPSG:3857)是投影坐标,和经纬度(EPSG:4326)之间是非线性的映射关系,不是简单的线性坐标轴能模拟的。

你的代码里用LinearAxis创建额外的3857坐标轴,本质上是把3857坐标当成了线性数值,这和瓦片服务要求的投影坐标系不匹配,所以瓦片无法正确渲染。另外,Bokeh的Tile Provider必须在EPSG:3857的坐标空间下才能正常显示,这是所有主流在线瓦片服务的标准要求。

可行解决方案

不需要手动转换你的经纬度数据,我们可以让Bokeh自动处理坐标转换,同时在图表上显示经纬度刻度。下面是两种实用的方法:

方法一:用GeoAxis显示经纬度刻度,底层用Web墨卡托坐标

这种方法的核心是让figure的底层坐标为EPSG:3857,同时替换默认坐标轴为GeoAxis,让它显示经纬度刻度。你绘制数据时只需要传入经纬度,Bokeh会自动帮你转换为3857坐标:

from bokeh.plotting import figure, show
from bokeh.tile_providers import CARTODBPOSITRON, get_provider
from bokeh.models import GeoAxis, MercatorTickFormatter, MercatorTicker

# 获取瓦片服务
tile_provider = get_provider(CARTODBPOSITRON)

# 创建figure,设置底层为Web墨卡托坐标范围(覆盖全球)
p = figure(
    x_range=(-20026376.39, 20026376.39),
    y_range=(-20048966.10, 20048966.10),
    x_axis_type="mercator",
    y_axis_type="mercator"
)

# 添加瓦片背景
p.add_tile(tile_provider)

# 替换坐标轴为显示经纬度的GeoAxis
p.xaxis = GeoAxis(ticker=MercatorTicker(), formatter=MercatorTickFormatter())
p.yaxis = GeoAxis(ticker=MercatorTicker(), formatter=MercatorTickFormatter())

# 直接用经纬度绘制数据,Bokeh自动转换坐标
# 示例:绘制北京的坐标(116.4, 39.9)
p.circle(x=116.4, y=39.9, size=12, color="crimson", transform=p.xaxis_transform)

show(p)

方法二:用GeoJSONDataSource加载经纬度数据

如果你的数据是GeoJSON格式(EPSG:4326),可以直接用GeoJSONDataSource,它会自动处理坐标转换,非常适合批量地理数据:

from bokeh.plotting import figure, show
from bokeh.tile_providers import CARTODBPOSITRON, get_provider
from bokeh.models import GeoJSONDataSource, GeoAxis, MercatorTickFormatter, MercatorTicker

tile_provider = get_provider(CARTODBPOSITRON)

# 创建Web墨卡托坐标的figure
p = figure(
    x_range=(-20026376.39, 20026376.39),
    y_range=(-20048966.10, 20048966.10),
    x_axis_type="mercator",
    y_axis_type="mercator"
)
p.add_tile(tile_provider)

# 示例EPSG:4326的GeoJSON数据
geo_data = {
    "type": "FeatureCollection",
    "features": [
        {"type": "Feature", "geometry": {"type": "Point", "coordinates": [116.4, 39.9]}},
        {"type": "Feature", "geometry": {"type": "Point", "coordinates": [121.5, 31.2]}}
    ]
}

# 加载GeoJSON数据,自动转换坐标
source = GeoJSONDataSource(geojson=geo_data)
p.circle(x='x', y='y', size=12, color="navy", source=source)

# 添加经纬度刻度坐标轴
p.xaxis = GeoAxis(ticker=MercatorTicker(), formatter=MercatorTickFormatter())
p.yaxis = GeoAxis(ticker=MercatorTicker(), formatter=MercatorTickFormatter())

show(p)

这两种方法都不需要你手动转换数据坐标,既满足了显示经纬度刻度的需求,又能正常加载瓦片地图背景。

内容的提问来源于stack exchange,提问作者CodePrinz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 19:42:35