Skip to content

hotspots() skips kernel validation: bad kernels raise AttributeError or divide by zero #2771

@brendancol

Description

@brendancol

Describe the bug

hotspots() in xrspatial/focal.py skips the kernel validation that apply() and focal_stats() both run. Those two call custom_kernel(kernel) before touching the kernel. hotspots() doesn't. It goes straight to _check_kernel_vs_raster_memory(kernel, ...) near line 1509, which reads kernel.shape directly.

So an invalid kernel either crashes with a confusing AttributeError or silently produces wrong output, depending on what you pass.

Failure modes (numpy backend)

  • hotspots(agg, kernel=None) raises AttributeError: 'NoneType' object has no attribute 'shape' instead of a clear validation error.
  • hotspots(agg, kernel=[[1, 1, 1]]) raises AttributeError: 'list' object has no attribute 'shape'. A list should get rejected with the same "not a Numpy array" message custom_kernel raises.
  • hotspots(agg, kernel=np.ones((2, 2))) succeeds, even though even-dimensioned kernels are rejected by custom_kernel everywhere else.
  • A zero-sum kernel (e.g. a Laplacian) divides by zero at line 1269: convolve_2d(data, kernel / kernel.sum(), boundary). It emits RuntimeWarnings and returns all-zero output instead of raising.

Expected behavior

hotspots() should validate its kernel the way apply() and focal_stats() do: route through custom_kernel() so None, lists, and even-dimensioned kernels raise clear, consistent ValueErrors. Zero-sum kernels should raise an explicit error rather than dividing by zero.

Additional context

custom_kernel() lives in xrspatial/convolution.py. It checks ndarray type and odd dimensions, but not the kernel sum. The zero-sum case is specific to hotspots() since it's the only focal function that divides by kernel.sum().

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingfocal toolsFocal statistics and hotspot analysis

    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