将栅格转DataFrame后,用ggplot自定义分配颜色失败求助
问题:自定义栅格转DataFrame后的ggplot填充颜色不符合预期
我将栅格文件转换为DataFrame以便使用ggplot绘图,每个像素对应唯一编码,但R默认的分类变量配色不符合需求。于是创建了包含颜色代码的tibble:
colors <- tibble( colors = c("000000","#ffff64","#aaf0f0","#dcf064","#c8c864","#006400","#00a000","#00a000","#285000","#788200","#8ca000","#be9600","#966400","#ffb432","#ffdcd2","#ffebaf","#00785a","#009678","#00DC82","#C31400","#FFF5D7","#0046C8","#FFFFFF"), cod_global = c(0,10,20,30,40,50,60,70,80,90,100,110,120,130,140,150,160,170,180,190,200,210,220) )
将该tibble与从栅格导出的、含约5800万行的Xinjiang_df执行left_join操作后,原本期望通过设置fill = colors让像素匹配指定颜色,但结果不符合预期:
- 未自定义颜色的效果:使用默认配色渲染,能区分不同编码的像素,但颜色不符合需求
- 自定义颜色后的效果:颜色混乱,未按指定的颜色代码对应像素
未自定义颜色时的绘图代码:
ggplot(Xinjiang_df, aes(x = x, y = y, fill = colors))
解决思路
核心问题
当你把fill映射到颜色字符串列时,ggplot会将颜色字符串视为分类变量,自动用默认配色给这些字符串分配颜色,而非直接使用字符串对应的颜色值。此外,5800万行的DataFrame做join操作会极大消耗内存,完全没必要。
方案1:用scale_fill_manual映射编码到颜色(推荐)
直接基于原始的cod_global编码做映射,不需要将颜色列join到DataFrame,效率更高:
- 先将颜色tibble转换为命名向量,同时补全缺失的
#(部分颜色代码没有前缀):
color_vec <- setNames(colors$colors, colors$cod_global) # 补全颜色代码的#前缀 color_vec <- ifelse(!grepl("^#", color_vec), paste0("#", color_vec), color_vec)
- 绘图时用
cod_global作为填充变量,手动指定颜色映射:
ggplot(Xinjiang_df, aes(x = x, y = y, fill = factor(cod_global))) + geom_raster() + # 绘制栅格用geom_raster比geom_tile更高效 scale_fill_manual(values = color_vec, name = "像素编码") + coord_equal() # 保持栅格像素的比例
方案2:用scale_fill_identity直接使用颜色列
如果一定要保留join后的颜色列,需要告诉ggplot直接使用列中的颜色值,而非当作分类变量:
- 先修复颜色列的格式(补全
#):
Xinjiang_df <- Xinjiang_df %>% mutate(colors = ifelse(!grepl("^#", colors), paste0("#", colors), colors))
- 绘图时添加
scale_fill_identity():
ggplot(Xinjiang_df, aes(x = x, y = y, fill = colors)) + geom_raster() + scale_fill_identity()
大栅格数据优化建议
不要把整个栅格转成DataFrame,用rasterVis包的gplot函数可以直接绘制栅格,避免处理千万级行数据:
library(rasterVis) gplot(your_raster_object) + geom_raster(aes(fill = value)) + scale_fill_manual(values = color_vec, name = "像素编码")
内容的提问来源于stack exchange,提问作者Aniel
相关产品推荐
相关产品推荐

