ggplot2条形图中的条形排序

我要做一个柱状图,其中最大的柱状图离y轴最近,最短的柱状图离y轴最远。这有点像我的表格

    Name   Position
1   James  Goalkeeper
2   Frank  Goalkeeper
3   Jean   Defense
4   Steve  Defense
5   John   Defense
6   Tim    Striker

所以我试图建立一个条形图,根据位置显示球员的数量

p <- ggplot(theTable, aes(x = Position)) + geom_bar(binwidth = 1)

但是图表显示的是门将条,然后是防守条,最后是前锋条。我希望图表的顺序是,防守条最靠近y轴,守门员条,最后是前锋条。 由于< / p >

503330 次浏览

你只需要将Position列指定为命令的因素,其中级别是根据它们的计数排序的:

theTable <- transform( theTable,
Position = ordered(Position, levels = names( sort(-table(Position)))))

(注意,table(Position)会生成Position列的频率计数。)

然后你的ggplot函数将按计数的递减顺序显示条形图。 我不知道geom_bar中是否有一个选项可以在不显式创建有序因子的情况下这样做

排序的关键是按照您想要的顺序设置因子的级别。不需要有序因子;在一个有序因子中的额外信息是不必要的,如果这些数据被用于任何统计模型,错误的参数化可能会导致。多项式对比不适用于这样的名义数据。

## set the levels in order we want
theTable <- within(theTable,
Position <- factor(Position,
levels=names(sort(table(Position),
decreasing=TRUE))))
## plot
ggplot(theTable,aes(x=Position))+geom_bar(binwidth=1)

barplot figure

在最一般的意义上,我们只需要将因子级别设置为所需的顺序。如果不指定,因子的级别将按字母顺序排序。您还可以如上所述在因子调用中指定级别顺序,也可以采用其他方法。

theTable$Position <- factor(theTable$Position, levels = c(...))

@GavinSimpson: reorder是一个强大而有效的解决方案:

ggplot(theTable,
aes(x=reorder(Position,Position,
function(x)-length(x)))) +
geom_bar()

使用scale_x_discrete (limits = ...)指定条形图的顺序。

positions <- c("Goalkeeper", "Defense", "Striker")
p <- ggplot(theTable, aes(x = Position)) + scale_x_discrete(limits = positions)

我认为已经提供的解决方案过于冗长。使用ggplot进行频率排序barplot的一种更简洁的方法是

ggplot(theTable, aes(x=reorder(Position, -table(Position)[Position]))) + geom_bar()

它类似于Alex Brown的建议,但更简短,并且不需要任何函数定义。

更新

我认为我的旧解决方案在当时是很好的,但现在我宁愿使用forcats::fct_infreq,它是根据频率排序因子水平:

require(forcats)


ggplot(theTable, aes(fct_infreq(Position))) + geom_bar()

一个简单的基于dplyr的因子重排序可以解决这个问题:

library(dplyr)


#reorder the table and reset the factor to that ordering
theTable %>%
group_by(Position) %>%                              # calculate the counts
summarize(counts = n()) %>%
arrange(-counts) %>%                                # sort by counts
mutate(Position = factor(Position, Position)) %>%   # reset factor
ggplot(aes(x=Position, y=counts)) +                 # plot
geom_bar(stat="identity")                         # plot histogram

我同意zach的观点,在dplyr内计数是最好的解决方案。我发现这是最短的版本:

dplyr::count(theTable, Position) %>%
arrange(-n) %>%
mutate(Position = factor(Position, Position)) %>%
ggplot(aes(x=Position, y=n)) + geom_bar(stat="identity")

这也将比事先重新排序因子级别要快得多,因为计数是在dplyr中完成的,而不是在ggplot中或使用table

就像Alex Brown回答中的reorder()一样,我们也可以使用forcats::fct_reorder()。它基本上会对第一个参数中指定的因子进行排序,根据应用指定函数后第二个参数中的值(default = median,这是我们在这里使用的,因为每个因子级别只有一个值)。

遗憾的是,在OP的问题中,所需的顺序也是字母顺序,因为这是创建因子时的默认排序顺序,因此将隐藏此函数的实际操作。为了更清楚,我将“守门员”替换为“Zoalkeeper”。

library(tidyverse)
library(forcats)


theTable <- data.frame(
Name = c('James', 'Frank', 'Jean', 'Steve', 'John', 'Tim'),
Position = c('Zoalkeeper', 'Zoalkeeper', 'Defense',
'Defense', 'Defense', 'Striker'))


theTable %>%
count(Position) %>%
mutate(Position = fct_reorder(Position, n, .desc = TRUE)) %>%
ggplot(aes(x = Position, y = n)) + geom_bar(stat = 'identity')

enter image description here

除了forcats::fct_infreq之外,由 @HolgerBrandl,有forcats::fct_rev,它颠倒了因子的顺序

theTable <- data.frame(
Position=
c("Zoalkeeper", "Zoalkeeper", "Defense",
"Defense", "Defense", "Striker"),
Name=c("James", "Frank","Jean",
"Steve","John", "Tim"))


p1 <- ggplot(theTable, aes(x = Position)) + geom_bar()
p2 <- ggplot(theTable, aes(x = fct_infreq(Position))) + geom_bar()
p3 <- ggplot(theTable, aes(x = fct_rev(fct_infreq(Position)))) + geom_bar()


