Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issues using Deck with Geoarrow #132

Open
janneskruseMapular opened this issue Jun 26, 2024 · 5 comments
Open

Issues using Deck with Geoarrow #132

janneskruseMapular opened this issue Jun 26, 2024 · 5 comments

Comments

@janneskruseMapular
Copy link

janneskruseMapular commented Jun 26, 2024

Hi Kyle,
first of all: Amazing work that you are doing! Thank you!

I just found your library and was trying out some of the things. From a blog of you I found earlier, I got this internet speeds dataset:
https://observablehq.com/@kylebarron/geoparquet-on-the-web.

And i wanted to make it run with your library but were getting into "not a polygon or multipolygon" errors when loading the parquet via parquet-wasm and then using your GeoarrowSolidpolygon layer.
For geoparquet-wasm I run into some errors of the wasm initialization. Maybe some of the parts you are doing here: https://github.com/developmentseed/lonboard/blob/main/src/parquet.ts are missing in the documentation :)

So in the end I tried to implement it with a feather of the centroids directly like you are doing in the blog. I had to adjust it somehow a little as you can see below, but am at least getting the same layer now from what I can see.
However, this layer is not showing on the map. If you could have a look, I would really appreciate it. Maybe you can spot the error I am not seeing.

So this is my script:

import React, { use, useEffect, useRef, useState } from "react";
import {Map, useControl} from 'react-map-gl';
import {MapboxOverlay} from '@deck.gl/mapbox';
import {DeckProps} from '@deck.gl/core';
import {ScatterplotLayer} from '@deck.gl/layers';
import 'mapbox-gl/dist/mapbox-gl.css';
import { Table, tableFromIPC } from "apache-arrow";
import { fromArrow, names } from 'arquero';
// import * as d3 from 'd3';

const MAPBOX_ACCESS_TOKEN = process.env.NEXT_PUBLIC_MAPBOX_ACCESS_TOKEN;

function DeckGLOverlay(props: DeckProps) {
  const overlay = useControl<MapboxOverlay>(() => new MapboxOverlay(props));
  overlay.setProps(props);
  return null;
}

async function fetchData() {
  try {
    // // Fetch Feather file
    const resp = await fetch("/data/2019-01-01_performance_mobile_tiles_uncomp.feather");
    if (!resp.ok) {
      throw new Error(`Failed to fetch Parquet file: ${resp.statusText}`);
    }
    // convert the response to an Arrow Table
    const arrayBuffer = await resp.arrayBuffer();
    const jsTable = tableFromIPC(new Uint8Array(arrayBuffer));

    let dt = fromArrow(jsTable);
    console.log("Arquero table", dt);
    const geometryColumn = jsTable.getChild('geometry');
    const colorsColumn = jsTable.getChild('colors');

    // Loop through each chunk in the geometryColumn.data array
    let allCoordinates = [];
    geometryColumn.data.forEach(chunk => {
      const coordinateValues = chunk.children[0].values;
      allCoordinates = allCoordinates.concat(coordinateValues);
    });

    // Create a new Float64Array with the total length times 2 (x, y)
    const totalLength = geometryColumn.length*2;
    const concatenatedArray = new Float64Array(totalLength);

    // Copy each Float64Array into the concatenatedArray
    let offset = 0;
    allCoordinates.forEach(array => {
      concatenatedArray.set(array, offset);
      offset += array.length;
    });

    // Loop through each chunk in the colors data array
    let allColors = [];
    colorsColumn.data.forEach(chunk => {
      const colorValues = chunk.children[0].values;
      allColors = allColors.concat(colorValues);
    });

    // new Float32Array with the total length times 3 (RGB)
    const totalColorLength = jsTable.getChild('colors').length*3;
    const concatenatedColorArray = new Float32Array(totalColorLength);

    // Copy each Float64Array into the concatenatedColorArray
    let colorOffset = 0;
    allColors.forEach(array => {
      concatenatedColorArray.set(array, colorOffset);
      colorOffset += array.length;
    });

    // Create the data object for the ScatterplotLayer (size: 2 for x, y and size: 3 for RGB)
    const data = [{
      length: jsTable.numRows,
      attributes: {
        getPosition: {value: concatenatedArray, size: 2 },
        getFillColor: { value: concatenatedColorArray, size: 3 }
      },
    }];

    return data;
  }
  catch (error) {
    console.error("Error fetching data", error);
  }
}

