Search code examples
reactjsdeck.glreact-map-gl

Deck.GL ScatterplotLayer does not render points


I've been scratching my head over this one for way too long. I've got the simplest React App, which passes some data as a prop to WhateverMap (so-called because I've been trying out many different Map libraries).

However, when I try to plot the data points on Deck.GL using a ScatterplotLayer, I simply do not see them on the rendered map.

According to React Developer Tools, the ScatterplotLayer component did receive my datapoints.

I'm expecting to see some markers along a specific part of the train tracks in Berlin.

import React, { Component } from 'react';
import Header from './Header';
import WhateverMap from './Map';
import Table from './Table';

class App extends Component {
  state = {
    // Trip along the Ringbahn
    data: [
        {'timestamp': Date.now()-10000, 'coordinates': [52.536131,13.447444], 'temperature': 19},
        {'timestamp': Date.now()-9000, 'coordinates': [52.538221,13.44376], 'temperature': 20},
        {'timestamp': Date.now()-8000, 'coordinates': [52.540247,13.43899], 'temperature': 21},
        {'timestamp': Date.now()-7000, 'coordinates': [52.541751,13.43513], 'temperature': 22},
        {'timestamp': Date.now()-6000, 'coordinates': [52.54264,13.433692], 'temperature': 23},
        {'timestamp': Date.now()-5000, 'coordinates': [52.543007,13.431339], 'temperature': 24},
        {'timestamp': Date.now()-4000, 'coordinates': [52.543755,13.428731], 'temperature': 25},
        {'timestamp': Date.now()-3000, 'coordinates': [52.544295,13.427207], 'temperature': 27}
    ]
  };
  render() {
    return (
      <div className="container">
        <Header />
        <WhateverMap data={this.state.data} />
        <Table data={this.state.data} />
      </div>
    );
  }
}

export default App;

WhateverMap:

import React, { PureComponent } from 'react';
import MapGL from 'react-map-gl';
import DeckGL, { ScatterplotLayer } from 'deck.gl';

const mapbox_token = ''
const mapConfig = {
  center: [52.540875, 13.438545],
  zoom: 13
};

class WhateverMap extends PureComponent {
  constructor(props) {
    super(props);

    this.state = {
      viewport: {
        width: 960,
        height: 600,
        latitude: mapConfig.center[0],
        longitude: mapConfig.center[1],
        zoom: mapConfig.zoom,
        startDragLngLat: mapConfig.center,
      },
    };

    this.onChangeViewport = this.onChangeViewport.bind(this);
  }

  onChangeViewport(viewport) {
    this.setState({
      viewport: { ...this.state.viewport, ...viewport }
    });
  }

  initialize(gl) {
    gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE, gl.ONE_MINUS_DST_ALPHA, gl.ONE);
    gl.blendEquation(gl.FUNC_ADD);
  }

  render() {
    const { viewport } = this.state;
    const { data } = this.props;

    const plot_position_layer = new ScatterplotLayer({
        id: 'scatterplot-layer',
        data,
        pickable: true,
        opacity: 0.8,
        radiusScale: 6,
        radiusMinPixels: 1,
        radiusMaxPixels: 100,
        getPosition: d => d.coordinates,
    })

    return (
      <div className="reactmapgldeckgl">
        <MapGL
          {...viewport}
          mapboxApiAccessToken={mapbox_token}
          mapStyle="mapbox://styles/mapbox/dark-v9"
          onChangeViewport={this.onChangeViewport}
        >
          <DeckGL
            {...viewport}
            onWebGLInitialized={this.initialize}
            layers={[plot_position_layer]}
          />
        </MapGL>
      </div>
    );
  }
}

export default WhateverMap;

Solution

  • Firstly, the answer. You code seems to be right, however, some tweaking seems to resolve the error.

    const plot_position_layer = new ScatterplotLayer({
      id: 'scatterplot-layer',
      data,
      pickable: true,
      opacity: 0.8,
      radiusScale: 30,  // make the dots visible or darker background
      radiusMinPixels: 15, // make the dots visible or darker background
      radiusMaxPixels: 100,
    
      getPosition: d => [d.coordinates[1], d.coordinates[0]], // -> Essential Change here
    
      getColor: d => [255, 255, 255], // make the dots visible or darker background
    })
    

    Now, what has changed essentially is getPosition: d => [d.coordinates[1], d.coordinates[0]]

    Strangely, the getPosition function is expected to return an array with the first element as longitude instead of latitude which is why the points were out of bounds.

    enter image description here

    Have a look at their example here at line number 11.

    // Source data CSV
    const DATA_URL =
      'https://raw.githubusercontent.com/uber-common/deck.gl-data/master/examples/scatterplot/manhattan.json'; // eslint-disable-line
    
    export const INITIAL_VIEW_STATE = {
      longitude: -74, //remember, longitude starts with 74
      latitude: 40.7,
      zoom: 11,
      maxZoom: 16,
      pitch: 0,
      bearing: 0
    };
    

    and the DATA_URL reads as

    [
      [-73.986022,40.730743,2], // the first element is longitude
      [-73.984293,40.729468,1],
      [-73.987752,40.732017,1],
      [-73.986887,40.730105,2],
      ...
    ]
    

    Hope this helps