Skip to content

dft_rast_classify(): classify factor input from its raw codes (#91) - #94

Open
NewGraphEnvironment wants to merge 6 commits into
mainfrom
91-dft-rast-classify-returns-empty-levels-w
Open

NewGraphEnvironment wants to merge 6 commits into
mainfrom
91-dft-rast-classify-returns-empty-levels-w

Conversation

@NewGraphEnvironment

Copy link
Copy Markdown
Owner

Summary

  • dft_rast_classify() returned a factor with no levels and no colours when given a raster that was already a factor, for example a published floodplain raster with a RAT, or a raster re-classified. The cause: terra::unique() returns a factor's labels, not its codes. The fix strips the levels on a copy (strip_copy(), which already existed) before reading the codes. The caller's raster is untouched.
  • The strip runs after the remap. terra::classify() already reads raw codes, so a remap that matches pays nothing extra. A remap that matches nothing had the same bug on main, and now works.
  • is.factor(x)[1]: the plan review and code-check round 1 each found, independently, that a bare is.factor(x) errors on a multi-layer stack. main classified a stack's layer 1 without error, and that behaviour is kept.

Scale check (BULK classified_2017.tif, 169M cells, published RAT, /usr/bin/time -l)

input main peak branch peak levels out (main → branch)
file-backed factor 1.05 GiB 1.05 GiB 0 → 9
in-memory factor 4.20 GiB 5.47 GiB 0 → 9
in-memory factor + matching remap 5.47 GiB 5.47 GiB 8 → 8

The one cost is an in-memory factor with no matching remap: one full extra copy. No R-level terra call reads a factor's codes without a copy (activeCat<- and levels<- both deepcopy()).

Related Issues

Test plan

  • devtools::test(): 1344 pass / 0 fail / 15 skip (network and bfast, opt-in)
  • New tests fail on main (9 assertions) and pass on the branch: re-classify, file-backed RAT with its own labels and palette, remap on a factor (matched and unmatched), caller unmodified, active category ≠ 1, 2-layer stacks
  • Mutation checks: an in-place strip turns both caller-unmodified tests red; dropping [1] turns the stack test red
  • /code-check: 3 rounds (the stack error, then Clean, Clean). Round 3 checked every NEWS claim against a copy of main.

Notes

Planning record: planning/archive/2026-09-issue-91-classify-factor-input/, which includes the plan review and the three review rounds.

🤖 Generated with Claude Code

https://claude.ai/code/session_01PRhUJsuKABLfpBGktPoiBN

NewGraphEnvironment and others added 6 commits September 29, 2026 23:16
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PRhUJsuKABLfpBGktPoiBN
terra::unique() returns a factor's labels, not its codes, so a raster
that was already a factor (a published RAT raster, or one re-classified)
matched no code in class_table and came back with no levels or colours.
Strip the levels on a copy with strip_copy() after the remap step, where
only an unremapped factor needs it; is.factor(x)[1] keeps a stack on the
pre-existing layer-1 path instead of erroring.

BULK classified_2017.tif: file-backed peak unchanged (1.05 GiB); an
in-memory unremapped factor pays one copy (5.47 vs 4.20 GiB).

Fixes #91

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PRhUJsuKABLfpBGktPoiBN
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PRhUJsuKABLfpBGktPoiBN
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PRhUJsuKABLfpBGktPoiBN
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PRhUJsuKABLfpBGktPoiBN
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PRhUJsuKABLfpBGktPoiBN

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

dft_rast_classify() returns empty levels when its input is already a factor

1 participant