Utilidad de mapa de calor para Google Maps en Android

Los mapas de calor son útiles para representar la distribución y densidad de puntos de datos de un mapa.

Introducción

La biblioteca de utilidades del SDK de Maps para Android incluye una utilidad de mapa de calor que puedes usar para agregar uno o más mapas de calor a un mapa de Google en tu app.

En este video se discute el uso de mapas de calor como alternativa a los marcadores cuando tus datos requieren una gran cantidad de puntos de datos en el mapa.

Los mapas de calor permiten a los usuarios comprender la distribución y la intensidad relativa de los puntos de datos de un mapa de manera sencilla. En los mapas de calor, en lugar de colocar un marcador en cada ubicación, se usan colores para representar la distribución de los datos.

En el siguiente ejemplo, el rojo representa las áreas con una alta concentración de comisarías en Victoria, Australia.

Mapa con un mapa de calor en el que se muestra la ubicación de comisarías
Mapa de calor en un mapa

Si todavía no configuraste la biblioteca de utilidades del SDK de Maps para Android, sigue la guía de configuración antes de leer el resto de esta página.

Cómo agregar un mapa de calor simple

Para agregar un mapa de calor a tu mapa, necesitarás un conjunto de datos compuesto por las coordenadas de cada ubicación de interés. Primero, crea HeatmapTileProvider y pásale la colección de objetos LatLng. Luego, crea una clase TileOverlay nueva, pásale el proveedor de mosaicos de mapas de calor y agrega la superposición de mosaicos al mapa.

La utilidad suministra la clase HeatmapTileProvider, que implementa la interfaz de TileProvider a fin de proporcionar las imágenes de mosaico del mapa de calor. La HeatmapTileProvider acepta una colección de objetos LatLng (o de objetos WeightedLatLng, según lo que se describe a continuación). Esta clase crea las imágenes de mosaicos para diferentes niveles de zoom según las opciones de radio, gradiente y opacidad suministradas. Puedes cambiar los valores predeterminados para estas opciones.

Una vista más detallada de los pasos:

  1. Usa HeatmapTileProvider.Builder() y pásale una colección de objetos LatLng para agregar una clase HeatmapTileProvider nueva.
  2. Crea un nuevo objeto TileOverlayOptions con las opciones relevantes, incluido HeatmapTileProvider.
  3. Llama a GoogleMap.addTileOverlay() para agregar la superposición al mapa.

Java

private void addHeatMap() {
    List<LatLng> latLngs = null;

    // Get the data: latitude/longitude positions of police stations.
    try {
        latLngs = readItems(R.raw.police_stations);
    } catch (JSONException e) {
        Toast.makeText(context, "Problem reading list of locations.", Toast.LENGTH_LONG).show();
    }

    // Create a heat map tile provider, passing it the latlngs of the police stations.
    HeatmapTileProvider provider = new HeatmapTileProvider.Builder()
        .data(latLngs)
        .build();

    // Add a tile overlay to the map, using the heat map tile provider.
    TileOverlay overlay = map.addTileOverlay(new TileOverlayOptions().tileProvider(provider));
}

private List<LatLng> readItems(@RawRes int resource) throws JSONException {
    List<LatLng> result = new ArrayList<>();
    InputStream inputStream = context.getResources().openRawResource(resource);
    String json = new Scanner(inputStream).useDelimiter("\\A").next();
    JSONArray array = new JSONArray(json);
    for (int i = 0; i < array.length(); i++) {
        JSONObject object = array.getJSONObject(i);
        double lat = object.getDouble("lat");
        double lng = object.getDouble("lng");
        result.add(new LatLng(lat, lng));
    }
    return result;
}
      

Kotlin

private fun addHeatMap() {
    var latLngs: List<LatLng?>? = null

    // Get the data: latitude/longitude positions of police stations.
    try {
        latLngs = readItems(R.raw.police_stations)
    } catch (e: JSONException) {
        Toast.makeText(context, "Problem reading list of locations.", Toast.LENGTH_LONG)
            .show()
    }

    // Create a heat map tile provider, passing it the latlngs of the police stations.
    val provider = HeatmapTileProvider.Builder()
        .data(latLngs)
        .build()

    // Add a tile overlay to the map, using the heat map tile provider.
    val overlay = map.addTileOverlay(TileOverlayOptions().tileProvider(provider))
}

@Throws(JSONException::class)
private fun readItems(@RawRes resource: Int): List<LatLng?> {
    val result: MutableList<LatLng?> = ArrayList()
    val inputStream = context.resources.openRawResource(resource)
    val json = Scanner(inputStream).useDelimiter("\\A").next()
    val array = JSONArray(json)
    for (i in 0 until array.length()) {
        val `object` = array.getJSONObject(i)
        val lat = `object`.getDouble("lat")
        val lng = `object`.getDouble("lng")
        result.add(LatLng(lat, lng))
    }
    return result
}
      

Para este ejemplo, los datos se almacenan en un archivo JSON, police_stations.json. Aquí se proporciona un extracto del archivo:

[
{"lat" : -37.1886, "lng" : 145.708 } ,
{"lat" : -37.8361, "lng" : 144.845 } ,
{"lat" : -38.4034, "lng" : 144.192 } ,
{"lat" : -38.7597, "lng" : 143.67 } ,
{"lat" : -36.9672, "lng" : 141.083 }
]

