3G覆盖地图 - 可视化经纬度、延迟数据

4 投票
2 回答
804 浏览
提问于 2025-04-17 12:38

假设我在用笔记本电脑的3G调制解调器和GPS开车沿着一条固定路线行驶,同时我在家里的电脑上记录网络延迟(ping)。我把延迟和GPS的经纬度数据关联起来,现在我想把这些数据可视化。

我每天大约有80,000个数据点,想要展示几个月的数据。我特别想显示那些网络延迟经常超时的区域(也就是ping值等于1000的地方)。

散点图

我第一次尝试用散点图来展示,每个数据点对应一个点。如果是超时的数据点,我把它的大小放大了5倍,这样就能很明显地看到这些区域。我还把透明度调到0.1,这样可以粗略地看到重叠的点。

# Colour
c = pings 
# Size
s = [2 if ping < 1000 else 10 for ping in pings]
# Scatter plot
plt.scatter(longs, lats, s=s, marker='o', c=c, cmap=cm.jet, edgecolors='none', alpha=0.1)

散点图

这个方法明显的问题是,每个数据点都显示一个标记,这对于展示大量数据来说效果很差。如果我经过同一个地方两次,第一次的数据就会覆盖在第二次的数据上。

在均匀网格上插值

接着我尝试用numpy和scipy在均匀网格上进行插值。

# Convert python list to np arrays
x = np.array(longs, dtype=float)
y = np.array(lats, dtype=float)
z = np.array(pings, dtype=float)

# Make even grid (200 rows/cols)
xi = np.linspace(min(longs), max(longs), 200)
yi = np.linspace(min(lats), max(lats), 200)

# Interpolate data points to grid
zi = griddata((x, y), z, (xi[None,:], yi[:,None]), method='linear', fill_value=0)

# Plot contour map
plt.contour(xi,yi,zi,15,linewidths=0.5,colors='k')
plt.contourf(xi,yi,zi,15,cmap=plt.cm.jet)

参考这个例子

这个看起来很有趣(有很多颜色和形状),但在我没有探索的区域插值太远了。你看不到我走过的路线,只能看到红色和蓝色的斑点。

如果我开车走了一个大弯,它会在两个点之间进行插值(见下图):

插值问题

在不均匀网格上插值

然后我尝试用meshgrid(xi, yi = np.meshgrid(lats, longs))而不是固定网格,但有人告诉我我的数组太大了。

有没有简单的方法可以从我的数据点创建一个网格?


我的需求:

  • 处理大数据集(80,000 x 60 = 大约500万点)
  • 对每个点显示重复数据,可以通过平均值(我想插值会做到这一点)或取每个点的最小值来实现。
  • 不要在数据点之外插值太远

我对散点图(上面)很满意,但我需要某种方法在展示之前对数据进行平均处理。

(抱歉,我的画图技术不太好,无法上传实际数据)


解决方案:

# Get sum
hsum, long_range, lat_range = np.histogram2d(longs, lats, bins=(res_long,res_lat), range=((a,b),(c,d)), weights=pings)
# Get count
hcount, ignore1, ignore2 = np.histogram2d(longs, lats, bins=(res_long,res_lat), range=((a,b),(c,d)))
# Get average
h = hsum/hcount
x, y = np.where(h)
average = h[x, y]
# Make scatter plot
scatterplot = ax.scatter(long_range[x], lat_range[y], s=3, c=average, linewidths=0, cmap="jet", vmin=0, vmax=1000)

2 个回答

1

GDAL库,包括GDALPython接口和相关工具,特别是gdal_grid,应该能满足你的需求。这个工具提供了多种插值和平均的方法,可以用来从散乱的点生成网格数据。你可以调整网格单元的大小,以获得理想的分辨率。

GDAL支持多种数据格式,你可以把你的坐标和数据以CSV格式传入,然后轻松得到PNG或JPEG格式的输出。

要注意的是,纬度和经度数据并不是平面坐标系统。如果你打算把结果和其他地图数据结合使用,你需要弄清楚应该使用什么样的地图投影、单位等。

2

为了简化你的问题,你有两组点,一组是ping小于1000的点,另一组是ping大于等于1000的点。因为点的数量非常多,所以你不能直接用scatter()来绘制它们。我通过以下方式创建了一些示例数据:

longs = (np.random.rand(60, 1) + np.linspace(-np.pi, np.pi, 80000)).reshape(-1)
lats = np.sin(longs) + np.random.rand(len(longs)) * 0.1

bad_index = (longs>0) & (longs<1)
bad_longs = longs[bad_index]
bad_lats = lats[bad_index]

(longs, lats)是ping小于1000的点,(bad_longs, bad_lats)是ping大于等于1000的点。

你可以使用numpy.histogram2d()来统计这些点的数量:

ranges = [[np.min(lats), np.max(lats)], [np.min(longs), np.max(longs)]]
h, lat_range, long_range = np.histogram2d(lats, longs, bins=(400,400), range=ranges)
bad_h, lat_range2, long_range2 = np.histogram2d(bad_lats, bad_longs, bins=(400,400), range=ranges)

h和bad_h是每个小方块区域内的点的数量。

然后你可以选择很多方法来可视化这些数据。例如,你可以用scatter()来绘制:

y, x = np.where(h)
count = h[y, x]
pl.scatter(long_range[x], lat_range[y], s=count/20, c=count, linewidths=0, cmap="Blues")

count = bad_h[y, x]
pl.scatter(long_range2[x], lat_range2[y], s=count/20, c=count, linewidths=0, cmap="Reds")

pl.show() 

这里是完整的代码:

import numpy as np
import pylab as pl

longs = (np.random.rand(60, 1) + np.linspace(-np.pi, np.pi, 80000)).reshape(-1)
lats = np.sin(longs) + np.random.rand(len(longs)) * 0.1

bad_index = (longs>0) & (longs<1)
bad_longs = longs[bad_index]
bad_lats = lats[bad_index]

ranges = [[np.min(lats), np.max(lats)], [np.min(longs), np.max(longs)]]
h, lat_range, long_range = np.histogram2d(lats, longs, bins=(300,300), range=ranges)
bad_h, lat_range2, long_range2 = np.histogram2d(bad_lats, bad_longs, bins=(300,300), range=ranges)

y, x = np.where(h)
count = h[y, x]
pl.scatter(long_range[x], lat_range[y], s=count/20, c=count, linewidths=0, cmap="Blues")

count = bad_h[y, x]
pl.scatter(long_range2[x], lat_range2[y], s=count/20, c=count, linewidths=0, cmap="Reds")

pl.show()

输出的图形是:

enter image description here

撰写回答