function InteractiveMap(): JSX.Element {
  const [layers, setLayers] = useState([
    new ScatterplotLayer({
      id: 'deckgl-circle',
      data: [
        {position: [0.45, 51.47]}
      ],
      getPosition: d => d.position,
      getFillColor: [255, 0, 0, 100],
      getRadius: 1000,
      beforeId: 'waterway-label' // In interleaved mode render the layer under map labels
    })
  ]);

  useEffect(() => {
    fetchData().then(data => {
      setLayers([
        new ScatterplotLayer({
          id: 'deckgl-circle2',
          data: [
            {position: [0.45, 51.47]}
          ],
          getPosition: d => d.position,
          getFillColor: [0, 130, 0, 100],
          getRadius: 1000,
          beforeId: 'waterway-label' // In interleaved mode render the layer under map labels
        }),
        new ScatterplotLayer({
          id: 'internet-speeds',
          data: data,
          getRadius: 100,
          radiusMinPixels: 0.4,
          beforeId: 'waterway-label' // In interleaved mode render the layer under map labels
        })
      ]);
    });
  }, []);

  useEffect(() => {
    console.log("Layers", layers);
  }
  , [layers]);

  return (
    <Map
      style={{  height: "100vh" }} // width: "100%",
      initialViewState={{
        longitude: 0.45,
        latitude: 51.47,
        zoom: 11
      }}
      mapStyle="mapbox://styles/mapbox/dark-v9" // {Mapstyles.dark}
      mapboxAccessToken={MAPBOX_ACCESS_TOKEN}
    >
      <DeckGLOverlay layers={layers} interleaved />
    </Map>
  );
}

const InteractiveMapMemo = React.memo(InteractiveMap);
export default InteractiveMapMemo;

This is the layer it produces:

1: Object { id: "internet-speeds", count: 14, lifecycle: "Initialized", … }
context: Object { mousePosition: {…}, userData: {}, layerManager: {…}, … }
count: 14
id: "internet-speeds"
internalState: Object { needsRedraw: false, needsUpdate: false, usesPickingColorCache: false, … }
lifecycle: "Initialized"
parent: null
props: Object { id: "internet-speeds", getRadius: 100, radiusMinPixels: 0.4, … }
	beforeId: "waterway-label"
	getRadius: 100
	id: "internet-speeds"
	radiusMinPixels: 0.4
	Symbol(component): Object { id: "internet-speeds", count: 14, lifecycle: "Initialized", … }
	Symbol(asyncPropOriginal): Object {  }
	Symbol(asyncPropResolved): Object { data: (1) […] }
		data: Array [ {…} ]
		0: Object { length: 3231245, attributes: {…} }
		attributes: Object { getPosition: {…}, getFillColor: {…} }
			getFillColor: Object { value: Float32Array(9693735), size: 3 }
				size: 3
				value: Float32Array(9693735) [ 0.6862902045249939, 0.8649733066558838, 0.843987226486206, … ]
				<prototype>: Object { … }
			getPosition: Object { value: Float64Array(6462490), size: 2 }
				size: 2
				value: Float64Array(6462490) [ -160.0186157226565, 70.63721610566131, -160.04058837890648, … ]
				<prototype>: Object { … }
			<prototype>: Object { … }
			length: 3231245
			<prototype>: Object { … }
			length: 1
			<prototype>: Array []
		<prototype>: Object { … }
	<prototype>: Object { data: Getter & Setter, visible: true, pickable: false, … }
state: Object { model: {…}, … }
<prototype>: Object { … }

Thanks a lot!

@kylebarron
Copy link
Member

And i wanted to make it run with your library but were getting into "not a polygon or multipolygon" errors

It's not clear to me; were you trying to render points with the solid polygon layer?

You can only use the SolidPolygonLayer with Polygon or MultiPolygon data, and the geometries need to be in native GeoArrow format, not WKT or WKB.

geoparquet-wasm

geoparquet-wasm isn't really production ready yet. But you can read the README of parquet-wasm, which has most of the same information.

However, this layer is not showing on the map

First try to render with a single color for all points, so then you know the geometry data is at least rendering. You may have to set radius_min_pixels to ensure data are rendered at your current zoom level

@janneskruseMapular
Copy link
Author

Thanks a lot for the quick response! Radius_min_pixels actually helped to notice, that the points are all rendered at origin (see screenshot). I am trying with the centroids created from you python script.
image

Might this be because I am using the Mapbox Overlay for Deck?

I also tried with the /examples/point setup, but get the following errors:
image

@kylebarron
Copy link
Member

I don't have a lot of bandwidth to help with this, and screenshots aren't reproducible. You should ensure that you can run the /examples/point demo as is without changing the data source, and then you can inspect what's different with your data compared to its data.

The reason I've focused on Lonboard is that it's easier to create GeoArrow-formatted data in Python than in JS, and there aren't a lot of resources yet for creating this data format in JS proper

@janneskruseMapular
Copy link
Author

Yes, also I think it is more of a problem with deck.gl, as also for random data it renders at origin. I started a discussion there.
Thank you anyways!
About the demo: I am running it as is in the folder and using the same data with the same script, but it throws those "destructered parameters" errors.

@kylebarron
Copy link
Member

Oh perhaps that's an issue with #124. The main library is using deck.gl v9 now but the examples (or at least the yarn.lock) hasn't been updated to use deck.gl v9, so there may be a version mismatch

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants