Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Doc strings #41

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
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
17 changes: 12 additions & 5 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,19 @@ repos:
- id: black
args: ['--safe']
-
repo: 'https://github.com/pre-commit/pre-commit-hooks'
rev: v2.0.0
repo: https://gitlab.com/pycqa/flake8
rev: 3.8.0
hooks:
- id: flake8
args: [
- id: flake8
language_version: python3.6
additional_dependencies: [
'flake8-black',
'flake8-docstrings',
'flake8-bugbear',
'flake8-isort'
]
args: [
# E501 let black handle all line length decisions
# W503 black conflicts with "line break before operator" rule
# E203 black conflicts with "whitespace before ':'" rule
'--ignore=E501,W503,E203,W605']
'--ignore=D401,E501,W503,E203,W605']
5 changes: 4 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
"""Supermercado."""

import os
from codecs import open as codecs_open
from setuptools import setup, find_packages

from setuptools import find_packages, setup

# Get the long description from the relevant file
with codecs_open("README.md", encoding="utf-8") as f:
long_description = f.read()


def read(fname):
"""Filename."""
return open(os.path.join(os.path.dirname(__file__), fname)).read()


Expand Down
5 changes: 2 additions & 3 deletions supermercado/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
"""Supermercado."""

from __future__ import absolute_import
from . import edge_finder as edgetiles
from . import burntiles
from . import uniontiles
63 changes: 61 additions & 2 deletions supermercado/burntiles.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
import numpy as np
"""Burntile."""

import mercantile
import numpy as np
from affine import Affine

from rasterio import features


