Skip to content

Commit d89d302

Browse files
authored
add make terrain sample data function (#439)
* add make terrain sample data function * add noise requirement * add noise requirement * add noise requirement * change noise to be an optional requirement * move make terrain function inside datasets module init
1 parent 9fc2ab6 commit d89d302

File tree

4 files changed

+99
-2
lines changed

4 files changed

+99
-2
lines changed

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
datashader
22
xarray
33
bokeh>2
4+
noise >=1.2.2

setup.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
'pyct <=0.4.6',
2828
'param >=1.6.1',
2929
'distributed >=2021.03.0',
30-
'spatialpandas'
30+
'spatialpandas',
3131
]
3232

3333
examples = [
@@ -37,6 +37,7 @@
3737
extras_require = {
3838
'tests': [
3939
'pytest',
40+
'noise >=1.2.2',
4041
],
4142
'examples': examples,
4243
}

xrspatial/datasets/__init__.py

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,18 @@
11
import os
2+
3+
import dask.array as da
4+
import datashader as ds
5+
import noise
6+
import numpy as np
7+
import pandas as pd
28
import xarray as xr
39

410

5-
__all__ = ["available", "get_data"]
11+
__all__ = [
12+
'available',
13+
'get_data',
14+
'make_terrain',
15+
]
616

717
_module_path = os.path.dirname(os.path.abspath(__file__))
818
_available_datasets = [p for p in next(os.walk(_module_path))[1]
@@ -34,3 +44,77 @@ def get_data(dataset):
3444
msg += f'Available folders are {available_datasets}.'
3545
raise ValueError(msg)
3646
return data
47+
48+
49+
def make_terrain(
50+
shape=(1024, 1024),
51+
scale=100.0,
52+
octaves=6,
53+
persistence=0.5,
54+
lacunarity=2.0,
55+
chunks=(512, 512)
56+
):
57+
"""
58+
Generate a pseudo-random terrain data dask array.
59+
60+
Parameters
61+
----------
62+
shape : int or tuple of int, default=(1024, 1024)
63+
Output array shape.
64+
scale : float, default=100.0
65+
Noise factor scale.
66+
octaves : int, default=6
67+
Number of waves when generating the noise.
68+
persistence : float, default=0.5
69+
Amplitude of each successive octave relative.
70+
lacunarity : float, default=2.0
71+
Frequency of each successive octave relative.
72+
chunks : int or tuple of int, default=(512, 512)
73+
Number of samples on each block.
74+
75+
Returns
76+
-------
77+
terrain : xarray.DataArray
78+
2D array of generated terrain values.
79+
"""
80+
def _func(arr, block_id=None):
81+
block_ystart = block_id[0] * arr.shape[0]
82+
block_xstart = block_id[1] * arr.shape[1]
83+
out = np.zeros(arr.shape)
84+
for i in range(out.shape[0]):
85+
for j in range(out.shape[1]):
86+
out[i][j] = noise.pnoise2(
87+
(block_ystart + i)/scale,
88+
(block_xstart + j)/scale,
89+
octaves=octaves,
90+
persistence=persistence,
91+
lacunarity=lacunarity,
92+
repeatx=1024,
93+
repeaty=1024,
94+
base=42,
95+
)
96+
return out
97+
98+
data = (
99+
da.zeros(shape=shape, chunks=chunks, dtype=np.float32)
100+
.map_blocks(_func, dtype=np.float32)
101+
)
102+
103+
cvs = ds.Canvas(
104+
x_range=(0, 500),
105+
y_range=(0, 500),
106+
plot_width=shape[1],
107+
plot_height=shape[0],
108+
)
109+
110+
hack_agg = cvs.points(pd.DataFrame({'x': [], 'y': []}), 'x', 'y')
111+
112+
agg = xr.DataArray(
113+
data,
114+
name='terrain',
115+
coords=hack_agg.coords,
116+
dims=hack_agg.dims,
117+
attrs={'res': 1},
118+
)
119+
120+
return agg

xrspatial/tests/test_datasets.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import dask.array as da
2+
import xarray as xr
3+
4+
from xrspatial.datasets import make_terrain
5+
6+
7+
def test_make_terrain():
8+
terrain = make_terrain()
9+
assert terrain is not None
10+
assert isinstance(terrain, xr.DataArray)
11+
assert isinstance(terrain.data, da.Array)

0 commit comments

Comments
 (0)