def test_apply(): def func(x): return 0 zones_val = np.zeros((3, 3), dtype=np.int) # define some zones zones_val[0, ...] = 1 zones_val[1, ...] = 2 zones = xa.DataArray(zones_val) values_val = np.array([[0, 1, 2], [3, 4, 5], [6, 7, np.nan]]) values = xa.DataArray(values_val) # add crs for tests values = _add_EPSG4326_crs_to_da(values) values_copy = values.copy() apply(zones, values, func) # agg.shape remains the same assert values.shape == values_copy.shape # crs tests assert values.attrs == values_copy.attrs for coord in values_copy.coords: assert np.all(values[coord] == values_copy[coord]) values_val = values.values # values within zones are all 0s assert (values_val[0] == [0, 0, 0]).all() assert (values_val[1] == [0, 0, 0]).all() # values outside zones remain assert (values_val[2, :2] == values_copy.values[2, :2]).all() # last element of the last row is nan assert np.isnan(values_val[2, 2])
def test_ndvi_numpy_contains_valid_values(): """ Assert aspect transfer function """ _x = np.mgrid[1:0:21j] a, b = np.meshgrid(_x, _x) red = a*b nir = (a*b)[::-1, ::-1] da_nir = xr.DataArray(nir, dims=['y', 'x']) # add crs for tests da_nir = _add_EPSG4326_crs_to_da(da_nir) da_red = xr.DataArray(red, dims=['y', 'x']) da_ndvi = ndvi(da_nir, da_red) # test preservation of dims, attrs, coords, including crs assert da_ndvi.dims == da_nir.dims assert da_ndvi.attrs == da_nir.attrs for coord in da_nir.coords: assert np.all(da_nir[coord] == da_ndvi[coord]) assert da_ndvi[0, 0] == -1 assert da_ndvi[-1, -1] == 1 assert da_ndvi[5, 10] == da_ndvi[10, 5] == -0.5 assert da_ndvi[15, 10] == da_ndvi[10, 15] == 0.5
def test_curvature_on_flat_surface(): # flat surface test_arr1 = np.array([[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]) test_raster1 = xr.DataArray(test_arr1) # add crs for tests test_raster1 = _add_EPSG4326_crs_to_da(test_raster1, res=(1, 1)) curv = curvature(test_raster1) # output must be an xarray DataArray assert isinstance(curv, xr.DataArray) assert isinstance(curv.values, np.ndarray) # shape, dims, coords, attr preserved, including crs assert test_raster1.shape == curv.shape assert test_raster1.dims == curv.dims assert test_raster1.attrs == curv.attrs for coord in test_raster1.coords: assert np.all(test_raster1[coord] == curv[coord]) # border edges are all nans assert np.isnan(curv.values[0, :]).all() assert np.isnan(curv.values[-1, :]).all() assert np.isnan(curv.values[:, 0]).all() assert np.isnan(curv.values[:, -1]).all() # curvature of a flat surface is all 0s # exclude border edges assert np.unique(curv.values[1:-1, 1:-1]) == [0]
def test_reclassify_cpu(): bins = [10, 20, 30] new_values = [1, 2, 3] # numpy # add crs for tests numpy_agg_crs = _add_EPSG4326_crs_to_da(numpy_agg) numpy_reclassify = reclassify(numpy_agg_crs, bins=bins, new_values=new_values, name='numpy_reclassify') unique_elements, counts_elements = np.unique(numpy_reclassify.data, return_counts=True) assert len(unique_elements) == 3 # crs tests assert numpy_reclassify.attrs == numpy_agg_crs.attrs for coord in numpy_agg_crs.coords: assert np.all(numpy_reclassify[coord] == numpy_agg_crs[coord]) # dask + numpy dask_reclassify = reclassify(dask_numpy_agg, bins=bins, new_values=new_values, name='dask_reclassify') assert isinstance(dask_reclassify.data, da.Array) dask_reclassify.data = dask_reclassify.data.compute() assert np.isclose(numpy_reclassify, dask_reclassify, equal_nan=True).all()
def test_mean_transfer_function(): da = xr.DataArray(data_random) # add crs for tests da = _add_EPSG4326_crs_to_da(da) da_mean = mean(da) assert da.shape == da_mean.shape # crs tests assert da_mean.attrs == da.attrs for coord in da.coords: assert np.all(da_mean[coord] == da[coord]) # Overall mean value should be the same as the original array. # Considering the default behaviour to 'mean' is to pad the borders # with zeros, the mean value of the filtered array will be slightly # smaller (considering 'data_random' is positive). assert da_mean.mean() <= data_random.mean() # And if we pad the borders with the original values, we should have a # 'mean' filtered array with _mean_ value very similar to the original one. da_mean[0, :] = data_random[0, :] da_mean[-1, :] = data_random[-1, :] da_mean[:, 0] = data_random[:, 0] da_mean[:, -1] = data_random[:, -1] assert abs(da_mean.mean() - data_random.mean()) < 10**-3
def test_quantile_cpu(): k = 5 # numpy # add crs for tests numpy_agg_crs = _add_EPSG4326_crs_to_da(numpy_agg) numpy_quantile = quantile(numpy_agg_crs, k=k) unique_elements, counts_elements = np.unique(numpy_quantile.data, return_counts=True) assert isinstance(numpy_quantile.data, np.ndarray) assert len(unique_elements) == k assert len(np.unique(counts_elements)) == 1 assert np.unique(counts_elements)[0] == 5 # crs tests assert numpy_quantile.attrs == numpy_agg_crs.attrs for coord in numpy_agg_crs.coords: assert np.all(numpy_quantile[coord] == numpy_agg_crs[coord]) # dask + numpy dask_quantile = quantile(dask_numpy_agg, k=k) assert isinstance(dask_quantile.data, da.Array)
def test_numpy_equals_qgis(): small_da = xr.DataArray(INPUT_DATA) # add crs for tests small_da = _add_EPSG4326_crs_to_da(small_da) xrspatial_aspect = aspect(small_da, name='numpy_aspect') # validate output attributes and coords including crs assert xrspatial_aspect.dims == small_da.dims assert xrspatial_aspect.attrs == small_da.attrs assert xrspatial_aspect.shape == small_da.shape assert xrspatial_aspect.name == 'numpy_aspect' for coord in small_da.coords: assert np.all(xrspatial_aspect[coord] == small_da[coord]) # TODO: We shouldn't ignore edges! # validate output values # ignore border edges xrspatial_vals = xrspatial_aspect.values[1:-1, 1:-1] qgis_vals = QGIS_OUTPUT[1:-1, 1:-1] # TODO: use np.is_close instead # set a tolerance of 1e-4 # aspect is nan if nan input # aspect is invalid (nan) if slope equals 0 # otherwise aspect are from 0 - 360 assert np.isclose(xrspatial_vals, qgis_vals, equal_nan=True).all()
def test_equal_interval_cpu(): k = 5 # numpy # add crs for tests numpy_agg_crs = _add_EPSG4326_crs_to_da(numpy_agg) numpy_ei = equal_interval(numpy_agg_crs, k=5) unique_elements, counts_elements = np.unique(numpy_ei.data, return_counts=True) assert isinstance(numpy_ei.data, np.ndarray) assert len(unique_elements) == k # crs tests assert numpy_ei.attrs == numpy_agg_crs.attrs for coord in numpy_agg_crs.coords: assert np.all(numpy_ei[coord] == numpy_agg_crs[coord]) # dask + numpy dask_ei = equal_interval(dask_numpy_agg, k=k, name='dask_reclassify') assert isinstance(dask_ei.data, da.Array) dask_ei.data = dask_ei.data.compute() assert np.isclose(numpy_ei, dask_ei, equal_nan=True).all()
def test_nbr_numpy(): nir = create_test_arr(arr1) # add crs for tests nir = _add_EPSG4326_crs_to_da(nir) swir = create_test_arr(arr2) result = nbr(nir, swir) assert result.dims == nir.dims assert isinstance(result, xa.DataArray) assert result.dims == nir.dims # crs tests assert result.attrs == nir.attrs for coord in nir.coords: assert np.all(result[coord] == nir[coord])
def test_regions_four_pixel_connectivity_int(): arr = np.array( [[0, 0, 0, 0], [0, 4, 0, 0], [1, 4, 4, 0], [1, 1, 1, 0], [0, 0, 0, 0]], dtype=np.int64) raster = create_test_arr(arr) # add crs for tests raster = _add_EPSG4326_crs_to_da(raster) raster_regions = regions(raster, neighborhood=4) assert len(np.unique(raster_regions.data)) == 3 assert raster.shape == raster_regions.shape # crs tests assert raster_regions.attrs == raster.attrs for coord in raster.coords: assert np.all(raster_regions[coord] == raster[coord])
def test_arvi_numpy(): nir = create_test_arr(arr1) red = create_test_arr(arr2) blue = create_test_arr(arr3) #add crs for tests (nir dims, attrs, coords are the ones arvi function sets on the return DataArray) nir = _add_EPSG4326_crs_to_da(nir) result = arvi(nir, red, blue) assert result.dims == nir.dims assert isinstance(result, xa.DataArray) assert result.dims == nir.dims #crs tests assert result.attrs == nir.attrs for coord in nir.coords: assert np.all(result[coord] == nir[coord])
def test_nbr2_numpy(): swir1 = create_test_arr(arr1) # add crs for tests swir1 = _add_EPSG4326_crs_to_da(swir1) swir2 = create_test_arr(arr2) result = nbr2(swir1, swir2) assert result.dims == swir1.dims assert isinstance(result, xa.DataArray) assert result.dims == swir1.dims # crs tests assert result.attrs == swir1.attrs for coord in swir1.coords: assert np.all(result[coord] == swir1[coord])
def test_ebbi_numpy(): red = create_test_arr(arr1) # add crs for tests red = _add_EPSG4326_crs_to_da(red) swir = create_test_arr(arr2) tir = create_test_arr(arr3) numpy_result = ebbi(red, swir, tir) assert numpy_result.dims == red.dims assert isinstance(numpy_result, xa.DataArray) assert numpy_result.dims == red.dims # crs tests assert numpy_result.attrs == red.attrs for coord in red.coords: assert np.all(numpy_result[coord] == red[coord])
def test_allocation(): # create test raster, all non-zero cells are unique, # this is to test against corresponding proximity raster = create_test_raster() # add crs for tests raster = _add_EPSG4326_crs_to_da(raster) allocation_agg = allocation(raster, x='lon', y='lat') # output must be an xarray DataArray assert isinstance(allocation_agg, xa.DataArray) assert type(allocation_agg.values[0][0]) == raster.dtype assert allocation_agg.shape == raster.shape # crs tests assert allocation_agg.attrs == raster.attrs for coord in raster.coords: assert np.all(allocation_agg[coord] == raster[coord]) # targets not specified, # Thus, targets are set to non-zero values of input @raster targets = np.unique(raster.data[np.where((raster.data != 0) & np.isfinite(raster.data))]) # non-zero cells (a.k.a targets) remain the same for t in targets: ry, rx = np.where(raster.data == t) for y, x in zip(ry, rx): assert allocation_agg.values[y, x] == t # values of allocation output assert (np.unique(allocation_agg.data) == targets).all() # check against corresponding proximity proximity_agg = proximity(raster, x='lon', y='lat') xcoords = allocation_agg['lon'].data ycoords = allocation_agg['lat'].data for y in range(raster.shape[0]): for x in range(raster.shape[1]): a = allocation_agg.data[y, x] py, px = np.where(raster.data == a) # non-zero cells in raster are unique, thus len(px)=len(py)=1 d = euclidean_distance(xcoords[x], xcoords[px[0]], ycoords[y], ycoords[py[0]]) assert proximity_agg.data[y, x] == d
def test_hillshade(): """ Assert Simple Hillshade transfer function """ da_gaussian = xr.DataArray(data_gaussian) # add crs for tests da_gaussian = _add_EPSG4326_crs_to_da(da_gaussian) da_gaussian_shade = hillshade(da_gaussian, name='hillshade_agg') # test preservation of attrs and coords, including crs assert da_gaussian_shade.dims == da_gaussian.dims assert da_gaussian_shade.attrs == da_gaussian.attrs assert da_gaussian_shade.name == 'hillshade_agg' for coord in da_gaussian.coords: assert np.all(da_gaussian_shade[coord] == da_gaussian[coord]) assert da_gaussian_shade.mean() > 0 assert da_gaussian_shade[60, 60] > 0
def test_sipi_numpy(): nir = create_test_arr(arr1) # add crs for tests nir = _add_EPSG4326_crs_to_da(nir) red = create_test_arr(arr2) blue = create_test_arr(arr3) result = sipi(nir, red, blue) assert result.dims == nir.dims assert isinstance(result, xa.DataArray) assert result.dims == nir.dims # crs tests assert result.attrs == nir.attrs for coord in nir.coords: assert np.all(result[coord] == nir[coord])
def test_natural_breaks_cpu(): k = 5 # vanilla numpy # add crs for tests numpy_agg_crs = _add_EPSG4326_crs_to_da(numpy_agg) numpy_natural_breaks = natural_breaks(numpy_agg_crs, k=k) # shape and other attributes remain the same, as well as coords, including crs assert numpy_agg_crs.shape == numpy_natural_breaks.shape assert numpy_agg_crs.dims == numpy_natural_breaks.dims assert numpy_agg_crs.attrs == numpy_natural_breaks.attrs for coord in numpy_agg_crs.coords: assert np.all(numpy_agg_crs[coord] == numpy_natural_breaks[coord]) unique_elements, counts_elements = np.unique(numpy_natural_breaks.data, return_counts=True) assert len(unique_elements) == k
def test_trim(): arr = np.array( [[0, 0, 0, 0], [0, 4, 0, 0], [0, 4, 4, 0], [0, 1, 1, 0], [0, 0, 0, 0]], dtype=np.int64) raster = create_test_arr(arr) # add crs for tests raster = _add_EPSG4326_crs_to_da(raster) trimmed_raster = trim(raster, values=(0, )) assert trimmed_raster.shape == (3, 2) # crs tests assert trimmed_raster.attrs == raster.attrs for coord in raster.coords: assert np.all(trimmed_raster[coord] == raster[coord]) trimmed_arr = np.array([[4, 0], [4, 4], [1, 1]], dtype=np.int64) compare = trimmed_arr == trimmed_raster.data assert compare.all()
def test_direction(): raster = create_test_raster() # add crs for tests raster = _add_EPSG4326_crs_to_da(raster) direction_agg = direction(raster, x='lon', y='lat') # output must be an xarray DataArray, and attrs and coords must be preserved, including crs assert isinstance(direction_agg, xa.DataArray) assert type(direction_agg.values[0][0]) == np.float64 assert direction_agg.shape == raster.shape assert direction_agg.dims == raster.dims assert direction_agg.attrs == raster.attrs for c in direction_agg.coords: assert (direction_agg[c] == raster.coords[c]).all() # in this test case, where no polygon is completely inside another polygon, # number of non-zeros (target pixels) in original image # must be equal to the number of zeros (target pixels) in proximity matrix assert len(np.where((raster.data != 0) & np.isfinite(raster.data))[0]) == \ len(np.where(direction_agg.data == 0)[0]) # values are within [0, 360] assert np.min(direction_agg.data) >= 0 assert np.max(direction_agg.data) <= 360 # test against allocation allocation_agg = allocation(raster, x='lon', y='lat') xcoords = allocation_agg['lon'].data ycoords = allocation_agg['lat'].data for y in range(raster.shape[0]): for x in range(raster.shape[1]): a = allocation_agg.data[y, x] py, px = np.where(raster.data == a) # non-zero cells in raster are unique, thus len(px)=len(py)=1 d = _calc_direction(xcoords[x], xcoords[px[0]], ycoords[y], ycoords[py[0]]) assert direction_agg.data[y, x] == d
def test_savi_numpy(): nir = create_test_arr(arr1) # add crs for tests nir = _add_EPSG4326_crs_to_da(nir) red = create_test_arr(arr2) # savi should be same as ndvi at soil_factor=0 result_savi = savi(nir, red, soil_factor=0.0) result_ndvi = ndvi(nir, red) assert np.isclose(result_savi.data, result_ndvi.data, equal_nan=True).all() assert result_savi.dims == nir.dims result_savi = savi(nir, red, soil_factor=1.0) assert isinstance(result_savi, xa.DataArray) assert result_savi.dims == nir.dims # crs tests assert result_savi.attrs == nir.attrs for coord in nir.coords: assert np.all(result_savi[coord] == nir[coord])
def test_viewshed_output_properties(): # add crs for tests empty_agg_crs = _add_EPSG4326_crs_to_da(empty_agg) for obs_elev in OBS_ELEVS: OBSERVER_X = xs[0] OBSERVER_Y = ys[0] v = viewshed(raster=empty_agg_crs, x=OBSERVER_X, y=OBSERVER_Y, observer_elev=obs_elev) assert v.shape[0] == empty_agg_crs.shape[0] assert v.shape[1] == empty_agg_crs.shape[1] assert isinstance(v, xa.DataArray) assert isinstance(v.values, np.ndarray) assert type(v.values[0, 0]) == np.float64 # crs tests assert v.attrs == empty_agg_crs.attrs for coord in empty_agg_crs.coords: assert np.all(v[coord] == empty_agg_crs[coord])
def test_evi_numpy(): nir = create_test_arr(arr1) # add crs for tests nir = _add_EPSG4326_crs_to_da(nir) red = create_test_arr(arr2) blue = create_test_arr(arr3) gain = 2.5 c1 = 6.0 c2 = 7.5 soil_factor = 1.0 result = evi(nir, red, blue, c1, c2, soil_factor, gain) assert result.dims == nir.dims assert isinstance(result, xa.DataArray) assert result.dims == nir.dims # crs tests assert result.attrs == nir.attrs for coord in nir.coords: assert np.all(result[coord] == nir[coord])
def test_crop(): arr = np.array( [[0, 4, 0, 3], [0, 4, 4, 3], [0, 1, 1, 3], [0, 1, 1, 3], [0, 0, 0, 0]], dtype=np.int64) raster = create_test_arr(arr) # add crs for tests raster = _add_EPSG4326_crs_to_da(raster) result = crop(raster, raster, zones_ids=(1, 3)) assert result.shape == (4, 3) # crs tests assert result.attrs == raster.attrs for coord in raster.coords: assert np.all(result[coord] == raster[coord]) trimmed_arr = np.array([[4, 0, 3], [4, 4, 3], [1, 1, 3], [1, 1, 3]], dtype=np.int64) compare = trimmed_arr == result.data assert compare.all()
def test_apply_crs(): n, m = 6, 6 raster = xr.DataArray(np.ones((n, m)), dims=['y', 'x']) # add crs raster = _add_EPSG4326_crs_to_da(raster, res=(1, 1)) raster['x'] = np.linspace(0, n, n) raster['y'] = np.linspace(0, m, m) cellsize_x, cellsize_y = calc_cellsize(raster) # add some nan pixels nan_cells = [(i, i) for i in range(n)] for cell in nan_cells: raster[cell[0], cell[1]] = np.nan # kernel array = [[1]] kernel = np.ones((1, 1)) raster_apply = apply(raster, kernel) assert raster_apply.attrs == raster.attrs for coord in raster.coords: assert np.all(raster_apply[coord] == raster[coord])
def test_slope_against_qgis(): small_da = xr.DataArray(elevation, attrs={'res': (10.0, 10.0)}) # add crs for tests small_da = _add_EPSG4326_crs_to_da(small_da) # slope by xrspatial xrspatial_slope = slope(small_da, name='slope_agg') # validate output attributes and coords, including crs preservation assert xrspatial_slope.dims == small_da.dims assert xrspatial_slope.attrs == small_da.attrs assert xrspatial_slope.shape == small_da.shape assert xrspatial_slope.name == 'slope_agg' for coord in small_da.coords: assert np.all(xrspatial_slope[coord] == small_da[coord]) # validate output values # ignore border edges xrspatial_vals = xrspatial_slope.values[1:-1, 1:-1] qgis_vals = qgis_slope[1:-1, 1:-1] assert (np.isclose(xrspatial_vals, qgis_vals, equal_nan=True).all() | ( np.isnan(xrspatial_vals) & np.isnan(qgis_vals))).all()
def test_hotspot(): n, m = 10, 10 raster = xr.DataArray(np.zeros((n, m), dtype=float), dims=['y', 'x']) # add crs for tests raster = _add_EPSG4326_crs_to_da(raster) raster['x'] = np.linspace(0, n, n) raster['y'] = np.linspace(0, m, m) cellsize_x, cellsize_y = calc_cellsize(raster) kernel = circle_kernel(cellsize_x, cellsize_y, 2.0) all_idx = zip(*np.where(raster.values == 0)) nan_cells = [(i, i) for i in range(m)] for cell in nan_cells: raster[cell[0], cell[1]] = np.nan # add some extreme values hot_region = [(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (2, 3), (3, 1), (3, 2), (3, 3)] cold_region = [(7, 7), (7, 8), (7, 9), (8, 7), (8, 8), (8, 9), (9, 7), (9, 8), (9, 9)] for p in hot_region: raster[p[0], p[1]] = 10000 for p in cold_region: raster[p[0], p[1]] = -10000 no_significant_region = [ id for id in all_idx if id not in hot_region and id not in cold_region ] hotspots_output = hotspots(raster, kernel) # check output's properties # output must be an xarray DataArray assert isinstance(hotspots_output, xr.DataArray) assert isinstance(hotspots_output.values, np.ndarray) assert issubclass(hotspots_output.values.dtype.type, np.int8) # shape, dims, coords, attr preserved, including crs assert raster.shape == hotspots_output.shape assert raster.dims == hotspots_output.dims assert raster.attrs == hotspots_output.attrs for coord in raster.coords: assert np.all(raster[coord] == hotspots_output[coord]) # no nan in output assert not np.isnan(np.min(hotspots_output)) # output of extreme regions are non-zeros # hot spots hot_spot = np.asarray([hotspots_output[p] for p in hot_region]) assert np.all(hot_spot >= 0) assert np.sum(hot_spot) > 0 # cold spots cold_spot = np.asarray([hotspots_output[p] for p in cold_region]) assert np.all(cold_spot <= 0) assert np.sum(cold_spot) < 0 # output of no significant regions are 0s no_sign = np.asarray([hotspots_output[p] for p in no_significant_region]) assert np.all(no_sign == 0)
def test_a_star_search(): agg = xr.DataArray(np.array([[0, 1, 0, 0], [1, 1, 0, 0], [0, 1, 2, 2], [1, 0, 2, 0], [0, 2, 2, 2]]), dims=['lat', 'lon']) # add crs for tests agg = _add_EPSG4326_crs_to_da(agg) height, width = agg.shape _lon = np.linspace(0, width - 1, width) _lat = np.linspace(0, height - 1, height) agg['lon'] = _lon agg['lat'] = _lat barriers = [] # no barriers, there always path from a start location to a goal location for x0 in _lon: for y0 in _lat: start = (x0, y0) for x1 in _lon: for y1 in _lat: goal = (x1, y1) path_agg = a_star_search(agg, start, goal, barriers, 'lon', 'lat') assert isinstance(path_agg, xr.DataArray) assert type(path_agg.values[0][0]) == np.float64 assert path_agg.shape == agg.shape assert path_agg.dims == agg.dims assert path_agg.attrs == agg.attrs for c in path_agg.coords: assert (path_agg[c] == agg.coords[c]).all() if start == goal: assert np.nanmax(path_agg) == 0 and \ np.nanmin(path_agg) == 0 else: assert np.nanmax(path_agg) > 0 and \ np.nanmin(path_agg) == 0 barriers = [1] # set pixels with value 1 as barriers, # cannot go from (0, 0) to anywhere since it is surrounded by 1s start = (0, 0) for x1 in _lon: for y1 in _lat: goal = (x1, y1) if goal != start: path_agg = a_star_search(agg, start, goal, barriers, 'lon', 'lat') assert isinstance(path_agg, xr.DataArray) assert type(path_agg.values[0][0]) == np.float64 assert path_agg.shape == agg.shape assert path_agg.dims == agg.dims assert path_agg.attrs == agg.attrs for c in path_agg.coords: assert (path_agg[c] == agg.coords[c]).all() # no path, all cells in path_agg are nans assert np.isnan(path_agg).all() # test with nans agg = xr.DataArray(np.array([[0, 1, 0, 0], [1, 1, np.nan, 0], [0, 1, 2, 2], [1, 0, 2, 0], [0, np.nan, 2, 2]]), dims=['lat', 'lon']) height, width = agg.shape _lon = np.linspace(0, width - 1, width) _lat = np.linspace(0, height - 1, height) agg['lon'] = _lon agg['lat'] = _lat # start and end at a nan pixel, coordinate in (lon, lat) format # in this example, each pixel is a unit of lon and lat, # start = (2, 1) corresponds to pixel at (1, 2), # goal = (1, 4) corresponds to pixel at (4, 1) start = (2, 1) goal = (1, 4) # no barriers barriers = [] # no snap no_snap_path_agg = a_star_search(agg, start, goal, barriers, 'lon', 'lat') # no path, all cells in path_agg are nans assert np.isnan(no_snap_path_agg).all() # set snap_start = True, snap_goal = False snap_start_path_agg = a_star_search(agg, start, goal, barriers, 'lon', 'lat', snap_start=True) # no path, all cells in path_agg are nans assert np.isnan(snap_start_path_agg).all() # set snap_start = False, snap_goal = True snap_goal_path_agg = a_star_search(agg, start, goal, barriers, 'lon', 'lat', snap_goal=True) # no path, all cells in path_agg are nans assert np.isnan(snap_goal_path_agg).all() # set snap_start = True, snap_goal = True # 8-connectivity as default path_agg_8 = a_star_search(agg, start, goal, barriers, 'lon', 'lat', snap_start=True, snap_goal=True) # path exists expected_result_8 = np.array([[np.nan, np.nan, 0., np.nan], [np.nan, 1.41421356, np.nan, np.nan], [np.nan, 2.41421356, np.nan, np.nan], [np.nan, 3.41421356, np.nan, np.nan], [np.nan, np.nan, np.nan, np.nan]]) assert ((np.isnan(path_agg_8) & np.isnan(expected_result_8)) | (abs(path_agg_8 - expected_result_8) <= 1e-5)).all() # 4-connectivity path_agg_4 = a_star_search(agg, start, goal, barriers, 'lon', 'lat', snap_start=True, snap_goal=True, connectivity=4) # path exists expected_result_4 = np.array([[np.nan, 1, 0., np.nan], [np.nan, 2, np.nan, np.nan], [np.nan, 3, np.nan, np.nan], [np.nan, 4, np.nan, np.nan], [np.nan, np.nan, np.nan, np.nan]]) assert ((np.isnan(path_agg_4) & np.isnan(expected_result_4)) | (abs(path_agg_4 - expected_result_4) <= 1e-5)).all()
def test_proximity(): raster = create_test_raster() # add crs for tests raster_for_default = _add_EPSG4326_crs_to_da(raster) # DEFAULT SETTINGS default_prox = proximity(raster_for_default, x='lon', y='lat') # output must be an xarray DataArray assert isinstance(default_prox, xa.DataArray) assert type(default_prox.values[0][0]) == np.float64 assert default_prox.shape == raster_for_default.shape # crs tests assert default_prox.attrs == raster_for_default.attrs for coord in raster_for_default.coords: assert np.all(default_prox[coord] == raster_for_default[coord]) # in this test case, where no polygon is completely inside another polygon, # number of non-zeros (target pixels) in original image # must be equal to the number of zeros (target pixels) in proximity matrix assert len(np.where((raster.data != 0) & np.isfinite(raster.data))[0]) == \ len(np.where(default_prox.data == 0)[0]) # TARGET VALUES SETTING target_values = [2, 3] target_prox = proximity(raster, x='lon', y='lat', target_values=target_values) # output must be an xarray DataArray assert isinstance(target_prox, xa.DataArray) assert type(target_prox.values[0][0]) == np.float64 assert target_prox.shape == raster.shape assert (len(np.where(raster.data == 2)[0]) + len(np.where(raster.data == 3)[0])) == \ len(np.where(target_prox.data == 0)[0]) # distance_metric SETTING: MANHATTAN manhattan_prox = proximity(raster, x='lon', y='lat', distance_metric='MANHATTAN') # output must be an xarray DataArray assert isinstance(manhattan_prox, xa.DataArray) assert type(manhattan_prox.values[0][0]) == np.float64 assert manhattan_prox.shape == raster.shape # all output values must be in range [0, max_possible_dist] max_possible_dist = manhattan_distance(raster.coords['lon'].values[0], raster.coords['lon'].values[-1], raster.coords['lat'].values[0], raster.coords['lat'].values[-1]) assert np.nanmax(manhattan_prox.values) <= max_possible_dist assert np.nanmin(manhattan_prox.values) == 0 # distance_metric SETTING: GREAT_CIRCLE great_circle_prox = proximity(raster, x='lon', y='lat', distance_metric='GREAT_CIRCLE') # output must be an xarray DataArray assert isinstance(great_circle_prox, xa.DataArray) assert type(great_circle_prox.values[0][0]) == np.float64 assert great_circle_prox.shape == raster.shape # all output values must be in range [0, max_possible_dist] max_possible_dist = great_circle_distance(raster.coords['lon'].values[0], raster.coords['lon'].values[-1], raster.coords['lat'].values[0], raster.coords['lat'].values[-1]) assert np.nanmax(great_circle_prox.values) <= max_possible_dist assert np.nanmin(great_circle_prox.values) == 0
def test_convolution(): n, m = 6, 6 raster = xr.DataArray(np.ones((n, m)), dims=['y', 'x']) # add crs for tests raster = _add_EPSG4326_crs_to_da(raster) raster['x'] = np.linspace(0, n, n) raster['y'] = np.linspace(0, m, m) cellsize_x, cellsize_y = calc_cellsize(raster) # add some nan pixels nan_cells = [(i, i) for i in range(n)] for cell in nan_cells: raster[cell[0], cell[1]] = np.nan # kernel array = [[1]] kernel = np.ones((1, 1)) # np.nansum(np.array([np.nan])) = 0.0 expected_out_sum_1 = np.array([[0., 1., 1., 1., 1., 1.], [1., 0., 1., 1., 1., 1.], [1., 1., 0., 1., 1., 1.], [1., 1., 1., 0., 1., 1.], [1., 1., 1., 1., 0., 1.], [1., 1., 1., 1., 1., 0.]]) # Convolution will return np.nan, so convert nan to 0 assert np.all(np.nan_to_num(expected_out_sum_1) == expected_out_sum_1) # crs tests: hold for edit to convolve_2d to return xarray.DataArray # assert sum_output_1.attrs == raster.attrs # for coord in raster.coords: # assert np.all(sum_output_1[coord] == raster[coord]) # np.nanmean(np.array([np.nan])) = nan mean_output_1 = convolve_2d(raster.values, kernel / kernel.sum()) for cell in nan_cells: assert np.isnan(mean_output_1[cell[0], cell[1]]) # remaining cells are 1s for i in range(n): for j in range(m): if i != j: assert mean_output_1[i, j] == 1 # kernel array: [[0, 1, 0], # [1, 1, 1], # [0, 1, 0]] kernel = circle_kernel(cellsize_x, cellsize_y, 2) sum_output_2 = convolve_2d(np.nan_to_num(raster.values), kernel, pad=False) expected_out_sum_2 = np.array([[2., 2., 4., 4., 4., 3.], [2., 4., 3., 5., 5., 4.], [4., 3., 4., 3., 5., 4.], [4., 5., 3., 4., 3., 4.], [4., 5., 5., 3., 4., 2.], [3., 4., 4., 4., 2., 2.]]) assert np.all(sum_output_2 == expected_out_sum_2) mean_output_2 = convolve_2d(np.ones((n, m)), kernel / kernel.sum(), pad=True) expected_mean_output_2 = np.ones((n, m)) assert np.all(mean_output_2 == expected_mean_output_2) # kernel array: [[0, 1, 0], # [1, 0, 1], # [0, 1, 0]] kernel = annulus_kernel(cellsize_x, cellsize_y, 2.0, 0.5) sum_output_3 = convolve_2d(np.nan_to_num(raster.values), kernel, pad=False) expected_out_sum_3 = np.array([[2., 1., 3., 3., 3., 2.], [1., 4., 2., 4., 4., 3.], [3., 2., 4., 2., 4., 3.], [3., 4., 2., 4., 2., 3.], [3., 4., 4., 2., 4., 1.], [2., 3., 3., 3., 1., 2.]]) assert np.all(sum_output_3 == expected_out_sum_3) mean_output_3 = convolve_2d(np.ones((n, m)), kernel / kernel.sum(), pad=True) expected_mean_output_3 = np.ones((n, m)) assert np.all(mean_output_3 == expected_mean_output_3)