Captain Hat
Captain Hat

Reputation: 3237

How can I drop a used value from the legend?

In Brief

I'm aware that scale_*_*(drop = TRUE) can be used to drop empty factor levels from a legend. Perhaps counterintuitively, I'm trying to drop used levels from plot.

As you may have guessed, it's a slightly hack-y use case: I'm using invisible bars with geom_bar to offset 'floating' likert response visualisations. I'm not interested in frame-challenges or alternative approaches to this problem, I'm asking specifically about how to drop a used level from the legend.

Use case and example

The code below reproduces a very simple version of my visualisation. It works well enough, but the legend is offset very slightly from the centre (this notices more in the 'real' visualisation). I would like to drop the 'invisible' level to present this. I'm aware that I could use numeric arguments to legend.position to re-centre the whole thing, but that's fiddly and non-generalisable.

## libraries ---
require(ggplot2)
#> Loading required package: ggplot2
require(dplyr)
#> Loading required package: dplyr
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union

## data ---
plotData <- tibble(label = 
                     factor(c("", "strawberries", "blueberries", "", "strawberries", "blueberries"),
                             levels = c("strawberries", "blueberries", ""), ordered = TRUE),
                   value = c(30, 40, 20, 15, 30, 15),
                   bowl = factor(c("bowl1", "bowl1", "bowl1", "bowl2", "bowl2", "bowl2"))) 

## plot ---

### Specs for the legend
legendSpecs <- guide_legend(nrow = 1, label.position = "bottom",
                            reverse = TRUE, title = NULL)
### desired plot
ggplot(plotData, aes(x = value, y = bowl,
                     fill = label, colour = label)) +
  geom_bar(stat = "identity", position = "stack") +
  scale_fill_manual(values = c("blue", "red", NA), guide = legendSpecs) +
  scale_colour_manual(values = c("black",  "black", NA), guide = legendSpecs) +
  theme_minimal() +
  theme(legend.position = "bottom")

Demonstrating the small offset in the legend that I'm trying to get rid of:

### demonstrating legend offset
ggplot(plotData, aes(x = value, y = bowl,
                     fill = label, colour = label)) +
  geom_bar(stat = "identity", position = "stack") +
  scale_fill_manual(values = c("blue", "red", NA), guide = legendSpecs) +
  scale_colour_manual(values = c("black",  "black", "black"), guide = legendSpecs) +
  theme_minimal() +
  theme(legend.position = "bottom")

Created on 2021-06-30 by the reprex package (v2.0.0)

Upvotes: 3

Views: 124

Answers (1)

stefan
stefan

Reputation: 124183

This could be achieved by setting the breaks of the scale to include only the desired categories:

## libraries ---
require(ggplot2)
require(dplyr)

## data ---
plotData <- tibble(label = 
                     factor(c("", "strawberries", "blueberries", "", "strawberries", "blueberries"),
                            levels = c("strawberries", "blueberries", ""), ordered = TRUE),
                   value = c(30, 40, 20, 15, 30, 15),
                   bowl = factor(c("bowl1", "bowl1", "bowl1", "bowl2", "bowl2", "bowl2"))) 

## plot ---

### Specs for the legend
legendSpecs <- guide_legend(nrow = 1, label.position = "bottom",
                            reverse = TRUE, title = NULL)
### desired plot
ggplot(plotData, aes(x = value, y = bowl,
                     fill = label, colour = label)) +
  geom_bar(stat = "identity", position = "stack") +
  scale_fill_manual(values = c("blue", "red", NA), na.value = NA,
                    guide = legendSpecs, breaks = c("blueberries", "strawberries"))  +
  scale_colour_manual(values = c("black",  "black", NA), , na.value = NA, 
                      guide = legendSpecs, 
                      breaks = c("blueberries", "strawberries")) +
  theme_minimal() +
  theme(legend.position = "bottom")

Upvotes: 1

Related Questions