visgl / deck.gl

WebGL2 powered visualization framework
https://deck.gl
MIT License
12.07k stars 2.08k forks source link

ScreenGridLayer renders incorrectly. #1880

Closed marcusraven-gmail-com closed 6 years ago

marcusraven-gmail-com commented 6 years ago

We seem to be having trouble rendering ScreenGridLayer. It depends on the data that is used, but the attached file does not seem to render correctly. We just get a single colored "blob" in the center of the map (which does not correspond to the data at all), and then when dragging the map the colored blob stays in the center of the view; it does not follow the map as it is dragged around.

test-data.zip

example blob

In addition; if we do not make our lowest color value 100% transparent, then the entire map shows a block over every cell in the grid, even when there is no data in that cell:

full grid

If we use full transparency, some of our data does show up and looks correct. However please note the bottom right corner where the tooltip pops up; the layer is putting our data in the gulf of mexico, even though we don't have any lat/lng coordinates in our data that is in that location? Basically every cell we hover over in our map, whether there is data for that cell in the grid or not, it thinks there is actually data there and pops up our tooltip:

mexico

The data that generated that map looks correct (only shows data in Texas) when using other layers (hexagon), and hovering over the gulf of mexico with the hex layer does not popup our tooltip.

So I suspect a bug somewhere, or quite possibly I'm using ScreenGridLayer incorrectly.

This is all using the latest version of deck.gl, with this src in our script tag: https://unpkg.com/deck.gl@latest/deckgl.min.js

Any tips, comments etc? Thanks in advance!

alldoami commented 6 years ago

I'm having the same exact issue!

1chandu commented 6 years ago

@marcusraven-gmail-com @alldoami

We just get a single colored "blob" in the center of the map (which does not correspond to the data at all)

We have known issue with specific GPUs (Intel and Nvidia), fix for it is in review, see if this fixes incorrect data rendering: https://github.com/uber/deck.gl/pull/2122. Are you using Intel or Nvidia GPU? Can you apply this patch and try.

and then when dragging the map the colored blob stays in the center of the view; it does not follow the map as it is dragged around.

