基于平均权重而不是数据点数量的热图

Posted

技术标签:

【中文标题】基于平均权重而不是数据点数量的热图【英文标题】:Heatmap based on average weights and not on the number of data points 【发布时间】:2013-01-05 21:12:53 【问题描述】:

我正在使用 Google API v3 制作热图。我举个例子。让我们考虑地震震级。我为每个点分配权重以指定它们的大小。但是,当您缩小时,谷歌会考虑点的密度。一个地方的点越多,它就越红。例如,如果两次地震发生在相距数英里的范围内,一次为 3 级,另一次为 8 级,则第一个应该是绿色/蓝色,第二个应该是红色。但是一旦你缩小并且这两个点在地图上越来越近,谷歌地图会考虑点的数量而不是权重,因此,它会显示为已读。我希望它是平均值,即 (3+8)/2=5.5...无论代表什么颜色。这可能吗?

【问题讨论】:

【参考方案1】:

您可以通过在地图顶部叠加热图图像来做到这一点。 https://github.com/jeffkaufman/apartment_prices 有一个非常好的开源示例

【讨论】:

【参考方案2】:

此示例使用热图作为地图上的图层,希望对您有所帮助:http://maps.forum.nu/v3/gm_customTiles.html

【讨论】:

链接已损坏。知道在哪里可以找到有效的吗? 也许这可以帮助developers.google.com/maps/documentation/javascript/… 虽然谷歌对热图有很好的实现,但遗憾的是,当颜色重叠时(例如,当绿色重叠时,它们没有(据我所知不能)做出“权重平均值”另一个绿色,使用谷歌地图将导致黄色(总和)而不是绿色(平均))。 经验教训,将相关代码片段保存在答案中:) 抱歉 2013 年的链接断开,不是【参考方案3】:

根据定义,热图会考虑点密度以及分配给每个点的权重。据我所知,至少谷歌的热图是这样工作的。 因此,您实际需要的不是热图,而是根据值对它们进行着色的点图。

我还需要更改 Google 热图考虑的比率密度/重量,以便为地图着色,但我没有找到任何方法。 目前热图的主要因素是密度,权重的变化对颜色的影响很小。

【讨论】:

【参考方案4】:

作为部分解决方案,我从以下项目修改了 heatmap.js: https://github.com/pa7/heatmap.js

为了获得单个 long/lat 点的平均值,我修改了 _organiseData 函数来存储每个 x,y 位置的 PointCount 和 PointSum;有了这些值,我得到了一个点的平均值:

存储[x][y] = storePointSum[x][y] / storePointCount[x][y];

当多个 x,y 坐标以不同的地图分辨率堆叠时,我仍在研究如何修改“混合”...如果我弄清楚了,我会发布它。

干杯

~亚伦

【讨论】:

*** 更新 *** 使用的“附加 alpha 混合”似乎是由 html 规范定义(和控制)的,这从根本上决定了在这个特殊的热度中绘制的颜色map ——可能还有其他大多数,因为它的高性能特性。不幸的是,我还没有找到一种方法来进行“平均渐变 alpha 混合”;上下文设置 globalCompositeOperation 似乎很有希望,但它似乎只支持传统的混合。如果有人想进一步探索,观察者的两个关键函数是 _drawAlpha 和 _getPointTemplate。【参考方案5】:

如果您像我一样没有处理时间或能力来生成叠加层并且您无法根据自己的喜好修改任何现有库,那么有一个不错的解决方法。

我使用了谷歌地图热图库并将 maxIntensity 和 dissipating 设置为 false。将 maxIntensity 设置为您选择的值将解决您的热图点相对于彼此着色而不是 0 或设定值的问题。将消散设置为 false 将禁用更改缩放级别时发生的自动半径设置。

接下来,每当缩放级别发生变化时,我都会创建一个事件,在该事件中,我将半径设置为一个值,该值似乎以最准确的方式代表该缩放级别的数据。

