Visualize data on a Google Map with deck.gl
Tags: googlemaps, javascript, deckgl
Published: 2019-09-05 18:46:27

Visualizing large datasets on a map is not easy, you say? In this article I’ll show how to do just that in 160 lines of JavaScript using deck.gl on a Google Map, loading data from a Google Sheet.

We are going to use a large open dataset with information on power plants from all over the world, which should be interesting to visualize. When we’re finished, the visualization will look like this:

{% glitch deck-gl-on-google-maps app %}

Read on to discover how we build this map.

### Get the data

First, grab the CSV data from the [World Resources Institute](http://datasets.wri.org/dataset/globalpowerplantdatabase) and upload it to a Google Sheet.

As we won’t need all the data in the document, it can be slimmed down by removing unneeded columns. This reduces the amount of data the visualization has to load. We’ll focus on the data in the six columns you see below. You can find the example Sheet [here](https://docs.google.com/spreadsheets/d/1MsFYOQlys_jyTACIZRbk3VWX9qaUdfrsr_r2Y-oxuZo) and reuse it.

![](https://thepracticaldev.s3.amazonaws.com/i/js546rzlejcbvpbk7hoy.png)

To show how power is produced, we will use the type of power plant to color a dot on the map. The size of the dot will be defined by the capacity of the power plant. Latitude and longitude will, of course, be used to place the dot on the map.

### No native rendering of large datasets on Google Maps

There are almost 30.000 power plants in this dataset. Visualizing that much data on a Google Map is not without its problems. Using the [Data Overlay](https://developers.google.com/maps/documentation/javascript/reference/data) provided by the Google Maps API is not very performant with that many items to render. Other methods such as using SVG as an overlay show similar performance problems with just a few hundreds of items already. So let’s take a look on deck.gl.

### What is deck.gl?

[deck.gl](https://deck.gl/) was published in 2016 and brought WebGL based rendering to maps, using the graphics card in our device. This is great news for us as it promises fast render performance! At first it didn’t work with Google Maps though. With the release of version 7 in April 2019, support for Google Maps was added and we’ll explore how easy it is to implement!

Of course deck.gl needs to be added to the visualization:

```html
<script src="https://unpkg.com/deck.gl@7.0.9/dist.min.js"></script>
```

### Create a Google Map

As a basis to render the data on, we create a Google Map. The Google Maps API is needed to create the map. Don’t forget to [get an API key](https://developers.google.com/maps/documentation/javascript/get-api-key). It can be included like this:

```html
<script src="https://maps.googleapis.com/maps/api/js?key=###YOUR_KEY###&callback=initMap"></script>
```

In the script tag, a callback is defined which will create the map when the API is loaded:

```js
let map;

function initMap() {
  map = new google.maps.Map(document.getElementById('map'), {
    center: {lat: 17, lng: 0},
    minZoom: 3,
    zoom: 3,
    clickableIcons: false,
    disableDefaultUI: true,
    zoomControl: true
  });
}
```

### Load data from the Google Sheet

As we have the data of the power plants in our [Google Sheet](https://docs.google.com/spreadsheets/d/1MsFYOQlys_jyTACIZRbk3VWX9qaUdfrsr_r2Y-oxuZo), we need to load that data first. To be able to pull data from a Sheet, it needs to be published to the web. In the spreadsheet, go to “File” -> “Publish to the web” and click the publish button. The Sheet can now be consumed by our app!

To load it, a script tag is added to the page. Be sure to insert the ID of your sheet in the URL of the script tag. The ID can be found in the URL of your Sheet following the `/d/` part. For our [example](https://docs.google.com/spreadsheets/d/1MsFYOQlys_jyTACIZRbk3VWX9qaUdfrsr_r2Y-oxuZo/edit#gid=1752080609) the ID is `1MsFYOQlys_jyTACIZRbk3VWX9qaUdfrsr_r2Y-oxuZo`.

At the end of the script tag, we define a callback that get’s called when the data is loaded:

```html
<script
src="https://spreadsheets.google.com/feeds/list/###SHEET_ID###/1/public/values?alt=json-in-script&callback=createOverlay">
</script>
```

In the callback, we can inspect the data loaded:

```js
function createOverlay(spreadsheetData) {
  console.log(spreadsheetData);
}
```

### Create a deck.gl GeoJSON overlay

Google Sheets gives us a JSON in a strange nested structure. To render that data as GeoJSON on the map, we need to create a GeoJSON first in the `createOverlay` callback:

```js
const data = {
  type: 'FeatureCollection',
  features: spreadsheetData.feed.entry.map(item => {
    return {
      type: 'Feature',
      geometry: {
        type: 'Point',
        coordinates: [
          Number(item.gsx$longitude.$t),
          Number(item.gsx$latitude.$t)
        ]
      },
      properties: {
        name: item.gsx$name.$t,
        country: item.gsx$countrylong.$t,
        capacity: Number(item.gsx$capacitymw.$t) || 0,
        primaryFuel: item.gsx$primaryfuel.$t
      }
    }
  })
};
```

Note that we add information on capacity and primary fuel to the properties so we can use it for the styling.

To add that GeoJSON to the map, we create a regular `GeoJsonLayer` from deck.gl:

```js
const geojsonLayer = new GeoJsonLayer({
  id: 'geojsonLayer',
  data: data,
  pickable: true,
  pointRadiusMinPixels: 2,
  pointRadiusMaxPixels: 140,
  wrapLongitude: true,
  getRadius: d => d.properties.capacity * 40,
  getFillColor: d => fuelColorMapping[d.properties.primaryFuel] || [100, 100, 100, 194]
});
```
  
The GeoJSON we just created get’s passed in. To calculate the radius, we use the `capacity` from the properties. The color of the dot is defined by the `primaryFuel`. We are using a mapping object with the fuel type as the key and the color array as the value.

This is a layer now, but it’s still not on the map.

### Add a deck.gl layer to a Google Map

Both the map and the layer need to be connected to render the data on the base map. deck.gl provides a `GoogleMapsOverlay` which does exactly that. Create one and assign it the map:

```js
const overlay = new GoogleMapsOverlay({
  layers: [geojsonLayer]
});
overlay.setMap(map);
```

Yay! The data can now be seen on the map!

![](https://thepracticaldev.s3.amazonaws.com/i/072tvnampv98pq8ipggy.png)

It’s really interesting to see the distribution of hydro power plants across the globe. The amount of coal power plants in China and India looks alarming with regard of the current climate crisis.

### Show an infowindow on click

Seeing the data on the map is great, but getting more information on the capacity or the name of the power plant would be a nice addition. An infowindow helps with that:

```js
const infowindow = new google.maps.InfoWindow({
  content: ''
});

map.addListener('click', event => {
  const picked = overlay._deck.pickObject({
    x: event.pixel.x,
    y: event.pixel.y,
    radius: 4,
    layerIds: ['geojsonLayer']
  });

  if (!picked) {
    infowindow.close();
    return;
  }

  infowindow.setContent(
    `<div>
      <div><b>${picked.object.properties.name}</b></div>
      <div>${picked.object.properties.country}</div>
      <div><b>capacity:</b> ${picked.object.properties.capacity}</div>
      <div><b>type:</b> ${picked.object.properties.primaryFuel}</div>
    </div>`
  );
  infowindow.setPosition({
    lng: picked.lngLat[0],
    lat: picked.lngLat[1]
  });
  infowindow.open(map);
});
```

When the map is clicked the overlay is checked for elements that can be picked at those coordinates. When none is found, close any open infowindow. Else, set the content to the data from the clicked power plants properties and open it at its location.

![](https://thepracticaldev.s3.amazonaws.com/i/ih7m0p7wbff2ltuylzi4.png)

### Conclusion

Loading data from a Google Sheet and creating a Google Map with a deck.gl GeoJsonLayer on top is possible with just a few lines of code. Creating visualizations from large datasets just became a lot easier and hopefully, this article helped you get started!

What are you going to visualize? Let us know on Twitter [@ubilabs](https://twitter.com/ubilabs) or via [info@ubilabs.net](mailto:info@ubilabs.net)

Be sure to check out the complete [source code](https://glitch.com/edit/#!/deck-gl-on-google-maps) of the example. You can find the standalone example right here: [deck-gl-on-google-maps.glitch.me](https://deck-gl-on-google-maps.glitch.me/).

*This article was published first on the [Ubilabs blog](https://ubilabs.net/en/news/how-to-visualize-data-with-deck-gl-and-google-maps).*