def project_geom(geom):
"""Project geometry.

Parameters
------------
geom: geojson

Returns
---------
json
"""
if geom["type"] == "Polygon":
return {
"type": geom["type"],
Expand All @@ -27,6 +38,7 @@ def project_geom(geom):


def _feature_extrema(geometry):
"""For each feature in geometry, return extrema."""
if geometry["type"] == "Polygon":
x, y = zip(*[c for part in geometry["coordinates"] for c in part])
elif geometry["type"] == "LineString":
Expand All @@ -39,6 +51,16 @@ def _feature_extrema(geometry):


def find_extrema(features):
"""For a collection of features, return extrema.

Parameters
------------
features: geojson

Returns
---------
tuple
"""
epsilon = 1.0e-10
min_x, min_y, max_x, max_y = zip(
*[_feature_extrema(f["geometry"]) for f in features]
Expand All @@ -53,6 +75,19 @@ def find_extrema(features):


def tile_extrema(bounds, zoom):
"""For given bounds and zoom, return extrema.

Parameters
------------
bounds: tuple
min(x), min(y), max(x), max(y)
zoom: int
Zoom level to burn.

Returns
---------
json
"""
minimumTile = mercantile.tile(bounds[0], bounds[3], zoom)
maximumTile = mercantile.tile(bounds[2], bounds[1], zoom)

Expand All @@ -63,6 +98,18 @@ def tile_extrema(bounds, zoom):


def make_transform(tilerange, zoom):
"""For given tilerange and zoom, create affine transformation.

Parameters
------------
tilerange: json
zoom: int
Zoom level to burn.

Returns
---------
Affine transformation object
"""
ulx, uly = mercantile.xy(
*mercantile.ul(tilerange["x"]["min"], tilerange["y"]["min"], zoom)
)
Expand All @@ -75,6 +122,18 @@ def make_transform(tilerange, zoom):


def burn(polys, zoom):
"""For a given geometry and zoom, return tiles.

Parameters
------------
polys: geojson
zoom: int
Zoom level to burn.

Returns
---------
numpy array
"""
bounds = find_extrema(polys)

tilerange = tile_extrema(bounds, zoom)
Expand Down
16 changes: 12 additions & 4 deletions supermercado/edge_finder.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,27 @@
import click, json, re
"""Edge finder."""

import numpy as np

from supermercado import super_utils as sutils


def findedges(inputtiles, parsenames):
"""For a given list of tiles, return tiles on the edges.

Parameters
------------
inputtiles: list
tiles in [x, y, z] format

Returns
---------
numpy array
"""
tiles = sutils.tile_parser(inputtiles, parsenames)

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

zoom = sutils.get_zoom(tiles)
# zoom = inputtiles[0, -1]

# make an array of shape (xrange + 3, yrange + 3)
burn = sutils.burnXYZs(tiles, xmin, xmax, ymin, ymax)
Expand All @@ -29,15 +38,14 @@ def findedges(inputtiles, parsenames):
)

# Set missed non-tiles to False
xys_edge[burn == False] = False
xys_edge[burn is False] = False

# Recreate the tile xyzs, and add the min vals
xys_edge = np.dstack(np.where(xys_edge))[0]
xys_edge[:, 0] += xmin - 1
xys_edge[:, 1] += ymin - 1

# Return the edge array

return np.append(
xys_edge, np.zeros((xys_edge.shape[0], 1), dtype=np.uint8) + zoom, axis=1
)
Expand Down
1 change: 1 addition & 0 deletions supermercado/scripts/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Supermercado script."""
22 changes: 11 additions & 11 deletions supermercado/scripts/cli.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
import click, json
"""CLI."""

import json

import click
import cligj
from supermercado import edge_finder, uniontiles, burntiles, super_utils

from supermercado import burntiles, edge_finder, super_utils, uniontiles


@click.group("supermercado")
def cli():
"""Cli."""
pass


@click.command("edges")
@click.argument("inputtiles", default="-", required=False)
@click.option("--parsenames", is_flag=True)
def edges(inputtiles, parsenames):
"""
For a stream of [<x>, <y>, <z>] tiles, return only those tiles that are on the edge.
"""
"""For a stream of [<x>, <y>, <z>] tiles, return only those tiles that are on the edge."""
try:
inputtiles = click.open_file(inputtiles).readlines()
except IOError:
Expand All @@ -34,9 +38,7 @@ def edges(inputtiles, parsenames):
@click.argument("inputtiles", default="-", required=False)
@click.option("--parsenames", is_flag=True)
def union(inputtiles, parsenames):
"""
Returns the unioned shape of a stream of [<x>, <y>, <z>] tiles in GeoJSON.
"""
"""Returns the unioned shape of a stream of [<x>, <y>, <z>] tiles in GeoJSON."""
try:
inputtiles = click.open_file(inputtiles).readlines()
except IOError:
Expand All @@ -54,9 +56,7 @@ def union(inputtiles, parsenames):
@cligj.sequence_opt
@click.argument("zoom", type=int)
def burn(features, sequence, zoom):
"""
Burn a stream of GeoJSONs into a output stream of the tiles they intersect for a given zoom.
"""
"""Burn a stream of GeoJSONs into a output stream of the tiles they intersect for a given zoom."""
features = [f for f in super_utils.filter_features(features)]

tiles = burntiles.burn(features, zoom)
Expand Down
53 changes: 53 additions & 0 deletions supermercado/super_utils.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,45 @@
"""Util."""

import json
import re

import numpy as np


def parseString(tilestring, matcher):
"""Parse string."""
tile = [int(r) for r in matcher.match(tilestring).group().split("-")]
tile.append(tile.pop(0))
return tile


def get_range(xyz):
"""Get min and max range of x and y.

Parameters
------------
xyz: numpy array

Returns
---------
tuple
xmin, xmax, ymin, ymax
"""
return xyz[:, 0].min(), xyz[:, 0].max(), xyz[:, 1].min(), xyz[:, 1].max()


def burnXYZs(tiles, xmin, xmax, ymin, ymax, pad=1):
"""Using the tile xys as indicides, burn in True where a tile exists.

Parameters
------------
tiles: numpy array
xmin, xmax, ymin, ymax: int

Returns
---------
numpy array
"""
# make an array of shape (xrange + 3, yrange + 3)
burn = np.zeros(
(xmax - xmin + (pad * 2 + 1), ymax - ymin + (pad * 2 + 1)), dtype=bool
Expand All @@ -27,6 +52,17 @@ def burnXYZs(tiles, xmin, xmax, ymin, ymax, pad=1):


def tile_parser(tiles, parsenames=False):
"""Convert list of tiles to numpy array.

Parameters
------------
inputtiles: list
tiles in [x, y, z] format

Returns
---------
numpy array
"""
if parsenames:
tMatch = re.compile(r"[\d]+-[\d]+-[\d]+")
tiles = np.array([parseString(t, tMatch) for t in tiles])
Expand All @@ -37,13 +73,24 @@ def tile_parser(tiles, parsenames=False):


def get_idx():
"""Create the indixes for rolling."""
tt = np.zeros((3, 3), dtype=bool)
tt[1, 1] = True

return np.dstack(np.where(~tt))[0] - 1


def get_zoom(tiles):
"""Get zoom level for given list of tiles.

Parameters
------------
tiles: numpy array

Returns
---------
int
"""
t, d = tiles.shape
if t < 1 or d != 3:
raise ValueError("Tiles must be of shape n, 3")
Expand All @@ -55,6 +102,7 @@ def get_zoom(tiles):


def filter_features(features):
"""Filter geometries based on type."""
for f in features:
if "geometry" in f and "type" in f["geometry"]:
if f["geometry"]["type"] == "Polygon":
Expand Down Expand Up @@ -84,11 +132,15 @@ def filter_features(features):


class Unprojecter:
"""Unproject."""

def __init__(self):
"""Should work as expected."""
self.R2D = 180 / np.pi
self.A = 6378137.0

def xy_to_lng_lat(self, coordinates):
"""Tile to latitude and longitude."""
for c in coordinates:
tc = np.array(c)
yield np.dstack(
Expand All @@ -100,5 +152,6 @@ def xy_to_lng_lat(self, coordinates):
)[0].tolist()

def unproject(self, feature):
"""Should work as expected."""
feature["coordinates"] = [f for f in self.xy_to_lng_lat(feature["coordinates"])]
return feature
Loading