Skip to content

feat(raster): label legend classes with the category names of the .aux.xml - #971

Merged
giswqs merged 1 commit into
opengeos:mainfrom
GISspecialistAlejandraDuque:legend-class-names
Oct 26, 2026
Merged

giswqs merged 1 commit into
opengeos:mainfrom
GISspecialistAlejandraDuque:legend-class-names

Conversation

@GISspecialistAlejandraDuque

@GISspecialistAlejandraDuque GISspecialistAlejandraDuque commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Summary

A classified raster with a colour table showed its values (1, 2, 3 …) in the Layers pane legend, even when GDAL's .aux.xml sidecar names each class. GDAL writes those names with SetCategoryNames, as <CategoryNames> in the band's <PAMRasterBand>.

  • pam.rs reads <CategoryNames>: one name per value from 0, empty for a value without a name, trimmed and cut at 256 characters like descriptions, and at most 65,536 per band.
  • Band gains classes and class_name(v). apply_pam fills them, next to the band's description.
  • The Colormap and Unique Values legend rows use the name. A value without a name still shows the value, so rasters without names look as before.
  • docs/user-guide/data.md mentions the category names next to the other things the sidecar supplies.

Not in this PR (the second part of #889 and related):

  • raster attribute tables (Class_Names / Value columns);
  • layer.classStyle setting labels on raster classes;
  • the layout colour bar, which draws ColorScale::Values with the values;
  • rasters converted through GDAL (read_converted), which don't read the sidecar today.

Testing

  • New tests:
    • rustgis-data, raster::pam::tests::reads_class_names: empty, unnamed and trailing categories, and the 256-character cut;
    • rustgis-data, raster::tests::gdal_sidecars_name_classes: a GeoTIFF written and read back with its .aux.xml;
    • rustgis-map, raster::tests::legend_labels_classes_with_their_names: Colormap and Unique Values labels, and the fallback to values.
  • CI on my fork: Linux, macOS and Windows tests, WebAssembly build, pre-commit lint and licences.
  • In the app: the Release workflow's Windows build of this branch, opening a slope-class raster written by GDAL with 8 category names. The legend shows the names, where v0.4.0 shows 1 to 7 (screenshot below). GDAL 3.12.2 and 3.13.1 read the same 8 names from that file.

Related issue

Part of #889.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Raster legends now display category names from GDAL sidecar files when available, with numeric values shown for unnamed classes.
  • Documentation
    • Updated the raster guide to explain how category names appear in Colormap and Unique Values legends.

…x.xml

A classified raster's legend listed its values (1, 2, 3...) even when
GDAL's .aux.xml sidecar names each class (<CategoryNames>, as written by
SetCategoryNames). The sidecar reader now keeps those names on the band,
and the Colormap and Unique Values legend rows use them, falling back to
the value for a class without a name.

Part of opengeos#889.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 37f2c376-6f70-4084-8d7b-4a9f236fd1f7
Commits

Reviewing files that changed from the base of the PR and between 889da8a and 2aa2c10.

Files selected for processing: 4
  • crates/data/src/raster/mod.rs
  • crates/data/src/raster/pam.rs
  • crates/map/src/raster.rs
  • docs/user-guide/data.md

Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 7 remain after this review.

Walkthrough

PAM category names now populate raster band classes. Unique Values and Colormap legends use available class names and fall back to formatted values. Tests cover PAM parsing, band lookup, and legend labels.

Changes: Raster class labels

Layer / File(s) Summary
Parse PAM categories
crates/data/src/raster/pam.rs
PamBand exposes category names parsed from PAM XML. Parsing trims names, limits name length and list size, and removes trailing empty entries while preserving interior empty entries.
Load categories into raster bands
crates/data/src/raster/mod.rs
Band stores class names and returns a name only for a valid, named index. apply_pam copies nonempty PAM category lists into bands.
Use class names in legends
crates/map/src/raster.rs, docs/user-guide/data.md
Unique Values and Colormap legends use class names when available and formatted values otherwise. The raster guide describes this behavior.

Priority: Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant PAM as PAM .aux.xml
  participant Parser as PamBand parser
  participant Raster as apply_pam
  participant Legend as RasterLayer::legend
  PAM->>Parser: provide CategoryNames
  Parser->>Raster: return PamBand categories
  Raster->>Legend: populate Band classes
  Legend->>Legend: use class_name or formatted value
