如何用Seaborn绘制带真实RSSI值色条的静态地图插值热力图?
实现带真实RSSI值色条的插值RSSI热力图
问题背景
我尝试用Python和Seaborn在静态地图上绘制RSSI(接收信号强度指示)点值的插值热力图,数据导出为CSV,还有对应的shape文件。当前代码用weights=gdf['rssi']生成的热力图视觉效果符合预期,但色条显示的是KDE权重计算结果,不是真实的RSSI值(范围-55至-145);换成hue=gdf['rssi']后色条数值正确,但无法生成插值热力图。需要实现带真实RSSI值色条的插值热力图。
原代码:
import requests as r import io import matplotlib.pyplot as plt import pandas as pd import geopandas as gpd import seaborn as sns import tilemapbase as tm df=pd.read_csv('rangemap.csv') gdf = gpd.GeoDataFrame(df, geometry = gpd.points_from_xy(df['lon'], df['lat']), crs = 'EPSG:4326') gdf = gdf.to_crs("EPSG:3857") vlk = gpd.read_file("Valkeakoski.shp") vlk = vlk.to_crs("EPSG:3857") tm.init(create=True) extent = tm.extent_from_frame(vlk) fig, ax = plt.subplots(figsize=(12,10),layout="constrained") ax.xaxis.set_visible(False) ax.yaxis.set_visible(False) plotter = tm.Plotter(extent, tm.tiles.build_OSM(), width=1000) plotter.plot(ax) sns.kdeplot(data=gdf,x=gdf['geometry'].x,y=gdf['geometry'].y,fill=True,cmap='turbo',alpha=0.3,levels=20,weights=gdf['rssi'],cbar=True,ax=ax,zorder=3) vlk.plot(color=(1,1,1,0),edgecolor="black",linewidth=0.5,ax=ax)
解决方案
Seaborn的kdeplot本质是核密度估计,用weights参数只会改变密度分布的权重,不会直接插值出真实的RSSI值。要实现真实RSSI值的插值热力图,需要用空间插值方法(如线性插值、最近邻或径向基函数),将离散的RSSI点值插值到连续网格上,再绘制热力图。
修改后的代码
import matplotlib.pyplot as plt import pandas as pd import geopandas as gpd import tilemapbase as tm import numpy as np from scipy.interpolate import griddata # 读取并处理数据 df = pd.read_csv('rangemap.csv') gdf = gpd.GeoDataFrame(df, geometry=gpd.points_from_xy(df['lon'], df['lat']), crs='EPSG:4326') gdf = gdf.to_crs("EPSG:3857") vlk = gpd.read_file("Valkeakoski.shp") vlk = vlk.to_crs("EPSG:3857") # 初始化地图 tm.init(create=True) extent = tm.extent_from_frame(vlk) fig, ax = plt.subplots(figsize=(12,10), layout="constrained") ax.xaxis.set_visible(False) ax.yaxis.set_visible(False) plotter = tm.Plotter(extent, tm.tiles.build_OSM(), width=1000) plotter.plot(ax) # 提取坐标和RSSI值 x = gdf['geometry'].x.values y = gdf['geometry'].y.values rssi = gdf['rssi'].values # 创建覆盖地图范围的网格 xi = np.linspace(x.min(), x.max(), 500) yi = np.linspace(y.min(), y.max(), 500) xi, yi = np.meshgrid(xi, yi) # 执行插值(可选方法:'linear'/'nearest'/'cubic') zi = griddata((x, y), rssi, (xi, yi), method='linear') # 绘制插值热力图 contour = ax.contourf(xi, yi, zi, levels=20, cmap='turbo', alpha=0.3, zorder=3) # 添加色条,设置范围为真实RSSI区间 cbar = plt.colorbar(contour, ax=ax) cbar.set_label('RSSI (dBm)') cbar.set_ticks(np.arange(-145, -54, 10)) # 匹配原始RSSI范围 # 叠加边界 vlk.plot(color=(1,1,1,0), edgecolor="black", linewidth=0.5, ax=ax) plt.show()
关键说明
- 空间插值:使用
scipy.interpolate.griddata将离散点的RSSI值插值到规则网格上,三种常用插值方法可选:nearest:最近邻插值,速度快但边缘不光滑linear:线性插值,平衡光滑度与计算量cubic:三次插值,最光滑但计算量大,可能出现异常值
- 色条校准:通过
cbar.set_ticks手动设置色条刻度,完全匹配原始RSSI的区间(-145至-55),确保色条显示真实数值 - 图层顺序:用
zorder参数保证热力图在地图上方、边界图层在最上层,避免遮挡
这样生成的热力图既能呈现插值后的信号分布,色条也会准确显示真实的RSSI值。
内容的提问来源于stack exchange,提问作者Stefan Gofferje
相关产品推荐
相关产品推荐