Cómo usar puntos ponderados de latitud y longitud

Cuando creas una clase HeatmapTileProvider, puedes pasarle una colección de coordenadas ponderadas de latitud y longitud. Esto resulta útil si deseas ilustrar la importancia de un conjunto determinado de ubicaciones.

Para aplicar la ponderación a ubicaciones específicas, sigue estos pasos:

  1. Crea un objeto WeightedLatLng nuevo para cada ubicación que requiera ponderación. Pasa LatLng y double, que representan la intensidad necesaria. La intensidad indica la importancia o el valor relativos de esta ubicación. Un valor superior generará un color más intenso en el gradiente del mapa de calor. De manera predeterminada, el color de mayor intensidad es el rojo.
  2. Llama a HeatmapTileProvider.Builder().weightedData(), en lugar de a HeatmapTileProvider.Builder().data(), para crear el mapa de calor.

Cómo personalizar el mapa de calor

Varias propiedades del mapa de calor son personalizables. Puedes configurar las opciones en el momento de la creación, a través de las funciones Builder. También puedes modificar una opción en cualquier momento si llamas al método set correspondiente en HeatmapTileProvider y, luego, borrar la caché de mosaicos de la superposición para que vuelva a dibujar todos los mosaicos con las opciones nuevas.

Están disponibles las siguientes opciones:

  1. Radio: Es el tamaño del desenfoque gaussiano que se aplica al mapa de calor, expresado en píxeles. El valor predeterminado es 20 y debe estar entre 10 y 50. Usa el elemento radius() de las funciones Builder para configurar el valor cuando creas el mapa de calor, o cambia el valor posteriormente con setRadius().
  2. Gradiente: Es una variedad de colores que se usan en el mapa de calor para generar el mapa de colores, con una intensidad de menor a mayor. Un gradiente se genera con dos arreglos: uno con valores enteros que contiene los colores, y uno con números de punto flotante en el que se indica el punto de partida para cada color, como un porcentaje de la intensidad máxima y expresado como una fracción de 0 a 1. Debes especificar solo un color para un gradiente de un único color o dos colores como mínimo para un gradiente multicolor. El mapa de colores se genera aplicando una interpolación entre dichos colores. El gradiente predeterminado tiene dos colores. Usa el elemento gradient() de las funciones Builder para configurar el valor cuando creas el mapa de calor, o cambia el valor posteriormente con setGradient().
  3. Opacidad: Es la opacidad de toda la capa del mapa de calor y varía de 0 a 1. El valor predeterminado es 0.7. Usa el elemento opacity() de las funciones Builder para configurar el valor cuando creas el mapa de calor, o cambia el valor posteriormente con setOpacity().

Por ejemplo, crea un objeto Gradient para configurar el gradiente antes de agregar el mapa de calor:

Java

// Create the gradient.
int[] colors = {
    Color.rgb(102, 225, 0), // green
    Color.rgb(255, 0, 0)    // red
};

float[] startPoints = {
    0.2f, 1f
};

Gradient gradient = new Gradient(colors, startPoints);

// Create the tile provider.
HeatmapTileProvider provider = new HeatmapTileProvider.Builder()
    .data(latLngs)
    .gradient(gradient)
    .build();

// Add the tile overlay to the map.
TileOverlay tileOverlay = map.addTileOverlay(new TileOverlayOptions().tileProvider(provider));
      

Kotlin

// Create the gradient.
val colors = intArrayOf(
    Color.rgb(102, 225, 0),  // green
    Color.rgb(255, 0, 0) // red
)
val startPoints = floatArrayOf(0.2f, 1f)
val gradient = Gradient(colors, startPoints)

// Create the tile provider.
val provider = HeatmapTileProvider.Builder()
    .data(latLngs)
    .gradient(gradient)
    .build()

// Add the tile overlay to the map.
val tileOverlay = map.addTileOverlay(
    TileOverlayOptions()
        .tileProvider(provider)
)
      

Para cambiar la opacidad de un mapa de calor existente, sigue estos pasos:

Java

provider.setOpacity(0.7);
tileOverlay.clearTileCache();
      

Kotlin

provider.setOpacity(0.7)
tileOverlay.clearTileCache()
      

Cómo cambiar el conjunto de datos

Si deseas cambiar el conjunto de datos a partir del cual se crea un mapa de calor, usa HeatmapTileProvider.setData(). O bien, usa HeatmapTileProvider.setWeightedData() para los puntos de WeightedLatLng. Nota: Si deseas agregar puntos al mapa de calor o quitarlos de este, actualiza tu colección de datos y, luego, usa setData() o setWeightedData().

Java

List<WeightedLatLng> data = new ArrayList<>();
provider.setWeightedData(data);
tileOverlay.clearTileCache();
      

Kotlin

val data: List<WeightedLatLng> = ArrayList()
provider.setWeightedData(data)
tileOverlay.clearTileCache()
      

Cómo quitar un mapa de calor

Para quitar el mapa de calor, debes quitar la superposición de mosaicos:

Java

tileOverlay.remove();
      

Kotlin

tileOverlay.remove()
      

Cómo consultar la app de demostración

Para ver otro ejemplo de la implementación de un mapa de calor, observa HeatmapsDemoActivity en la app de demostración que se incluye en la biblioteca de utilidades En la guía de configuración, se muestra cómo ejecutar la app de demostración.