R语言ggplot2绘制散点图时如何保留含NA值的观测点
ggplot2保留含缺失值散点的实现方案
核心机制说明
ggplot2在图层构建的预处理阶段,会自动剔除所有映射到*aes()*美学参数存在NA的行,不会进入后续绘制流程。之前几类尝试失效的本质原因:
- 给
geom_point传入na.rm=FALSE:该参数仅控制“存在缺失行时是否弹出剔除警告”,不会改变“缺失行被默认剔除”的逻辑;当参数被误识别为美学参数时,就会出现“未知参数被忽略”的提示 - 给
scale_size设置na.value:该参数仅在数据进入尺度转换环节后生效,而含NA的行早在预处理阶段就被剔除,根本走不到尺度转换环节,参数自然不会触发 - 分层绘制报错:在单独绘制缺失行的图层内,仍然把含NA的col3、col4写入了*aes()*映射,导致同样触发预处理剔除逻辑
具体实现方法
核心思路是绕开“NA值直接进入美学映射”的触发点,有两种可直接复用的写法:
方案1:分层独立绘制(逻辑最直接,无需复杂预处理)
分别针对无缺失、有缺失的观测绘制独立图层,含缺失值的图层不设置需要映射的美学参数,直接手动指定固定视觉属性:
library(dplyr) library(ggplot2) ggplot(df, aes(x = col1, y = col2)) + # 第一层:绘制所有字段无缺失的观测,按需求映射size、颜色、形状 geom_point( data = ~ .x %>% filter(complete.cases(select(.x, col3, col4))), aes(size = col3, color = col4) ) + # 第二层:绘制含缺失值的观测,手动指定可区分的形状、颜色、大小 geom_point( data = ~ .x %>% filter(!complete.cases(select(.x, col3, col4))), shape = 4, # 用叉号和正常的实心点区分 color = "#999999", # 用中性灰色和正常分类颜色区分 size = 2 ) + theme_classic() + scale_size(range = c(0.25, 4))
这种写法不会把含NA的字段传入*aes()*映射,从根源上避免了预处理剔除的问题,控制台也不会再弹出缺失值警告。
方案2:占位值预处理后映射(适合需要统一图例展示的场景)
先对含NA的字段做占位值替换,让NA变成有明确标识的分类/数值,再通过scale参数设置对应的视觉编码:
df_processed <- df %>% mutate( # 连续型size字段:把NA替换为不在正常取值范围的占位值 col3_for_size = ifelse(is.na(col3), -1, col3), # 分类型颜色字段:把NA替换为带明确标签的分类值 col4_for_color = ifelse(is.na(col4), "存在缺失", col4) ) ggplot(df_processed, aes(x = col1, y = col2)) + geom_point(aes(size = col3_for_size, color = col4_for_color)) + # 自定义连续size的映射规则,把占位值-1对应为固定大小 scale_size_continuous( range = c(0.25, 4), # 用越界处理函数把占位值映射为固定尺寸 oob = function(x, ...) ifelse(x < 0, 0.5, x), # 图例里不展示占位值的断点 breaks = seq(min(df$col3, na.rm = T), max(df$col3, na.rm = T), length.out = 3) ) + # 自定义分类型颜色的映射规则,给缺失标签设置专属颜色 scale_color_manual( values = c( "CD8CTL" = "#1f77b4", "CD8Mem" = "#ff7f0e", "CD8STAT1" = "#2ca02c", "存在缺失" = "#999999" ) ) + theme_classic()
这种写法可以把缺失值的标识直接整合到图例里,不需要单独给缺失值做额外说明。
内容的提问来源于stack exchange,提问作者BioProgram
相关产品推荐
相关产品推荐

