Air Quality and Pollen in areas and routes

Objective

Air Quality and Pollen APIs offer great opportunities to add more insights into a trip or map at any given location. There are two ways to consume the data available from those APIs: index as text or heatmap tiles as raster images.

alt_text

While using the heatmap tiles APIs endpoints, you may face a couple of challenges while loading the individual raster tiles such as:

  • how to load the tiles on a Google Map on the Web? (also to comply with the APIs Terms of use)
  • how to manage the number of requests during the experience?
  • how to read the tiles values?

Sample use cases

You will be presented sample use cases to try to answer the above questions.

  • Air Quality & Pollen in an area: visualize heatmap tiles (current conditions) raster data inside one or multiple custom polygons.
  • Air Quality & Pollen along route: visualize heatmap tiles (current conditions) raster data mapped on routes waypoints.

Implementation

You will discover what tiles are available and how they can be loaded in a Web experience. You will also see what can be done to manage the number of requests in a scenario where the tiles are loaded onto a map. Finally you will be presented how to read the tiles.

Available heatmap tiles by types

Air Quality API

- UAQI_RED_GREEN (UAQI, red-green palette): Universal Air Quality Index red-green palette.
- UAQI_INDIGO_PERSIAN (UAQI, indigo-persian palette): Universal Air Quality Index indigo-persian palette.
- PM25_INDIGO_PERSIAN: PM2.5 index indigo-persian palette.
- GBR_DEFRA: Daily Air Quality Index (UK) color palette.
- DEU_UBA: German Local Air Quality Index color palette.
- CAN_EC: Canadian Air Quality Health Index color palette.
- FRA_ATMO: France Air Quality Index color palette.
- US_AQI: US Air Quality Index color palette.

Pollen API

- TREE_UP: The heatmap type will represent a tree index graphical map.
- GRASS_UPI: The heatmap type will represent a grass index graphical map.
- WEED_UPI: The heatmap type will represent a weed index graphically map.

Display heatmap tiles in Web

Load the tiles and apply a vector mask to only display desired areas of the map's viewport.

Loading the tiles

import { TileLayer } from "deck.gl";
import { GoogleMapsOverlay } from "@deck.gl/google-maps";

// const TileLayer = deck.TileLayer;
// const GoogleMapsOverlay = deck.GoogleMapsOverlay;

// Initialize and add the map
function initMap() {
  const map = new google.maps.Map(document.getElementById("map"), {
    center: { lat: 40, lng: -110 },
    zoom: 4,
  });

  const apiKey = 'YOUR_API_KEY';
 const airqualityType = 'UAQI_RED_GREEN' // AirQuality API heatmap type
  const deckOverlay = new GoogleMapsOverlay({
    layers: [
       // Heatmap Tiles layer
new TileLayer({
    id: 'heatmap-tiles',
    data: 'https://airquality.googleapis.com/v1/mapTypes/'+ heatmapType + +'/heatmapTiles/{z}/{x}/{y}?key=' + apiKey,
...
 })
    ],
  });

  deckOverlay.setMap(map);
}

window.initMap = initMap;

Applying a vector Mask

You can visually hide or show any part of the heatmap tiles. Important: You will need to acquire the data that will be used to create the vector mask applied to the heatmap tiles.

  • In an Area:
  • use deck.gl GeoJson to create a Mask over the Air Quality TileLayer.

alt_text

The example below is using a multipolygon geojson of France

// geojson sample

{  "type": "Feature",
  "geometry": {
    "type": "MultiPolygon",
    "coordinates": [[[[-54.111527,2.11427],...[-54.194491,2.163073]]]]
  },
  "properties": {
    "name": "France"
  }
}

Here is a reference for the deckgl implementation:

  // Loaded layers in maps overlay
  const deckOverlay = new GoogleMapsOverlay({ layers: layers });
  const MaskExtension = deck.MaskExtension; // or import extension
  ...

  // As part of object containing the different layers
  const layers = [
    // Masking layer
  new GeoJsonLayer({
    id: 'country-vector',
    operation: 'mask',
    data: "geojson.json", // <-- any custom geometry
  })
  ...
  ...

  // Heatmap Tiles layer
  new TileLayer({
      id: 'heatmap-tiles',
      maskId: 'country-vector', // <-- same as mask id
    extensions: [new MaskExtension()],  // <-- enable mask extension
  ...
  })
  ]
  • Along a Route: Use deck.gl with its TripsLayer to create a Mask over the Air Quality TileLayer

Air Quality heatmap tile over a trip

alt_text

Manage API requests and cost

While the browser’s default behavior is usually to cache all loaded tiles in local storage (within the same session) you can further optimize:

  • Restrict the loading area: create a bounding box (in red) and assign it to the layer, only heatmap tiles (in blue) covering the bounding box will load at any given zoom level

Bounding Box (in red), Heatmap tiles (in blue)

alt_text

 // Heatmap Tile layer
 new TileLayer({
    id: 'heatmap-tiles',
    extent: [minX, minY, maxX, maxY] // bounding box: southwest lat, southwest lng, northeast lat, northeast lng
    ...
 })
  • Set visual display tile size to cover the entire viewport at any given zoom level; recommended: between 256 to 1024.

    Important: APIs tiles remain at 256x256 resolution but visual display adjustment will allow you to increase/decrease the number of tiles requests to cover the entire map Viewport

    (make sure it works with minZoom and maxZoom of the Google Map, ie: tilesize:1024 will not load tiles at zoom 0 or 1).

Viewport with tiles 256x256 pixels vs 512x512 pixels

alt_text alt_text



    // Heatmap Tile layer
    new TileLayer({
        id: 'heatmap-tiles',
        tilesize:256, // <-- change to 512 for instance
        ...
    })

Read pixel values

To display the corresponding value on a color scale

You can use Luma.gl library and its readPixelsToArray method upon an onClick event assigned as prop to the deck.gl layer.

Pixel value: rgba(128,0,0,255)

alt_text

LOW alt_text HIGH

  // Uint8Array pixel sample
  import { readPixelsToArray } from "@luma.gl/core";
  ...

  // assign on the TileLayer
  new TileLayer({
      id: 'heatmap-tiles',
  ...
    onClick: ({
    bitmap,
    layer
  }) => {
    if (bitmap) {
      const pixel = readPixelsToArray(layer.props.image, {
        sourceX: bitmap.pixel[0],
        sourceY: bitmap.pixel[1],
        sourceWidth: 1,
        sourceHeight: 1
      });
      // console.log("color picked:"+ pixel);
    }
  }
  })

Conclusion

You discovered how Air Quality and Pollen heatmap tiles API endpoints can be:

  • loaded on a Google Map in Web also making sure to be inline with the Terms of use
  • optimized to match your use case
  • read the tiles values

Next Actions

Suggested further reading:

Contributors

Principal authors:

Thomas Anglaret | Google Maps Platform Solutions Engineer