为数百万个点生成热图层
Generating heatmap layer for milions of points
我正在使用 Google 地图中的热图图层来显示热图,但是,我现在有太多点并且它停止工作,因为浏览器无法再处理它。我发现他们提供了 Fusion Tables,但也有限制:最多 10 万行,这太少了。我需要渲染数百万甚至更多点的热图。如果我的服务器可以有一些 PHP 脚本来渲染热图,我会很完美,例如,每天一次。然后来自 js 的客户端将只下载预加载的热图(在地图上像 google 地图,但也可能是不同的地图)。这是否可以通过某些现有技术(可以商业化)实现?
我使用 heatmap.js 进行可视化。它真的很快,可以处理很多点。不确定 150 万点是否有效。
我能想到的是使用 Javascript 解决方案之一和 node.js 进行预渲染。快速 google 搜索 'heatmap js nodejs prerender' 找到了这个
https://github.com/substack/node-heatmap and this https://mango-is.com/blog/engineering/pre-render-d3-js-charts-at-server-side/
您只需要将您的点预先聚类为较少数量的点,然后将这些组传递给 Google 地图,就好像它们是您的原始点一样。因此,如果您有 3 个附近的点,其值为 3、5 和 10,您将在其坐标的加权平均值处创建一个值为 18 的点。对所有数据集执行此操作,您将减少 3 倍。将 3 更改为任何适当的值以进一步减少您的数据集。
对数据进行聚类的简单方法是使用地理哈希[1]。这是 PHP[2] 的不错的地理哈希库。您可以在添加时为每个点计算一组不同精度的 geohashes,然后使用所需的精度使用简单的 GROUP BY
来减少您的数据集。示例(元):
use Lvht\GeoHash;
class DataPoint extends ActiveRecord {
public geo_hash_precision4, geo_hash_precision5, geo_hash_precision6;
public function save() {
$this->geo_hash_precision4 = GeoHash::encode($this->lat,$this->lon, 0.0001);
$this->geo_hash_precision5 = GeoHash::encode($this->lat,$this->lon, 0.00001);
$this->geo_hash_precision6 = GeoHash::encode($this->lat,$this->lon, 0.000001);
parent::save();
}
}
class DataSet extends ActiveQuery {
/**
* @param int $p Desired precision
*/
public function getValues($p = 6) {
$data = $this->rawQuery("SELECT geo_hash_precision{$p}, SUM(value) FROM {$this->table} GROUP BY geo_hash_precision{$p}");
// Add bounding box WHERE to reduce set for map size
foreach ($data as $row) {
list($minLon, $maxLon, $minLat, $maxLat) = GeoHash::decode($row["geo_hash_precision{$p}"]);
$row['lat'] = ($maxLat - $minLat) / 2;
$row['lon'] = ($maxLon - $minLon) / 2;
unset($row["geo_hash_precision{$p}"]);
}
}
}
我正在使用 Google 地图中的热图图层来显示热图,但是,我现在有太多点并且它停止工作,因为浏览器无法再处理它。我发现他们提供了 Fusion Tables,但也有限制:最多 10 万行,这太少了。我需要渲染数百万甚至更多点的热图。如果我的服务器可以有一些 PHP 脚本来渲染热图,我会很完美,例如,每天一次。然后来自 js 的客户端将只下载预加载的热图(在地图上像 google 地图,但也可能是不同的地图)。这是否可以通过某些现有技术(可以商业化)实现?
我使用 heatmap.js 进行可视化。它真的很快,可以处理很多点。不确定 150 万点是否有效。
我能想到的是使用 Javascript 解决方案之一和 node.js 进行预渲染。快速 google 搜索 'heatmap js nodejs prerender' 找到了这个 https://github.com/substack/node-heatmap and this https://mango-is.com/blog/engineering/pre-render-d3-js-charts-at-server-side/
您只需要将您的点预先聚类为较少数量的点,然后将这些组传递给 Google 地图,就好像它们是您的原始点一样。因此,如果您有 3 个附近的点,其值为 3、5 和 10,您将在其坐标的加权平均值处创建一个值为 18 的点。对所有数据集执行此操作,您将减少 3 倍。将 3 更改为任何适当的值以进一步减少您的数据集。
对数据进行聚类的简单方法是使用地理哈希[1]。这是 PHP[2] 的不错的地理哈希库。您可以在添加时为每个点计算一组不同精度的 geohashes,然后使用所需的精度使用简单的 GROUP BY
来减少您的数据集。示例(元):
use Lvht\GeoHash;
class DataPoint extends ActiveRecord {
public geo_hash_precision4, geo_hash_precision5, geo_hash_precision6;
public function save() {
$this->geo_hash_precision4 = GeoHash::encode($this->lat,$this->lon, 0.0001);
$this->geo_hash_precision5 = GeoHash::encode($this->lat,$this->lon, 0.00001);
$this->geo_hash_precision6 = GeoHash::encode($this->lat,$this->lon, 0.000001);
parent::save();
}
}
class DataSet extends ActiveQuery {
/**
* @param int $p Desired precision
*/
public function getValues($p = 6) {
$data = $this->rawQuery("SELECT geo_hash_precision{$p}, SUM(value) FROM {$this->table} GROUP BY geo_hash_precision{$p}");
// Add bounding box WHERE to reduce set for map size
foreach ($data as $row) {
list($minLon, $maxLon, $minLat, $maxLat) = GeoHash::decode($row["geo_hash_precision{$p}"]);
$row['lat'] = ($maxLat - $minLat) / 2;
$row['lon'] = ($maxLon - $minLon) / 2;
unset($row["geo_hash_precision{$p}"]);
}
}
}