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)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:
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"))