Mapbox clusterProperties 计算点 属性 值的 'average'

Mapbox clusterProperties calculate 'average' of point property value

我正在开发一个使用 Mapbox GL JS 的应用程序,我在其中显示了一个热图图层,其中包含数据驱动 'heatmap-weight' 属性(基于我的 GeoJSON 中的自定义数值属性数据 - 'detections').

因为我数据中的许多点彼此非常接近甚至重叠,它们的 'detections' 值通常计算相同的检测结果,从而使热图着色比应有的更重,因此我尝试对它们进行聚类并在 'clusterProperties' 对象内添加一个新的 'average'(平均值)属性,然后使用它来插入聚类点的热图权重。

我一直在研究有关使用表达式的 mapbox 文档和示例,实现属性似乎相当简单(例如本例中的 'sum':https://docs.mapbox.com/mapbox-gl-js/style-spec/sources/#geojson-clusterProperties),但我无法做到想出一个工作表达式来计算我需要的'average'。

基本上我试图得到我的 'detections' 属性 的 'sum',并将它除以集群的 'point_count' 属性,所以我第一次尝试:

map.addSource(detections_heatmap_src, {
    type: "geojson",
    data: heatmapCloud_value.recordings,
    cluster: true,
    clusterRadius: 10, // Radius of each cluster when clustering points (defaults to 50)
    clusterProperties: {
        clusterTotal: ["+", ["get", "detections"]], //used for debug output  text layer
        average: [
                    "let",
                    "total",
                    ["+", ["to-number", ["get", "detections"]]],
                    ["/", ["number", ["var", "total"], 0], ["number", ["get", "point_count"], 1]],
        ]
    },
});

但是这种方法总是抛出以下错误,我无法理解/修复:

Error: sources.detections_heatmap_src.average.reduce: Expected at least 3 arguments, but found 2 instead.
at Object.ai [as emitValidationErrors] (mapbox-gl.js:31)
at Oe (mapbox-gl.js:35)
at je._validate (mapbox-gl.js:35)
at je.addSource (mapbox-gl.js:35)
at Map.addSource (mapbox-gl.js:35)
at addHeatmapLayer (Map.svelte:516)

我也试过另一种比较简单的方法,像这样:

(...)
clusterProperties: {
    (...)
    average: [
        "/",
        ["number", ["+", ["to-number", ["get", "detections"]]]],
        ["number", ["get", "point_count"], 1],
    ],
}

我没有得到任何错误,在某些情况下它甚至似乎计算出正确的值(例如 9/9 = 1),但对于大多数其他情况它计算的值完全错误,比如155 / 92 = 0.004408...,应该是 1.6847... 或 154 / 106 = 0.46875 而不是 1.4528...

我正在检查/调试这些值,方法是添加一个文本层以将它们输出到地图上(附上示例屏幕截图),如下所示:

map.addLayer({
    id: detections_heatmap_clusterCount,
    type: "symbol",
    source: detections_heatmap_src,
    filter: ["has", "point_count"],
    layout: {
    "text-field": [
            "concat",
            ["get", "clusterTotal"],
            "/",
            ["get", "point_count"],
            " = ",
            ["get", "average"],
        ],
        "text-font": ["DIN Offc Pro Medium", "Arial Unicode MS Bold"],
        "text-size": 12,
        "text-allow-overlap": true,
    },
    paint: {
        "text-color": "#EE4B2B",
    },
});

bad-at-math

看起来用这些表达式计算平均值应该是可行的,但我无法理解我尝试过的任何一个表达式到底有什么问题,所以我希望这里有人能够帮我解决这个问题。


更新:

根据@steve-bennet 的建议/接受的答案,我只添加 'clusterTotal'(总和)作为一个集群 属性,像这样:

map.addSource(detections_heatmap_src, {
    type: "geojson",
    data: heatmapCloud_value.recordings,
    cluster: true,
    clusterRadius: 10, // Radius of each cluster when clustering points (defaults to 50)
    clusterProperties: {
        clusterTotal: ["+", ["get", "detections"]],
    },
});

然后计算我实际需要使用它的平均值 (sum/count),在我的例子中,对于热图权重 属性,这意味着从这里开始:

  "heatmap-weight": [
    "interpolate",
    ["linear"],
    ["get", "detections"],
    0, 0,
    6, 1,
    18, 5
  ],

为此:

"heatmap-weight": [
    "case",
    ["has", "point_count"],
    [
        "interpolate",
        ["linear"],
        ["/", ["number", ["get", "clusterTotal"]], ["number", ["get", "point_count"]]],
        0,
        0,
        6,
        1,
        18,
        5
    ],
    ["interpolate", ["linear"], ["get", "detections"], 0, 0, 6, 1, 18, 5]
],

Mapbox 文档在这里非常简洁。

An object defining custom properties on the generated clusters if clustering is enabled, aggregating values from clustered points. Has the form {"property_name": [operator, map_expression]}. operator is any expression function that accepts at least 2 operands (e.g. "+" or "max") — it accumulates the property value from clusters/points the cluster contains; map_expression produces the value of a single point.

Example: {"sum": ["+", ["get", "scalerank"]]}.

您的第一个问题是您需要在 MapReduce 范式中编写您的表达式 - 这就是他们所指的 map_expression。运算符实际上是 reduce 表达式:将 map_expression 应用于两个不同输入值的结果组合起来的东西。

第二个问题是,将平均函数写成 map/reduce 表达式实际上并不那么容易。求和很简单:只需继续添加下一个值即可。但是平均函数需要跟踪事物的总数,以及 运行 总和。

我的建议可能是创建两个单独的集群属性,一个用于总和,一个用于计数,并在您使用表达式时计算平均值 (sum/count),而不是在聚类。

既然已经为你提供了point_count,并且那里已经为你提供了求和的例子,你应该拥有你所需要的一切。