Adicionar uma camada de mapa de calor (Android SDK)

Nota

Aposentadoria do SDK do Android do Azure Maps

O SDK nativo do Azure Maps para Android foi preterido e será desativado em 31/03/25. Para evitar interrupções de serviço, migre para o SDK da Web do Azure Maps até 31/03/25. Para obter mais informações, consulte O guia de migração do SDK do Android do Azure Maps.

Os mapas de calor, também conhecidos como mapas de densidade de pontos, são um tipo de visualização de dados. Eles são usados para representar a densidade de dados usando um intervalo de cores e mostrar os "pontos quentes" de dados em um mapa. Os mapas de calor são uma ótima maneira de renderizar conjuntos de dados com um grande número de pontos.

Renderizar dezenas de milhares de pontos como símbolos pode cobrir a maior parte da área do mapa. Este caso provavelmente resulta na sobreposição de muitos símbolos. Dificultando uma melhor compreensão dos dados. No entanto, visualizar esse mesmo conjunto de dados como um mapa de calor facilita a visualização da densidade e da densidade relativa de cada ponto de dados.

Você pode usar mapas de calor em muitos cenários diferentes, incluindo:

  • Dados de temperatura: fornece aproximações para qual é a temperatura entre dois pontos de dados.
  • Dados para sensores de ruído: Mostra não só a intensidade do ruído onde o sensor está, mas também pode fornecer informações sobre a dissipação à distância. O nível de ruído em qualquer local pode não ser alto. Se a área de cobertura de ruído de vários sensores se sobrepuser, é possível que essa área sobreposta tenha níveis de ruído mais altos. Como tal, a área sobreposta seria visível no mapa de calor.
  • Rastreamento GPS: Inclui a velocidade como um mapa de altura ponderada, onde a intensidade de cada ponto de dados é baseada na velocidade. Por exemplo, esta funcionalidade fornece uma forma de ver onde um veículo estava em excesso de velocidade.

Gorjeta

Por padrão, as camadas de mapa de calor renderizam as coordenadas de todas as geometrias em uma fonte de dados. Para limitar a camada para que ela processe apenas recursos de geometria de ponto, defina a filter opção da camada como eq(geometryType(), "Point"). Se você quiser incluir recursos do MultiPoint também, defina a filter opção da camada como any(eq(geometryType(), "Point"), eq(geometryType(), "MultiPoint")).


Pré-requisitos

Certifique-se de concluir as etapas no Guia de início rápido: criar um documento de aplicativo Android. Os blocos de código neste artigo podem ser inseridos no manipulador de eventos maps onReady .

Adicionar uma camada de mapa térmico

Para renderizar uma fonte de dados de pontos como um mapa de calor, passe sua fonte de dados para uma instância da HeatMapLayer classe e adicione-a ao mapa.

O exemplo de código a seguir carrega um feed GeoJSON de terremotos da semana passada e os renderiza como um mapa de calor. Cada ponto de dados é renderizado com um raio de 10 pixels em todos os níveis de zoom. Para garantir uma melhor experiência do usuário, o mapa de calor fica abaixo da camada de etiquetas para que elas permaneçam claramente visíveis. Os dados nesta amostra são do Programa de Riscos de Terremoto do USGS. Este exemplo carrega dados GeoJSON da Web usando o bloco de código do utilitário de importação de dados fornecido no documento Criar uma fonte de dados.

//Create a data source and add it to the map.
DataSource source = new DataSource();

//Import the geojson data and add it to the data source.
source.importDataFromUrl("https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_week.geojson");

//Add data source to the map.
map.sources.add(source);

//Create a heat map layer.
HeatMapLayer layer = new HeatMapLayer(source,
  heatmapRadius(10f),
  heatmapOpacity(0.8f)
);

//Add the layer to the map, below the labels.
map.layers.add(layer, "labels");
//Create a data source and add it to the map.
val source = DataSource()

