xarray-spatial 0.9.3__tar.gz → 0.9.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (296) hide show
  1. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/CHANGELOG.md +21 -0
  2. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/PKG-INFO +8 -1
  3. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/README.md +7 -0
  4. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xarray_spatial.egg-info/PKG-INFO +8 -1
  5. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xarray_spatial.egg-info/SOURCES.txt +6 -0
  6. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/_version.py +3 -3
  7. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/bump.py +3 -3
  8. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/classify.py +4 -4
  9. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/convolution.py +15 -7
  10. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/flood.py +4 -4
  11. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/focal.py +30 -23
  12. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/geotiff/__init__.py +418 -37
  13. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/geotiff/_compression.py +2 -1
  14. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/geotiff/_geotags.py +43 -1
  15. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/geotiff/_vrt.py +2 -0
  16. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/geotiff/_writer.py +405 -13
  17. xarray_spatial-0.9.4/xrspatial/geotiff/tests/test_accuracy_1081.py +292 -0
  18. xarray_spatial-0.9.4/xrspatial/geotiff/tests/test_compression_level.py +171 -0
  19. xarray_spatial-0.9.4/xrspatial/geotiff/tests/test_dtype_read.py +117 -0
  20. xarray_spatial-0.9.4/xrspatial/geotiff/tests/test_streaming_write.py +263 -0
  21. xarray_spatial-0.9.4/xrspatial/geotiff/tests/test_vrt_write.py +111 -0
  22. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/glcm.py +15 -0
  23. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/multispectral.py +5 -7
  24. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/reproject/_interpolate.py +26 -32
  25. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/reproject/_projections.py +5 -10
  26. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/reproject/_projections_cuda.py +16 -7
  27. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_bump.py +43 -0
  28. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_classify.py +33 -0
  29. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_flood.py +26 -0
  30. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_focal.py +158 -0
  31. xarray_spatial-0.9.4/xrspatial/tests/test_glcm_metric_order.py +162 -0
  32. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_multispectral.py +56 -12
  33. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_reproject.py +126 -0
  34. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_viewshed.py +55 -0
  35. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_zonal.py +67 -20
  36. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/viewshed.py +8 -3
  37. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/zonal.py +101 -26
  38. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/.claude/commands/backend-parity.md +0 -0
  39. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/.claude/commands/bench.md +0 -0
  40. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/.claude/commands/dask-notebook.md +0 -0
  41. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/.claude/commands/efficiency-audit.md +0 -0
  42. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/.claude/commands/new-issues.md +0 -0
  43. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/.claude/commands/release-major.md +0 -0
  44. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/.claude/commands/release-minor.md +0 -0
  45. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/.claude/commands/release-patch.md +0 -0
  46. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/.claude/commands/review-pr.md +0 -0
  47. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/.claude/commands/rockout.md +0 -0
  48. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/.claude/commands/user-guide-notebook.md +0 -0
  49. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/.claude/commands/validate.md +0 -0
  50. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/.gitattributes +0 -0
  51. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  52. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/.github/ISSUE_TEMPLATE/feature-proposal.md +0 -0
  53. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/.github/labeler.yml +0 -0
  54. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/.github/pull_request_template.md +0 -0
  55. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/.github/workflows/benchmarks.yml +0 -0
  56. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/.github/workflows/labeler.yml +0 -0
  57. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/.github/workflows/pypi-publish.yml +0 -0
  58. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/.github/workflows/test.yml +0 -0
  59. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/.gitignore +0 -0
  60. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/.readthedocs.yml +0 -0
  61. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/CODE_OF_CONDUCT.md +0 -0
  62. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/CONTRIBUTING.md +0 -0
  63. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/Citation-styles.md +0 -0
  64. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/LICENSE.txt +0 -0
  65. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/MANIFEST.in +0 -0
  66. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/RELEASE.md +0 -0
  67. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/codecov.yml +0 -0
  68. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/pyproject.toml +0 -0
  69. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/setup.cfg +0 -0
  70. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/setup.py +0 -0
  71. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xarray_spatial.egg-info/dependency_links.txt +0 -0
  72. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xarray_spatial.egg-info/entry_points.txt +0 -0
  73. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xarray_spatial.egg-info/not-zip-safe +0 -0
  74. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xarray_spatial.egg-info/requires.txt +0 -0
  75. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xarray_spatial.egg-info/top_level.txt +0 -0
  76. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/__init__.py +0 -0
  77. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/__main__.py +0 -0
  78. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/accessor.py +0 -0
  79. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/analytics.py +0 -0
  80. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/aspect.py +0 -0
  81. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/balanced_allocation.py +0 -0
  82. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/bilateral.py +0 -0
  83. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/contour.py +0 -0
  84. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/corridor.py +0 -0
  85. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/cost_distance.py +0 -0
  86. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/curvature.py +0 -0
  87. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/dasymetric.py +0 -0
  88. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/dataset_support.py +0 -0
  89. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/datasets/__init__.py +0 -0
  90. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/datasets/sentinel-2/blue_band.nc +0 -0
  91. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/datasets/sentinel-2/green_band.nc +0 -0
  92. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/datasets/sentinel-2/nir_band.nc +0 -0
  93. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/datasets/sentinel-2/red_band.nc +0 -0
  94. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/datasets/sentinel-2/swir1_band.nc +0 -0
  95. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/datasets/sentinel-2/swir2_band.nc +0 -0
  96. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/diagnostics.py +0 -0
  97. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/diffusion.py +0 -0
  98. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/edge_detection.py +0 -0
  99. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/emerging_hotspots.py +0 -0
  100. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/erosion.py +0 -0
  101. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/experimental/__init__.py +0 -0
  102. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/experimental/min_observable_height.py +0 -0
  103. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/fire.py +0 -0
  104. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/geodesic.py +0 -0
  105. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/geotiff/_dtypes.py +0 -0
  106. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/geotiff/_gpu_decode.py +0 -0
  107. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/geotiff/_header.py +0 -0
  108. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/geotiff/_reader.py +0 -0
  109. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/geotiff/tests/__init__.py +0 -0
  110. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/geotiff/tests/bench_vs_rioxarray.py +0 -0
  111. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/geotiff/tests/conftest.py +0 -0
  112. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/geotiff/tests/test_accessor_io.py +0 -0
  113. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/geotiff/tests/test_cog.py +0 -0
  114. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/geotiff/tests/test_compression.py +0 -0
  115. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/geotiff/tests/test_edge_cases.py +0 -0
  116. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/geotiff/tests/test_features.py +0 -0
  117. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/geotiff/tests/test_geotags.py +0 -0
  118. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/geotiff/tests/test_header.py +0 -0
  119. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/geotiff/tests/test_jpeg.py +0 -0
  120. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/geotiff/tests/test_jpeg2000.py +0 -0
  121. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/geotiff/tests/test_lerc.py +0 -0
  122. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/geotiff/tests/test_lz4.py +0 -0
  123. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/geotiff/tests/test_reader.py +0 -0
  124. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/geotiff/tests/test_writer.py +0 -0
  125. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/gpu_rtx/__init__.py +0 -0
  126. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/gpu_rtx/cuda_utils.py +0 -0
  127. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/gpu_rtx/hillshade.py +0 -0
  128. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/gpu_rtx/mesh_utils.py +0 -0
  129. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/gpu_rtx/viewshed.py +0 -0
  130. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hillshade.py +0 -0
  131. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/__init__.py +0 -0
  132. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/_boundary_store.py +0 -0
  133. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/basin_d8.py +0 -0
  134. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/fill_d8.py +0 -0
  135. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/flow_accumulation_d8.py +0 -0
  136. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/flow_accumulation_dinf.py +0 -0
  137. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/flow_accumulation_mfd.py +0 -0
  138. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/flow_direction_d8.py +0 -0
  139. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/flow_direction_dinf.py +0 -0
  140. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/flow_direction_mfd.py +0 -0
  141. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/flow_length_d8.py +0 -0
  142. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/flow_length_dinf.py +0 -0
  143. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/flow_length_mfd.py +0 -0
  144. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/flow_path_d8.py +0 -0
  145. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/flow_path_dinf.py +0 -0
  146. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/flow_path_mfd.py +0 -0
  147. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/hand_d8.py +0 -0
  148. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/hand_dinf.py +0 -0
  149. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/hand_mfd.py +0 -0
  150. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/sink_d8.py +0 -0
  151. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/snap_pour_point_d8.py +0 -0
  152. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/stream_link_d8.py +0 -0
  153. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/stream_link_dinf.py +0 -0
  154. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/stream_link_mfd.py +0 -0
  155. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/stream_order_d8.py +0 -0
  156. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/stream_order_dinf.py +0 -0
  157. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/stream_order_mfd.py +0 -0
  158. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/tests/__init__.py +0 -0
  159. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/tests/conftest.py +0 -0
  160. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/tests/test_basin_d8.py +0 -0
  161. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/tests/test_fill_d8.py +0 -0
  162. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/tests/test_flow_accumulation_d8.py +0 -0
  163. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/tests/test_flow_accumulation_dinf.py +0 -0
  164. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/tests/test_flow_accumulation_mfd.py +0 -0
  165. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/tests/test_flow_direction_d8.py +0 -0
  166. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/tests/test_flow_direction_dinf.py +0 -0
  167. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/tests/test_flow_direction_mfd.py +0 -0
  168. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/tests/test_flow_length_d8.py +0 -0
  169. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/tests/test_flow_length_dinf.py +0 -0
  170. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/tests/test_flow_length_mfd.py +0 -0
  171. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/tests/test_flow_path_d8.py +0 -0
  172. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/tests/test_flow_path_dinf.py +0 -0
  173. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/tests/test_flow_path_mfd.py +0 -0
  174. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/tests/test_hand_d8.py +0 -0
  175. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/tests/test_hand_dinf.py +0 -0
  176. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/tests/test_hand_mfd.py +0 -0
  177. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/tests/test_sink_d8.py +0 -0
  178. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/tests/test_snap_pour_point_d8.py +0 -0
  179. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/tests/test_stream_link_d8.py +0 -0
  180. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/tests/test_stream_link_dinf.py +0 -0
  181. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/tests/test_stream_link_mfd.py +0 -0
  182. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/tests/test_stream_order_d8.py +0 -0
  183. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/tests/test_stream_order_dinf.py +0 -0
  184. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/tests/test_stream_order_mfd.py +0 -0
  185. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/tests/test_twi_d8.py +0 -0
  186. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/tests/test_watershed_d8.py +0 -0
  187. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/tests/test_watershed_dinf.py +0 -0
  188. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/tests/test_watershed_mfd.py +0 -0
  189. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/twi_d8.py +0 -0
  190. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/watershed_d8.py +0 -0
  191. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/watershed_dinf.py +0 -0
  192. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/hydro/watershed_mfd.py +0 -0
  193. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/interpolate/__init__.py +0 -0
  194. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/interpolate/_idw.py +0 -0
  195. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/interpolate/_kriging.py +0 -0
  196. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/interpolate/_spline.py +0 -0
  197. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/interpolate/_validation.py +0 -0
  198. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/mahalanobis.py +0 -0
  199. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/mcda/__init__.py +0 -0
  200. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/mcda/combine.py +0 -0
  201. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/mcda/constrain.py +0 -0
  202. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/mcda/sensitivity.py +0 -0
  203. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/mcda/standardize.py +0 -0
  204. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/mcda/weights.py +0 -0
  205. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/morphology.py +0 -0
  206. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/normalize.py +0 -0
  207. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/pathfinding.py +0 -0
  208. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/perlin.py +0 -0
  209. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/polygonize.py +0 -0
  210. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/preview.py +0 -0
  211. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/proximity.py +0 -0
  212. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/rasterize.py +0 -0
  213. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/reproject/__init__.py +0 -0
  214. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/reproject/_crs_utils.py +0 -0
  215. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/reproject/_datum_grids.py +0 -0
  216. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/reproject/_grid.py +0 -0
  217. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/reproject/_itrf.py +0 -0
  218. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/reproject/_lite_crs.py +0 -0
  219. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/reproject/_merge.py +0 -0
  220. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/reproject/_transform.py +0 -0
  221. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/reproject/_vertical.py +0 -0
  222. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/reproject/grids/at_bev_AT_GIS_GRID.tif +0 -0
  223. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/reproject/grids/au_icsm_A66_National_13_09_01.tif +0 -0
  224. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/reproject/grids/be_ign_bd72lb72_etrs89lb08.tif +0 -0
  225. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/reproject/grids/ch_swisstopo_CHENyx06_ETRS.tif +0 -0
  226. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/reproject/grids/de_adv_BETA2007.tif +0 -0
  227. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/reproject/grids/es_ign_SPED2ETV2.tif +0 -0
  228. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/reproject/grids/nl_nsgi_rdcorr2018.tif +0 -0
  229. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/reproject/grids/pt_dgt_D73_ETRS89_geo.tif +0 -0
  230. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/reproject/grids/uk_os_OSTN15_NTv2_OSGBtoETRS.tif +0 -0
  231. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/reproject/grids/us_nga_egm96_15.tif +0 -0
  232. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/reproject/grids/us_noaa_alaska.tif +0 -0
  233. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/reproject/grids/us_noaa_conus.tif +0 -0
  234. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/reproject/grids/us_noaa_hawaii.tif +0 -0
  235. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/reproject/grids/us_noaa_nadcon5_nad27_nad83_1986_conus.tif +0 -0
  236. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/reproject/grids/us_noaa_prvi.tif +0 -0
  237. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/sky_view_factor.py +0 -0
  238. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/slope.py +0 -0
  239. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/surface_distance.py +0 -0
  240. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/terrain.py +0 -0
  241. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/terrain_metrics.py +0 -0
  242. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/__init__.py +0 -0
  243. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/bench_reproject_vs_rioxarray.py +0 -0
  244. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/conftest.py +0 -0
  245. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/general_checks.py +0 -0
  246. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_accessor.py +0 -0
  247. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_analytics.py +0 -0
  248. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_aspect.py +0 -0
  249. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_balanced_allocation.py +0 -0
  250. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_bilateral.py +0 -0
  251. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_contour.py +0 -0
  252. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_corridor.py +0 -0
  253. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_cost_distance.py +0 -0
  254. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_curvature.py +0 -0
  255. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_dask_cupy_gaps.py +0 -0
  256. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_dasymetric.py +0 -0
  257. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_dataset_support.py +0 -0
  258. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_datasets.py +0 -0
  259. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_diagnostics.py +0 -0
  260. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_diffusion.py +0 -0
  261. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_edge_detection.py +0 -0
  262. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_emerging_hotspots.py +0 -0
  263. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_erosion.py +0 -0
  264. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_fire.py +0 -0
  265. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_fused_overlap.py +0 -0
  266. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_geodesic_aspect.py +0 -0
  267. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_geodesic_slope.py +0 -0
  268. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_glcm.py +0 -0
  269. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_hillshade.py +0 -0
  270. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_interpolation.py +0 -0
  271. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_lite_crs.py +0 -0
  272. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_mahalanobis.py +0 -0
  273. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_mcda.py +0 -0
  274. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_min_observable_height.py +0 -0
  275. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_morphology.py +0 -0
  276. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_morphology_derived.py +0 -0
  277. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_multi_overlap.py +0 -0
  278. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_normalize.py +0 -0
  279. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_northness_eastness.py +0 -0
  280. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_pathfinding.py +0 -0
  281. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_perlin.py +0 -0
  282. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_polygonize.py +0 -0
  283. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_preview.py +0 -0
  284. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_proximity.py +0 -0
  285. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_rasterize.py +0 -0
  286. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_rasterize_accuracy.py +0 -0
  287. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_rechunk_no_shuffle.py +0 -0
  288. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_sky_view_factor.py +0 -0
  289. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_slope.py +0 -0
  290. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_surface_distance.py +0 -0
  291. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_terrain.py +0 -0
  292. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_terrain_metrics.py +0 -0
  293. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_utils.py +0 -0
  294. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/tests/test_validation.py +0 -0
  295. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/utils.py +0 -0
  296. {xarray_spatial-0.9.3 → xarray_spatial-0.9.4}/xrspatial/worley.py +0 -0
