问题
I am trying to create a weighted heat map for my android app project. I had a look at the google documentation for it. I don't understand how to create a new gradient using colors array and starting points array. The starting array is denoted as
The starting point for each color, given as a percentage of the maximum intensity.
What does it mean? How to relate color array with starting point array?
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 = {
};
I need to fill this startpoints array.
回答1:
Here are some assumptions:
- the gradient colorMapSize is 1000 (default) but should be set to 500
- the color values length is 6
- the startPoints length is 6 (has to be the same length as the colors)
- the colors array is specified in OP
- the startingPoints array should be { 0.1F, 0.2F, 0.3F, 0.4F, 0.6F, 1.0F }
Here's a diagram to help the discussion:
ColorMap
The first thing to understand is the colorMap. This is generated by the Gradient builder. It is an 'int' array with size by default of 1000 but is customizable in one of the constructors - recommend 500 in your example. So every value in this array is a color value. (The size affects the resolution of your gradient.)
Color values in the colorMap are affected by 2 controls which produce color intervals: the startPoints array and the colors array. In your example there is 6 color intervals.
A color interval is defined as a starting color and end color and the number of 'colorMap' slots in range. All colorMap values for any given interval are interpolated using the start/end colors for that range.
If the first value of the startPoints array is 0 then the first color interval is assumed to be solid - non-zero implies a transition from transparent to the first color which seems most desirable. (See example where the startPoints is set to 0 and notice the jaggedness of the outside areas.)
If the first value of the startPoints array is not 0 then the first color interval is defined as starting with the first color (colors[0]) and a range of the colorMapSize * the first starting point, e.g. 500 * 0.1 = 50 and ending with the same color.
For all remaining defined colors an interval is generated - again with a starting colorMap slot, a starting color (which is the previous color end), and ending color (which is the current color in the table) and a range.
If the last startingPoint is not 1.0, then the last color is used for start and stop. In this example, 1.0 is probably best.
(Opacity applies to the whole layer and simply affects the alpha channel of the color.)
Tiles
This is where 'intensity' is appreciated and the effect a WeightedLatLng can play a part.
When the map is generated it divides the viewable area into tiles - the number of tiles is a function of zoom level. At zoom level 0 there is 1 tile, and the arbitrary zoom level tile count is 2^n (where n is the zoom level).
Each tile is further divided into buckets. The number of buckets is a function of zoom level and Radius (blur). Each bucket corresponds to a geographical area within the tile - think rectangle-grid.
The points inside the current tile are obtained from the data set.
For all of the points within the geographic bounds of the tile, the intensity value of the point is added to its corresponding bucket. The intensity value for a point by default is 1. The WeightedLatLng allows you to bias a point by changing this value from 1 to some number (larger to increase importance, smaller to decrease importance). So the result is the bucket intensity tally is affected from what it would be for just LatLngs.
Once the intensity buckets are tallied, the intensity values are colorized using the colorMap determined in the first section. Note that the range of intensity values are scaled to the size of the colorMap such that the maximum intensity value maps to the last color.
The buckets are then applied to the tile and the tile is made into a bitmap and is rendered.
Example
For an example I used some data on crime in Sacramento. I first created a non-weighted heatmap. And then created a weighted heatmap to give an importance to auto-thefts by specifying an intensity of 5.0 (verses the default of 1.0 for any point) for crimes with an NCIC code of 2404 (vehicle-theft). The 5.0 is somewhat arbitrary and really depends on the data and what you're trying to convey.
Non-Weighted / Weighted (by vehicle theft)
And an example where the first startPoint[0] is 0.0 - which shows the lack of a transition from transparent to initial color:
Here are the relevant portions of the 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
};
Start of Interval
OK, so you may have noticed that the start of each colorMap interval starts at a nice round number (0,50,100...) which doesn't quite match your requirements (51, 101...301). I would argue that your commented-ranges are not right since really that means there are 501 possible colors which is a bit odd. But if you really wanted that range as specified then you'd have to do some math on to come up with an alternate startPoints array of: (51/501,101/501,151/501,201/501,301/501,501/501) = (.101796407,.201596806,.301397206,.401197605,.600798403, 1.0)
Radius
The radius value is an input to the HeatMap's Gaussian Blur implementation. Sometimes a picture is the best explanation: this is an animated Gif which cycles through a HeatMap of radius 20 to 50 in steps of 10 (with the blurriest being radius 50).
Since the heat map is intended to convey meaning to the information, it's really left to the data presenter to assess what is the best radius effect. So for example, in the case of crime data, as a consumer of the data looking for a place to live, I'd probably gain more value from the data with some blur. On the other hand if the data was presenting fire stations then too much blur could very well lead one to believe they are covered when they are not.
Dots
Just using dots (circles) tells a more accurate story than the heat map and which at the broader zoom levels visually blurs just like a heat map albeit without the color. For example, here are two dot renderings, unweighted and weighted. The weighted bias is for drug crimes (NCIC codes [3500,3600)) which shows that drug crimes predominate this area.
HeatMap Trivia
From the referenced book (3):
The term "heat map" was trademarked in 1991 by software developer Cormac Kinney. It was then acquired by SS&C Technologies, Inc. but they did not extend the license and it was annulled in 2006.
References
- Crime data: https://support.spatialkey.com/spatialkey-sample-csv-data/
- Android code: https://github.com/googlemaps/android-maps-utils/blob/master/library/src/com/google/maps/android/heatmaps/
- HeatMap trademark: https://books.google.com/books?id=clIWDAAAQBAJ&pg=PA219&lpg=PA219&dq=is+heatmap+trademarked&source=bl&ots=XfcTsOc2pG&sig=EPaHG95M8uXiI5WAAwpa-e3zHXE&hl=en&sa=X&ved=0ahUKEwijtKSl2IfaAhUNy1kKHdBUAdsQ6AEIlwEwCg#v=onepage&q=is%20heatmap%20trademarked&f=false
来源:https://stackoverflow.com/questions/49465240/weighted-heat-maps-in-android