Skip to content

hotspots() silently returns all-zeros for degenerate dask inputs where NumPy/CuPy raise #2843

@brendancol

Description

@brendancol

Describe the bug

hotspots() returns an all-zeros ("no significance") raster for degenerate dask inputs, while the NumPy and CuPy backends raise an error on the same input.

The NumPy and CuPy paths validate the global Gi* terms through _gistar_global_stats, which raises ValueError when there are fewer than 2 valid (non-NaN) cells, and ZeroDivisionError when the global standard deviation is 0 (a constant raster). The dask paths (_hotspots_dask_numpy, _hotspots_dask_cupy) keep the global mean, std, and valid-cell count as lazy 0-d dask arrays and never run that validation. _gistar_zscore maps every non-finite z-score to 0, so a constant raster, an all-NaN raster, or a raster with a single valid cell computes to an all-zeros result that looks valid instead of failing.

So the same input errors on NumPy/CuPy but quietly answers "no hotspots" on dask. A downstream user gets a plausible-looking statistic with no hint that the input was degenerate.

To Reproduce

import numpy as np
import xarray as xr
import dask.array as da
from xrspatial.focal import hotspots

kernel = np.ones((3, 3))
data = np.zeros((10, 10))  # constant raster -> global std == 0

# NumPy raises ZeroDivisionError
hotspots(xr.DataArray(data), kernel)

# dask quietly returns all zeros
hotspots(xr.DataArray(da.from_array(data, chunks=(5, 5))), kernel).compute()

Expected behavior

The dask backends should signal the degenerate input the same way NumPy does instead of returning a silent all-zeros raster. The dask path is lazy by design (issue #2772), so the validation should fire at compute time, not when the graph is built.

Additional context

  • File: xrspatial/focal.py
  • NumPy validation: _gistar_global_stats
  • Dask paths missing it: _hotspots_dask_numpy, _hotspots_dask_cupy
  • Affected backends: dask+numpy, dask+cupy

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingdaskDask backend / chunked arrays

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions