ggplot 不会绘制缺失的类别

Posted

技术标签:

【中文标题】ggplot 不会绘制缺失的类别【英文标题】:ggplot will not plot missing category 【发布时间】:2017-03-19 18:46:53 【问题描述】:

我在 ggplot 上苦苦挣扎(我总是这样)。关于强制 ggplot 在图例中包含零值类别有许多非常类似的问题 - here 和 here(例如)。但是我(认为我)有一个稍微不同的要求,我所有的 scale_x_discrete 和 scale_fill_manual 都没有帮助。

要求:如您所见;右侧图没有 TM=5 类别中的数据 - 因此缺失。我需要的是正确的情节在轴上显示类别 5,但显然没有点或框。

当前剧情脚本

#data
plotData <- data.frame("TM"    = c(3,2,3,3,3,4,3,2,3,3,4,3,4,3,2,3,2,2,3,2,3,3,3,2,3,1,3,2,2,4,4,3,2,3,4,2,3),
                       "Score" = c(5,4,4,4,3,5,5,5,5,5,5,3,5,5,4,4,5,4,5,4,5,4,5,4,4,4,4,4,5,4,4,5,3,5,5,5,5))
#vars
xTitle <- bquote("T"["M"])
v.I    <- plotData$TM
depVar <- plotData$Score

#plot
p <- ggplot(plotData, aes_string(x=v.I,y=depVar,color=v.I)) +
  geom_point() +
  geom_jitter(alpha=0.8, position = position_jitter(width = 0.2, height = 0.2)) +
  geom_boxplot(width=0.75,alpha=0.5,aes_string(group=v.I)) +
  theme_bw() +
  labs(x=xTitle) +
  labs(y=NULL) +
  theme(legend.position='none', 
        axis.text=element_text(size=10, face="bold"),
        axis.title=element_text(size=16))

尝试的解决方案

    drop=False 缩放(由@Jarretinha here 建议)完全破坏边距和 x 轴标签

    &gt; plot + scale_x_discrete(drop=FALSE) + scale_fill_manual(drop=FALSE)

    遵循here 中的逻辑并手动设置scale_fill_manual 中的标签不会执行任何操作,并且会产生与上例相同的右侧图。

    > p + scale_fill_manual(values = c("red", "blue", "green", "purple", "pink"), labels = c("Cat1", "Cat2", "Cat3", "Cat4", "Cat5"), drop=FALSE)

    使用此逻辑并尝试使用 scale_x_discrete 会导致 x 轴上的类别名称发生变化,但第五个仍然丢失,并且边距(作为尝试 1)再次被破坏。但显然scale_x_discrete 很重要,不是整个答案

    &gt; p + scale_x_discrete(limits = c("Cat1", "Cat2", "Cat3", "Cat4", "Cat5"), drop=FALSE)

ANSWER 以上示例由@Bouncyball 和@aosmith 提供的输入提供

#data
plotData    <- data.frame("TM"    = c(3,2,3,3,3,4,3,2,3,3,4,3,4,3,2,3,2,2,3,2,3,3,3,2,3,1,3,2,2,4,4,3,2,3,4,2,3),
                       "Score" = c(5,4,4,4,3,5,5,5,5,5,5,3,5,5,4,4,5,4,5,4,5,4,5,4,4,4,4,4,5,4,4,5,3,5,5,5,5))
plotData$TM <- factor(plotData$TM, levels=1:5) # add correct (desired number of factors to input data)

#vars
xTitle <- bquote("T"["M"])
v.I    <- plotData$TM
depVar <- plotData$Score
myPalette <- c('#5c9bd4','#a5a5a4','#4770b6','#275f92','#646464','#002060')

#plot
ggplot(plotData, aes_string(x=v.I,y=depVar,color=v.I)) +
  geom_jitter(alpha=0.8, position = position_jitter(width = 0.2, height = 0.2)) +
  geom_boxplot(width=0.75,alpha=0.5,aes_string(group=v.I)) +
  scale_colour_manual(values = myPalette, drop=F) +  # new line added here
  scale_x_discrete(drop=F) + # new line added here
  theme_bw() +
  labs(x=xTitle) +
  labs(y=NULL) +
  theme(legend.position='none', 
        axis.text=element_text(size=10, face="bold"),
        axis.title=element_text(size=16))

