npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

vt-grid

v4.1.1

Published

Build up a pyramid of vector tiles by aggregating quantitative data into grids at lower zooms.

Downloads

33

Readme

vt-grid

Build up a pyramid of Mapbox vector tiles by aggregating quantitative data into grids at lower zooms.

Motivation

Say you have a dataset of polygons that have some kind of density data (population, vegetation, ...), and you want to build an interactive map with it. Vector tiles are great for this--especially with mapbox-gl steadily maturing.

But if your data is at a fine resolution and you don't want to be limited to very high zoom levels, you're stuck using standard simplification techniques. (Or, much better, the rather badass and blazingly fast simplification and point dropping techniques offered by tippecanoe). For many cases, this works great, but it's not ideal here: for instance, in simplification many small, high-density polygons get dropped, even though these are often important features.

This tool is an alternative to simplification: using a grid whose resolution varies with zoom level, aggregate the quantitative features of interest, so that you can visualize the spatial distribution of your data at any scale.

Installation

Install tippecanoe, and then:

npm install -g vt-grid

Usage

To start, you'll need an mbtiles file containing the original feature data at some (high) zoom level. If you've got the data in, say, a shapefile or PostGIS, you can use Mapbox Studio to create a source and then export to MBTiles -- just set the min and max zoom to something high enough.

CLI

Let's say you've got the data in data.mbtiles, at zoom 12 in a layer called 'foo', and each polygon in this layer has a field called density. Then, you can build the grid pyramid above this base layer with:

vt-grid input.mbtiles -o output.mbtiles --basezoom 12 --minzoom 1 --gridsize 16 \
 --aggregations 'foo:areaWeightedMean(density)'

Starting at zoom 11 and going down to zoom 1, this will build a 16x16 grid in each tile, aggregating the data from the zoom level above. The aggregations are defined by the --aggregations parameters. Each one is of the form: layer:aggregationFunction(field), where aggregationFunction can be any of the built-in aggregations available in geojson-polygon-aggregate. So, in this case, we'll end up with a grid where each box has a density property, which is the (correctly weighted) mean of the densities of the polygons from the previous (higher) zoom level that fall within that box.

With other aggregations, other stats. For instance, we could have done:

# first use count() to find out the number of polygons from the original
# dataset being aggregated into each grid box at z11
vt-grid input.mbtiles output.mbtiles --basezoom 12 --minzoom 11 --gridsize 16 \
  --aggregations 'foo:areaWeightedMean(density)' 'foo:count(numzones)'

# now, for z10 and below, sum the counts
vt-grid input.mbtiles output.mbtiles --basezoom 12 --minzoom 11 --gridsize 16 \
  --aggregations 'foo:areaWeightedMean(density)' 'foo:sum(numzones)'

Node

You can have a little more flexibility with aggregations (and post-aggregation functions) by using vt-grid programmatically:

var path = require('path')
var vtGrid = require('vt-grid')
var reducers = require('geojson-polygon-aggregate/reducers')

if (require.main === module) {
  vtGrid('/path/to/output.mbtiles', 'path/to/input.mbtiles', {
    minzoom: 1,
    basezoom: 10,
    aggregations: __filename, // this can be any file that exports an `aggregations` object like the one below
    postAggregations: __filename // same for this
  }, function (err) {
    if (err) { throw err }
    console.log('Finished!')
  })
}

module.exports = {
  aggregations: {
    footprints: {
      FID: reducers.union('FID'),
      someField: function myCustomAggregator (memo, feature) {
        var newMemo = -1
        // do stuff, works like an Array.reduce() function
        return newMemo
      }
    }
  },
  postAggregations: {
    footprints: {
      // called on each grid square feature after all aggregations are run, with
      // the result added to its properties under the given key (unique_count)
      unique_count: function (feature) {
        return feature.properties.FID ? JSON.parse(feature.properties.FID).length : 0
      }
    }
  }
}

This yields features that look like:

{
  "type": "Feature",
  "geometry": {
    "type": "Polygon",
    "coordinates": [
      [
        [
          -111.09375,
          40.97989806962016
        ],
        [
          -111.09375,
          40.9964840143779
        ],
        [
          -111.07177734375,
          40.9964840143779
        ],
        [
          -111.07177734375,
          40.97989806962016
        ],
        [
          -111.09375,
          40.97989806962016
        ]
      ]
    ]
  },
  "properties": {
    "FID": "[59, 707, 1002]",
    "unique_count": 3,
    "someField": -1
  }
}

API

vtGrid

Build a pyramid of aggregated square-grid features.

Parameters

  • output string Path to output aggregated mbtiles data
  • input string Path to the input mbtiles data
  • opts (Object|Array) Options OR an array of options objects to allow different aggregations/settings for different zoom levels
    • opts.basezoom number The zoom level at which to find the initial data
    • opts.inputTiles Array= An array of [z, x, y] tile coordinates to start with
    • opts.gridsize number Number of grid squares per tile
    • opts.aggregations (Object|string) If an object, then it maps layer names to aggregation objects, which themselves map field names to geojson-polygon-aggregate aggregation function names. Each worker will construct the actual aggregation function from geojson-polygon-aggregate by passing it the field name as an argument. If a string, then it's the path of a module that exports a layer to aggregation object map (see #grid for details).
    • opts.postAggregations string= Path to a module mapping layer names to postAggregations objects. See #grid for details.
    • opts.jobs number The number of jobs to run in parallel.
  • done function called with (err) when done

Built With

  • Turf.js, geojson-vt, and several other super fly modules by Mapbox
  • Also, several conversations with @morganherlocker (the author of many of the aforementioned modules, including Turf.)