修复ggplot中facets的顺序问题

157

数据:

df <- data.frame(
    type   = c("T", "F", "P", "T", "F", "P", "T", "F", "P", "T", "F", "P"), 
    size   = c("50%", "50%", "50%", "100%", "100%", "100%", "150%", "150%", "150%", "200%", "200%", "200%"),
    amount = c(48.4, 48.1, 46.8, 25.9, 26, 24.9, 21.1, 21.4, 20.1, 20.8, 21.5, 16.5)
)

我需要使用ggplot绘制上述数据的条形图(x轴->type,y轴->amount,按size分组)。当我使用以下代码时,我没有按照数据中显示的顺序获得变量typesize。请参见下图。我已经使用了以下代码。

 ggplot(df, aes(type, amount , fill=type, group=type, shape=type, facets=size)) + 
  geom_col(width=0.5, position = position_dodge(width=0.6)) + 
  facet_grid(.~size) + 
  theme_bw() + 
  scale_fill_manual(values = c("darkblue","steelblue1","steelblue4"), 
                    labels = c("T", "F", "P"))

enter image description here.

为了解决顺序问题,我使用了一种因子方法来处理变量"type",具体如下。请参见下图。

temp$new = factor(temp$type, levels=c("T","F","P"), labels=c("T","F","P")) 

enter image description here

然而,现在我不知道如何调整变量size的顺序。它应该是50%,100%,150%和200%。

7个回答

204

通过以下方法将您的大小作为数据框的因素:

temp$size_f = factor(temp$size, levels=c('50%','100%','150%','200%'))

facet_grid(.~size) 更改为 facet_grid(.~size_f)

然后绘制: enter image description here

现在图表的顺序是正确的。


52

这里有几个好的解决方案。

与 Harpal 的答案类似,但是在 facet 内部,因此不需要更改底层数据或预制图形处理

# Change this code:
facet_grid(.~size) + 
# To this code:
facet_grid(~factor(size, levels=c('50%','100%','150%','200%')))

这是灵活的,可以根据您改变分面元素的内容来实现任何变量,而无需对数据进行基本更改。


levels是facet_grid的一个秘密输入? - Arthur Yip
3
对我来说没有起作用(R4.0.3,ggplot2 3.3.3)。 - elarry
1
@elarry 我已经编辑了我的代码,应该可以为你工作。让我知道。 - glenn_in_boston
1
在这种情况下,如何通过 labeller 更改条带标签? - just_rookie
1
@just_rookie,我之前没有做过这个,但是稍微探索了一下,我成功地用了这个方法:"facet_grid(~factor(size, levels = c('50%', '100%', '150%', '200%'), labels = c('50%' = "fifty", '100%' = "one hundred", '150%' = "one fifty", '200%' = "two hundred")))。 - glenn_in_boston

35
甚至更简单: facet_grid(~fct_relevel(size,'50%','100%','150%','200%'))

11
好的回答!可能值得注意的是,该函数来自于forcats包:forcats::fct_relevel - A_Murphy

10
这里有一个在 dplyr 管道链中保持一致性的解决方案。您需要事先对数据进行排序,然后使用 mutate_at 将其转换为因子。我稍微修改了数据,以展示如何应用此解决方案,假设数据可以合理排序。
# the data
temp <- data.frame(type=rep(c("T", "F", "P"), 4),
                    size=rep(c("50%", "100%", "200%", "150%"), each=3), # cannot sort this
                    size_num = rep(c(.5, 1, 2, 1.5), each=3), # can sort this
                    amount=c(48.4, 48.1, 46.8, 
                             25.9, 26.0, 24.9,
                             20.8, 21.5, 16.5,
                             21.1, 21.4, 20.1))

temp %>% 
  arrange(size_num) %>% # sort
  mutate_at(vars(size), funs(factor(., levels=unique(.)))) %>% # convert to factor

  ggplot() + 
  geom_bar(aes(x = type, y=amount, fill=type), 
           position="dodge", stat="identity") + 
  facet_grid(~ size)

你可以使用这个方案来安排分面内的条形图,但是你只能选择单一的偏好顺序:

    temp %>% 
  arrange(size_num) %>%
  mutate_at(vars(size), funs(factor(., levels=unique(.)))) %>%
  arrange(desc(amount)) %>%
  mutate_at(vars(type), funs(factor(., levels=unique(.)))) %>%
  ggplot() + 
  geom_bar(aes(x = type, y=amount, fill=type), 
           position="dodge", stat="identity") + 
  facet_grid(~ size)


  ggplot() + 
  geom_bar(aes(x = type, y=amount, fill=type), 
           position="dodge", stat="identity") + 
  facet_grid(~ size)