【问题讨论】:

注意在您的第一个链接中推荐drop = FALSE,x 变量是一个因素。您的 x 变量当前是数字。如果您将其作为一个因素并确保它具有所有 5 个兴趣级别(例如,plotData$TM = factor(plotData$TM, levels = 1:5)),您可以使用您链接到的答案。 这是一个旁白,但我对aes_string(x=v.I,y=depVar,color=v.I) 感到非常困惑。 aes_string 用于将数据框中列的 names 作为字符串传递,但您似乎正在映射原始数字向量,即使您本身传递了数据框。这是故意的吗? @joran 是故意的。为了获得一个可重现的示例,我只是从我更大的 .RMD 脚本中复制了基本脚本,因为这些图是从动态创建的数据帧中生成的。更有意义? @aosmith - 我根据下面弹力球的帮助推测了这些因素,这一切都不同了!干杯 有点,只是它让你的例子有点荒谬。因为我的第一直觉是建议添加明确的因子水平,如下所述,但是这样做在您的数据框中实际上不会解决您提供的示例中的问题,因为您有将正在绘制的数据与您的数据框完全分离。以后最好还是aes_string(x="TM",y="Score",color= "TM") 【参考方案1】:

您可以使用以下解决方法:

# generate dummy data 
set.seed(123)
df1 <- data.frame(lets = sample(letters[1:4], 20, replace = T),
                  y = rnorm(20), stringsAsFactors = FALSE)
# define factor, including the missing category as a level
df1$lets <- factor(df1$lets, levels = letters[1:5])
# make plot
ggplot(df1, aes(x = lets, y = y))+
    geom_boxplot(aes(fill = lets))+
    geom_point(data = NULL, aes(x = 'e', y = 0), pch = NA)+
    scale_fill_brewer(drop = F, palette = 'Set1')+
    theme_bw()

基本上,我们绘制一个“空”点(即pch = NA),以便类别显示在 x 轴上,但没有可见的 geom 与之关联。我们还将离散变量lets 定义为具有五个级别的factor,而data.frame 中只有四个级别。缺少的类别是字母e

注意:您必须调整这个“空”点的位置,以免它歪斜您的 y 轴。

否则,您可以使用this answer 的结果来避免绘制“空”点。

# generate dummy data 
set.seed(123)
df1 <- data.frame(lets = sample(letters[1:4], 20, replace = T),
                  y = rnorm(20), stringsAsFactors = FALSE)
# define factor, including the missing category as a level
df1$lets <- factor(df1$lets, levels = letters[1:5])
# make plot
ggplot(df1, aes(x = lets, y = y)) +
    geom_boxplot(aes(fill = lets)) +
    scale_x_discrete(drop = F) +
    scale_fill_brewer(drop = F, palette = 'Set1') +
    theme_bw()

【讨论】:

美丽!诀窍在于考虑 x 轴类别(我只是假设它可以作为整数工作)和 NULL 数据技巧 - 现在我只需将其滚动到绘图脚本中以考虑到实际上有时缺少的任何类别它是 1,有时是 5。 这很明显。初始化 plotData df 时,根据@aosmith 的评论,只需为 xAxis 数据设置正确的因子级别。宾果游戏!

以上是关于ggplot 不会绘制缺失的类别的主要内容,如果未能解决你的问题,请参考以下文章

用单独的线型在 ggplot2 中绘制缺失值

通过 Plotly 在 Shiny 应用程序中绘制的缺失数据

R语言ggplot2可视化:去除可视化结果中的NA图例删除缺失值图例

如何在ggplot2中填充空单元格以获取缺失数据

堆叠条形图将变量转换为ggplot2 R中不相关变量的基于存在缺失的百分比

R语言ggplot2可视化:计算dataframe中每个数据列缺失值的个数使用堆叠的条形图(Stacked Barplot)可视化每个数据列的缺失值的情况(设置坐标轴为百分比以显示缺失值的比例)