将ggplot2箱线图转为小提琴图时遇错误:离散值传入连续刻度
问题描述
想用ggplot2将现有的箱线图代码修改为小提琴图,但代码包含循环结构,调整时遇到困难。使用geom_violin绘制时出现错误提示:Discrete value supplied to continuous scale。尝试过将y变量转为数值型(如y=as.numeric(variable)),或添加scale_x_discrete(),均无法解决问题。
可正常运行的箱线图代码
lapply(cytokine_names, function(s){ Tukey_data <- TukeyHSD(aov(as.formula(paste0(s, " ~ ICH_SAH")), data = current_data))$ICH_SAH maxvalues <- dat %>% group_by(ICH_SAH) %>% summarise(MAX = max(.data[[s]], na.rm = T)) pval <- as.data.frame(Tukey_data) %>% tibble::rownames_to_column("Group") %>% rowwise() %>% mutate(Start = unlist(strsplit(Group,"-"))[1], End = unlist(strsplit(Group,"-"))[2]) %>% left_join(.,maxvalues, by = c("Start" = "ICH_SAH")) %>% left_join(.,maxvalues, by = c("End" = "ICH_SAH")) %>% ungroup() %>% mutate(ypos = c(11,12,13)) %>% mutate(End = factor(End, levels = c("CTL","ICH","SAH"))) %>% rowwise() pval$p_adj_num <- pval$`p adj` i <- pval$`p adj` < 0.05 ii <- pval$`p adj` < 0.01 iii <- pval$`p adj` < 0.001 pval$`p adj` <- as.character(paste0("p = ",round(pval$`p adj`, 3))) pval[i,]$`p adj` <- paste0(pval[i,]$`p adj`, "*") pval[ii,]$`p adj` <- paste0(pval[ii,]$`p adj`, "**") pval[iii,]$`p adj` <- "p < 0.001***" print(pval) ggboxplot(dat, x ="ICH_SAH" , y = s , fill = "ICH_SAH", palette = "grey") + geom_signif(data = pval, manual = TRUE, aes(xmax = End, xmin = Start, y_position= ypos, annotations = (`p adj`))) + ggtitle("CSF cytokine concentrations: Control vs ICH vs SAH") + theme(axis.title.x = element_blank()) + theme(legend.position = "right") + labs(fill = "Sample Type") + theme(plot.title = element_text(hjust = 0.5)) + scale_y_continuous(limits=c(0,14), breaks=seq(0,14,by=5)) })
报错的小提琴图尝试代码
lapply(cytokine_names, function(s){ Tukey_data <- TukeyHSD(aov(as.formula(paste0(s, " ~ ICH_SAH")), data = current_data))$ICH_SAH maxvalues <- dat %>% group_by(ICH_SAH) %>% summarise(MAX = max(.data[[s]], na.rm = T)) pval <- as.data.frame(Tukey_data) %>% tibble::rownames_to_column("Group") %>% rowwise() %>% mutate(Start = unlist(strsplit(Group,"-"))[1], End = unlist(strsplit(Group,"-"))[2]) %>% left_join(.,maxvalues, by = c("Start" = "ICH_SAH")) %>% left_join(.,maxvalues, by = c("End" = "ICH_SAH")) %>% ungroup() %>% mutate(ypos = c(11,12,13)) %>% mutate(End = factor(End, levels = c("CTL","ICH","SAH"))) %>% rowwise() pval$p_adj_num <- pval$`p adj` i <- pval$`p adj` < 0.05 ii <- pval$`p adj` < 0.01 iii <- pval$`p adj` < 0.001 pval$`p adj` <- as.character(paste0("p = ",round(pval$`p adj`, 3))) pval[i,]$`p adj` <- paste0(pval[i,]$`p adj`, "*") pval[ii,]$`p adj` <- paste0(pval[ii,]$`p adj`, "**") pval[iii,]$`p adj` <- "p < 0.001***" print(pval) ggplot(dat, aes(x ="ICH_SAH" , y = s, fill = "ICH_SAH", palette = "grey")) + geom_violin(trim=FALSE) + theme(axis.title.x = element_blank()) + theme(legend.position = "right") + labs(fill = "Sample Type") + theme(plot.title = element_text(hjust = 0.5)) + scale_y_continuous(limits=c(0,14), breaks=seq(0,14,by=5)) + geom_signif(data = pval, manual = TRUE, aes(xmax = End, xmin = Start, y_position= ypos, annotations = (`p adj`))) + ggtitle("CSF cytokine concentrations: Control vs ICH vs SAH") })
解决方案
错误核心是原生ggplot的aes参数写法与ggboxplot不同:
ggboxplot(ggpubr包)允许直接传字符串作为变量名,但原生ggplot的aes需要直接引用数据列,不能加引号;palette不是aes的参数,原生ggplot要通过scale_fill_*系列函数设置颜色;- 循环中引用动态变量
s时,要用.data[[s]]来正确调用数据列,而不是直接写s。
修正后的完整小提琴图代码
lapply(cytokine_names, function(s){ Tukey_data <- TukeyHSD(aov(as.formula(paste0(s, " ~ ICH_SAH")), data = current_data))$ICH_SAH maxvalues <- dat %>% group_by(ICH_SAH) %>% summarise(MAX = max(.data[[s]], na.rm = T)) pval <- as.data.frame(Tukey_data) %>% tibble::rownames_to_column("Group") %>% rowwise() %>% mutate(Start = unlist(strsplit(Group,"-"))[1], End = unlist(strsplit(Group,"-"))[2]) %>% left_join(.,maxvalues, by = c("Start" = "ICH_SAH")) %>% left_join(.,maxvalues, by = c("End" = "ICH_SAH")) %>% ungroup() %>% mutate(ypos = c(11,12,13)) %>% mutate(End = factor(End, levels = c("CTL","ICH","SAH"))) %>% rowwise() pval$p_adj_num <- pval$`p adj` i <- pval$`p adj` < 0.05 ii <- pval$`p adj` < 0.01 iii <- pval$`p adj` < 0.001 pval$`p adj` <- as.character(paste0("p = ",round(pval$`p adj`, 3))) pval[i,]$`p adj` <- paste0(pval[i,]$`p adj`, "*") pval[ii,]$`p adj` <- paste0(pval[ii,]$`p adj`, "**") pval[iii,]$`p adj` <- "p < 0.001***" print(pval) # 核心修正部分 ggplot(dat, aes(x = ICH_SAH, y = .data[[s]], fill = ICH_SAH)) + geom_violin(trim=FALSE) + # 替换palette参数为scale_fill_grey scale_fill_grey() + theme(axis.title.x = element_blank()) + theme(legend.position = "right") + labs(fill = "Sample Type") + theme(plot.title = element_text(hjust = 0.5)) + scale_y_continuous(limits=c(0,14), breaks=seq(0,14,by=5)) + geom_signif(data = pval, manual = TRUE, aes(xmax = End, xmin = Start, y_position= ypos, annotations = (`p adj`))) + ggtitle("CSF cytokine concentrations: Control vs ICH vs SAH") })
错误原因解释
之前的代码把x="ICH_SAH"和y=s传入aes,导致ggplot将x识别为一个固定的离散字符串值,而非数据列;y被识别为变量名的字符串,而非对应的数据列数值,因此触发"离散值传入连续刻度"的错误。用.data[[s]]可以正确引用循环中的动态列,去掉引号后x=ICH_SAH会正确映射到数据中的分组列。
内容的提问来源于stack exchange,提问作者jrmagid
相关产品推荐
相关产品推荐