使用dplyr 1.0,更新方法将结合mutate()和across()。 - tef2128

8
类似于 glenn_in_boston 的回答,但不需要在级别中进行硬编码。
# Change this code:
facet_grid(.~size) + 
# To this code:
facet_grid(~factor(size, levels=unique(df$size)))

这个操作的原理是数据框内的size大小已经按从小到大排序。

如果size已经被转换为因子(factor)并且你只想在绘图时改变顺序,你可以选择以下选项:

# Updating dataframe so size is a factor ordered smallest to largest
df <- data.frame(
  type   = c("T", "F", "P", "T", "F", "P", "T", "F", "P", "T", "F", "P"), 
  size   = factor(c("50%", "50%", "50%", "100%", "100%", "100%", "150%", "150%", "150%", "200%", "200%", "200%"), levels=c("50%", "100%","150%","200%"), ordered = TRUE),
  amount = c(48.4, 48.1, 46.8, 25.9, 26, 24.9, 21.1, 21.4, 20.1, 20.8, 21.5, 16.5)
)

# Now plotting with facets in the reverse order
ggplot(df, aes(type, amount , fill=type, group=type, shape=type, facets=size)) + 
  geom_col(width=0.5, position = position_dodge(width=0.6)) + 
  facet_grid(~factor(size, levels=rev(unique(df$size)))) +  #this part updated
  theme_bw() + 
  scale_fill_manual(values = c("darkblue","steelblue1","steelblue4"), 
                    labels = c("T", "F", "P"))

1
字符特征标签包含数字的自然排序可以通过使用stringr::str_sort( , numeric = TRUE)自动实现,无需解析或修改原始数据:
首先定义一个小的辅助函数:
as_fct_innatural <- function(x, ordered= TRUE) factor(x, stringr::str_sort(unique(x), numeric = TRUE), ordered = ordered)

然后像这样使用facet_grid/wrap:
  ... +
  facet_grid(cols = vars(as_fct_innatural( <name of your facet variable>))) +
  ...

完整示例:
library(ggplot2)

df <- data.frame(
  type   = c("T", "F", "P", "T", "F", "P", "T", "F", "P", "T", "F", "P"), 
  size   = c("50%", "50%", "50%", "100%", "100%", "100%", "150%", "150%", "150%", "200%", "200%", "200%"),
  amount = c(48.4, 48.1, 46.8, 25.9, 26, 24.9, 21.1, 21.4, 20.1, 20.8, 21.5, 16.5)
)

as_fct_innatural <- function(x, ordered= TRUE) factor(x, stringr::str_sort(unique(x), numeric = TRUE), ordered = ordered)

ggplot(df, aes(type, amount , fill=type, group=type, shape=type, facets=size)) + 
  geom_col(width=0.5, position = position_dodge(width=0.6)) + 
  facet_grid(cols = vars(as_fct_innatural(size))) + 
  theme_bw() + 
  scale_fill_manual(values = c("darkblue","steelblue1","steelblue4"), 
                    labels = c("T", "F", "P"))

2023-08-23创建,使用reprex v2.0.2生成


1
通常,就像在这种情况下一样,指定外观顺序的愿望源于它们代表某些有序数据。在这种情况下,最好先正确清理数据,即从字符列中解析数字值。在这种情况下,可以使用df$size <- as.numeric(sub("%", "", df$size))/100轻松完成。然后可以使用标记函数来控制外观标签,例如facet_grid(.~size, labeller = function(x) lapply(x, scales::label_percent()))
library(ggplot2)

df <- data.frame(
  type   = c("T", "F", "P", "T", "F", "P", "T", "F", "P", "T", "F", "P"), 
  size   = c("50%", "50%", "50%", "100%", "100%", "100%", "150%", "150%", "150%", "200%", "200%", "200%"),
  amount = c(48.4, 48.1, 46.8, 25.9, 26, 24.9, 21.1, 21.4, 20.1, 20.8, 21.5, 16.5)
)

df$size <- as.numeric(sub("%", "", df$size))/100

ggplot(df, aes(type, amount , fill=type, group=type, shape=type, facets=size)) + 
  geom_col(width=0.5, position = position_dodge(width=0.6)) + 
  facet_grid(.~size, labeller = function(x) lapply(x, scales::label_percent())) + 
  theme_bw() + 
  scale_fill_manual(values = c("darkblue","steelblue1","steelblue4"), 
                    labels = c("T", "F", "P"))

reprex package(v2.0.1)于2022-03-11创建


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接