【问题标题】:3g coverage map - visualise lat, long, ping data3g 覆盖图 - 可视化纬度、经度、ping 数据
【发布时间】:2012-03-01 14:00:38
【问题描述】:

假设我一直在使用笔记本电脑上的 3g 调制解调器和 GPS 驾驶设定的路线,而我在家里的电脑记录了 ping 延迟。我已将 ping 与 GPS 纬度/经度相关联,现在我想可视化这些数据。

我每天有大约 80,000 个数据点,我想展示几个月的数据。我对显示 ping 始终超时的区域(即 ping == 1000)特别感兴趣。

散点图

我的第一次尝试是使用散点图,每个数据输入一个点。如果超时,我将点的大小放大 5 倍,因此这些区域的位置很明显。我还将 alpha 降低到 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)

来自this example

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

如果我在一条大曲线上行驶,它会在之间的区域内插值(见下文):

在不均匀的网格上插值

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

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


我的要求:

  • 处理大型数据集(80,000 x 60 = ~5m 点)
  • 通过平均(我假设插值会这样做)或通过为每个点取最小值来显示每个点的重复数据。
  • 不要从数据点推断太远

我对散点图(顶部)很满意,但我需要一些方法在显示之前对数据进行平均。

(对于不可靠的 mspaint 图纸,我无法上传实际数据表示歉意)


解决方案:

# 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)

【问题讨论】:

  • 我建议对数据进行聚类,即组合一定距离内的点并在散点图中显示它们的平均值/最小值。话虽如此,我对python中的集群算法了解不多,但我相信你可以很容易地在google上找到一些想法。

标签: python numpy matplotlib scipy interpolation


【解决方案1】:

GDAL 库包括Python API 和相关实用程序,尤其是gdal_grid 应该适合您。它包括许多用于从散点生成网格数据的插值和平均方法和选项。您应该能够操纵网格单元大小以获得令人满意的分辨率。

GDAL 可以处理多种数据格式,但您应该能够将坐标和 ping 值作为 CSV 传递并轻松返回 PNG 或 JPEG。

请记住,纬度/经度数据不是平面坐标系。如果您打算将结果与其他地图数据结合起来,您必须弄清楚要使用的地图投影、单位等。

【讨论】:

    【解决方案2】:

    为了简化您的问题,您有两组点,一组用于 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) 是 ping1000 的点

    您可以使用 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()
    

    输出图为:

    【讨论】:

    • 感谢您的出色回答,np.histogram2d 非常有帮助。你能想出一种方法来轻松地让尺寸/颜色代表当时的平均/最小 ping 值,而不是计数吗?
    • 要计算平均值,您可以调用 np.histogram2d 并使用 weights = pings,这将汇总正方形区域中的所有 ping。然后将结果除以计数。
    • 感谢@HYRY,我已将您的答案标记为已接受,并将最终使用的解决方案添加到我的问题末尾。
    猜你喜欢
    • 1970-01-01
    • 2014-08-15
    • 1970-01-01
    • 1970-01-01
    • 2013-09-09
    • 2020-09-29
    • 1970-01-01
    • 2012-08-22
    • 1970-01-01
    相关资源
    最近更新 更多