//Import the geojson data and add it to the data source.
source.importDataFromUrl("https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_week.geojson")

//Add data source to the map.
map.sources.add(source)

//Create a heat map layer.
val layer = HeatMapLayer(
    source,
    heatmapRadius(10f),
    heatmapOpacity(0.8f)
)

//Add the layer to the map, below the labels.
map.layers.add(layer, "labels")

A captura de tela a seguir mostra um mapa carregando um mapa de calor usando o código acima.

Mapa com camada de mapa de calor de terremotos recentes

Personalizar a camada de mapa de calor

O exemplo anterior personalizou o mapa de calor definindo as opções de raio e opacidade. A camada de mapa de calor fornece várias opções de personalização, incluindo:

  • heatmapRadius: Define um raio de pixel no qual renderizar cada ponto de dados. Você pode definir o raio como um número fixo ou como uma expressão. Usando uma expressão, você pode dimensionar o raio com base no nível de zoom e representar uma área espacial consistente no mapa (por exemplo, um raio de 5 milhas).

  • heatmapColor: Especifica como o mapa de calor é colorido. Um gradiente de cores é uma característica comum dos mapas de calor. Você pode obter o efeito com uma interpolate expressão. Você também pode usar uma step expressão para colorir o mapa de calor, dividindo a densidade visualmente em intervalos que se assemelham a um mapa de contorno ou estilo de radar. Essas paletas de cores definem as cores do valor de densidade mínima para máxima.

    Você especifica valores de cor para mapas de calor como uma expressão no heatmapDensity valor. A cor da área onde não há dados é definida no índice 0 da expressão "Interpolação" ou a cor padrão de uma expressão "Escalonada". Você pode usar esse valor para definir uma cor de plano de fundo. Muitas vezes, esse valor é definido como transparente ou um preto semitransparente.

    Aqui estão exemplos de expressões de cores:

    Expressão de cores de interpolação Expressão de cor escalonada
    interpolar(
        linear(),
        heatmapDensity(),
        stop(0, cor(Color.TRANSPARENT)),
        stop(0.01, cor(Color.MAGENTA)),
        stop(0.5, color(parseColor("#fb00fb"))),
        stop(1, color(parseColor("#00c3ff")))
    )'
    passo(
        heatmapDensity(),
        cor (Color.TRANSPARENT),
        stop(0.01, color(parseColor("#000080"))),
        stop(0.25, color(parseColor("#000080"))),
        stop(0.5, cor(Color.GREEN)),
        stop(0.5, cor(Color.YELLOW)),
        stop(1, cor(Color.RED))
    )
  • heatmapOpacity: Especifica o quão opaca ou transparente é a camada do mapa de calor.

  • heatmapIntensity: Aplica um multiplicador ao peso de cada ponto de dados para aumentar a intensidade geral do mapa de calor. Isso causa uma diferença no peso dos pontos de dados, facilitando a visualização.

  • heatmapWeight: Por padrão, todos os pontos de dados têm um peso de 1 e são ponderados igualmente. A opção de peso atua como um multiplicador e você pode defini-la como um número ou uma expressão. Se um número é definido como o peso, é a equivalência de colocar cada ponto de dados no mapa duas vezes. Por exemplo, se o peso é 2, então a densidade dobra. Definir a opção de peso para um número renderiza o mapa de calor de forma semelhante ao uso da opção de intensidade.

    No entanto, se você usar uma expressão, o peso de cada ponto de dados pode ser baseado nas propriedades de cada ponto de dados. Por exemplo, suponha que cada ponto de dados representa um terremoto. O valor da magnitude tem sido uma métrica importante para cada ponto de dados do terremoto. Os terremotos acontecem o tempo todo, mas a maioria tem uma baixa magnitude e não é notada. Use o valor de magnitude em uma expressão para atribuir o peso a cada ponto de dados. Usando o valor de magnitude para atribuir o peso, você obtém uma melhor representação do significado dos terremotos dentro do mapa de calor.

  • minZoom e maxZoom: O intervalo de nível de zoom onde a camada deve ser exibida.

  • filter: Uma expressão de filtro usada para limitar a recuperação da fonte e renderizada na camada.

  • sourceLayer: Se a fonte de dados conectada à camada for uma fonte de mosaico vetorial, uma camada de origem dentro dos blocos vetoriais deverá ser especificada.

  • visible: Oculta ou mostra a camada.