Loading

Possibly related issues

  • opengeos/RustGIS#889: Requests raster legend class names, which this change reads from PAM sidecars and uses in legend entries.

Possibly related PRs

  • opengeos/RustGIS#890: Extends the same PAM band metadata and sidecar-reading path used by this change.

Suggested reviewers: giswqs

Merge Risk: Minimal · up to 2aa2c

No confirmed issue prevents merging after normal checks.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 12 functions across 3 files. (1 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Title check Passed The title clearly and concisely describes the main change: using category names from GDAL .aux.xml files to label raster legend classes.
Description check Passed The description follows the required Summary, Testing, and Related issue sections. It explains the change, documents scope exclusions, lists new tests and verification steps, and links the work to iss…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Description check

Explanation

The description follows the required Summary, Testing, and Related issue sections. It explains the change, documents scope exclusions, lists new tests and verification steps, and links the work to issue #889.

Full details: Docstring Coverage

Explanation

Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 12 functions across 3 files. (1 skipped: 1 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

A rabbit found names in the sidecar one day
And carried them neatly to legends on display
For unnamed classes, the numbers remain
While category labels hop into the frame
The raster now wears its names with delight

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

Code review

Bugs: None found. I checked the Band and PamBand struct literals across the workspace: the only Band { .. } literal (raster/mod.rs:308) sets classes, and the PamBand literals use ..Default, so nothing else breaks. class_name returns None for negative, fractional, NaN and infinite values and for values past the end of the names, so the fallback to the value holds. The legend's UniqueValues and Colormap paths fall back to fmt_num when no name exists. I could not compile or run the tests here (no shell), so the new tests are checked by reading only.

Security: None found. Category names come from the sidecar, but they are plain text in egui, trimmed, cut to 256 characters, capped at 65,536 per band, and the sidecar itself is capped at 16 MiB. The new code adds no unwrap, expect, panic or indexing outside tests.

Performance: None significant. Lookups are O(1) via get. apply_pam clones each band's name list once, bounded by the sidecar size cap.

Quality (nits, confidence high unless noted):

  • crates/map/src/raster.rs:1075: the Colormap label hard-codes band 0 in class_label(0, *v). This matches the r.bands.first() lookup on the line above, but a short comment would say why the Colormap layer reads band 0.
  • crates/data/src/raster/mod.rs:221: the class_name doc says None is returned "when v isn't a whole number or has no name". It also returns None for negative values and for values past the end of classes. Adding those cases would make the contract explicit.
  • crates/data/src/raster/pam.rs:132: line breaks inside a category name survive trim, so a legend row could wrap. Low impact; confidence medium.

AGENTS.md: Compliant. No unwrap, expect or panic outside tests, and get() is used for lookups. The new tests are in place. No new UI literals need tl!, and file-supplied names are not translated. docs/user-guide/data.md is updated. No assets, dependencies or ribbon changes are involved. The repository has no changelog to update.

I left no inline comments: the findings above are nits that don't justify separate threads.

Change size

Compared: the whole PR against main (merge base 9285e05 to PR head 2aa2c10).

Measure Value
Files changed 4 (0 added, 4 modified, 0 removed, 0 renamed)
Size before 183.1 KB
Size after 189.2 KB
Total size change +6.1 KB
Path Before After Change
crates/data/src/raster/pam.rs 9.5 KB 11.7 KB +2.2 KB
crates/data/src/raster/mod.rs 49.0 KB 51.1 KB +2.0 KB
crates/map/src/raster.rs 55.9 KB 57.6 KB +1.7 KB
docs/user-guide/data.md 68.6 KB 68.8 KB +179 B

@github-actions

Copy link
Copy Markdown
Contributor

📖 Docs preview

Item Value
Preview https://preview.rustgis.app/pr-971/
Web app https://preview.rustgis.app/pr-971/app/
Commit 2aa2c10

GitHub Pages takes a minute or two to publish a new commit.

@giswqs
giswqs merged commit 6f4533e into opengeos:main Oct 26, 2026
18 checks passed
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.

2 participants