ggplot2条形图中的订购条


301

我正在尝试制作一个条形图,其中最大的条形图最接近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轴,守门员最接近,前锋最接近。谢谢


12
ggplot是否可以为您重新排序,而不必弄乱表(或数据框)?
tumultous_rooster 2014年

1
@ MattO'Brien我发现令人难以置信的是,没有一个简单的命令就可以做到这一点
Euler_Salter,

@Zimano太糟糕了,这就是您从我的评论中得到的。我的观察是针对ggplot2OP 的创建者,而不是OP
Euler_Salter,

2
@Euler_Salter谢谢您的澄清,我诚挚的歉意让您这样跳。我删除了我的原话。
Zimano

Answers:


214

订购的关键是按照所需的顺序设置因子的水平。不需要有序的因子;不需要有序因素中的额外信息,并且如果在任何统计模型中使用这些数据,则可能会导致错误的参数设置-多项式对比不适用于此类标称数据。

## 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)

条形图

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

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

1
@Gavin:2种简化方法:由于您已经在使用within,因此无需使用theTable$Position,而您可以只执行sort(-table(...))降序操作。
Prasad Chalasani 2011年

2
@Prasad前者是测试遗留的东西,因此感谢您指出这一点。就后者而言,我更喜欢显式地请求反向排序而不是-您使用反向排序,因为从中获得意图decreasing = TRUE比比-在所有其余代码中注意到要容易得多。
加文·辛普森

2
@GavinSimpson; 我认为有关的部分levels(theTable$Position) <- c(...)会导致不良行为,在该行为中数据帧的实际条目将被重新排序,而不仅仅是因素的级别。看到这个问题。也许您应该修改或删除这些行?
安东

2
完全同意安东的观点。我只是看到了这个问题,就四处寻找他们得到不好建议的地方levels<-。我将至少暂时地编辑该部分。
格雷戈尔·托马斯

2
@Anton感谢您的建议(并感谢Gregor进行编辑);我levels<-()今天永远不会这样做。这是8年前的事情,我不记得当时情况是否有所不同,或者我是否只是完全错误,但无论如何,它是错误的,应该删除!谢谢!
加文·辛普森,

220

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

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

7
确实为+1,尤其是在这种情况下,存在可以数字化利用的逻辑顺序。如果我们考虑类别的任意排序,并且我们不希望按字母顺序排列,那么直接如图所示指定级别也一样容易(更轻松吗?)。
加文·辛普森

2
这是最干净的。取消修改原始数据帧的需要
T.Fung

可爱,只是注意到您可以更简洁地执行此操作,如果您只想按长度函数进行排序并且升序是可以的,这就是我经常要做的事情:ggplot(theTable,aes(x=reorder(Position,Position,length))+geom_bar()
postylem

146

使用scale_x_discrete (limits = ...)指定的巴左右。

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

12
您的解决方案最适合我的情况,因为我要编程以x为由data.frame中的变量表示的任意列进行绘图。其他建议将更难通过涉及变量的表达式来表示x的顺序排列。谢谢!如果有兴趣,我可以根据您的建议分享我的解决方案。再加上一个问题,添加scale_x_discrete(limits = ...),我发现在图表的右侧有与条形图一样宽的空白。我如何摆脱空白?由于它没有任何作用。
Yu Shen

订购直方图条似乎
很有

9
QIBIN:哇...这里的其他答案都可行,但是到目前为止,您的答案似乎不仅是最简洁明了的,而且是从ggplot框架中进行思考时最明显的答案。谢谢。
阮丹(Dan Nguyen)

当我尝试此解决方案时,在我的数据上没有绘制NA图。有没有办法使用此解决方案并用图形表示NA?
user2460499

这是一个优雅而简单的解决方案-谢谢!
卡利夫·沃恩18/11/11

91

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

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()

我不了解重新排序功能的第二个论点及其作用。您能解释一下发生了什么吗?
user3282777

1

1
很好的解决方案!很高兴看到其他人使用tidyverse解决方案!
迈克,

29

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

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

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')

在此处输入图片说明


1
恕我直言,最好的解决方案是forcats和dplyr tidyverse软件包。
c0bra

赞扬Zoalkeeper
otwtm

23

一个简单的基于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

19

您只需要将Position列指定为有序因子,即可按其计数对级别进行排序:

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

(请注意,将table(Position)产生该Position列的频率计数。)

然后,您的ggplot函数将以计数的降序显示条形图。我不知道是否有一个选项geom_bar可以不必显式创建有序因子来执行此操作。


我没有在那里完全解析您的代码,但是我很确定reorder()stats库可以完成相同的任务。
大通

@Chase reorder()在这种情况下您打算如何使用?需要重新排序的因素需要通过自身的某些功能进行重新排序,而我正在努力寻找一种实现此目的的好方法。
加文·辛普森

好的,with(theTable, reorder(Position, as.character(Position), function(x) sum(duplicated(x))))是一种方法,而另一种方法with(theTable, reorder(Position, as.character(Position), function(x) as.numeric(table(x))))却令人费解……
Gavin Simpson

我略微简化了答案,sort而不是使用它order
Prasad Chalasani 2011年

@Gavin-也许我误解了Prasad的原始代码(我在这台机器上没有R可以测试...),但看来他似乎是根据频率对类别进行重新排序,这reorder很容易做到。对于这个问题,我同意需要更多的参与。对困惑感到抱歉。
大通

17

除了@HolgerBrandl提到的forcats :: fct_infreq外,还有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输出


“ fct_infreq(Position)”是个小事情,非常感谢,谢谢!
保罗

12

我同意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


12

如果图表列来自下面的数据框中的数字变量,则可以使用更简单的解决方案:

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

当我找到该线程时,这就是我想要的答案。希望对其他人有用。


8

另一种使用重排序对因子水平进行排序的方法。基于计数按升序(n)或降序(-n)。与fct_reorderforcats包中使用的非常相似:

降序

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

在此处输入图片说明

升序

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

在此处输入图片说明

数据框:

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))

5

由于我们只查看单个变量(“位置”)的分布,而不是查看两个变量之间的关系,因此直方图可能是更合适的图形。ggplot具有geom_histogram(),可以轻松实现:

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

在此处输入图片说明

使用geom_histogram():

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

对于连续数据,您可以仅使用不带参数的geom_histogram()。例如,如果我们添加数字矢量“分数” ...

    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

并在“分数”变量上使用geom_histogram()...

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

在此处输入图片说明

对于像“位置”这样的离散数据,我们必须指定一个通过美学计算的统计量,以使用以下公式给出钢筋高度的y值stat = "count"

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

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

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

在此处输入图片说明

编辑:扩展答案,以响应DebanjanB的有用建议。


0

我感到很烦人,ggplot2没有为此提供“自动”解决方案。这就是为什么我在中创建bar_chart()函数的原因ggcharts

ggcharts::bar_chart(theTable, Position)

在此处输入图片说明

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.