Skip to content

Fix polygon legend keys in geom_sf() (#6804) - #6923

Open
josefelipe0036 wants to merge 2 commits into
tidyverse:mainfrom
josefelipe0036:fix/issue-6804-sf-polygon-legend
Open

josefelipe0036 wants to merge 2 commits into
tidyverse:mainfrom
josefelipe0036:fix/issue-6804-sf-polygon-legend

Conversation

@josefelipe0036

Copy link
Copy Markdown

Closes #6804.

Diagnosis

"polygon" is one of the documented values of geom_sf(show.legend), but LayerSf$compute_geom_1() stores a character show.legend verbatim as the legend type, whereas the rest of the sf machinery calls polygons "other" (which is also what the automatic detection returns).

For legend keys, LayerSf$compute_geom_2() writes that type into the geometry column, and GeomSf$use_defaults() splits the key data with factor(type, c("point", "line", "other", "collection")). "polygon" is not one of those levels, so it becomes NA, every subset is empty and the key data loses all of its aesthetics:

  • ggplot2 4.0.3 (CRAN): vctrs::vec_slice() receives NULL, which is the error reported in the issue (backtrace: guide$process_layers() → layer$compute_geom_2() → GeomSf$use_defaults() → vec_slice(data, order(unlist(index)))).
  • development version: the linetype fix-up added in 5b928ae turns that NULL into an empty list, so there is no error anymore, but the key data that reaches draw_key() only contains .draw and the legend shows a label without a key.

Fix

LayerSf$compute_geom_1() now translates the documented "polygon" into the internal "other" type. Keys drawn with show.legend = "polygon" are then identical to the polygon keys chosen automatically. The "point", "line" and automatic legend types are unaffected.

(Normalising in GeomSf$use_defaults() would also work, but doing it where the legend type is determined keeps computed_geom_params$legend in the same vocabulary as the automatic detection.)

Reprex

library(ggplot2)
nc <- sf::st_read(system.file("shape/nc.shp", package = "sf"), quiet = TRUE)
nc$const_var <- "a"

p <- ggplot(nc) +
  geom_sf(aes(fill = const_var), show.legend = "polygon")
b <- ggplot_build(p)
str(unclass(b@plot@guides$params[[1]]$decor[[1]]$data), give.attr = FALSE)

Before (main @ b638d65): no key is drawn next to the a label.

List of 1
 $ .draw: logi TRUE

After (this PR): a filled polygon key, the same as with show.legend = TRUE.

List of 9
 $ fill     : chr "#F8766D"
 $ .id      : int 1
 $ geometry : chr "other"
 $ alpha    : logi NA
 $ stroke   : num 0.5
 $ colour   : chr "#595959FF"
 $ linewidth: num 0.2
 $ linetype : int 1
 $ .draw    : logi TRUE

Tests

A new test in test-geom-sf.R compares the legend key data of show.legend = "polygon" with the automatic polygon key (show.legend = TRUE) for polygon, point and mixed-geometry data. It maps a factor with an unused level and an NA (drop = FALSE, so four keys) and also covers empty layers. It fails on main (3 failures) and passes with this change.

Run locally on R 4.6.0 (Windows 11):

  • devtools::test(): 2979 expectations, 0 failures, 0 errors, 0 warnings.
  • devtools::check(document = TRUE, args = "--no-manual"): 0 errors | 0 warnings | 1 note. The note (checking Rd metadata: Rd files without \alias: 'shared_layer_parameters.Rd') comes from man/shared_layer_parameters.Rd, which this PR doesn't touch, so it is also present on main.

🤖 Generated with Claude Code

`show.legend = "polygon"` is a documented value for `geom_sf()`, but
`LayerSf$compute_geom_1()` passed it on verbatim while the rest of the sf
machinery calls polygons "other". `GeomSf$use_defaults()` splits legend
key data by `factor(type, c("point", "line", "other", "collection"))`, so
"polygon" became `NA`, every subset was empty and the key lost all of its
aesthetics: an error in `vec_slice()` on ggplot2 4.0.3, an empty key in
the development version.

Translate "polygon" to the internal "other" type, so that the key matches
the one chosen automatically for polygon data.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@josefelipe0036
josefelipe0036 marked this pull request as ready for review November 7, 2026 00:02

@teunbrand teunbrand left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the contribution! The logic was right, but I've streamlined it a bit so it falls out naturally from the switch() statement above. We'll wait with merging until an intermediate release is resolved.

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.

geom_sf(show.legend = "polygon") leads to error "Error in vec_slice()"

2 participants