Skip to contents

A general usage pattern of geoarrowWidget is to enable attaching data to an existing widget and then using some JavaScript to update/extend the functionality of the existing widget.

Using {listviewer} to examine a geoarrow file

As an example, we will use listviewer::jsonedit() to examine a geoarrow file.

First, we create some spatial data from scratch:

library(geoarrowWidget)
library(sf)
library(colourvalues)
library(nanoarrow)
library(geoarrow)
library(listviewer)

### generate some random sf points data ========================================
n = 1e3
dat = data.frame(
  id = 1:n
  , x = runif(n, -160, 160)
  , y = runif(n, -40, 40)
)
dat = st_as_sf(
  dat
  , coords = c("x", "y")
  , crs = 4326
)
dat$fillColor = color_values(
  rnorm(nrow(dat))
  , alpha = sample.int(255, nrow(dat), replace = TRUE)
)
dat$lineColor = color_values(
  rnorm(nrow(dat))
  , alpha = sample.int(255, nrow(dat), replace = TRUE)
  , palette = "inferno"
)
dat$radius = sample.int(15, nrow(dat), replace = TRUE)
dat$lineWidth = sample.int(5, nrow(dat), replace = TRUE)

Then, we convert to and save the data as a geoarrow file:

fl = tempfile()
dir.create(fl)
path = file.path(
  fl
  , "test.arrow"
)

interleaved = TRUE

data_stream = nanoarrow::as_nanoarrow_array_stream(
  dat
  , geometry_schema = geoarrow::infer_geoarrow_schema(
    dat
    , coord_type = ifelse(interleaved, "INTERLEAVED", "SEPARATE")
  )
)

nanoarrow::write_nanoarrow(data_stream, path)

Next, we create an empty listviewer widget and attach the relevant JavaScript libraries and the geoarrow file:

js = jsonlite::toJSON("")
wgt = listviewer::jsonedit(js, elementId = "lv-example")

wgt$dependencies = c(
  wgt$dependencies
  , geoarrowWidget:::arrowJSDependencies()
  , geoarrowWidget:::geoarrowJSDependencies()
  , geoarrowWidget:::.dataAttachment(
    file = path
    # url = "https://geoarrow-test.s3.eu-central-1.amazonaws.com/test_layer_interleaved.arrow"
    , name = "mydata"
  )
)

Finally, we specify the JavaScript code that handles the population of the created JsonEditor in the browser with our geoarrow data and render the widget.

js_code = htmlwidgets::JS(
  'function (el, x, data) {

        // helper function to extract data from arrow table as arrays
        // adapted from https://stackoverflow.com/a/78524270
        
        function extractDataFromTable(table) {
          const result = {};
          
          // table.schema.fields is an Array of Field objects
          // which hold information about the column including its name
          
          for(let field of table.schema.fields) {
            // use the field name to extract the column as a Vector from the table
          
            const vector = table.getChild(field.name);
            
            if(!vector) {
              continue;
            }
            
            //convert the Vector to an Array.
            //this gives you all the values in the column as an array
            
            if (vector.numChildren > 0) {
              result[field.name] = [vector.toArray()];
            } else {
              result[field.name] = [vector.toJSON()];
            }
            
          }
          
          return result;
        }

        // find data attachment in document
        
        let data_fl = document.getElementById(data.id + "-geoarrowWidget-attachment");
        
        // find listviewer jsonedit element in document and delete current contents
        
        let jse = document.getElementById("lv-example");
        jse.innerHTML = null;

        // load data from attachment into jsonedit element identified and emptied earlier
        
        fetch(data_fl.href)
          .then(result => Arrow.tableFromIPC(result))
          .then(arrow_table => {

            let newed = new JSONEditor.JSONEditor({
              target: jse, 
              props: {
                content: { 
                  //json: JSON.parse(arrow_table.toString())
                  json: [
                    Object(extractDataFromTable(arrow_table))
                  ]
                }
              }
            });
            
            //debugger;
            //console.log(arrow_table);

          });
  }'
)

htmlwidgets::onRender(wgt, js_code, data = list(id = "mydata"))