Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions supermercado/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
from . import edge_finder as edgetiles
from . import burntiles
from . import uniontiles
from . import tile_density
22 changes: 21 additions & 1 deletion supermercado/scripts/cli.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import click, json
import cligj
from supermercado import edge_finder, uniontiles, burntiles, super_utils
from supermercado import edge_finder, uniontiles, burntiles, super_utils, tile_density


@click.group("supermercado")
Expand Down Expand Up @@ -49,6 +49,26 @@ def union(inputtiles, parsenames):
cli.add_command(union)


@click.command("heatmap")
@click.argument("inputtiles", default="-", required=False)
@click.option("--parsenames", is_flag=True)
def heatmap(inputtiles, parsenames):
"""
Returns the unioned shape of a stream of [<x>, <y>, <z>] tiles in GeoJSON.
"""
try:
inputtiles = click.open_file(inputtiles).readlines()
except IOError:
inputtiles = [inputtiles]
density_feautures = tile_density.heatmap(inputtiles, parsenames)

for u in density_feautures:
click.echo(json.dumps(u))


cli.add_command(heatmap)


@click.command("burn")
@cligj.features_in_arg
@cligj.sequence_opt
Expand Down
79 changes: 79 additions & 0 deletions supermercado/tile_density.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import numpy as np

from supermercado import super_utils as sutils
from rasterio import features, Affine
import mercantile


def create_density(tiles, xmin, xmax, ymin, ymax, pad=1):
"""Given an ndarray or tiles and range,
create a density raster of tile frequency
"""
burn = np.zeros(
(xmax - xmin + (pad * 2 + 1), ymax - ymin + (pad * 2 + 1)), dtype=np.uint32
)

tiles, counts = np.unique(tiles, return_counts=True, axis=0)

burn[(tiles[:, 0] - xmin + pad, tiles[:, 1] - ymin + pad)] = counts

return burn


def heatmap(inputtiles, parsenames):
"""Creates a vector "heatmap" of tile densities

Parameters
----------
inputtiles: sequence of [x, y, z] or strings
tiles to create a density heatmap from
parsenames: boolean
parse tile names from strings

Returns
-------
density_features: generator
sequence of features
"""
tiles = sutils.tile_parser(inputtiles, parsenames)

xmin, xmax, ymin, ymax = sutils.get_range(tiles)

zoom = sutils.get_zoom(tiles)

# make an array of shape (xrange + 3, yrange + 3)
burn = sutils.burnXYZs(tiles, xmin, xmax, ymin, ymax, 0)

nw = mercantile.xy(*mercantile.ul(xmin, ymin, zoom))

se = mercantile.xy(*mercantile.ul(xmax + 1, ymax + 1, zoom))

aff = Affine(
((se[0] - nw[0]) / float(xmax - xmin + 1)),
0.0,
nw[0],
0.0,
-((nw[1] - se[1]) / float(ymax - ymin + 1)),
nw[1],
)

unprojecter = sutils.Unprojecter()

density = create_density(tiles, xmin, xmax, ymin, ymax)

density = np.asarray(np.flipud(np.rot90(density)).astype(np.uint8), order="C")

density_features = (
{
"geometry": unprojecter.unproject(feature),
"properties": {"n": count},
"type": "Feature",
}
for feature, count in features.shapes(
density,
mask=density > 0,
transform=aff,
)
)

return density_features