Search code examples
rggplot2ggnewscale

How to remove duplicate legend in R ggplot


My map is producing two legends for my DMA boundaries. The one seen at the bottom of my figure is correct, but the at the top (placed above the "Frequency of Mentions") is incorrect and I'd like removed. However, when I remove it, it messes up other features in my map. Apologies for the likely simple fix, my brain is tired!

# Filter out zero counts and apply binning
ok_cities_correct_clean <- ok_cities_correct_clean %>%
  filter(COUNT > 0) %>%
  mutate(
    color_gradient = cut(
      COUNT,  # Cut the COUNT values into the specified ranges
      breaks = c(0, 10, 20, 30, Inf),  # Include 0 as the lower bound for first bin
      labels = c("1 - 10", "11 - 20", "21 - 30", "> 30"),  # Correct number of labels
      right = TRUE  # Ensure the upper bound is included in each bin
    )
  )

# Define color palettes
cities_urban <- c("lightblue", "lightskyblue", "dodgerblue", "darkblue")
names(cities_urban) <- labels


cities_rural <- c("lightpink", "lightcoral", "firebrick", "darkred")
names(cities_rural) <- labels



ggplot() +
  
  # Add OK counties
  geom_sf(
    data = ok_counties_reproj,
    fill = "#f5f5f5",
    color = "black",
    size = 0
  ) +
  
  # Add DMA 
  geom_sf(
    data = ok_DMA,
    aes(fill = DMA, color = DMA),
    linewidth = 1.5,
    alpha = 0.75,
    show.legend = c(fill = TRUE, color = FALSE)
  ) +
  
  # OK counties (border, no fill)
  geom_sf(
    data = ok_counties_reproj,
    fill = NA,
    color = "black",
    size = 1
  ) +
  
  # Set fill colors for DMA
  scale_fill_manual(
    values = c(
      "Tulsa, OK" = "#4575b4",
      "Oklahoma City, OK" = "#5ab4ac"
    ),
    aesthetics = c("fill", "color"),
    guide = guide_legend(override.aes = list(
      color = c("#5ab4ac", "#4575b4")
    ))
  ) +
  
  new_scale_color() +
  
  # Add cities with color_gradient based on urban/rural classification
  geom_sf(
    data = ok_cities_correct_clean %>%
      filter(COUNT > 0, CLASSIF == "Urban"),
    aes(size = COUNT, color = color_gradient)
  ) +
  
  scale_color_manual(
    values = cities_urban, na.value = "gray", name = "Urban"
  ) +
  
  new_scale_color() +
  
  # Add cities with color g radient based on urban/rural classification
  geom_sf(
    data = ok_cities_correct_clean %>%
      filter(COUNT > 0, CLASSIF == "Rural"),
    aes(size = COUNT, color = color_gradient)
  ) +
  
  scale_color_manual(
    values = cities_rural, na.value = "gray", name = "Rural"
  ) +
  
  scale_size_continuous(
    range = c(1, 10),
    name = "Frequency of Mentions"
  )

Figure: enter image description here

P.S. Please ignore the map clutter -- the final product will utilize a facet_wrap to declutter what you currently see.


Solution

  • As I already mentioned in my answer on your previous question the issue with the duplicated legend seems to be related to the use of ggnewscale. The fix I proposed there works for new_scale_fill. But as you use new_scale_color instead we have to switch fill and color in the fix, i.e. use show.legend = c(fill = FALSE, color = TRUE) and guide_legend(override.aes = list(fill = c("#5ab4ac", "#4575b4")):

    Using an adapted version of the minimal reproducible example from your previous question:

    library(tidyverse)
    library(ggnewscale)
    
    ## Make example data
    set.seed(123)
    
    nc_counties <- sf::st_read(system.file("shape/nc.shp", package = "sf"), quiet = TRUE)
    
    dma <- sample(nrow(nc_counties), 20)
    
    ok_counties_reproj <- nc_counties
    
    ok_DMA <- nc_counties[dma, ]
    ok_DMA$DMA <- c("Tulsa, OK", "Oklahoma City, OK")
    
    ok_cities_correct_clean <- nc_counties
    ok_cities_correct_clean <- sf::st_centroid(ok_cities_correct_clean)
    ok_cities_correct_clean$CLASSIF <- sample(
      c("Urban", "Rural"),
      nrow(ok_cities_correct_clean),
      replace = TRUE
    )
    ok_cities_correct_clean$COUNT <- sample(
      seq(0, 40),
      nrow(ok_cities_correct_clean),
      replace = TRUE
    )
    ###
    
    breaks <- c(-Inf, 10, 20, 30, Inf)
    labels <- labels <- c("1 - 10", "11 - 20", "21 - 30", "> 30")
    
    ## Bin the COUNT variable
    ok_cities_correct_clean$color_gradient <- cut(
      ok_cities_correct_clean$COUNT, breaks, labels
    )
    
    ## Define color palettes
    cities_urban <- c("lightblue", "lightskyblue", "dodgerblue", "darkblue")
    names(cities_urban) <- labels
    
    cities_rural <- c("lightpink", "lightcoral", "firebrick", "darkred")
    names(cities_rural) <- labels
    
    ggplot() +
      # Add OK counties
      geom_sf(
        data = ok_counties_reproj,
        fill = "#f5f5f5",
        color = "black",
        size = 0
      ) +
      # Add DMA
      geom_sf(
        data = ok_DMA,
        aes(fill = DMA, color = DMA),
        linewidth = 1.5,
        alpha = 0.75,
        show.legend = c(fill = FALSE, color = TRUE)
      ) +
      # OK counties (border, no fill)
      geom_sf(
        data = ok_counties_reproj,
        fill = NA,
        color = "black",
        size = 1
      ) +
      # Set fill colors for DMA
      scale_fill_manual(
        values = c(
          "Tulsa, OK" = "#4575b4",
          "Oklahoma City, OK" = "#5ab4ac"
        ),
        aesthetics = c("color", "fill"),
        guide = guide_legend(override.aes = list(
          fill = c("#5ab4ac", "#4575b4")
        ))
      ) +
      new_scale_color() +
      # Add cities with color_gradient based on urban/rural classification
      geom_sf(
        data = ok_cities_correct_clean %>%
          filter(COUNT > 0, CLASSIF == "Urban"),
        aes(size = COUNT, color = color_gradient)
      ) +
      scale_color_manual(
        values = cities_urban, na.value = "gray", name = "Urban"
      ) +
      new_scale_color() +
      # Add cities with color g radient based on urban/rural classification
      geom_sf(
        data = ok_cities_correct_clean %>%
          filter(COUNT > 0, CLASSIF == "Rural"),
        aes(size = COUNT, color = color_gradient)
      ) +
      scale_color_manual(
        values = cities_rural, na.value = "gray", name = "Rural"
      ) +
      scale_size_continuous(
        range = c(1, 10),
        name = "Frequency of Mentions"
      )
    

    enter image description here