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

在R语言ggplot2的facet_wrap中设置变量自定义显示顺序

解决ggplot2分面时自定义填充类别顺序的问题

我有一个数据集,需要分组后用facet_wrap分面展示。目前分面功能正常,但填充变量(Name)按字母顺序排序,而非数据框中的原始顺序。常规绘图中可通过scale_x_discrete指定顺序,但搭配facet_wrap使用时出现如下错误:

Error in seq_len(n) : argument must be coercible to non-negative integer
In addition: Warning messages:
1: Removed 8 rows containing missing values (position_stack).
2: In max(f) : no non-missing arguments to max; returning -Inf

需求:左侧分面展示Jim、Bob,右侧展示Sue、Sally的顺序。

原代码示例

无scale_x_discrete的代码

library(ggplot2)
library(reshape2)

df_dtype <- data.frame(Name = c("Jim","Bob","Sue","Sally"),
                       Pre = c(150, 200, 325, 120),
                       Post = c(70,120,200,100) )

mdtype <- melt(df_dtype)

mdtype$group = ifelse(mdtype$Name %in% c("Jim", "Bob"),
                      "Group1", "Group2")

names = c("Jim","Bob","Sue","Sally")
p <- ggplot(mdtype, aes(x=variable, y=value, fill=Name)) + 
  geom_bar(position="stack", stat="identity") +
  ylab("Frequency") + xlab("") + ggtitle("Report Type") +
  theme(axis.ticks.x = element_blank(),axis.text.x = element_text(angle = 45, vjust = 1, hjust=1)) 
p + facet_wrap(~group) #+ scale_x_discrete(limits = names)

含scale_x_discrete的代码

library(ggplot2)
library(reshape2)

df_dtype <- data.frame(Name = c("Jim","Bob","Sue","Sally"),
                       Pre = c(150, 200, 325, 120),
                       Post = c(70,120,200,100) )

mdtype <- melt(df_dtype)

mdtype$group = ifelse(mdtype$Name %in% c("Jim", "Bob"),
                      "Group1", "Group2")

names = c("Jim","Bob","Sue","Sally")
p <- ggplot(mdtype, aes(x=variable, y=value, fill=Name)) + 
  geom_bar(position="stack", stat="identity") +
  ylab("Frequency") + xlab("") + ggtitle("Report Type") +
  theme(axis.ticks.x = element_blank(),axis.text.x = element_text(angle = 45, vjust = 1, hjust=1)) 
p + facet_wrap(~group) + scale_x_discrete(limits = names)

问题原因

错误根源是用错了scale参数:你要控制的是填充变量Name的顺序,但scale_x_discrete是用来设置x轴(此处为Pre/Post)的类别顺序。把Name的列表传给scale_x_discrete,会导致x轴找不到对应类别,进而触发报错。

解决方案

有两种可靠方法实现需求:

方法1:提前将Name转为有序因子

在数据预处理阶段,把Name设置为指定顺序的因子,ggplot会自动沿用这个顺序:

library(ggplot2)
library(reshape2)

df_dtype <- data.frame(Name = c("Jim","Bob","Sue","Sally"),
                       Pre = c(150, 200, 325, 120),
                       Post = c(70,120,200,100) )

# 自定义Name的顺序,转为有序因子
df_dtype$Name <- factor(df_dtype$Name, levels = c("Jim","Bob","Sue","Sally"), ordered = TRUE)

mdtype <- melt(df_dtype)

mdtype$group = ifelse(mdtype$Name %in% c("Jim", "Bob"),
                      "Group1", "Group2")

p <- ggplot(mdtype, aes(x=variable, y=value, fill=Name)) + 
  geom_bar(position="stack", stat="identity") +
  ylab("Frequency") + xlab("") + ggtitle("Report Type") +
  theme(axis.ticks.x = element_blank(),axis.text.x = element_text(angle = 45, vjust = 1, hjust=1)) 

p + facet_wrap(~group)

方法2:用scale_fill_discrete控制填充顺序

直接在绘图代码中用scale_fill_discrete指定Name的顺序,无需修改原始数据:

library(ggplot2)
library(reshape2)

df_dtype <- data.frame(Name = c("Jim","Bob","Sue","Sally"),
                       Pre = c(150, 200, 325, 120),
                       Post = c(70,120,200,100) )

mdtype <- melt(df_dtype)

mdtype$group = ifelse(mdtype$Name %in% c("Jim", "Bob"),
                      "Group1", "Group2")

name_order <- c("Jim","Bob","Sue","Sally")
p <- ggplot(mdtype, aes(x=variable, y=value, fill=Name)) + 
  geom_bar(position="stack", stat="identity") +
  ylab("Frequency") + xlab("") + ggtitle("Report Type") +
  theme(axis.ticks.x = element_blank(),axis.text.x = element_text(angle = 45, vjust = 1, hjust=1)) +
  scale_fill_discrete(limits = name_order) # 控制填充类别顺序

p + facet_wrap(~group)

两种方法都能让分面中的Name按需求顺序堆叠,且不会触发报错。

内容的提问来源于stack exchange,提问作者John Conor

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 17:50:27