You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于ggpattern包的地图图例创建及绘制逻辑优化咨询

解决方案:ggpattern地图的图例创建与代码优化

问题回顾

我用ggpattern包绘制了一张为不同县区分配颜色和图案的地图,但无法生成包含对应颜色+图案组合的图例;同时当前逐个添加县区的方式较为繁琐,希望得到更优实现方案。

原代码:

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)


  
</think_never_used_51bce0c785ca2f68081bfa7d91973934>用户现在需要把之前的问题和代码整理成符合要求的Markdown格式,还要翻译成中文,去掉AI味,最后标注来源。首先,先理清楚结构:

首先是问题描述,然后是代码,然后是解决方案,分两部分:一是优化绘图方式(不用循环逐个加),二是创建带颜色和图案的图例。

首先,问题部分:
我用ggpattern包做了一张给不同县区添加颜色和图案的地图,但没法生成对应颜色和图案的图例。我逐个添加县区是为了控制特定县区的图案,也想知道有没有更好的实现方式。

然后是原代码,用代码块包裹。

接下来是解决方案,分两部分:

## 一、优化绘图逻辑(避免循环逐个添加)
原来的循环方式不仅繁琐,还不利于自动生成图例。正确的做法是把颜色、图案信息提前合并到nc的sf数据框里,然后一次调用geom_sf_pattern,这样ggplot能自动识别映射关系,方便后续做图例。

代码示例:
先处理颜色和图案的随机分配,合并到nc数据框:
```r
library(ggplot2)
library(sf)
library(tidyverse)
library(ggpattern)
library(cowplot)

# 读取数据
nc <- st_read(system.file("shape/nc.shp", package="sf")) %>%
  mutate(row_id = row_number())

# 准备图案列表
df1 <- data.frame(
  x    = rep(1:6, 9),
  y    = rep(1:9, each=6),
  name = gridpattern::names_magick,
  stringsAsFactors = FALSE
) %>%
  mutate(row_id = row_number())

# 为前10个县区随机分配颜色和图案
set.seed(123) # 设置种子保证结果可复现
nc_plot <- nc %>%
  filter(row_id %in% 1:10) %>%
  mutate(
    # 随机生成填充色
    fill_color = rgb(
      red = sample(0:255, n(), replace = TRUE),
      green = sample(0:255, n(), replace = TRUE),
      blue = sample(0:255, n(), replace = TRUE),
      maxColorValue = 255
    ),
    # 随机分配图案ID和名称
    random_pattern_id = sample(1:54, n(), replace = TRUE)
  ) %>%
  left_join(df1, by = c("random_pattern_id" = "row_id"))

# 绘制地图
p1 <- ggplot() +
  geom_sf_pattern(
    data = nc_plot,
    aes(fill = fill_color, pattern_type = name),
    color = "black",
    pattern = "magick"
  )
p1

二、创建自定义颜色+图案图例

因为ggplot默认的图例分开显示颜色和图案,我们需要用cowplot手动创建组合图例,步骤如下:

  1. 先制作每个图例项的小图(颜色+图案)
  2. 组合这些小图和标签,生成自定义图例
  3. 把地图和图例拼接在一起

代码示例:

# 准备图例数据(包含县区名、颜色、图案)
legend_data <- nc_plot %>%
  st_drop_geometry() %>%
  select(county = NAME, fill_color, name)

# 生成每个图例项的小绘图
legend_plots <- map2(legend_data$fill_color, legend_data$name, function(col, pat) {
  ggplot() +
    geom_rect_pattern(
      aes(xmin = 0, xmax = 1, ymin = 0, ymax = 1),
      fill = col,
      pattern = "magick",
      pattern_type = pat,
      color = "black"
    ) +
    theme_void()
})

# 组合图例项和标签
legend <- plot_grid(
  plotlist = legend_plots,
  ncol = 1,
  labels = legend_data$county,
  label_size = 9,
  label_x = 0.1,
  hjust = 0
)

# 拼接地图和图例
final_plot <- plot_grid(p1, legend, rel_widths = c(2, 1))
final_plot

然后说明这样做的好处:

  • 避免循环,代码更简洁易维护
  • 数据和绘图逻辑分离,便于调整颜色、图案规则
  • 自定义图例完美匹配每个县区的颜色+图案组合

最后标注:内容的提问来源于stack exchange,提问作者jsimpsno

现在要把这些整理成Markdown,注意格式:标题用#,列表用-,代码用```r,强调用*。还要去掉AI味,语言要像stackoverflow的专家回答,直接给解决方案,不要多余的话。

