示例#1
0
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
示例#3
0
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]
示例#4
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
示例#6
0
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()
示例#8
0
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])
示例#10
0
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])
示例#17
0
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
示例#18
0
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])
示例#23
0
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])
示例#25
0
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)