O trecho de código a seguir é um exemplo de um mapa de calor onde uma expressão de interpolação de linha é usada para criar um gradiente de cor suave. A mag propriedade definida nos dados é usada com uma interpolação exponencial para definir o peso ou a relevância de cada ponto de dados.

HeatMapLayer layer = new HeatMapLayer(source,
    heatmapRadius(10f),

    //A linear interpolation is used to create a smooth color gradient based on the heat map density.
    heatmapColor(
        interpolate(
            linear(),
            heatmapDensity(),
            stop(0, color(Color.TRANSPARENT)),
            stop(0.01, color(Color.BLACK)),
            stop(0.25, color(Color.MAGENTA)),
            stop(0.5, color(Color.RED)),
            stop(0.75, color(Color.YELLOW)),
            stop(1, color(Color.WHITE))
        )
    ),

    //Using an exponential interpolation since earthquake magnitudes are on an exponential scale.
    heatmapWeight(
       interpolate(
            exponential(2),
            get("mag"),
            stop(0,0),

            //Any earthquake above a magnitude of 6 will have a weight of 1
            stop(6, 1)
       )
    )
);
val layer = HeatMapLayer(source,
    heatmapRadius(10f),

    //A linear interpolation is used to create a smooth color gradient based on the heat map density.
    heatmapColor(
        interpolate(
            linear(),
            heatmapDensity(),
            stop(0, color(Color.TRANSPARENT)),
            stop(0.01, color(Color.BLACK)),
            stop(0.25, color(Color.MAGENTA)),
            stop(0.5, color(Color.RED)),
            stop(0.75, color(Color.YELLOW)),
            stop(1, color(Color.WHITE))
        )
    ),

    //Using an exponential interpolation since earthquake magnitudes are on an exponential scale.
    heatmapWeight(
       interpolate(
            exponential(2),
            get("mag"),
            stop(0,0),

            //Any earthquake above a magnitude of 6 will have a weight of 1
            stop(6, 1)
       )
    )
)

A captura de tela a seguir mostra a camada de mapa de calor personalizada acima usando os mesmos dados do exemplo de mapa de calor anterior.

Mapa com camada de mapa de calor personalizada de terremotos recentes

Mapa de calor com zoom consistente

Por padrão, os raios dos pontos de dados renderizados na camada de mapa de calor têm um raio de pixel fixo para todos os níveis de zoom. À medida que você amplia o mapa, os dados se agregam e a camada do mapa de calor parece diferente. O vídeo a seguir mostra o comportamento padrão do mapa de calor, onde ele mantém um raio de pixels ao ampliar o mapa.

Animação mostrando um mapa ampliando com uma camada de mapa de calor mostrando um tamanho de pixel consistente

Use uma zoom expressão para dimensionar o raio para cada nível de zoom, de modo que cada ponto de dados cubra a mesma área física do mapa. Essa expressão faz com que a camada de mapa de calor pareça mais estática e consistente. Cada nível de zoom do mapa tem o dobro de pixels vertical e horizontalmente do que o nível de zoom anterior.

Dimensionar o raio para que ele duplique a cada nível de zoom cria um mapa de calor que parece consistente em todos os níveis de zoom. Para aplicar esse dimensionamento, use zoom com uma expressão de base 2 exponential interpolation , com o raio de pixel definido para o nível mínimo de zoom e um raio dimensionado para o nível de zoom máximo calculado conforme 2 * Math.pow(2, minZoom - maxZoom) mostrado no exemplo a seguir. Amplie o mapa para ver como o mapa de calor é dimensionado com o nível de zoom.

