block by timelyportfolio 2239f04ed0d6ffa6868aac90a8afed1a

geo pivot table with turf

Full Screen

Great Idea - Geo Pivot Table

I had this idea yesterday afternoon as I combined Tom MacWright’s library simple-statistics for custom aggregation in Nicolas Kructhen’s amazing pivottable. Well, Tom works at Mapbox, and I have been doing some geo recently, so I thought

*Wouldn’t a geo pivot table be something amazing?! *

Quick Dirty Example

For those that don’t know, many fine folks at Mapbox make another fantastic open source library turf which can provide pivottable aggregators for geo features. I’ll put it all together in R using the htmlwidget rpivotTable. The R package randgeo will supply some random polygons as seed data. This idea deserves much better than this quick sketch, but for now offer a centroid and centerOfMass aggregator.

library(rpivotTable)
library(tibble)
library(randgeo)
library(htmltools)
library(dplyr)

n = 30
df_geos <- tibble(
  ltr_cat = letters[floor(runif(n, 1, 5))],
  rand_poly = lapply(1:n, function(x) {geo_polygon(count=10)})
)

rpvt <- rpivotTable(
  df_geos,
  aggregators = htmlwidgets::JS(
    '{turf_centroid: turf_centroid(), turf_centermass: turf_centermass()}'
  )
)

# rpivotTable auto boxes everything except inclusions and exclusions
#  https://github.com/smartinsightsfromdata/rpivotTable/blame/master/R/rpivotTable.R#L110-L117
#  so we need to unbox or unlist
rpvt$x$params$aggregators <- rpvt$x$params$aggregators[[1]]

tagList(
  tags$script(src = "https://unpkg.com/@turf/turf/turf.min.js"),
  tags$script(
"
var turf_centroid = function(formatter) {
  if (formatter == null) {
    formatter = function(d){return JSON.stringify(d)}
  }
  return function(arg) {
    var attr;
    attr = arg[0];
    return function(data, rowKey, colKey) {
      return {
        arr: [],
        push: function(record) {
          var that = this;
          if(attr) {record[attr].features.forEach(function(d) {that.arr.push(d)});}
        },
        value: function() {
          return typeof(this.arr[0]) !== 'undefined'  ?
            turf.centroid(turf.featureCollection(this.arr)) :
            null;
        },
        format: formatter,
        numInputs: attr != null ? 0 : 1
      };
    };
  };
}

var turf_centermass = function(formatter) {
  if (formatter == null) {
    formatter = function(d){return JSON.stringify(d)}
  }
  return function(arg) {
    var attr;
    attr = arg[0];
    return function(data, rowKey, colKey) {
      return {
        arr: [],
        push: function(record) {
          var that = this;
          if(attr) {record[attr].features.forEach(function(d) {that.arr.push(d)});}
        },
        value: function() {
          return this.arr.length  ?
            turf.centerOfMass(turf.featureCollection(this.arr)) :
            null;
        },
        format: formatter,
        numInputs: attr != null ? 0 : 1
      };
    };
  };
}
"
  ),
  rpvt
  ) %>%
  browsable()

Help and Idea

I would love any help, ideas, feedback, examples. Please let me know what you are thinking.