rasterio/tests/test_rio_features.py

344 lines
11 KiB
Python

import logging
import os
import re
import sys
import click
from click.testing import CliRunner
import rasterio
from rasterio.rio import features
# logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
TEST_FEATURES = """{
"geometry": {
"coordinates": [
[
[-110, 40],
[-100, 40],
[-100, 45],
[-105, 45],
[-110, 40]
]
],
"type": "Polygon"
},
"properties": {
"val": 15
},
"type": "Feature"
}"""
# > rio shapes tests/data/shade.tif --mask --sampling 500 --projected --precision 0
TEST_MERC_FEATURECOLLECTION = """{
"bbox": [-11858135.0, 4803914.0, -11848351.0, 4813698.0],
"features": [{
"bbox": [-11853357.504145855, 4808920.97837715,
-11848580.189878704, 4813698.2926443005],
"geometry": {
"coordinates": [
[
[-11853357.504145855, 4813698.2926443005],
[-11853357.504145855, 4808920.97837715],
[-11848580.189878704, 4808920.97837715],
[-11848580.189878704, 4813698.2926443005],
[-11853357.504145855, 4813698.2926443005]
]
],
"type": "Polygon"
},
"properties": {
"val": 2
},
"type": "Feature"
}, {
"bbox": [-11858134.818413004, 4804143.66411,
-11853357.504145855, 4808920.97837715],
"geometry": {
"coordinates": [
[
[-11858134.818413004, 4808920.97837715],
[-11858134.818413004, 4804143.66411],
[-11853357.504145855, 4804143.66411],
[-11853357.504145855, 4808920.97837715],
[-11858134.818413004, 4808920.97837715]
]
],
"type": "Polygon"
},
"properties": {
"val": 3
},
"type": "Feature"
}],
"type": "FeatureCollection"
}"""
def test_err():
runner = CliRunner()
result = runner.invoke(
features.shapes, ['tests/data/shade.tif', '--bidx', '4'])
assert result.exit_code == 1
def test_shapes(runner):
result = runner.invoke(features.shapes, ['tests/data/shade.tif'])
assert result.exit_code == 0
assert result.output.count('"FeatureCollection"') == 1
assert result.output.count('"Feature"') == 232
def test_shapes_sequence(runner):
result = runner.invoke(features.shapes, ['tests/data/shade.tif', '--sequence'])
assert result.exit_code == 0
assert result.output.count('"FeatureCollection"') == 0
assert result.output.count('"Feature"') == 232
def test_shapes_sequence_rs(runner):
result = runner.invoke(
features.shapes, [
'tests/data/shade.tif',
'--sequence',
'--rs'])
assert result.exit_code == 0
assert result.output.count('"FeatureCollection"') == 0
assert result.output.count('"Feature"') == 232
assert result.output.count(u'\u001e') == 232
def test_shapes_with_nodata(runner):
result = runner.invoke(features.shapes, ['tests/data/shade.tif', '--with-nodata'])
assert result.exit_code == 0
assert result.output.count('"FeatureCollection"') == 1
assert result.output.count('"Feature"') == 288
def test_shapes_indent(runner):
result = runner.invoke(features.shapes, ['tests/data/shade.tif', '--indent', '2'])
assert result.exit_code == 0
assert result.output.count('"FeatureCollection"') == 1
assert result.output.count('\n') == 70139
def test_shapes_compact(runner):
result = runner.invoke(features.shapes, ['tests/data/shade.tif', '--compact'])
assert result.exit_code == 0
assert result.output.count('"FeatureCollection"') == 1
assert result.output.count(', ') == 0
assert result.output.count(': ') == 0
def test_shapes_sampling(runner):
result = runner.invoke(
features.shapes, ['tests/data/shade.tif', '--sampling', '10'])
assert result.exit_code == 0
assert result.output.count('"FeatureCollection"') == 1
assert result.output.count('"Feature"') == 124
def test_shapes_precision(runner):
result = runner.invoke(
features.shapes, ['tests/data/shade.tif', '--precision', '1'])
assert result.exit_code == 0
assert result.output.count('"FeatureCollection"') == 1
# Find no numbers with 2+ decimal places.
assert re.search(r'\d*\.\d{2,}', result.output) is None
def test_shapes_mask(runner):
result = runner.invoke(features.shapes, ['tests/data/RGB.byte.tif', '--mask'])
assert result.exit_code == 0
assert result.output.count('"FeatureCollection"') == 1
assert result.output.count('"Feature"') == 9
def test_rasterize_err(tmpdir, runner):
output = str(tmpdir.join('test.tif'))
# Test invalid stdin
result = runner.invoke(features.rasterize, [output], input='BOGUS')
assert result.exit_code == -1
# Test invalid GeoJSON
result = runner.invoke(features.rasterize, [output],
input='{"foo": "bar"}')
assert result.exit_code == 2
# Test invalid res
result = runner.invoke(features.rasterize, [output], input=TEST_FEATURES)
assert result.exit_code == 2
# Test invalid CRS for bounds
result = runner.invoke(features.rasterize, [output, '--res', 1],
input=TEST_MERC_FEATURECOLLECTION)
assert result.exit_code == 2
# Test invalid CRS value
result = runner.invoke(features.rasterize, [output,
'--res', 1,
'--src_crs', 'BOGUS'],
input=TEST_MERC_FEATURECOLLECTION)
assert result.exit_code == 2
def test_rasterize(tmpdir, runner):
# Test dimensions
output = str(tmpdir.join('test.tif'))
result = runner.invoke(features.rasterize,
[output, '--dimensions', 20, 10],
input=TEST_FEATURES)
assert result.exit_code == 0
assert os.path.exists(output)
with rasterio.open(output) as out:
assert out.count == 1
assert out.meta['width'] == 20
assert out.meta['height'] == 10
data = out.read_band(1, masked=False)
assert (data == 0).sum() == 55
assert (data == 1).sum() == 145
# Test dimensions and bounds
output = str(tmpdir.join('test2.tif'))
result = runner.invoke(features.rasterize,
[output,
'--dimensions', 40, 20,
'--bounds', -120, 30, -90, 50
], input=TEST_FEATURES)
assert result.exit_code == 0
assert os.path.exists(output)
with rasterio.open(output) as out:
assert out.count == 1
assert out.meta['width'] == 40
assert out.meta['height'] == 20
data = out.read_band(1, masked=False)
assert (data == 0).sum() == 748
assert (data == 1).sum() == 52
# Test resolution
output = str(tmpdir.join('test3.tif'))
result = runner.invoke(features.rasterize,
[output, '--res', 0.5], input=TEST_FEATURES)
assert result.exit_code == 0
assert os.path.exists(output)
with rasterio.open(output) as out:
assert out.count == 1
assert out.meta['width'] == 20
assert out.meta['height'] == 10
data = out.read_band(1, masked=False)
assert (data == 0).sum() == 55
assert (data == 1).sum() == 145
def test_rasterize_existing_output(tmpdir, runner):
output = str(tmpdir.join('test.tif'))
result = runner.invoke(features.rasterize,
[output, '--res', 0.5], input=TEST_FEATURES)
assert result.exit_code == 0
assert os.path.exists(output)
geojson = """{
"geometry": {
"coordinates": [
[
[-102, 40],
[-98, 40],
[-98, 45],
[-100, 45],
[-102, 40]
]
],
"type": "Polygon"
},
"type": "Feature"
}"""
result = runner.invoke(features.rasterize, [output, '--default_value', 2],
input=geojson)
with rasterio.open(output) as out:
assert out.count == 1
data = out.read_band(1, masked=False)
assert (data == 0).sum() == 55
assert (data == 1).sum() == 125
assert (data == 2).sum() == 20
def test_rasterize_like(tmpdir, runner):
output = str(tmpdir.join('test.tif'))
result = runner.invoke(features.rasterize,
[output, '--like', 'tests/data/shade.tif'],
input=TEST_MERC_FEATURECOLLECTION)
assert result.exit_code == 0
assert os.path.exists(output)
with rasterio.open(output) as out:
assert out.count == 1
data = out.read_band(1, masked=False)
assert (data == 0).sum() == 548576
assert (data == 1).sum() == 500000
# Test invalid like raster
output = str(tmpdir.join('test2.tif'))
result = runner.invoke(features.rasterize,
[output, '--like', 'foo.tif'], input=TEST_FEATURES)
assert result.exit_code == 2
def test_rasterize_property_value(tmpdir, runner):
# Test feature collection property values
output = str(tmpdir.join('test.tif'))
result = runner.invoke(features.rasterize,
[output,
'--res', 1000,
'--property', 'val',
'--src_crs', 'EPSG:3857'
],
input=TEST_MERC_FEATURECOLLECTION)
assert result.exit_code == 0
assert os.path.exists(output)
with rasterio.open(output) as out:
assert out.count == 1
data = out.read_band(1, masked=False)
assert (data == 0).sum() == 50
assert (data == 2).sum() == 25
assert (data == 3).sum() == 25
# Test feature property values
output = str(tmpdir.join('test2.tif'))
result = runner.invoke(features.rasterize,
[output, '--res', 0.5, '--property', 'val'],
input=TEST_FEATURES)
assert result.exit_code == 0
assert os.path.exists(output)
with rasterio.open(output) as out:
assert out.count == 1
data = out.read_band(1, masked=False)
assert (data == 0).sum() == 55
assert (data == 15).sum() == 145
def test_rasterize_out_of_bounds(tmpdir, runner):
output = str(tmpdir.join('test.tif'))
# Test out of bounds of --like raster
result = runner.invoke(features.rasterize,
[output, '--like', 'tests/data/shade.tif'],
input=TEST_FEATURES)
assert result.exit_code == 2
# Test out of bounds of existing output raster (first have to create one)
result = runner.invoke(features.rasterize,
[output,
'--res', 1000,
'--property', 'val',
'--src_crs', 'EPSG:3857'
],
input=TEST_MERC_FEATURECOLLECTION)
assert result.exit_code == 0
assert os.path.exists(output)
result = runner.invoke(features.rasterize, [output], input=TEST_FEATURES)
assert result.exit_code == 2