Please note, ScreenGridLayer performs aggregation in screen space (unlike GridLayer, which performs in world space), hence when dragging, cell boundaries do change to newer projections and amount of data falls into each cell will change. But when dragging, aggregation count of each cell should move along with map. Can you reproduce this issue with our example (https://github.com/uber/deck.gl/tree/master/examples/website/screen-grid)?

In addition; if we do not make our lowest color value 100% transparent, then the entire map shows a block over every cell in the grid, even when there is no data in that cell:

This is the side affect of using minColor and maxColor prop, can you not provide both props (these are deprecated in 6.0), when not provided it uses default values for colorRange and colroDomain or you can provide custom values for these props. Docs: https://github.com/uber/deck.gl/blob/master/docs/layers/screen-grid-layer.md

Basically every cell we hover over in our map, whether there is data for that cell in the grid or not, it thinks there is actually data there and pops up our tooltip:

The picking data for ScreenGridLayer returns cellCount and cellWeight, when no data present in this cell, both should have value 0, can you filter out based on this?

alldoami commented 6 years ago

@1chandu Even when filtering out the cellCount and cellWeight, the data that shows up on the tooltip is incorrect. When using Hexagons, the information is correct, and the tooltip recognizes the correct objects. But when using ScreenGrid, it thinks there are objects everywhere and is identifying all of the points on the map as the incorrect location.

1chandu commented 6 years ago

@alldoami , can you give me more details, on how you are rendering your tool tip.

the data that shows up on the tooltip is incorrect

Can yo provide more deails whats is incorrect. What is expected.

When you hover over cells that don't have any data, the picking information returned by ScrenGridLayer, is an object with that contains {index, object, ...}, index is going to be a valid value. (Code: https://github.com/uber/deck.gl/blob/79b6cc736cb42fd65eac02edf5bf8de1f1e5d775/modules/layers/src/screen-grid-layer/screen-grid-layer.js#L178) In other layers, this index can be used to index into original data to get object details, but in case of ScreenGrid, each cell could be a result of mutliple orginal data items, this index refers to a cell, and object contains cellCount, cellWeight etc. In HexagonLayer, aggregation is done one CPU, and it maintains original JS objects of all data elements that fall into a hexagon cell and returns all of them as part of picking data.

Please note, this behavior of ScreenGridLayer is not a regression, older version of ScreenGridLayer was in-correctly using index value to return on data item. We fixed it in this version by providing aggregation data cellCount, cellWeight etc. Was this working for you before (5.3 or earlier deck.gl versions) and broken in 6.0 release?

alldoami commented 6 years ago

@1chandu

How should I access the index that actually matches the latlong?

I recently started working on it, so it hasn't worked since I started working on it. Here are some screenshots of my map (the cursor is not on a square, like the example above): image

When I inspect the page, here is what I see (I erased the id for privacy purposes): image

As you can see, the lat long, and the position are not equaled. So I am not sure why it is being matched for that position on the map.

When I use hexagons, only objects that are on the map show up in the console when inspecting and show the correct lat long and position coordinates.

alldoami commented 6 years ago

@1chandu I'm also on version 0.25.6 for Superset. I'm not sure how to check which version of deck gl I have.

alldoami commented 6 years ago

This is Superset's implementation of ScreenGrid:

/ eslint no-underscore-dangle: ["error", { "allow": ["", "__timestamp"] }] /

import React from 'react'; import ReactDOM from 'react-dom'; import PropTypes from 'prop-types';

import { ScreenGridLayer } from 'deck.gl';

import AnimatableDeckGLContainer from '../AnimatableDeckGLContainer';

import * as common from './common'; import { getPlaySliderParams } from '../../../modules/time'; import sandboxedEval from '../../../modules/sandbox';

function getPoints(data) { return data.map(d => d.position); }

function getLayer(formData, payload, slice, filters) { const fd = formData; const c = fd.color_picker; let data = payload.data.features.map(d => ({ ...d, color: [c.r, c.g, c.b, 255 * c.a], }));

if (fd.js_data_mutator) { // Applying user defined data mutator if defined const jsFnMutator = sandboxedEval(fd.js_data_mutator); data = jsFnMutator(data); }

if (filters != null) { filters.forEach((f) => { data = data.filter(f); }); }

// Passing a layer creator function instead of a layer since the // layer needs to be regenerated at each render return new ScreenGridLayer({ id: screengrid-layer-${fd.slice_id}, data, pickable: true, cellSizePixels: fd.grid_size, minColor: [c.r, c.g, c.b, 0], maxColor: [c.r, c.g, c.b, 255 * c.a], outline: false, getWeight: d => d.weight || 0, ...common.commonLayerProps(fd, slice), }); }

const propTypes = { slice: PropTypes.object.isRequired, payload: PropTypes.object.isRequired, setControlValue: PropTypes.func.isRequired, viewport: PropTypes.object.isRequired, };

class DeckGLScreenGrid extends React.PureComponent { / eslint-disable-next-line react/sort-comp / static getDerivedStateFromProps(nextProps) { const fd = nextProps.slice.formData;

const timeGrain = fd.time_grain_sqla || fd.granularity || 'PT1M';
const timestamps = nextProps.payload.data.features.map(f => f.__timestamp);
const { start, end, step, values, disabled } = getPlaySliderParams(timestamps, timeGrain);

return { start, end, step, values, disabled };

} constructor(props) { super(props); this.state = DeckGLScreenGrid.getDerivedStateFromProps(props);

this.getLayers = this.getLayers.bind(this);

} componentWillReceiveProps(nextProps) { this.setState(DeckGLScreenGrid.getDerivedStateFromProps(nextProps, this.state)); } getLayers(values) { const filters = [];

// time filter
if (values[0] === values[1] || values[1] === this.end) {
  filters.push(d => d.__timestamp >= values[0] && d.__timestamp <= values[1]);
} else {
  filters.push(d => d.__timestamp >= values[0] && d.__timestamp < values[1]);
}

const layer = getLayer(
  this.props.slice.formData,
  this.props.payload,
  this.props.slice,
  filters);

return [layer];

} render() { return (

);

} }

DeckGLScreenGrid.propTypes = propTypes;

function deckScreenGrid(slice, payload, setControlValue) { const fd = slice.formData; let viewport = { ...fd.viewport, width: slice.width(), height: slice.height(), };

if (fd.autozoom) { viewport = common.fitViewport(viewport, getPoints(payload.data.features)); }

ReactDOM.render( <DeckGLScreenGrid slice={slice} payload={payload} setControlValue={setControlValue} viewport={viewport} />, document.getElementById(slice.containerId), ); }

module.exports = { default: deckScreenGrid, getLayer, };

1chandu commented 6 years ago

I'm also on version 0.25.6 for Superset. I'm not sure how to check which version of deck gl I have.

Can you do npm ls deck.gl ?

When I use hexagons, only objects that are on the map show up in the console when inspecting and show the correct lat long and position coordinates.

ScreenGrid layer never supported this feature, HexagonLayer maintains a list of original JS objects of all data points that fall into a hexagon. Similar functionality is also supported by GridLayer. If you are ok with aggregation in world space, you can try using GridLayer

alldoami commented 6 years ago

@1chandu

Ok that works for me. Do you know how to change the colors in GridLayer dynamically? I don't understand the color schemes. I'd like to change it to a bright green for the objects that are tall and a lighter green for the objects that are short. I also want to change the scale because there doesn't seem to be that big of a difference between objects with weight 1000+ and those with weights smaller than 1. Here is a screenshot of what I'm seeing (the object on the bottom left has a height of 1000+ and the other ones have less than 200): image

I appreciate all the help! :D

1chandu commented 6 years ago

Good that worked out !!

I don't understand the color schemes. I'd like to change it to a bright green for the objects that are tall and a lighter green for the objects that are short.

You need to pass a custom colorRange prop to the layer, for what you are asking may be try this :

const colorRange = [
  [0, 100, 0],
  [0, 125, 0],
  [0, 150, 0],
  [0, 175, 0],
  [0, 200, 0],
  [0, 255, 0],
];

I also want to change the scale because there doesn't seem to be that big of a difference between objects with weight 1000+ and those with weights smaller than 1.

Use prop elevationScale, set it a value like 2 or 5, higher the value, taller will be the cells with hight count, default value is 1.

Also do check our docs, all the props are explained here : https://github.com/uber/deck.gl/blob/master/docs/layers/grid-layer.md

alldoami commented 6 years ago

Do you know how to do this in superset? I've tried adding both colorRange and elevationScale, but I don't think it knows what those are in its scope.

1chandu commented 6 years ago

Those are the props for GridLayer, I don't know about superset. Basically you have to find where this layer is used and provide those props.

alldoami commented 6 years ago

Ah I don't think there is a colorRange prop in the old version of deck gl unless I'm not looking in the right location.

SymbolixAU commented 6 years ago

When I supply my own colorRange I get various errors as shown in this console log

screen shot 2018-08-08 at 5 19 23 pm


Whereas if I leave it empty/default, the grids work

screen shot 2018-08-08 at 5 08 09 pm


I'm using a pure-JS implementation where my screen grid layer is

  const screengridLayer = new deck.ScreenGridLayer({
    id: 'screengrid-'+layer_id,  // TODO
    data: screengrid_data,
    opacity: opacity,
    cellSizePixels: cell_size,
    //colorRange: to_rgba( colour_range ),
    getPosition: d => decode_points( d.polyline ),
    getWeight: d => d.weight,
    onClick: info => layer_click( map_id, "screengrid", info )
  });
1chandu commented 6 years ago

@SymbolixAU , colorRange should be an array of 6 colors, it looks like you are providing only 5, that might be the problem.

1chandu commented 6 years ago

@SymbolixAU https://github.com/uber/deck.gl/pull/2172/files , improves colorRange documentation.

SymbolixAU commented 6 years ago

@1chandu yes, perfect thanks.

ibgreen commented 6 years ago

@1chandu - if we need such a specific length, maybe add an assert to help folks find this?

1chandu commented 6 years ago

@ibgreen we do have an assert, and it is failing resulting in first warning in above console image. And later it actually crashes when it is used as uniform.

https://github.com/uber/deck.gl/blob/544aab7cd5f76bce02a29d91e54b52b09be725f6/modules/layers/src/screen-grid-layer/screen-grid-layer.js#L330

1chandu commented 6 years ago

@alldoami , please open a separate issue if any, as this has been used for several different issues and is confusing.