HeatMapLayer layer = new HeatMapLayer(source,
  heatmapRadius(
    interpolate(
      exponential(2),
      zoom(),

      //For zoom level 1 set the radius to 2 pixels.
      stop(1, 2f),

      //Between zoom level 1 and 19, exponentially scale the radius from 2 pixels to 2 * (maxZoom - minZoom)^2 pixels.
      stop(19, Math.pow(2, 19 - 1) * 2f)
    )
  ),
  heatmapOpacity(0.75f)
);
val layer = HeatMapLayer(source,
  heatmapRadius(
    interpolate(
      exponential(2),
      zoom(),

      //For zoom level 1 set the radius to 2 pixels.
      stop(1, 2f),

      //Between zoom level 1 and 19, exponentially scale the radius from 2 pixels to 2 * (maxZoom - minZoom)^2 pixels.
      stop(19, Math.pow(2.0, 19 - 1.0) * 2f)
    )
  ),
  heatmapOpacity(0.75f)
)

O vídeo a seguir mostra um mapa executando o código acima, que dimensiona o raio enquanto o mapa está sendo ampliado para criar uma renderização consistente de mapa de calor em todos os níveis de zoom.

Animação mostrando um mapa ampliando com uma camada de mapa de calor mostrando um tamanho geoespacial consistente

A zoom expressão só pode ser usada em step e interpolate expressões. A expressão a seguir pode ser usada para aproximar um raio em metros. Esta expressão usa um espaço reservado radiusMeters, que você deve substituir pelo raio desejado. Esta expressão calcula o raio aproximado de pixels para um nível de zoom no equador para os níveis de zoom 0 e 24 e usa uma exponential interpolation expressão para dimensionar entre esses valores da mesma forma que o sistema de mosaico no mapa funciona.

interpolate(
    exponential(2),
    zoom(),
    stop(1, product(radiusMeters, 0.000012776039596366526)),
    stop(24, product(radiusMeters, 214.34637593279402))
)

Gorjeta

Quando você habilita o clustering na fonte de dados, os pontos próximos uns dos outros são agrupados como um ponto clusterizado. Você pode usar a contagem de pontos de cada cluster como a expressão de peso para o mapa de calor. Isso pode reduzir significativamente o número de pontos a serem renderizados. A contagem de pontos de um cluster é armazenada em uma point_count propriedade do recurso de ponto:

HeatMapLayer layer = new HeatMapLayer(dataSource,
   heatmapWeight(get("point_count"))
);

Se o raio de agrupamento for de apenas alguns pixels, haveria uma pequena diferença visual na renderização. Um raio maior agrupa mais pontos em cada cluster e melhora o desempenho do mapa de calor.

interpolate(
    exponential(2),
    zoom(),
    stop(1, product(radiusMeters, 0.000012776039596366526)),
    stop(24, product(radiusMeters, 214.34637593279402))
)

Gorjeta

Quando você habilita o clustering na fonte de dados, os pontos próximos uns dos outros são agrupados como um ponto clusterizado. Você pode usar a contagem de pontos de cada cluster como a expressão de peso para o mapa de calor. Isso pode reduzir significativamente o número de pontos a serem renderizados. A contagem de pontos de um cluster é armazenada em uma point_count propriedade do recurso de ponto:

var layer = new HeatMapLayer(dataSource,
   heatmapWeight(get("point_count"))
)

Se o raio de agrupamento for de apenas alguns pixels, haveria uma pequena diferença visual na renderização. Um raio maior agrupa mais pontos em cada cluster e melhora o desempenho do mapa de calor.

Próximos passos

Para obter mais exemplos de código para adicionar aos seus mapas, consulte os seguintes artigos: