You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将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不同:

  1. ggboxplot(ggpubr包)允许直接传字符串作为变量名,但原生ggplot的aes需要直接引用数据列,不能加引号;
  2. palette不是aes的参数,原生ggplot要通过scale_fill_*系列函数设置颜色;
  3. 循环中引用动态变量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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 08:44:58