简体   繁体   中英

Controlling legend key spacing and color in ggplot2

Issue

I am sure this is a very fix for someone who has done it before. I want to have a different spacing between legend key box 2 and 3 in ggplot2. Is there any trick to have a different spacing between the boxes of the legend? I also want to match the color of the legend box and the text. Currently, the legend text is black. So, I have two questions here

  1. How I add a different spacing between the legend keys: bigger spacing between box 2 and 3, keep the spacing between other legends key boxes similar).
  2. How to match the color of the legend key box with the text? Here is my data and code. I have also added the design of the graph I want to produce from this code.

Packages

library(tidyverse)
   library(ggplot2)
   library(ggtext)

Sample Data

Food = c("meat", "meat", "meat", "meat", "wheat","wheat","wheat", 
"wheat", "maize","maize","maize","maize")

 Subgroup = c("Male", "Female", "Urban", "Rural", "Male",  "Female", 
"Urban", "Rural",  "Male",  "Female","Urban", "Rural")

  mean = c(8.66, 10.45,  9.88,  7.32, 21.04, 19.65, 20.26, 20.87, 51.06 , 44.51,  47.60, 48.40)
df <- data.frame(Food, Subgroup,  mean)

df$Subgroup[df$Subgroup == "Urban"]  <- 1
df$Subgroup[df$Subgroup == "Rural"]  <- 2
df$Subgroup[df$Subgroup == "Female"] <- 3
df$Subgroup[df$Subgroup == "Male"]   <- 4

df$Subgroup <- factor(df$Subgroup,
                      levels = c(1, 2, 3, 4),
                      labels = c("Urban", "Rural", "Female", "Male"))



    #Color code
    
    
    colorPanel = c( '#42235e', '#7d103d', '#007da5', '#003b5d' )
    
    # bar chart
    
    
    Plot_FBGDS <-  ggplot(df, aes(x = Food, y = mean,  fill = Subgroup)) + 
      geom_col(stat = "identity", position = position_dodge(-0.84), width = 0.82) + 
      
      scale_y_continuous(breaks = c(0,20, 40, 60,80), expand = c(0,0),
                         limits = c(0,100), 
                         labels = function(x) paste0(x, "%")) + 
      geom_text(aes(label = paste0(mean,"%"), y = mean + 2, color = Subgroup), stat = "identity", 
                size = 3, vjust = 0.5, face = "bold", family = "sans",   position = position_dodge(-0.88)) +
      scale_color_manual(values = colorPanel) +
      scale_x_discrete(limits = c("meat",
                                  "wheat",
                                  "maize"))  + 
      
      coord_flip() +  
      scale_fill_manual(values =  colorPanel) +
                    
      labs( x= " ", 
            y = " ") +
      theme(text = element_text(size = 14, color = "black", family = "sans"),
            panel.background = element_rect(fill = "white"), 
            panel.border = element_blank(),
            axis.text.y = element_text(family = "sans", color = "black", size = 14),
            axis.text.x = element_blank(),
            axis.line.x =  element_blank(), 
            axis.line.y =  element_line(),
            axis.ticks.y.left = element_line(colour = "green"),
            axis.ticks.length=unit(0, "cm"),
            axis.title.x = element_text(size = 10, color = "black", family = "sans"),
            axis.text = element_text(size = 10, color = "black",family = "sans"),
            legend.key = element_rect(colour = NA, fill=NA, size= 7),
            legend.text = element_text(size = 10, family = "sans"),
            legend.margin=margin(t= -1, r= 2, b= 2, l= 2),
            legend.title =  element_blank(), 
            legend.key.height = unit(0.03, "npc"),
            legend.key.width = unit(0.03, "npc"),
            legend.position = c(0.85, 0.70),  
            panel.grid.major.x = element_blank(), 
            panel.grid.minor.y =  element_blank(),
            panel.grid.major.y = element_blank(),
            panel.grid.minor.x =  element_blank())
    
    
    
    
    Plot_FBGDS 

Current Plot

在此处输入图像描述

One option would be the ggnewscale package which allows to add a second fill legend. Doing so we could draw separate legends for Urban/Rural and for Male/Female for which the spacing could be set via legend.spacing.y . To make this work we have to add a duplicated geom_col where we have to explicitly map on the fill aes.

To color the legend text according to the bars you could make use of the ggtext package which allows styling of text via markdown, HTML and CSS.To this end use ggtext::element_markdown for legend.text and add labels to the legends where you set your desired colors using some HTML and CSS.

library(ggplot2)
library(ggtext)

# Color code
colorPanel <- c("#42235e", "#7d103d", "#007da5", "#003b5d")
names(colorPanel) <- c("Urban", "Rural", "Female", "Male")

labels <- paste0("<span style='color:", colorPanel, ";'>", names(colorPanel), "</span>")
names(labels) <- names(colorPanel)
# bar chart

library(ggnewscale)

Plot_FBGDS <- ggplot(df, aes(x = Food, y = mean, fill = Subgroup)) +
  geom_col(position = position_dodge(-0.84), width = 0.82) +
  geom_text(aes(label = paste0(mean, "%"), y = mean + 1, color = Subgroup),
            size = 3, hjust = 0, vjust = 0.5, fontface = "bold", family = "sans", position = position_dodge(-0.88), show.legend = FALSE
  ) +
  scale_fill_manual(values = colorPanel, breaks = c("Urban", "Rural"), labels = labels[c("Urban", "Rural")],
                    aesthetics = c("color", "fill"),
                    guide = guide_legend(order = 1)) +
  new_scale_fill() +
  new_scale_color() +
  geom_col(aes(fill = Subgroup), position = position_dodge(-0.84), width = 0.82) +
  scale_fill_manual(values = colorPanel, breaks = c("Female", "Male"), labels = labels[c("Female", "Male")], 
                    aesthetics = c("color", "fill"),
                    guide = guide_legend(order = 2)) +
  scale_y_continuous(
    breaks = c(0, 20, 40, 60, 80), expand = c(0, 0),
    limits = c(0, 100),
    labels = function(x) paste0(x, "%")
  ) +
  scale_x_discrete(limits = c(
    "meat",
    "wheat",
    "maize"
  )) +
  coord_flip() +
  labs(x = " ", y = " ") +
  theme(
    text = element_text(size = 14, color = "black", family = "sans"),
    panel.background = element_rect(fill = "white"),
    panel.border = element_blank(),
    axis.text.y = element_text(family = "sans", color = "black", size = 14),
    axis.text.x = element_blank(),
    axis.line.x = element_blank(),
    axis.line.y = element_line(),
    axis.ticks.y.left = element_line(colour = "green"),
    axis.ticks.length = unit(0, "cm"),
    axis.title.x = element_text(size = 10, color = "black", family = "sans"),
    axis.text = element_text(size = 10, color = "black", family = "sans"),
    legend.text = element_markdown(size = 10, family = "sans"),
    legend.key = element_rect(colour = NA, fill = NA, size = 7),
    legend.key.height = unit(0.03, "npc"),
    legend.key.width = unit(0.03, "npc"),
    legend.margin = margin(t = -1, r = 2, b = 2, l = 2),
    legend.title = element_blank(),
    legend.position = c(0.85, 0.70),
    legend.spacing.y = unit(2, "pt"),
    panel.grid.major.x = element_blank(),
    panel.grid.minor.y = element_blank(),
    panel.grid.major.y = element_blank(),
    panel.grid.minor.x = element_blank()
  )

Plot_FBGDS
#> Warning: position_dodge requires non-overlapping x intervals

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM