以下是一些假设:
- 渐变 colorMapSize 为 1000(默认),但应设置为 500
- 颜色值长度为 6
- startPoints 长度为 6(必须与颜色长度相同)
- 颜色数组在OP中指定
- 起始点数组应为 { 0.1F, 0.2F, 0.3F, 0.4F, 0.6F, 1.0F }
这是一个有助于讨论的图表:
ColorMap
首先要了解的是 colorMap。这是由
渐变生成器。它是一个“int”数组,默认大小为 1000,但
在其中一个构造函数中可自定义 - 在您的示例中推荐 500。所以这个数组中的每个值都是一个颜色值。 (大小会影响渐变的分辨率。)
colorMap 中的颜色值受 2 个产生颜色的控件影响
间隔:startPoints 数组和颜色数组。在你的例子中有
是 6 个颜色间隔。
颜色间隔定义为起始颜色和结束颜色以及数量
范围内的“colorMap”插槽。任何给定间隔的所有 colorMap 值
使用该范围的开始/结束颜色进行插值。
如果 startPoints 数组的第一个值为 0,则第一个颜色间隔
假设为实心 - 非零意味着从透明到第一种颜色的过渡,这似乎是最理想的。 (参见 startPoints 设置为 0 的示例,并注意外部区域的锯齿状。)
如果 startPoints 数组的第一个值不为 0,则为第一个颜色
间隔定义为从第一种颜色 (colors[0]) 和一个范围开始
colorMapSize * 第一个起点,例如500 * 0.1 = 50
并以相同的颜色结束。
对于所有剩余的定义颜色,会生成一个间隔 - 再次使用
起始 colorMap 插槽,起始颜色(即前一个颜色结束),
结束颜色(表中的当前颜色)和范围。
如果最后一个起始点不是1.0,则使用最后一个颜色作为开始
并停止。在此示例中,1.0 可能是最好的。
(不透明度适用于整个图层,并且仅影响颜色的 Alpha 通道。)
Tiles
这就是“强度”被重视的地方,也是 WeightedLatLng 可以发挥作用的地方。
生成地图时,它将可视区域划分为图块 -
瓦片的数量是缩放级别的函数。在缩放级别 0 处有 1 个图块,
任意缩放级别图块计数为 2^n(其中 n 是缩放级别)。
每个图块进一步分为多个桶。桶的数量是一个函数
缩放级别和半径(模糊)。每个桶对应一个地理区域
瓷砖内的面积 -认为矩形网格.
当前图块内的点是从数据集中获取的。
对于图块地理边界内的所有点,该点的强度值被添加到其相应的存储桶中。默认情况下,点的强度值为 1。WeightedLatLng 允许您通过将该值从 1 更改为某个数字(较大以增加重要性,较小以降低重要性)来偏置点。因此,结果是桶强度计数受到仅 LatLngs 的影响。
一旦对强度桶进行计数,强度值就会使用以下方法进行着色
第一节中确定的 colorMap。请注意,强度值的范围会缩放为 colorMap 的大小,以便最大强度值映射到最后一种颜色。
然后将桶应用到图块并将图块制作成位图
并被渲染。
Example
例如,我使用了萨克拉门托的一些犯罪数据。我首先创建了一个非加权热图。然后创建一个加权热图,通过将 NCIC 代码为 2404(车辆盗窃)的犯罪强度指定为 5.0(相对于任何点的默认值 1.0)来强调汽车盗窃的重要性。 5.0 有点随意,实际上取决于数据和您想要传达的内容。
非加权/加权(车辆盗窃)
还有一个示例,其中第一个 startPoint[0] 为 0.0 - 这表明缺乏从透明到初始颜色的过渡:
以下是 MapActivity 的相关部分:
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
mMap.getUiSettings().setZoomControlsEnabled(true);
// Add a marker in Sydney and move the camera
LatLng sydney = new LatLng(-34, 151);
mMap.addMarker(new MarkerOptions().position(sydney).title("Marker in Sydney"));
mMap.moveCamera(CameraUpdateFactory.newLatLng(sydney));
addHeatMapWeighted();
//addHeatMap();
}
public void addHeatMapWeighted() {
Gradient gradient = new Gradient(colors,startpoints);
List<WeightedLatLng> wDat = new CrimeData().getWeightedPositions();
HeatmapTileProvider provider = new HeatmapTileProvider.Builder().weightedData(wDat).gradient(gradient).build();
mMap.addTileOverlay(new TileOverlayOptions().tileProvider(provider));
}
public void addHeatMap() {
Gradient gradient = new Gradient(colors,startpoints);
List<LatLng> cDat = new CrimeData().getPositions();
HeatmapTileProvider provider = new HeatmapTileProvider.Builder().data(cDat).gradient(gradient).build();
mMap.addTileOverlay(new TileOverlayOptions().tileProvider(provider));
}
int[] colors = {
Color.GREEN, // green(0-50)
Color.YELLOW, // yellow(51-100)
Color.rgb(255,165,0), //Orange(101-150)
Color.RED, //red(151-200)
Color.rgb(153,50,204), //dark orchid(201-300)
Color.rgb(165,42,42) //brown(301-500)
};
float[] startpoints = {
0.1F, 0.2F, 0.3F, 0.4F, 0.6F, 1.0F
};
间隔开始
好的,所以您可能已经注意到,每个 colorMap 间隔的开始都以一个很好的整数(0,50,100...)开始,这不太符合您的要求(51, 101...301)。我认为你的注释范围是不正确的,因为这实际上意味着有 501 种可能的颜色,这有点奇怪。但是,如果您确实想要指定的范围,那么您必须进行一些数学运算才能得出替代的 startPoints 数组: (51/501,101/501,151/501,201/501,301/501,501/501) = (.101796407,. 201596806,.301397206,.401197605,.600798403,1.0)
Radius
半径值是热图的输入高斯模糊执行。有时图片是最好的解释:这是一个动画 Gif,它以 10 为步长在半径 20 到 50 的热图中循环(最模糊的是半径 50)。
由于热图旨在传达信息的含义,因此实际上需要数据呈现者来评估什么是最佳半径效果。例如,就犯罪数据而言,作为寻找居住地的数据消费者,我可能会从数据中获得更多价值some模糊。另一方面,如果数据显示的是消防站,那么太多的模糊很可能会导致人们相信它们已被覆盖,但实际上并未被覆盖。
Dots
仅使用点(圆圈)就能比热图讲述更准确的故事,并且在更广泛的缩放级别下,尽管没有颜色,但在视觉上就像热图一样模糊。例如,这里有两个点渲染,未加权和加权。加权偏差针对毒品犯罪(NCIC 代码[3500,3600)),这表明毒品犯罪在该领域占主导地位。
热图琐事
摘自参考书(3):
“热图”一词由软件开发商于 1991 年注册商标
科马克·金尼.随后它被 SS&C Technologies, Inc. 收购,但
他们没有延长许可证,并于 2006 年被废除。
参考
- 犯罪数据:https://support.spatialkey.com/spatialkey-sample-csv-data/
- 安卓代码:https://github.com/googlemaps/android-maps-utils/blob/master/library/src/com/google/maps/android/heatmaps/
- 热图商标: