Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Feb 5, 2026

When groups have different observed levels of x, grouped_ggbarstats/grouped_ggpiestats produce duplicate legends because patchwork::guides("collect") can't merge non-identical fill scales.

Root cause: descriptive_data() reconstructs the factor via factor(x, unique(x)), discarding unobserved levels after .cat_counter() filters zero-count rows. Each subplot ends up with a different set of factor levels → different legends.

Changes:

  • R/ggpiestats-ggbarstats-helpers.R: Capture original factor levels before counting/filtering, then use union(unique(x), all_lvls) when reconstructing the factor to retain unobserved levels
  • R/ggbarstats.R, R/ggpiestats.R: Add drop = FALSE to scale_fill_paletteer_d() so the fill scale includes all factor levels even when absent from the subplot's data
  • Removed stale snapshot SVGs for regeneration in CI
# Previously produced two separate legends (4 vs 5 levels)
grouped_ggbarstats(
  data          = dt,
  x             = GenderIdentity,
  y             = subject,
  grouping.var  = school,
)
Original prompt

This section details on the original issue you should resolve

<issue_title>double legend in grouped_ggbarstats</issue_title>
<issue_description>I am potting some data that you can find below:

structure(list(school = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L), levels = c("School 1", 
"School 2", "School 3", "School 4", "School 5", "School 6"), class = "factor"), 
    subject = structure(c(2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
    2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
    2L, 2L, 2L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
    1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
    1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
    1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
    2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
    2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
    2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 3L, 3L, 
    3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 
    3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 
    3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 
    3L, 3L, 3L, 3L, 3L, 3L), levels = c("Biology", "Chemistry", 
    "Physics"), class = "factor"), GenderIdentity = structure(c(1L, 
    1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 
    2L, 2L, 2L, 2L, 3L, 3L, 4L, 4L, NA, NA, NA, 1L, 1L, 1L, 1L, 
    1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
    2L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 5L, 5L, 5L, 5L, 
    5L, 5L, 5L, 5L, 5L, 5L, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
    NA, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 
    2L, 2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 
    3L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, NA, NA, NA, NA, 
    NA, NA, NA, NA, NA, NA, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
    1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 
    3L, 3L, 3L, 3L, 3L, 3L, 4L, 4L, 4L, 5L, 5L, 5L, 5L, 5L, 5L, 
    5L, 5L, 5L, 5L, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), levels = c("Man", 
    "Woman", "Non-binary", "Not listed", "Prefer not to answer"
    ), class = "factor")), class = c("grouped_df", "tbl_df", 
"tbl", "data.frame"), row.names = c(NA, -180L), groups = structure(list(
    school = structure(c(1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 
    2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L), levels = c("School 1", 
    "School 2", "School 3", "School 4", "School 5", "School 6"
    ), class = "factor"), subject = structure(c(2L, 2L, 2L, 2L, 
    2L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 
    3L, 3L), levels = c("Biology", "Chemistry", "Physics"), class = "factor"), 
    GenderIdentity = structure(c(1L, 2L, 3L, 4L, NA, 1L, 2L, 
    3L, 5L, NA, 1L, 2L, 3L, 5L, NA, 1L, 2L, 3L, 4L, 5L, NA), levels = c("Man", 
    "Woman", "Non-binary", "Not listed", "Prefer not to answer"
    ), class = "factor"), .rows = structure(list(1:10, 11:20, 
        21:22, 23:24, 25:27, 28:37, 38:47, 48:57, 58:67, 68:77, 
        78:87, 88:97, 98:107, 108:117, 118:127, 128:137, 138:147, 
        148:157, 158:160, 161:170, 171:180), ptype = integer(0), class = c("vctrs_list_of", 
    "vctrs_vctr", "list"))), row.names = c(NA, -21L), .drop = TRUE, class = c("tbl_df", 
"tbl", "data. Frame")))

When i plot, the legend is somehow messed up, and i cant figure out why there are two legends

grouped_ggbarstats(
  data          = dt,
  x             = GenderIdentity,
  y             = subject,
  grouping.var  = school,
  plotgrid.args = list(nrow = 2)
)

image

  • I tried converting everything to characters- did not work
    </issue_description>

Comments on the Issue (you are @copilot in this section)


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

@codecov
Copy link

codecov bot commented Feb 6, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (7979ee2) to head (fe97bf5).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@             Coverage Diff             @@
##             main     #1040      +/-   ##
===========================================
+ Coverage   99.86%   100.00%   +0.13%     
===========================================
  Files          17        17              
  Lines         767       770       +3     
===========================================
+ Hits          766       770       +4     
+ Misses          1         0       -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@IndrajeetPatil IndrajeetPatil force-pushed the copilot/fix-double-legend-issue branch 3 times, most recently from e4c7009 to 7c3a50a Compare February 6, 2026 21:10
When using grouped_ggbarstats() or grouped_ggpiestats() with groups that
have different observed levels of a factor, patchwork could not collect
legends because the fill scales differed across panels.

Changes:
- Add drop = FALSE to scale_fill_paletteer_d() in ggbarstats and ggpiestats
  so all factor levels appear in each panel's legend
- In descriptive_data(), conditionally use tidyr::complete() to add zero-count
  rows for missing factor levels (only when levels are actually missing, to
  avoid unnecessary row reordering that would affect geom_label_repel layout)
- Preserve original descending level order using rev(all_lvls)
- Add edge-case tests for grouped plots with differing factor levels

Closes #868
@IndrajeetPatil IndrajeetPatil force-pushed the copilot/fix-double-legend-issue branch from 7c3a50a to 0e51658 Compare February 7, 2026 11:02
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.

double legend in grouped_ggbarstats

2 participants