Skip to content
Merged
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
307 changes: 201 additions & 106 deletions mapshader/tests/test_tile_utils.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import pytest

import numpy as np

import datashader as ds
import geopandas as gpd
import spatialpandas as spd
from shapely.geometry import Polygon, Point, LineString

from mapshader.sources import VectorSource
from mapshader.sources import VectorSource, RasterSource

from mapshader.tile_utils import (
get_tile,
render_tiles_by_extent,
Expand All @@ -19,107 +23,171 @@


@pytest.fixture
def full_map_polygon_vector_source(min_zoom, max_zoom):

if min_zoom > max_zoom:
polygon_source = None
else:
# create a polygon that fully covers the whole map
lat_point_list = [85.05112878, -85.05112878, -85.05112878, 85.05112878, 85.05112878]
lon_point_list = [-180, -180, 180, 180, -180]
polygon_geom = Polygon(zip(lon_point_list, lat_point_list))
crs = {'init': 'epsg:4326'}
polygon_gdf = gpd.GeoDataFrame(index=[0], crs=crs, geometry=[polygon_geom])

# construct transforms
buffered_extent_transform = dict(name='add_projected_buffered_extent',
args=dict(crs='4326',
buffer_distance=.01,
geometry_field='geometry'))
transforms = [buffered_extent_transform]
# construct value obj
source_obj = dict()
source_obj['geometry_type'] = 'polygon'
source_obj['data'] = polygon_gdf
source_obj['transforms'] = transforms
source_obj['tiling'] = dict(
min_zoom=min_zoom,
max_zoom=max_zoom,
xmin_field='buffer_0_4326_xmin',
xmax_field='buffer_0_4326_xmax',
ymin_field='buffer_0_4326_ymin',
ymax_field='buffer_0_4326_ymax',
)

# VectorSource from source object we created above
polygon_source = VectorSource.from_obj(source_obj)
polygon_source.load()
def polygon_gdf():
# create a polygon that fully covers the whole map
lat_point_list = [85.05112878, -85.05112878, -85.05112878, 85.05112878, 85.05112878]
lon_point_list = [-180, -180, 180, 180, -180]
geom = Polygon(zip(lon_point_list, lat_point_list))
gdf = gpd.GeoDataFrame(
index=[0], crs={'init': 'epsg:4326'}, geometry=[geom]
)
gdf['xmin'] = -180
gdf['xmax'] = 180
gdf['ymin'] = -85.05112878
gdf['ymax'] = 85.05112878
return gdf


@pytest.fixture
def polygon_vector_source(min_zoom, max_zoom, polygon_gdf):
source_obj = dict()
source_obj['geometry_type'] = 'polygon'
source_obj['data'] = polygon_gdf
source_obj['tiling'] = dict(
min_zoom=min_zoom,
max_zoom=max_zoom,
xmin_field='xmin',
xmax_field='xmax',
ymin_field='ymin',
ymax_field='ymax',
)
polygon_source = VectorSource.from_obj(source_obj)
return polygon_source, min_zoom, max_zoom


@pytest.fixture
def polygon_raster(polygon_gdf):
xrange = (-180, 180)
yrange = (-90, 90)
width = 360
height = 180
cvs = ds.Canvas(plot_width=width, plot_height=height, x_range=xrange, y_range=yrange)
raster = cvs.polygons(spd.GeoDataFrame(polygon_gdf), geometry='geometry')
return raster


@pytest.fixture
def polygon_raster_source(min_zoom, max_zoom, polygon_raster):
source_obj = dict()
source_obj['geometry_type'] = 'raster'
source_obj['data'] = polygon_raster
source_obj['tiling'] = dict(
min_zoom=min_zoom,
max_zoom=max_zoom,
)
polygon_source = RasterSource.from_obj(source_obj)
polygon_source.load()
return polygon_source, min_zoom, max_zoom


@pytest.fixture
def point_vector_source(min_zoom, max_zoom):
if min_zoom > max_zoom:
point_source = None
else:
# create a point at (0, 0)
point = Point(0, 0)
crs = {'init': 'epsg:4326'}
point_gdf = gpd.GeoDataFrame(index=[0], crs=crs, geometry=[point])
point_gdf['x'] = [point.x]
point_gdf['y'] = [point.y]

# construct value obj
source_obj = dict()
source_obj['geometry_type'] = 'point'
source_obj['data'] = point_gdf
source_obj['tiling'] = dict(
min_zoom=min_zoom,
max_zoom=max_zoom,
xmin_field='x',
xmax_field='x',
ymin_field='y',
ymax_field='y',
)

# VectorSource from source object we created above
point_source = VectorSource.from_obj(source_obj)
def point_gdf():
# create a point at (0, 0)
geom = Point(0, 0)
crs = {'init': 'epsg:4326'}
gdf = gpd.GeoDataFrame(index=[0], crs=crs, geometry=[geom])
gdf['x'] = [geom.x]
gdf['y'] = [geom.y]
return gdf


@pytest.fixture
def point_vector_source(min_zoom, max_zoom, point_gdf):
source_obj = dict()
source_obj['geometry_type'] = 'point'
source_obj['data'] = point_gdf
source_obj['tiling'] = dict(
min_zoom=min_zoom,
max_zoom=max_zoom,
xmin_field='x',
xmax_field='x',
ymin_field='y',
ymax_field='y',
)
point_source = VectorSource.from_obj(source_obj)
return point_source, min_zoom, max_zoom


@pytest.fixture
def point_raster(point_gdf):
xrange = (1e-5, 0)
yrange = (-1e-5, 0)
width = 1
height = 1
cvs = ds.Canvas(plot_width=width, plot_height=height, x_range=xrange, y_range=yrange)
raster = cvs.points(spd.GeoDataFrame(point_gdf), geometry='geometry').astype(np.float32)
return raster


@pytest.fixture
def point_raster_source(min_zoom, max_zoom, point_raster):
source_obj = dict()
source_obj['geometry_type'] = 'raster'
source_obj['data'] = point_raster
source_obj['tiling'] = dict(
min_zoom=min_zoom,
max_zoom=max_zoom,
)
# RasterSource from source object we created above
point_source = RasterSource.from_obj(source_obj)
return point_source, min_zoom, max_zoom


@pytest.fixture
def line_vector_source(min_zoom, max_zoom):
if min_zoom > max_zoom:
line_source = None
else:
# create a horizontal line y=0 crossing 2 points (-180, 0), and (180, 0)
p1 = Point(-180, 0)
p2 = Point(180, 0)
line = LineString([p1, p2])
line_gdf = gpd.GeoDataFrame(index=[0], crs={'init': 'epsg:4326'}, geometry=[line])
line_gdf['xmin'] = [p1.x]
line_gdf['ymin'] = [p1.y]
line_gdf['xmax'] = [p2.x]
line_gdf['ymax'] = [p2.y]

# construct value obj
source_obj = dict()
source_obj['geometry_type'] = 'line'
source_obj['data'] = line_gdf
source_obj['tiling'] = dict(
min_zoom=min_zoom,
max_zoom=max_zoom,
xmin_field='xmin',
xmax_field='xmax',
ymin_field='ymin',
ymax_field='ymax',
)

# VectorSource from source object we created above
line_source = VectorSource.from_obj(source_obj)
def line_gdf():
# create a horizontal line y=0 crossing 2 points (-180, 0), and (180, 0)
p1 = Point(-180, 0)
p2 = Point(180, 0)
geom = LineString([p1, p2])
gdf = gpd.GeoDataFrame(index=[0], crs={'init': 'epsg:4326'}, geometry=[geom])
gdf['xmin'] = [p1.x]
gdf['ymin'] = [p1.y]
gdf['xmax'] = [p2.x]
gdf['ymax'] = [p2.y]
return gdf


@pytest.fixture
def line_vector_source(min_zoom, max_zoom, line_gdf):
source_obj = dict()
source_obj['geometry_type'] = 'line'
source_obj['data'] = line_gdf
source_obj['tiling'] = dict(
min_zoom=min_zoom,
max_zoom=max_zoom,
xmin_field='xmin',
xmax_field='xmax',
ymin_field='ymin',
ymax_field='ymax',
)
line_source = VectorSource.from_obj(source_obj)
return line_source, min_zoom, max_zoom


@pytest.fixture
def line_raster(line_gdf):
# create a line raster
xrange = (-180, 180)
yrange = (-1, 0)
width = 360
height = 1
cvs = ds.Canvas(plot_width=width, plot_height=height, x_range=xrange, y_range=yrange)
raster = cvs.line(spd.GeoDataFrame(line_gdf), geometry='geometry').astype(np.float32)
return raster


@pytest.fixture
def line_raster_source(min_zoom, max_zoom, line_raster):
# construct value obj
source_obj = dict()
source_obj['geometry_type'] = 'raster'
source_obj['data'] = line_raster
source_obj['tiling'] = dict(
min_zoom=min_zoom,
max_zoom=max_zoom,
)
# RasterSource from source object we created above
line_source = RasterSource.from_obj(source_obj)
return line_source, min_zoom, max_zoom


Expand Down Expand Up @@ -154,12 +222,7 @@ def test_get_tiles_by_extent():
assert len(tile_list) == 6


@pytest.mark.parametrize("min_zoom", ZOOM_LEVELS_1_8)
@pytest.mark.parametrize("max_zoom", [8])
def test_list_tiles_polygon(full_map_polygon_vector_source):

polygon_source, minz, maxz = full_map_polygon_vector_source

def _test_list_tiles_polygon(polygon_source, minz, maxz):
if polygon_source is not None:
tiles_ddf = list_tiles(polygon_source)
# the polygon fully covers the whole map,
Expand All @@ -168,13 +231,23 @@ def test_list_tiles_polygon(full_map_polygon_vector_source):
assert len(tiles_ddf) == num_all_possible_tiles


@pytest.mark.parametrize("min_zoom", ZOOM_LEVELS_1_24)
@pytest.mark.parametrize("max_zoom", [24])
def test_list_tiles_point(point_vector_source):
@pytest.mark.parametrize("min_zoom", ZOOM_LEVELS_1_8)
@pytest.mark.parametrize("max_zoom", [8])
def test_list_tiles_polygon_vector(polygon_vector_source):
polygon_source, minz, maxz = polygon_vector_source
_test_list_tiles_polygon(polygon_source, minz, maxz)


@pytest.mark.parametrize("min_zoom", ZOOM_LEVELS_1_8)
@pytest.mark.parametrize("max_zoom", [8])
def test_list_tiles_polygon_raster(polygon_raster_source):
polygon_source, minz, maxz = polygon_raster_source
_test_list_tiles_polygon(polygon_source, minz, maxz)

point_source, minz, maxz = point_vector_source

def _test_list_tiles_point_geometry(point_source, minz, maxz):
if point_source is not None:

tiles_ddf = list_tiles(point_source).compute()
# there is only a single point at (0, 0) in the vector point source,
# thus at each zoom level, only one tile will be generated
Expand All @@ -188,14 +261,22 @@ def test_list_tiles_point(point_vector_source):
assert x == y == 2**(z-1)


@pytest.mark.parametrize("min_zoom", ZOOM_LEVELS_1_8)
@pytest.mark.parametrize("max_zoom", [8])
def test_list_tiles_line(line_vector_source):
@pytest.mark.parametrize("min_zoom", ZOOM_LEVELS_1_24)
@pytest.mark.parametrize("max_zoom", [24])
def test_list_tiles_point_vector(point_vector_source):
point_source, minz, maxz = point_vector_source
_test_list_tiles_point_geometry(point_source, minz, maxz)

line_source, minz, maxz = line_vector_source

if line_source is not None:
@pytest.mark.parametrize("min_zoom", ZOOM_LEVELS_1_24)
@pytest.mark.parametrize("max_zoom", [24])
def test_list_tiles_point_raster(point_raster_source):
point_source, minz, maxz = point_raster_source
_test_list_tiles_point_geometry(point_source, minz, maxz)


def _test_list_tiles_line_geometry(line_source, minz, maxz):
if line_source is not None:
tiles_ddf = list_tiles(line_source)
assert len(tiles_ddf) == sum([2 ** z for z in range(minz, maxz + 1)])
tiles_ddf = tiles_ddf.compute()
Expand All @@ -205,3 +286,17 @@ def test_list_tiles_line(line_vector_source):
assert len(tiles_z) == 2**z
assert np.all(np.unique(tiles_z['y']) == [2**(z - 1)])
assert np.all(np.sort(np.unique(tiles_z['x'])) == range(2**z))


@pytest.mark.parametrize("min_zoom", ZOOM_LEVELS_1_8)
@pytest.mark.parametrize("max_zoom", [8])
def test_list_tiles_line_vector(line_vector_source):
line_source, minz, maxz = line_vector_source
_test_list_tiles_line_geometry(line_source, minz, maxz)


@pytest.mark.parametrize("min_zoom", ZOOM_LEVELS_1_8)
@pytest.mark.parametrize("max_zoom", [8])
def test_list_tiles_line_raster(line_raster_source):
line_source, minz, maxz = line_raster_source
_test_list_tiles_line_geometry(line_source, minz, maxz)