R:ggplot 中的因子水平被视为连续数据集
Posted
技术标签:
【中文标题】R:ggplot 中的因子水平被视为连续数据集【英文标题】:R: Factor level in ggplot treated as continuous data set 【发布时间】:2021-10-05 14:48:06 【问题描述】:我正在使用分类变量为 ggplot 创建的绘图中的线条、标签和色带着色。数值阈值用于区分三个不同的类别,这些类别被分配为绿色、蓝色或红色线条/标签/色带。我所拥有的在大多数情况下都运作良好,但在一种情况下它会崩溃。如果我的数据从一个类别转换到另一个类别,然后又回到原始类别,则第一组和最后一组中的数据将被视为连续数据。下面是一个最小的可重现示例,但首先我包含两个 CSV 格式的数据集,它们被读入数据帧(一个“好”集,然后是一个“坏”集):
良好的数据:
drug,dose,value,samples,conf,lower,upper
verapamil,1,72.56565,800,0.95,69.8194345,75.33907125
verapamil,2,72.44075,800,0.95,69.44212025,75.1824985
verapamil,3,70.79216,800,0.95,67.52461925,73.76032875
verapamil,4,68.91252,800,0.95,65.1242505,71.9545765
verapamil,5,66.91399,800,0.95,62.3466355,70.25188075
verapamil,6,65.07556,800,0.95,59.776704,68.484171
verapamil,7,63.52973,800,0.95,57.2319935,66.67006225
verapamil,8,62.22067,800,0.95,54.90753525,65.26015775
verapamil,9,60.65876,800,0.95,52.87391825,64.0331005
verapamil,10,59.57872,800,0.95,50.9498555,63.08050025
verapamil,15,56.44804,800,0.95,42.66295,73.614082
verapamil,20,55.23902,800,0.95,29.75458325,109.266985
verapamil,25,55.16381,800,0.95,23.006594,120.3280525
错误数据:
drug,dose,value,samples,conf,lower,upper
ranolazine,1,70.481,800,0.95,67.05068975,73.7571095
ranolazine,2,70.37064,800,0.95,66.865067,73.9150805
ranolazine,3,69.93621,800,0.95,66.70263375,74.0239275
ranolazine,4,69.53205,800,0.95,66.58873925,73.8851205
ranolazine,5,69.15334,800,0.95,66.0595545,73.833377
ranolazine,6,68.59902,800,0.95,65.4348675,73.7104295
ranolazine,7,68.09159,800,0.95,64.82512825,73.588261
ranolazine,8,67.53056,800,0.95,63.9937705,73.09860775
ranolazine,9,66.89892,800,0.95,63.253657,72.61998375
ranolazine,10,66.58314,800,0.95,62.4634455,71.94309325
ranolazine,15,67.00043,800,0.95,49.49385475,70.59155425
ranolazine,20,75.5989,800,0.95,33.52134225,86.43966325
ranolazine,25,88.64885,800,0.95,31.974256,104.275215
还有 R 脚本:
infile <-"good.csv"
#infile <-"bad.csv"
cidf <- read.csv(file = infile, stringsAsFactors = FALSE)
# prepare results for plotting
cidf[,c("value","lower","upper")]<-cidf[,c("value","lower","upper")]/1e3 # convert units
# assign value used to color lines, labels, and ribbons
for (row in 1:nrow(cidf))
if(is.na(cidf$value[row]))
cidf$CiPA[row] = 2
else if (cidf$value[row] > 0.0689)
cidf$CiPA[row] = 0
else if (cidf$value[row] > 0.0579)
cidf$CiPA[row] = 1
else cidf$CiPA[row] = 2
cidf$CiPA<-factor(cidf$CiPA, levels=c(2,1,0)) # THIS IS CAUSING THE WEIRD ISSUE WITH THE RANOLAZINE PLOT!
#cidf$CiPA<-factor(cidf$CiPA, levels=c(0))
#cidf$CiPA<-factor(cidf$CiPA, levels=c(1))
#cidf <- droplevels(cidf)
#cidf$CiPA <- as.numeric(as.character(cidf$CiPA))
# data frame of drug labels
newdf<-aggregate(dose ~ drug, data=cidf, max)
colnames(newdf)<-c("drug","max")
newdf<-merge(cidf,newdf,by.x="drug",by.y="drug",all=TRUE)
newdf<-newdf[newdf$dose==newdf$max,]
tofix<-which(is.na(newdf$value))
for(fixi in tofix)
newdf[fixi,"value"]<-mean(as.numeric(newdf[fixi, c("lower","upper")]))
figfile<-"plot.pdf"
pdf(figfile, width=8, height=4.5)
p<-ggplot(cidf, aes(dose, value, group=interaction(drug, CiPA))) +
scale_color_manual(values = c("2" = "#e82929", "1"="#337cb4", "0"="#44ae52")) +
scale_fill_manual(values = c("2" = "#e82929", "1"="#337cb4", "0"="#44ae52"), name="fill") +
geom_line(aes(color=CiPA)) +
geom_ribbon(aes(ymin=lower, ymax=upper, fill = CiPA), alpha=0.3) +
geom_text(data=newdf, aes(label=drug, color=CiPA), hjust=-0.2, vjust=0.5, size=3, show.legend=F) +
coord_cartesian(xlim=c(0,max(cidf$dose)*1.2)) +
xlab(~"Concentration (\u00D7"~C[max]*")") +
ylab(~"qNet ("*mu*"C/"*mu*"F)") +
theme_bw() +
theme(legend.position="none")
x11(title="Plot") # switch dev from pdf to x11
show(p) # show the plot in a window
while(names(dev.cur()) !='pdf') # dev changes from x11 back to pdf when window is closed
print(names(dev.cur())) # this conditional is required, otherwise window closes immediately
Sys.sleep(1)
print(p)
dev.off()
我在 Ubuntu 中工作,所以如果你不是,你可以删除 X11 绘图显示。使用“好”的数据集,情节仍然不太正确。我必须操纵数据以在颜色变化的阈值处添加一些额外的点(我不想在此示例中包含该函数,因为它很大并且不直接涉及手头的问题)。当我这样做时,情节如下:
我们从一个分类变量开始,然后到下一个,最后是第三个。然而,使用“坏”数据集,问题是我们从一个分类变量到另一个分类变量,然后又回到第一个。在这种情况下,第一个和第三个数据块被视为连续的而不是离散的。当您将因子水平从 c(2,1,0)
更改为 c(1)
或 c(0)
时,这一点更容易看到。我最终得到的是:
添加了一条线,将 Cmax = 5 处的数据点连接到 Cmax = 15,将这两个离散集视为连续的。然后具有不同分类变量的中间数据集是单独的,不连接到相邻的数据点。这显然不是我想要的,我无法弄清楚我哪里出错了。如果我尝试使用数值,我最终会出现错误:
Error: Continuous value supplied to discrete scale
降低级别也不起作用。我不确定这里是否有一个简单的解决方案,但我希望会有。任何指针将不胜感激。
编辑:请求了 dput(cidf) 的输出。对于我收到的“好”数据:
> dput(cidf)
structure(list(drug = c("verapamil", "verapamil", "verapamil",
"verapamil", "verapamil", "verapamil", "verapamil", "verapamil",
"verapamil", "verapamil", "verapamil", "verapamil", "verapamil"
), dose = c(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 15L, 20L,
25L), value = c(0.07256565, 0.07244075, 0.07079216, 0.06891252,
0.06691399, 0.06507556, 0.06352973, 0.06222067, 0.06065876, 0.05957872,
0.05644804, 0.05523902, 0.05516381), samples = c(800L, 800L,
800L, 800L, 800L, 800L, 800L, 800L, 800L, 800L, 800L, 800L, 800L
), conf = c(0.95, 0.95, 0.95, 0.95, 0.95, 0.95, 0.95, 0.95, 0.95,
0.95, 0.95, 0.95, 0.95), lower = c(0.0698194345, 0.06944212025,
0.06752461925, 0.0651242505, 0.0623466355, 0.059776704, 0.0572319935,
0.05490753525, 0.05287391825, 0.0509498555, 0.04266295, 0.02975458325,
0.023006594), upper = c(0.07533907125, 0.0751824985, 0.07376032875,
0.0719545765, 0.07025188075, 0.068484171, 0.06667006225, 0.06526015775,
0.0640331005, 0.06308050025, 0.073614082, 0.109266985, 0.1203280525
), CiPA = structure(c(3L, 3L, 3L, 3L, 2L, 2L, 2L, 2L, 2L, 2L,
1L, 1L, 1L), .Label = c("2", "1", "0"), class = "factor")), row.names = c(NA,
-13L), class = "data.frame")
对于我得到的“坏”数据:
> dput(cidf)
structure(list(drug = c("ranolazine", "ranolazine", "ranolazine",
"ranolazine", "ranolazine", "ranolazine", "ranolazine", "ranolazine",
"ranolazine", "ranolazine", "ranolazine", "ranolazine", "ranolazine"
), dose = c(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 15L, 20L,
25L), value = c(0.070481, 0.07037064, 0.06993621, 0.06953205,
0.06915334, 0.06859902, 0.06809159, 0.06753056, 0.06689892, 0.06658314,
0.06700043, 0.0755989, 0.08864885), samples = c(800L, 800L, 800L,
800L, 800L, 800L, 800L, 800L, 800L, 800L, 800L, 800L, 800L),
conf = c(0.95, 0.95, 0.95, 0.95, 0.95, 0.95, 0.95, 0.95,
0.95, 0.95, 0.95, 0.95, 0.95), lower = c(0.06705068975, 0.066865067,
0.06670263375, 0.06658873925, 0.0660595545, 0.0654348675,
0.06482512825, 0.0639937705, 0.063253657, 0.0624634455, 0.04949385475,
0.03352134225, 0.031974256), upper = c(0.0737571095, 0.0739150805,
0.0740239275, 0.0738851205, 0.073833377, 0.0737104295, 0.073588261,
0.07309860775, 0.07261998375, 0.07194309325, 0.07059155425,
0.08643966325, 0.104275215), CiPA = structure(c(3L, 3L, 3L,
3L, 3L, 2L, 2L, 2L, 2L, 2L, 2L, 3L, 3L), .Label = c("2",
"1", "0"), class = "factor")), row.names = c(NA, -13L), class = "data.frame")
【问题讨论】:
这对我来说很多。我希望还有比我更勇敢的人。在这两种情况下分享dput(cidf)
的输出是否有意义,这样我们就可以跳过准备步骤,还是会错过您的问题的重点?
@JonSpring,不,它不会错过重点。数据仅在“坏”数据集中很重要,因为数据被分配了一个从 0 -> 1 -> 0 传播的分类变量,并且分类变量的因式分解将分配为 0 的两组数据视为连续的而不是离散的。我现在将使用该输出编辑问题。
【参考方案1】:
这能解决您的问题吗?我添加了一个变量来分隔 CiPA 中的每个更改,即使它会回到已使用的更改。这样它就不会连接共享 CiPA 级别的非连续部分。
编辑 - 此处显示在我的计算机上逐字运行的完整代码。
EDIT #2 - 为文本添加调整后的行以忽略 newdf
没有的 CiPA_grp
分组变量。该层中的aes(group = 1)
将指定它应该将所有元素(实际上只有一个)放在同一组中,而不是为此寻找CiPA_grp
变量。
library(dplyr)
cidf %>% # using the "bad" version
arrange(drug, dose) %>%
group_by(drug) %>%
mutate(CiPA_grp = cumsum(as.numeric(CiPA) != lag(as.numeric(CiPA), default = Inf))) %>%
ungroup() %>%
ggplot(aes(dose, value, group=interaction(drug, CiPA_grp))) +
scale_color_manual(values = c("2" = "#e82929", "1"="#337cb4", "0"="#44ae52")) +
scale_fill_manual(values = c("2" = "#e82929", "1"="#337cb4", "0"="#44ae52"), name="fill") +
geom_line(aes(color=CiPA)) +
geom_ribbon(aes(ymin=lower, ymax=upper, fill = CiPA), alpha=0.3) +
geom_text(data=newdf, aes(label=drug, color=CiPA, group = 1), hjust=-0.2, vjust=0.5, size=3, show.legend=F) +
coord_cartesian(xlim=c(0,max(cidf$dose)*1.2)) +
xlab(~"Concentration (\u00D7"~C[max]*")") +
ylab(~"qNet ("*mu*"C/"*mu*"F)") +
theme_bw() +
theme(legend.position="none")
【讨论】:
从剧情来看,这正是我要找的。但是,我无法让它真正发挥作用。我很确定调用ungroup()
之后的悬空管道需要被移除。在上述最小示例的上下文中,没有数据框cidf_bad
也没有列CiPA_grp
。而且我还认为 ggplot 调用缺少数据框。我还不能重现你的结果,所以如果你可以清理你的帖子,使其与上面的最小示例集成,我会非常乐意接受这个作为答案。非常感谢!
啊,我想您将数据框直接通过管道传输到 ggplot 中?
已编辑以显示适用于我的系统的确切代码。我喜欢将数据直接传输到 ggplot 中,但也可以将这些数据保存到数据框中并使用 ggplot(data = wrangled_data, ...
引用该数据框;这也有助于您如何在 coord_cartesian 中引用数据框,以帮助它们保持对齐。
如果您想分配给 p,您可以在任何管道步骤之前添加 p <-
或在所有步骤末尾添加 -> p
。如果要分配绘图并显示一步打印的副作用,也可以使用(p <- all_the %>% wrangling %>% and %>% plotting %>% stuff %>% here)
。
已修复。该层的数据没有在ggplot(aes(...
中定义的全局aes()
中引用的CiPA_grp
变量,但不需要它,因此我们可以告诉它使用aes(group = 1)
跳过它。以上是关于R:ggplot 中的因子水平被视为连续数据集的主要内容,如果未能解决你的问题,请参考以下文章
R语言ggplot2可视化条形图(bar plot)配置因子变量的全局填充色方案这样不同数据集相同因子的填充色具有一致性(Fix colors to factor levels)
通过 geom_tile ggplot R 的热图 - 正确组织每月因子的 y 轴水平
在 R 的 randomForest 包中,因子是不是必须明确标记为因子?