我有一个分组条形图,我想根据一个子组的最大值对组进行排序。我读过很多类似的问题,但大多数都是在组级别而不是子组级别处理排序。下面是一个例子,看看我的意思。
这里是关于七个人和他们的音乐偏好的一些编造数据。
set.seed(3)
df <- data.frame(person = c("John", "Sarah", "Alex", "Kate", "Oliver", "Emily", "Daniel"),
music_genre = rep(c("pop", "classical", "rap"), each = 7),
listens = sample(40:90, size = 21, replace = TRUE))
包方面,我用的是
library(tidyverse)
。这是一个没有任何排序的简单条形图。
ggplot(data=df) +
geom_bar(aes(x=person,
y=listens,
fill=music_genre),
stat="identity",
position="dodge")
我的目标是创建一个条形图,按特定
persons
的 listens
的数量对 music_genre
进行排序,同时将所有音乐流派的条形保留在图中。
我知道如何做的是根据
persons
的数量对listens
的所有值排序music_genre
。然而,这不是我想要的。 (顺便说一句,请注意古典音乐如何在下面的情节中消失,因为它与说唱具有相同的价值。如果你知道如何解决这个问题,我很想知道。
ggplot(data=df) +
geom_bar(aes(x=reorder(person, listens, max),
y=listens,
fill=music_genre,
group=position),
stat="identity",
position="dodge")
很多帖子中讨论但没有解决我的问题的另一件事是如何对子组进行排序,即如何在
persons
内排序。为此,我们可以向 df 添加一个新变量,然后按此变量进行分组。与之前的代码相比,这是通过包含一个 mutate()
调用的额外行完成的。
set.seed(3)
df <- data.frame(person = c("John", "Sarah", "Alex", "Kate", "Oliver", "Emily", "Daniel"),
music_genre = rep(c("pop", "classical", "rap"), each = 7),
listens = sample(40:90, size = 21, replace = TRUE)) %>%
mutate(position = rank(-listens))
现在可以像这样对子组进行排序。 (再次注意 Daniel 的经典类别是如何消失的。)
ggplot(data=df) +
geom_bar(aes(x=person,
y=listens,
fill=music_genre,
group=position),
stat="identity",
position="dodge")
组级别的排序和子组级别的排序也可以组合。
ggplot(data=df) +
geom_bar(aes(x=reorder(person, listens, max),
y=listens,
fill=music_genre,
group=position),
stat="identity",
position="dodge")
再一次,这没有解决我的问题。我提到这一点只是为了让我的问题更清楚,并展示我所理解的和我不理解的。
重申一下,我怎样才能得到一个根据特定组(音乐类型)的 y 轴值(收听)的最大数量对 x 轴(人)进行排序的图?
library(tidyverse)
df %>%
pivot_wider(id_cols = person, names_from = music_genre, values_from = listens) %>%
mutate(pos_id = rank(pop)) %>% ## genre that subgroups will be ordered based on
pivot_longer(-c(person, pos_id), names_to = "music_genre", values_to = "listens") %>%
group_by(person) %>%
mutate(position = rank(-listens)) %>%
ggplot() +
geom_bar(aes(x=reorder(person, pos_id, max),
y=listens,
fill=music_genre,
group=position), ## use music_genre if you don't want to order subgroups
stat="identity",
position="dodge") +
xlab("person")
structure(list(person = c("John", "Sarah", "Alex", "Kate", "Oliver",
"Emily", "Daniel", "John", "Sarah", "Alex",
"Kate", "Oliver", "Emily", "Daniel", "John",
"Sarah", "Alex", "Kate", "Oliver", "Emily", "Daniel"),
music_genre = c("pop", "pop", "pop", "pop", "pop", "pop", "pop",
"classical", "classical", "classical", "classical",
"classical", "classical", "classical", "rap", "rap",
"rap", "rap", "rap", "rap", "rap"),
listens = c(44L, 51L, 78L, 75L, 79L, 82L, 70L, 47L, 59L, 49L, 79L,
87L, 79L, 47L, 76L, 41L, 68L, 83L, 84L, 44L, 79L)),
class = "data.frame", row.names = c(NA, -21L))
经过更多的修补,我找到了实现它的方法。
通过将人员(即 x 轴上的分类变量)编码为一个因素,然后通过仅包含感兴趣的排名类别(例如, ,“流行音乐”)。
df <- df %>%
mutate(
person = factor(
person,
levels = df %>%
filter(music_genre=="pop") %>%
arrange(listens) %>%
pull(person),
ordered= T))
绘制分组条形图可以实现我们想要的:人员按“pop”值从最高到最低排序。
ggplot(data=df) +
geom_bar(aes(x=person,
y=listens,
fill=music_genre),
stat="identity",
position="dodge")
如果有人找到了一种更聪明的方法来做到这一点,尤其是在
ggplot()
电话中工作的方法,我很想听听。