按频率/值排序的离散 x 刻度

我正在使用具有离散 x 比例尺的 ggplot 制作一个避开的条形图,x 轴现在是按字母顺序排列的,但是我需要重新排列它,使它按 y 轴的值排列(也就是说,最高的条形图将位于左侧)。

我尝试了 order 或 sort,但是结果是 x 轴的 sort,而不是条形图。

我做错了什么?

271117 次浏览

试着手动设置 x 轴上因子的等级,例如:

library(ggplot2)
# Automatic levels
ggplot(mtcars, aes(factor(cyl))) + geom_bar()

ggplot of the cars dataset with factor levels automatically determined

# Manual levels
cyl_table <- table(mtcars$cyl)
cyl_levels <- names(cyl_table)[order(cyl_table)]
mtcars$cyl2 <- factor(mtcars$cyl, levels = cyl_levels)
# Just to be clear, the above line is no different than:
# mtcars$cyl2 <- factor(mtcars$cyl, levels = c("6","4","8"))
# You can manually set the levels in whatever order you please.
ggplot(mtcars, aes(cyl2)) + geom_bar()

ggplot of the cars dataset with factor levels reordered manually

正如詹姆斯在他的回答中指出的那样,reorder是重新排序要素水平的惯用方法。

mtcars$cyl3 <- with(mtcars, reorder(cyl, cyl, function(x) -length(x)))
ggplot(mtcars, aes(cyl3)) + geom_bar()

ggplot of the cars dataset with factor levels reordered using the reorder function

你可以使用 reorder:

qplot(reorder(factor(cyl),factor(cyl),length),data=mtcars,geom="bar")

编辑:

要在左边有一个最高的酒吧,你必须使用一个小组件:

qplot(reorder(factor(cyl),factor(cyl),function(x) length(x)*-1),
data=mtcars,geom="bar")

我希望这也有负高度,但它没有,所以它的工作!

对我来说,最好的方法是使用矢量与类别,以便我需要作为 limits参数的 scale_x_discrete。我认为这是一个非常简单明了的解决方案。

ggplot(mtcars, aes(factor(cyl))) +
geom_bar() +
scale_x_discrete(limits=c(8,4,6))

enter image description here

我知道这个函数有点老旧,但也许我创建的这个函数对其他人有用:

order_axis<-function(data, axis, column)
{
# for interactivity with ggplot2
arguments <- as.list(match.call())
col <- eval(arguments$column, data)
ax <- eval(arguments$axis, data)


# evaluated factors
a<-reorder(with(data, ax),
with(data, col))


#new_data
df<-cbind.data.frame(data)
# define new var
within(df,
do.call("<-",list(paste0(as.character(arguments$axis),"_o"), a)))
}

现在,使用这个函数,您可以使用 ggplot2交互式绘图,如下所示:

ggplot(order_axis(df, AXIS_X, COLUMN_Y),
aes(x = AXIS_X_o, y = COLUMN_Y)) +
geom_bar(stat = "identity")

可以看到,order_axis函数创建了另一个数据框,新列的名称相同,但末尾有一个 _o。这个新列的级别按升序排列,因此 ggplot2会自动按照这个顺序绘制图形。

这有些局限(仅适用于字符或因子以及列的数字组合,并按升序排列) ,但我仍然发现它对于一边走一边绘图非常有用。

哈德利一直在开发一个叫 forcats的软件包。这个软件包使这项任务变得容易得多。当你想通过因子的频率来改变 x 轴的顺序时,你可以利用 fct_infreq()。在这篇文章中的 mtcars例子中,你需要根据每个级别的频率重新排序 cyl的级别。出现最频繁的水平停留在左侧。你只需要 fct_infreq()

library(ggplot2)
library(forcats)


ggplot(mtcars, aes(fct_infreq(factor(cyl)))) +
geom_bar() +
labs(x = "cyl")

如果你想反过来,你可以使用 fct_rev()fct_infreq()

ggplot(mtcars, aes(fct_rev(fct_infreq(factor(cyl))))) +
geom_bar() +
labs(x = "cyl")

enter image description here

@ Yuriy Petrovskiy 的回答 非常棒,如果你事先知道你想要绘制的等级。如果不这样做(例如,因为您不想绘制数据中不存在的级别) ,可以考虑使用 limit功能来指定顺序:

library(ggplot2)


my_order <- as.character(c(8,3,4,5,6))    # the `as.character` calls are only
ggplot(mtcars, aes(as.character(cyl))) +  # necessary for the OP's example
geom_bar() +
scale_x_discrete(limits = function(x) my_order[my_order %in% x])

根据 scale_x_discrete的文件:

limits
其中之一:
- 使用默认刻度值为 NULL
- 定义比例尺及其顺序的可能值的字符向量
< strong >-接受现有(自动)值并返回新值的函数

否则你的图表最终会是这样的(可能更好) :

ggplot(mtcars, aes(as.character(cyl))) +
geom_bar() +
scale_x_discrete(limits = my_order)

另一种选择是使用来自 forcats(tidyverse的一部分)的 fct_relevel沿 x 轴手动设置顺序。然而,对于按频率排列,@jazzurro 通过使用 fct_infreq(也来自 forcats)提供了最佳答案。

library(tidyverse)


ggplot(iris, aes(
x = fct_relevel(Species, 'virginica', 'versicolor', 'setosa'),
y = Petal.Width)) +
geom_col() +
xlab("Species") +
ylab("Petal Width") +
theme_bw()

输出

enter image description here

此外,在 ggplot中使用 fct_relevel之前,变量需要是一个因子。因此,只需要先对变量应用 factor,然后使用 fct_relevel

ggplot(mtcars, aes(fct_relevel(factor(cyl), "6", "8", "4"))) +
geom_bar() +
labs(x = "cyl")

输出

enter image description here