visgl / deck.gl

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

hexagon layer with height column #1852

Closed localdevjs closed 5 years ago

localdevjs commented 6 years ago

I'm trying to get the hexagon layer/heatmap chart working with a height column. So my csv has 3 columns: lng,lat,height. Each lng/lat value will only occur once in the csv, but the height value is then used to determine how high to build that hex cell.

From what I understand, I should be looking at the "getElevationValue" function. But I'm not sure how to apply that function to my csv data? Is there a quick code example somewhere that demonstrates this?

Thanks in advance!

danmarshall commented 6 years ago

In this example they are using the getPosition function here. You would just add getElevationValue in the sample place.

localdevjs commented 6 years ago

ok, but what is "d"? Is that a row in my csv? Is that some javascript object? How do I know what value to return in the getElevationValue? My question is that in the "getElevationValue", somehow I have to dig back into my csv and retrieve the height value for the current lat/lng pair.

danmarshall commented 6 years ago

Yes it appears that each row in your csv will become an object. See https://github.com/uber/deck.gl/blob/5.2-release/examples/website/3d-heatmap/app.js#L30

The object should have property names which are the column titles in the csv.

veikkoeeva commented 6 years ago

@danmarshall It looks like the problem is that the parameter is the points in the given bin and by default it returns the length of that bin. If that's the case, I don't see there is a way to set the height of the bar via explicit value. One option would be to preprocess the data.

I see there's a similar question at https://github.com/uber/deck.gl/issues/829, but I don't know how to proceed with that. Maybe @heshan0131 can kindly chime in? :) Specifically I don't know how to actually do the subclassing (for a reason or another). I can handle the data and get things to draw by returning random numbers like so (to paraphrase the examples)

const csvData = d3.csv(DATA_URL);
hexagonLayer = new MapboxLayer({
    type: HexagonLayer,
    id: 'heatmap',
    data: csvData,
    radius: 1000,
    coverage: 1,
    upperPercentile: 100,
    colorRange: COLOR_RANGE,
    elevationRange: [0, 1000],
    elevationScale: 25,
    getElevationValue: points => Math.floor(Math.random() * 5),
    extruded: true,
    getPosition: d => [Number(d.lon), Number(d.lat)],
    lightSettings: LIGHT_SETTINGS,
    onHover: true,
    opacity: 0.5
}); 

// Add the deck.gl hex layer below labels in the Mapbox map
map.addLayer(hexagonLayer, "waterway");

I prepared some data at https://gist.githubusercontent.com/veikkoeeva/29cdb7e5cf9438a8e0181c9e5d8a99b8/raw/4640ef338dfd672e8e83228ff19003f7c27c0301/data.csv, just in case someone has the time to help here (it's data around China, Vietnam, Philippines).

Immediately writing that I realize I should write getElevationValue: points => Number(points[0].val), and it works. I feel dumb now. I excuse myself to bed now, it's wee ours here. Thank you for rubberducking me. :)

hijiangtao commented 5 years ago

@danmarshall I thought there's more than one modification that developers should concern about when they want to customize the elevation value via their own data,getColorValue is required at least since we change the display elevation of our map.

@veikkoeeva I think the problem you met can be resolved in this way.

Suppose your data is consists of many points, and you have property SPACES to defined the height you want to show:

[{
    COORDS: [lng, lat],
    SPACES: Math.random()*100,
    ...
}, ...]

you can iterate the elevation input and take out the result from it in this way:

const getElevationValue = d => d.reduce(
    (accumulator, currentValue) => currentValue ? 
        accumulator + currentValue.SPACES : accumulator, 
    0
),

the input format can be found like this:

[
    {}, // YOUR ORIGINAL POINT
    {}, // YOUR ORIGINAL POINT
    ...
    x: NUMBER,
    y: NUMBER,
]

the same approach can be applied in getColorValue method, for rendering the right color corresponding each hexagon with your customized height in getElevationValue method.

The issue #829 can be resolved by this way, too. Last, if your data not met the format of default data format, you should also define getPosition to get your project work well.

veikkoeeva commented 5 years ago

@hijiangtao I appreciate very much your points and the issue you created and linked. It describes pretty much the things I was searching for (had some hiatus but returning to this topic in the coming weeks).

Ashirogi-Muto commented 3 years ago

I am trying to achieve the same result where I have property which I wanna use to define the height of the cells.

const layers = [
    new HexagonLayer({
        id: 'crowding-pattern',
    colorRange,
    coverage: 1,
    data,
    elevationRange: [0, 1000],
    elevationScale: 50,
    extruded: true,
    getPosition: d => d.coordinates,
    pickable: true,
        radius: 20,
    upperPercentile: 100,
    material,
    getElevationValue: d => {
        const { weight } = d[0]
        return weight * 100
    },
    transitions: {
        getElevationValue: { duration: 800 }
    }
    })
]

I have gone through the other issues related to this but the cells that get drawn have no height! Am I missing something?