gridExtra::grid.arrange(p1, p2, p3, nrow=3)

gplot output

如果图表列来自一个数值变量,如下面的数据框架所示,您可以使用一个更简单的解决方案:

ggplot(df, aes(x = reorder(Colors, -Qty, sum), y = Qty))
+ geom_bar(stat = "identity")

排序变量(-Qty)前面的负号控制排序方向(升序/降序)

以下是一些用于测试的数据:

df <- data.frame(Colors = c("Green","Yellow","Blue","Red","Yellow","Blue"),
Qty = c(7,4,5,1,3,6)
)


**Sample data:**
Colors Qty
1  Green   7
2 Yellow   4
3   Blue   5
4    Red   1
5 Yellow   3
6   Blue   6

当我发现这条线索时,这就是我一直在寻找的答案。希望对其他人有用。

另一种方法是使用重新排序对因子的级别进行排序。根据计数的升序(n)或降序(-n)。非常类似于使用forcats包中的fct_reorder:

降序排列

df %>%
count(Position) %>%
ggplot(aes(x = reorder(Position, -n), y = n)) +
geom_bar(stat = 'identity') +
xlab("Position")

enter image description here

升序排序

df %>%
count(Position) %>%
ggplot(aes(x = reorder(Position, n), y = n)) +
geom_bar(stat = 'identity') +
xlab("Position")
< p > enter image description here < p > 数据帧:< / p >
df <- structure(list(Position = structure(c(3L, 3L, 1L, 1L, 1L, 2L), .Label = c("Defense",
"Striker", "Zoalkeeper"), class = "factor"), Name = structure(c(2L,
1L, 3L, 5L, 4L, 6L), .Label = c("Frank", "James", "Jean", "John",
"Steve", "Tim"), class = "factor")), class = "data.frame", row.names = c(NA,
-6L))

由于我们只考虑单变量(“位置”)的分布,而不考虑两个变量之间的关系,那么可能柱状图是更合适的图。ggplot有geom_histogram (),这使得它很容易:

ggplot(theTable, aes(x = Position)) + geom_histogram(stat="count")

enter image description here

使用geom_histogram ():

我认为geom_histogram ()有点古怪,因为它对待连续数据和离散数据是不同的。

对于连续的数据,你可以只使用不带参数的geom_histogram ()。 例如,如果我们添加数字向量“Score”…

    Name   Position   Score
1   James  Goalkeeper 10
2   Frank  Goalkeeper 20
3   Jean   Defense    10
4   Steve  Defense    10
5   John   Defense    20
6   Tim    Striker    50

然后在“Score”变量上使用geom_histogram()…

ggplot(theTable, aes(x = Score)) + geom_histogram()

enter image description here

对于像“Position”这样的离散数据,我们必须指定一个由美学计算的计算统计量,以使用stat = "count"给出条形高度的y值:

 ggplot(theTable, aes(x = Position)) + geom_histogram(stat = "count")

奇怪而令人困惑的是,你也可以将stat = "count"用于连续数据,我认为它提供了一个更美观的图形。

ggplot(theTable, aes(x = Score)) + geom_histogram(stat = "count")

enter image description here

编辑:对DebanjanB的有用建议的扩展回答。

我发现ggplot2没有为此提供“自动”解决方案非常令人恼火。这就是为什么我在ggcharts中创建了bar_chart()函数。

ggcharts::bar_chart(theTable, Position)

enter image description here

默认情况下,bar_chart()对条形图进行排序并显示水平线。要更改该集合horizontal = FALSE。此外,bar_chart()删除了条和轴之间难看的“间隙”。

你可以简单地使用下面的代码:

ggplot(yourdatasetname, aes(Position, fill = Name)) +
geom_bar(col = "black", size = 2)

enter image description here

如果你不想使用ggplot2,还有ggpubr,它为ggbarplot函数提供了一个非常有用的参数。你可以用sort.val在"desc"和“;asc"是这样的:

library(dplyr)
library(ggpubr)
# desc
df %>%
count(Position) %>%
ggbarplot(x = "Position",
y = "n",
sort.val = "desc")

< img src = " https://i.imgur.com/ShjSU4w.png " alt = " / >

# asc
df %>%
count(Position) %>%
ggbarplot(x = "Position",
y = "n",
sort.val = "asc")

< img src = " https://i.imgur.com/WjLCkGX.png " alt = " / >

reprex包 (v2.0.1)创建于2022-08-14

如您所见,对条形进行排序非常简单。如果条形图是分组的,也可以这样做。查看上面的链接,获取一些有用的例子。

library(ggplot2)
library(magrittr)


dd <- tibble::tribble(
~Name,    ~Position,
"James", "Goalkeeper",
"Frank", "Goalkeeper",
"Jean",    "Defense",
"John",    "Defense",
"Steve",    "Defense",
"Tim",    "Striker"
)




dd %>% ggplot(aes(x = forcats::fct_infreq(Position))) + geom_bar()

< img src = " https://i.imgur.com/ODVm2YZ.png " alt = " / >

创建于2022-08-30,包含reprex v2.0.2