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
,并且那里已经为你提供了求和的例子,你应该拥有你所需要的一切。
我正在开发一个使用 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
,并且那里已经为你提供了求和的例子,你应该拥有你所需要的一切。