rggplot2ggpattern

create legend from ggpattern


I have created a map that iterates through counties and adds a color and a pattern based on the great ggpattern r package, however I cannot figure out how to create a legend to add to the map with the cooresponding colors and hex patterns. The reason i'm iterating and adding each individual county is so i can eventually control which patterns go with certain counties. If there is a better way i am open to that as well!

library(ggplot2)
library(sf)
library(tidyverse)
library(ggpattern)
library(cowplot)

nc <- st_read(system.file("shape/nc.shp", package="sf"))


nc<-nc%>%mutate(row_id=row_number())

ids=unique(nc$row_id)

##pattern
df1 <- data.frame(
  x    = rep(1:6, 9),
  y    = rep(1:9, each=6),
  name = gridpattern::names_magick,
  stringsAsFactors = FALSE
)

df1<-df1%>%mutate(row_id=row_number())



df_color<-data.frame()

pattern_rand_df_final<-data.frame()


p1 <- ggplot()

ids=1:10

for(id in ids){
  df <- nc%>%filter(id==row_id)
  x=paste(sample(0:255,size=1,replace=TRUE),collapse=" ")
  y=paste(sample(0:255,size=1,replace=TRUE),collapse=" ")
  z=paste(sample(0:255,size=1,replace=TRUE),collapse=" ")
  
  zz=rgb(x,y,z, maxColorValue = 255)
  df_color<<-rbind(df_color,zz)
  df_color=df_color%>%mutate(row_id=row_number())
  df_color_f<-  df_color%>%filter(row_id==id)
  colnames(df_color_f)[1]='fill_color'
    
  num_rand=sample(1:54,1)
  pattern_rand_df_final<<-rbind(pattern_rand_df_final,num_rand)
  pattern_rand_df_final=pattern_rand_df_final%>%mutate(row_id=row_number())
  pattern_rand_df_final_filter<-  pattern_rand_df_final%>%filter(row_id==id)
  colnames(pattern_rand_df_final_filter)[1]='random_pattern'
  
  df1_f<-df1%>%filter(row_id==pattern_rand_df_final_filter$random_pattern)


  
p1<-p1 +  geom_sf_pattern(data = df, fill=df_color_f$fill_color, color = "black",pattern='magick',
                          pattern_type = I(df1_f$name))


}

##this creates the map 
p1

legend_df<-full_join(df_color,pattern_rand_df_final)

colnames(legend_df)[1]='color_fill'
colnames(legend_df)[3]='hex_fill_number_id'


legend_df<-left_join(legend_df,df1%>%select(name,row_id),by=c("hex_fill_number_id"="row_id"))

###this is the legend information i would like to add using cowplot 
legend_df<-left_join(legend_df,st_drop_geometry(nc)%>%select(row_id,NAME)%>%rename(county=NAME))


Solution

  • As a general rule, if you want to have a legend then map on aesthetics. This said, one option and a probably easier approach would be to create two named vectors of fill colors and patterns, which assign colors and or patterns to county names. Then map the county NAME on the fill and pattern_type aes inside aes() and apply your desired colors and patterns using scale_xxx_manual:

    library(ggplot2)
    library(sf)
    library(ggpattern)
    
    set.seed(123)
    
    nc <- st_read(system.file("shape/nc.shp", package = "sf"))
    
    pal_color <- rgb(
      sample(255, nrow(nc), replace = TRUE),
      sample(255, nrow(nc), replace = TRUE),
      sample(255, nrow(nc), replace = TRUE),
      maxColorValue = 255
    )
    
    n_counties <- 10
    
    dat_map <- nc |>
      head(n_counties)
    
    pal_color <- pal_color[seq_len(n_counties)]
    pal_pattern <- sample(gridpattern::names_magick, n_counties)
    
    names(pal_color) <- names(pal_pattern) <- dat_map$NAME
    
    ggplot() +
      geom_sf_pattern(
        data = dat_map,
        aes(
          fill = NAME,
          pattern_type = NAME
        ),
        color = "black", pattern = "magick",
      ) +
      scale_fill_manual(values = pal_color) +
      scale_pattern_type_manual(values = pal_pattern) +
      theme(legend.position = "bottom")