@@ -2,6 +2,27 @@
2
2
  -----------
3
3
 
4
4
 
5
+ ### Version 0.9.4 - 2026-03-30
6
+
7
+ #### New features
8
+ - Streaming TIFF write for dask inputs (#1084) (#1108)
9
+ - Add dtype, compression_level, and VRT output to geotiff I/O (#1083) (#1085)
10
+
11
+ #### Bug fixes and improvements
12
+ - Use float64 in Jenks natural breaks internals (#1100) (#1101)
13
+ - Fix multi-metric output mislabeling in glcm_texture (#1106) (#1107)
14
+ - Fix inverted decay and off-by-one in bump spread (#1102) (#1103)
15
+ - Propagate NaN from curve_number in curve_number_runoff (#1104) (#1105)
16
+ - Fix target_elev contaminating horizon in dask viewshed distance sweep (#1098) (#1099)
17
+ - Preserve float64 precision in convolve_2d (#1096) (#1097)
18
+ - Fix SAVI formula: (1+L) was in denominator instead of numerator (#1094) (#1095)
19
+ - Fix NaN handling in focal_stats CUDA kernels (#1092) (#1093)
20
+ - Fix three accuracy bugs in zonal stats dask backend (#1090) (#1091)
21
+ - Add longitude normalization to CUDA inverse projection kernels (#1089)
22
+ - Fix three accuracy bugs in reproject resampling kernels (#1087)
23
+ - Fix three accuracy bugs in open_geotiff/to_geotiff (#1081) (#1082)
24
+
25
+
5
26
  ### Version 0.9.3 - 2026-03-27
6
27
 
7
28
  #### New features
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xarray-spatial
3
- Version: 0.9.3
3
+ Version: 0.9.4
4
4
  Summary: xarray-based spatial analysis tools
5
5
  Home-page: https://github.com/xarray-contrib/xarray-spatial
6
6
  Author: Xarray-Spatial Developers
@@ -231,6 +231,13 @@ to_geotiff(data, 'out.tif', gpu=True) # force GPU compress
231
231
  to_geotiff(data, 'ortho.tif', compression='jpeg') # JPEG for orthophotos
232
232
  write_vrt('mosaic.vrt', ['tile1.tif', 'tile2.tif']) # generate VRT
233
233
 
234
+ open_geotiff('dem.tif', dtype='float32') # half memory
235
+ open_geotiff('dem.tif', dtype='float32', chunks=512) # Dask + half memory
236
+ to_geotiff(data, 'out.tif', compression_level=1) # fast scratch write
237
+ to_geotiff(data, 'out.tif', compression_level=22) # max compression
238
+ to_geotiff(dask_da, 'out.tif') # stream Dask to single TIFF
239
+ to_geotiff(dask_da, 'mosaic.vrt') # stream Dask to VRT
240
+
234
241
  # Accessor methods
235
242
  da.xrs.to_geotiff('out.tif', compression='lzw') # write from DataArray
236
243
  ds.xrs.open_geotiff('large_dem.tif') # read windowed to Dataset extent
@@ -165,6 +165,13 @@ to_geotiff(data, 'out.tif', gpu=True) # force GPU compress
165
165
  to_geotiff(data, 'ortho.tif', compression='jpeg') # JPEG for orthophotos
166
166
  write_vrt('mosaic.vrt', ['tile1.tif', 'tile2.tif']) # generate VRT
167
167
 
168
+ open_geotiff('dem.tif', dtype='float32') # half memory
169
+ open_geotiff('dem.tif', dtype='float32', chunks=512) # Dask + half memory
170
+ to_geotiff(data, 'out.tif', compression_level=1) # fast scratch write
171
+ to_geotiff(data, 'out.tif', compression_level=22) # max compression
172
+ to_geotiff(dask_da, 'out.tif') # stream Dask to single TIFF
173
+ to_geotiff(dask_da, 'mosaic.vrt') # stream Dask to VRT
174
+
168
175
  # Accessor methods
169
176
  da.xrs.to_geotiff('out.tif', compression='lzw') # write from DataArray
170
177
  ds.xrs.open_geotiff('large_dem.tif') # read windowed to Dataset extent
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xarray-spatial
3
- Version: 0.9.3
3
+ Version: 0.9.4
4
4
  Summary: xarray-based spatial analysis tools
5
5
  Home-page: https://github.com/xarray-contrib/xarray-spatial
6
6
  Author: Xarray-Spatial Developers
@@ -231,6 +231,13 @@ to_geotiff(data, 'out.tif', gpu=True) # force GPU compress
231
231
  to_geotiff(data, 'ortho.tif', compression='jpeg') # JPEG for orthophotos
232
232
  write_vrt('mosaic.vrt', ['tile1.tif', 'tile2.tif']) # generate VRT
233
233
 
234
+ open_geotiff('dem.tif', dtype='float32') # half memory
235
+ open_geotiff('dem.tif', dtype='float32', chunks=512) # Dask + half memory
236
+ to_geotiff(data, 'out.tif', compression_level=1) # fast scratch write
237
+ to_geotiff(data, 'out.tif', compression_level=22) # max compression
238
+ to_geotiff(dask_da, 'out.tif') # stream Dask to single TIFF
239
+ to_geotiff(dask_da, 'mosaic.vrt') # stream Dask to VRT
240
+
234
241
  # Accessor methods
235
242
  da.xrs.to_geotiff('out.tif', compression='lzw') # write from DataArray
236
243
  ds.xrs.open_geotiff('large_dem.tif') # read windowed to Dataset extent
@@ -109,8 +109,11 @@ xrspatial/geotiff/tests/__init__.py
109
109
  xrspatial/geotiff/tests/bench_vs_rioxarray.py
110
110
  xrspatial/geotiff/tests/conftest.py
111
111
  xrspatial/geotiff/tests/test_accessor_io.py
112
+ xrspatial/geotiff/tests/test_accuracy_1081.py
112
113
  xrspatial/geotiff/tests/test_cog.py
113
114
  xrspatial/geotiff/tests/test_compression.py
115
+ xrspatial/geotiff/tests/test_compression_level.py
116
+ xrspatial/geotiff/tests/test_dtype_read.py
114
117
  xrspatial/geotiff/tests/test_edge_cases.py
115
118
  xrspatial/geotiff/tests/test_features.py
116
119
  xrspatial/geotiff/tests/test_geotags.py
@@ -120,6 +123,8 @@ xrspatial/geotiff/tests/test_jpeg2000.py
120
123
  xrspatial/geotiff/tests/test_lerc.py
121
124
  xrspatial/geotiff/tests/test_lz4.py
122
125
  xrspatial/geotiff/tests/test_reader.py
126
+ xrspatial/geotiff/tests/test_streaming_write.py
127
+ xrspatial/geotiff/tests/test_vrt_write.py
123
128
  xrspatial/geotiff/tests/test_writer.py
124
129
  xrspatial/gpu_rtx/__init__.py
125
130
  xrspatial/gpu_rtx/cuda_utils.py
@@ -257,6 +262,7 @@ xrspatial/tests/test_fused_overlap.py
257
262
  xrspatial/tests/test_geodesic_aspect.py
258
263
  xrspatial/tests/test_geodesic_slope.py
259
264
  xrspatial/tests/test_glcm.py
265
+ xrspatial/tests/test_glcm_metric_order.py
260
266
  xrspatial/tests/test_hillshade.py
261
267
  xrspatial/tests/test_interpolation.py
262
268
  xrspatial/tests/test_lite_crs.py
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '0.9.3'
22
- __version_tuple__ = version_tuple = (0, 9, 3)
21
+ __version__ = version = '0.9.4'
22
+ __version_tuple__ = version_tuple = (0, 9, 4)
23
23
 
24
- __commit_id__ = commit_id = 'gb6a15e5b6'
24
+ __commit_id__ = commit_id = 'g0ad1feb6e'
@@ -29,11 +29,11 @@ def _finish_bump(width, height, locs, heights, spread):
29
29
  z = heights[i]
30
30
  out[y, x] = out[y, x] + z
31
31
  if s > 0:
32
- for nx in range(max(x - spread, 0), min(x + spread, width)):
33
- for ny in range(max(y - spread, 0), min(y + spread, height)):
32
+ for nx in range(max(x - spread, 0), min(x + spread + 1, width)):
33
+ for ny in range(max(y - spread, 0), min(y + spread + 1, height)):
34
34
  d2 = (nx - x) * (nx - x) + (ny - y) * (ny - y)
35
35
  if d2 <= s:
36
- out[ny, nx] = out[ny, nx] + (out[y, x] * (d2 / s))
36
+ out[ny, nx] = out[ny, nx] + (out[y, x] * ((s - d2) / s))
37
37
  return out
38
38
 
39
39
 
@@ -547,12 +547,12 @@ def quantile(agg: xr.DataArray,
547
547
  def _run_numpy_jenks_matrices(data, n_classes):
548
548
  n_data = data.shape[0]
549
549
  lower_class_limits = np.zeros(
550
- (n_data + 1, n_classes + 1), dtype=np.float32
550
+ (n_data + 1, n_classes + 1), dtype=np.float64
551
551
  )
552
552
  lower_class_limits[1, 1:n_classes + 1] = 1.0
553
553
 
554
554
  var_combinations = np.zeros(
555
- (n_data + 1, n_classes + 1), dtype=np.float32
555
+ (n_data + 1, n_classes + 1), dtype=np.float64
556
556
  )
557
557
  var_combinations[2:n_data + 1, 1:n_classes + 1] = np.inf
558
558
 
@@ -568,7 +568,7 @@ def _run_numpy_jenks_matrices(data, n_classes):
568
568
  lower_class_limit = l - m
569
569
  i4 = lower_class_limit - 1
570
570
 
571
- val = np.float32(data[i4])
571
+ val = data[i4]
572
572
 
573
573
  # here we're estimating variance for each potential classing
574
574
  # of the data, for each potential number of classes. `w`
@@ -610,7 +610,7 @@ def _run_jenks(data, n_classes):
610
610
  lower_class_limits, _ = _run_numpy_jenks_matrices(data, n_classes)
611
611
 
612
612
  k = data.shape[0]
613
- kclass = np.zeros(n_classes + 1, dtype=np.float32)
613
+ kclass = np.zeros(n_classes + 1, dtype=np.float64)
614
614
  kclass[0] = data[0]
615
615
  kclass[-1] = data[-1]
616
616
  count_num = n_classes
@@ -17,6 +17,13 @@ except ImportError:
17
17
  ndarray = False
18
18
 
19
19
 
20
+ def _promote_float(dtype):
21
+ """Return at least float32; preserve float64."""
22
+ if np.issubdtype(dtype, np.floating):
23
+ return dtype
24
+ return np.float32
25
+
26
+
20
27
  DEFAULT_UNIT = 'meter'
21
28
  METER = 1
22
29
  FOOT = 0.3048
@@ -286,8 +293,7 @@ def custom_kernel(kernel):
286
293
  @jit(nopython=True, nogil=True)
287
294
  def _convolve_2d_numpy(data, kernel):
288
295
  # apply kernel to data image.
289
- # TODO: handle nan
290
- data = data.astype(np.float32)
296
+ # Caller must ensure data is a float type (float32 or float64).
291
297
  nx = data.shape[0]
292
298
  ny = data.shape[1]
293
299
  nkx = kernel.shape[0]
@@ -295,7 +301,7 @@ def _convolve_2d_numpy(data, kernel):
295
301
  wkx = nkx // 2
296
302
  wky = nky // 2
297
303
 
298
- out = np.zeros(data.shape, dtype=np.float32)
304
+ out = np.empty_like(data)
299
305
  out[:] = np.nan
300
306
  for i in prange(wkx, nx-wkx):
301
307
  iimin = max(i - wkx, 0)
@@ -315,6 +321,7 @@ def _convolve_2d_numpy(data, kernel):
315
321
 
316
322
 
317
323
  def _convolve_2d_numpy_boundary(data, kernel, boundary='nan'):
324
+ data = data.astype(_promote_float(data.dtype))
318
325
  if boundary == 'nan':
319
326
  return _convolve_2d_numpy(data, kernel)
320
327
  pad_h = kernel.shape[0] // 2
@@ -329,7 +336,7 @@ def _convolve_2d_numpy_boundary(data, kernel, boundary='nan'):
329
336
 
330
337
 
331
338
  def _convolve_2d_dask_numpy(data, kernel, boundary='nan'):
332
- data = data.astype(np.float32)
339
+ data = data.astype(_promote_float(data.dtype))
333
340
  pad_h = kernel.shape[0] // 2
334
341
  pad_w = kernel.shape[1] // 2
335
342
  _func = partial(_convolve_2d_numpy, kernel=kernel)
@@ -393,8 +400,9 @@ def _convolve_2d_cupy(data, kernel, boundary='nan'):
393
400
  c1 = -pad_w if pad_w else None
394
401
  return result[r0:r1, c0:c1]
395
402
 
396
- data = data.astype(cupy.float32)
397
- out = cupy.empty(data.shape, dtype='f4')
403
+ fdtype = _promote_float(data.dtype)
404
+ data = data.astype(fdtype)
405
+ out = cupy.empty(data.shape, dtype=fdtype)
398
406
  out[:, :] = cupy.nan
399
407
  griddim, blockdim = cuda_args(data.shape)
400
408
  _convolve_2d_cuda[griddim, blockdim](data, kernel, cupy.asarray(out))
@@ -402,7 +410,7 @@ def _convolve_2d_cupy(data, kernel, boundary='nan'):
402
410
 
403
411
 
404
412
  def _convolve_2d_dask_cupy(data, kernel, boundary='nan'):
405
- data = data.astype(cupy.float32)
413
+ data = data.astype(_promote_float(data.dtype))
406
414
  pad_h = kernel.shape[0] // 2
407
415
  pad_w = kernel.shape[1] // 2
408
416
  _func = partial(_convolve_2d_cupy, kernel=kernel)
@@ -328,8 +328,8 @@ def _cn_runoff_numpy(p, cn):
328
328
  s = (25400.0 / cn) - 254.0
329
329
  ia = 0.2 * s
330
330
  q = np.where(p > ia, (p - ia) ** 2 / (p + 0.8 * s), 0.0)
331
- # propagate NaN from rainfall
332
- q = np.where(np.isnan(p), np.nan, q)
331
+ # propagate NaN from rainfall or curve number
332
+ q = np.where(np.isnan(p) | np.isnan(cn), np.nan, q)
333
333
  return q
334
334
 
335
335
 
@@ -340,7 +340,7 @@ def _cn_runoff_cupy(p, cn):
340
340
  s = (25400.0 / cn) - 254.0
341
341
  ia = 0.2 * s
342
342
  q = cp.where(p > ia, (p - ia) ** 2 / (p + 0.8 * s), 0.0)
343
- q = cp.where(cp.isnan(p), cp.nan, q)
343
+ q = cp.where(cp.isnan(p) | cp.isnan(cn), cp.nan, q)
344
344
  return q
345
345
 
346
346
 
@@ -349,7 +349,7 @@ def _cn_runoff_dask(p, cn):
349
349
  s = (25400.0 / cn) - 254.0
350
350
  ia = 0.2 * s
351
351
  q = _da.where(p > ia, (p - ia) ** 2 / (p + 0.8 * s), 0.0)
352
- q = _da.where(_da.isnan(p), np.nan, q)
352
+ q = _da.where(_da.isnan(p) | _da.isnan(cn), np.nan, q)
353
353
  return q
354
354
 
355
355
 
@@ -608,13 +608,13 @@ def _focal_min_cuda(data, kernel, out):
608
608
 
609
609
  if 0 <= ii < rows and 0 <= jj < cols:
610
610
  v = data[ii, jj]
611
+ if v != v: # NaN check
612
+ continue
611
613
  if (not found) or (v < m):
612
614
  m = v
613
615
  found = True
614
616
 
615
- # With your mask containing the center, found should be True.
616
- # But keep a safe fallback anyway.
617
- out[i, j] = m if found else data[i, j]
617
+ out[i, j] = m if found else math.nan
618
618
 
619
619
 
620
620
  @cuda.jit
@@ -636,20 +636,20 @@ def _focal_max_cuda(data, kernel, out):
636
636
  for h in range(kernel.shape[1]):
637
637
  w = kernel[k, h]
638
638
  if w == 0:
639
- continue # mask says "ignore this neighbor"
639
+ continue
640
640
 
641
641
  ii = i + k - dr
642
642
  jj = j + h - dc
643
643
 
644
644
  if 0 <= ii < rows and 0 <= jj < cols:
645
645
  v = data[ii, jj]
646
+ if v != v: # NaN check
647
+ continue
646
648
  if (not found) or (v > m):
647
649
  m = v
648
650
  found = True
649
651
 
650
- # With your mask containing the center (1), found should always be True.
651
- # But keep this for safety.
652
- out[i, j] = m if found else data[i, j]
652
+ out[i, j] = m if found else math.nan
653
653
 
654
654
 
655
655
  def _focal_range_cupy(data, kernel):
@@ -684,6 +684,8 @@ def _focal_range_cuda(data, kernel, out):
684
684
 
685
685
  if 0 <= ii < rows and 0 <= jj < cols:
686
686
  v = data[ii, jj]
687
+ if v != v: # NaN check
688
+ continue
687
689
  if not found:
688
690
  mx = v
689
691
  mn = v
@@ -694,7 +696,7 @@ def _focal_range_cuda(data, kernel, out):
694
696
  if v < mn:
695
697
  mn = v
696
698
 
697
- out[i, j] = (mx - mn) if found else 0.0
699
+ out[i, j] = (mx - mn) if found else math.nan
698
700
 
699
701
 
700
702
  @cuda.jit
@@ -716,29 +718,29 @@ def _focal_std_cuda(data, kernel, out):
716
718
  for h in range(kernel.shape[1]):
717
719
  w = kernel[k, h]
718
720
  if w == 0:
719
- continue # mask says ignore
721
+ continue
720
722
 
721
723
  ii = i + k - dr
722
724
  jj = j + h - dc
723
725
 
724
726
  if 0 <= ii < rows and 0 <= jj < cols:
725
727
  x = data[ii, jj]
728
+ if x != x: # NaN check
729
+ continue
726
730
  w_sum += w
727
731
  sum_wx += w * x
728
732
  sum_wx2 += w * x * x
729
733
 
730
- # With your mask including the center, w_sum should be > 0. Guard anyway.
731
734
  if w_sum > 0.0:
732
735
  mean = sum_wx / w_sum
733
736
  var = (sum_wx2 / w_sum) - (mean * mean)
734
737
 
735
- # Numerical safety (tiny negative due to floating point)
736
738
  if var < 0.0:
737
739
  var = 0.0
738
740
 
739
741
  out[i, j] = math.sqrt(var)
740
742
  else:
741
- out[i, j] = 0.0
743
+ out[i, j] = math.nan
742
744
 
743
745
 
744
746
  @cuda.jit
@@ -760,13 +762,15 @@ def _focal_var_cuda(data, kernel, out):
760
762
  for h in range(kernel.shape[1]):
761
763
  w = kernel[k, h]
762
764
  if w == 0:
763
- continue # mask says ignore
765
+ continue
764
766
 
765
767
  ii = i + k - dr
766
768
  jj = j + h - dc
767
769
 
768
770
  if 0 <= ii < rows and 0 <= jj < cols:
769
771
  x = data[ii, jj]
772
+ if x != x: # NaN check
773
+ continue
770
774
  w_sum += w
771
775
  sum_wx += w * x
772
776
  sum_wx2 += w * x * x
@@ -775,13 +779,12 @@ def _focal_var_cuda(data, kernel, out):
775
779
  mean = sum_wx / w_sum
776
780
  var = (sum_wx2 / w_sum) - (mean * mean)
777
781
 
778
- # numerical guard for tiny negative due to float rounding
779
782
  if var < 0.0:
780
783
  var = 0.0
781
784
 
782
785
  out[i, j] = var
783
786
  else:
784
- out[i, j] = 0.0
787
+ out[i, j] = math.nan
785
788
 
786
789
 
787
790
  @cuda.jit
@@ -856,15 +859,18 @@ def _focal_sum_cuda(data, kernel, out):
856
859
  for h in range(kernel.shape[1]):
857
860
  w = kernel[k, h]
858
861
  if w == 0:
859
- continue # mask says ignore
862
+ continue
860
863
 
861
864
  ii = i + k - dr
862
865
  jj = j + h - dc
863
866
 
864
867
  if 0 <= ii < rows and 0 <= jj < cols:
865
- s += w * data[ii, jj]
868
+ v = data[ii, jj]
869
+ if v != v: # NaN check
870
+ continue
871
+ s += w * v
866
872
 
867
- out[i, j] = s
873
+ out[i, j] = s # nansum: 0 when all NaN (matches numpy)
868
874
 
869
875
 
870
876
  def _focal_stats_func_cupy(data, kernel, func=_focal_max_cuda):
@@ -894,21 +900,22 @@ def _focal_mean_cuda(data, kernel, out):
894
900
  for h in range(kernel.shape[1]):
895
901
  w = kernel[k, h]
896
902
  if w == 0:
897
- continue # mask says ignore
903
+ continue
898
904
 
899
905
  ii = i + k - dr
900
906
  jj = j + h - dc
901
907
 
902
908
  if 0 <= ii < rows and 0 <= jj < cols:
903
- s += w * data[ii, jj]
909
+ v = data[ii, jj]
910
+ if v != v: # NaN check
911
+ continue
912
+ s += w * v
904
913
  w_sum += w
905
914
 
906
- # With your mask including the center, w_sum should be > 0.
907
- # Guard anyway to avoid divide-by-zero.
908
915
  if w_sum > 0.0:
909
916
  out[i, j] = s / w_sum
910
917
  else:
911
- out[i, j] = data[i, j]
918
+ out[i, j] = math.nan
912
919
 
913
920
 
914
921
  def _focal_stats_cupy(agg, kernel, stats_funcs):