现在,为了解决地图上的数据点混合并添加到一个大红色斑点中的问题,我决定在我的地图上为我想要使用的每个缩放级别制作一个单独的网格。我对同一网格点内的所有值进行平均,并确保网格足够大以防止热图点重叠,但又足够小以至于看起来不像一堆圆圈。 (我发现网格应该是地图上热点半径大小的 0.4 倍,以获得平滑的外观)。

热图点的半径由 google 设置,以像素为单位。我不知道如何将像素转换为纬度/经度,所以我只是通过在具有一定半径的圆上画线来测量它,并测量这些线之间的距离。如果您不打算绘制比一个小国家更多的地图,那么这种转换方法将非常有效。

就性能而言,这并没有我想象的那么糟糕。我正在加载大约 2300 个点,并且地图的加载速度与我为每个缩放级别制作网格之前一样快,并且当您更改缩放级别时,您实际上并没有看到数据点正在刷新。

以下是上述所有内容的一些代码:

地图设置:

map.heatmap.set('maxIntensity', 12000);
map.heatmap.set('dissipating', false);

更改每个缩放级别的网格和半径:

map._on(
    obj: map.gMap,
    event: "zoom_changed",
    callback: function()
        var zoomLevel = map.zoom();
        switch(zoomLevel)
            case 7:
                map.heatmap.setData(gridData[zoomLevel]);
                map.heatmap.set('radius', 0.04);
                break;
            case 8:
                map.heatmap.setData(gridData[zoomLevel]);
                map.heatmap.set('radius', 0.03);
                break;
            case 9:
                map.heatmap.setData(gridData[zoomLevel]);
                map.heatmap.set('radius', 0.02);
                break;
            case 10:
                map.heatmap.setData(gridData[zoomLevel]);
                map.heatmap.set('radius', 0.01);
                break;
            case 11:
                map.heatmap.setData(gridData[zoomLevel]);
                map.heatmap.set('radius', 0.005);
                break;
            case 12:
                map.heatmap.setData(gridData[zoomLevel]);
                map.heatmap.set('radius', 0.0025);
                break;
            case 13:
                map.heatmap.setData(gridData[zoomLevel]);
                map.heatmap.set('radius', 0.00225);
                break;
            default:
                map.heatmap.setData(gridData[zoomLevel]);
                map.heatmap.set('radius', 0.000625);
        
    
);

我的网格是用 php 生成的,可能每个人看起来都不一样,但作为一个例子,这是我使用的函数:

function getHeatGrid($gridSize)
$mapGrid = false;
$mapData = false;
$radius = $gridSize * 2.8 * 0.3; //grid size is multiplied by 2.8 to convert from the heat map radius to lat/long values(works for my lat/long, maybe not yours). * 0.3 is arbitrary to avoid seeing the grid on the map.
$string = file_get_contents("mapData.json");
$json_a = json_decode($string, true);

forEach($json_a as $key => $value)
    $row = intval(round(($value['center_longitude'] / $radius)));
    $column = intval(round(($value['center_latitude'] / $radius)/68*111)); //around 52.0;5.0 latitude needs to be scaled to make a square grid with the used longitude grid size
    if(isset($mapGrid[$row][$column]))
        $mapGrid[$row][$column] = round(($value['solarValue'] + $mapGrid[$row][$column]) / 2);
     else 
        $mapGrid[$row][$column] = $value['solarValue'];
    


forEach($mapGrid as $long => $array)
    forEach($array as $lat => $weight)
        $mapData[] = array(
            "center_longitude" => $long * $radius,
            "center_latitude" => ($lat * $radius)/111*68,
            "solarValue" => $weight
        );
    

return $mapData;

很遗憾,我现在无法显示该地图,因为它目前对我工作的公司的客户保密,但如果它公开可用,我将添加一个链接,以便您了解这种方法的效果如何。

希望这对某人有所帮助。

卢卡斯

【讨论】:

以上是关于基于平均权重而不是数据点数量的热图的主要内容,如果未能解决你的问题,请参考以下文章

在R中创建连续热图

ggplot中带有圆圈而不是瓷砖的热图

在热图中重用颜色键

基于运输时间的热图/轮廓(反向等时轮廓)

更改绘图热图中的颜色条标签 (R)

在 D3.js 中绘制 17K x 1K 数据点的热图的建议