现在把结构整理好:

解决方案:ggpattern地图的图例创建与代码优化

问题回顾

我用ggpattern包绘制了一张为不同县区分配颜色和图案的地图,但无法生成包含对应颜色+图案组合的图例;同时当前逐个添加县区的方式较为繁琐,希望得到更优实现方案。

原代码:

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))

一、优化绘图逻辑(替代循环逐个添加)

循环添加图层的方式不仅冗余,还会导致ggplot无法自动识别映射关系,不利于图例生成。正确做法是将颜色、图案信息提前合并到sf数据框中,一次性调用geom_sf_pattern:

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

# 读取并预处理数据
nc <- st_read(system.file("shape/nc.shp", package="sf")) %>%
  mutate(row_id = row_number())

# 准备magick图案列表
df1 <- data.frame(
  x    = rep(1:6, 9),
  y    = rep(1:9, each=6),
  name = gridpattern::names_magick,
  stringsAsFactors = FALSE
) %>%
  mutate(row_id = row_number())

# 为目标县区分配随机颜色和图案(这里取前10个)
set.seed(123) # 设置种子保证结果可复现
nc_plot <- nc %>%
  filter(row_id %in% 1:10) %>%
  mutate(
    # 生成随机RGB填充色
    fill_color = rgb(
      red = sample(0:255, n(), replace = TRUE),
      green = sample(0:255, n(), replace = TRUE),
      blue = sample(0:255, n(), replace = TRUE),
      maxColorValue = 255
    ),
    # 随机分配图案ID
    random_pattern_id = sample(1:54, n(), replace = TRUE)
  ) %>%
  # 关联图案名称
  left_join(df1, by = c("random_pattern_id" = "row_id"))

# 绘制地图
p1 <- ggplot() +
  geom_sf_pattern(
    data = nc_plot,
    aes(fill = fill_color, pattern_type = name),
    color = "black",
    pattern = "magick"
  ) +
  theme_minimal()
p1

二、创建自定义颜色+图案组合图例

ggplot默认会将颜色和图案拆分为两个独立图例,我们可以用cowplot手动生成组合式图例,步骤如下:

# 提取图例所需数据(去除几何信息)
legend_data <- nc_plot %>%
  st_drop_geometry() %>%
  select(county = NAME, fill_color, name)

# 为每个县区生成带颜色和图案的小矩形图
legend_items <- map2(legend_data$fill_color, legend_data$name, function(col, pat) {
  ggplot() +
    geom_rect_pattern(
      aes(xmin = 0, xmax = 1, ymin = 0, ymax = 1),
      fill = col,
      pattern = "magick",
      pattern_type = pat,
      color = "black"
    ) +
    theme_void() # 去除多余元素
})

# 组合图例项与县区名称标签
custom_legend <- plot_grid(
  plotlist = legend_items,
  ncol = 1,
  labels = legend_data$county,
  label_size = 9,
  label_x = 0.1,
  hjust = 0,
  align = "v"
)

# 拼接地图与自定义图例
final_plot <- plot_grid(p1, custom_legend, rel_widths = c(2, 1), align = "h")
final_plot

优化点说明

  • 去除循环逻辑,代码更简洁易维护,便于后续调整颜色/图案规则
  • 数据与绘图逻辑分离,符合ggplot的映射思想
  • 自定义图例完美匹配每个县区的颜色+图案组合,解决原问题中的图例缺失问题

内容的提问来源于stack exchange,提问作者jsimpsno

这样应该就符合要求了,格式正确,语言专业,没有AI味,解决了用户的两个问题:图例创建和代码优化。</think_never_used_51bce0c785ca2f68081bfa7d91973934># 解决方案:ggpattern地图的图例创建与代码优化

问题回顾

我用ggpattern包绘制了一张为不同县区分配颜色和图案的地图,但无法生成包含对应颜色+图案组合的图例;同时当前逐个添加县区的方式较为繁琐,希望得到更优实现方案。

原代码:

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))

一、优化绘图逻辑(替代循环逐个添加)

循环添加图层的方式不仅冗余,还会导致ggplot无法自动识别映射关系,不利于图例生成

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 00:14:29