1. 问题描述
使用ggplot
绘制柱状图时,我们可能需要对柱进行排序,例如,我们想探究看电视的平均时长和宗教信仰之间的关系:
# 生成数据
relig_summary <- gss_cat %>%
group_by(relig) %>%
summarise(
age = mean(age, na.rm = TRUE),
tvhours = mean(tvhours, na.rm = TRUE),
n = n()
)
# 绘制
ggplot(relig_summary, aes(tvhours, relig)) + geom_col(width = .7, alpha = .7, color = "black")
由于柱子排布没有明显规律,所以图非常难解读。因此,我们期望对柱子排序进行调整。
由于柱子排序,取决于Y轴上作为因子型变量的宗教顺序,所以,我们可以调整relig
的因子顺序,也就是该变量的levels
。
2. 解决方案
2.1 fct_reorder()
使用fct_reorder
命令,它包含三个参数:
-
f
, 你希望调整顺序的因子 -
x
, 你希望用来调整顺序的依据(必须是一个和f
等长的vector
) -
fun
, 如果x
包含多个数值,你希望用何种方式处理他们,来对f
进行排序(默认是median
)。
使用该函数,我们可以轻松的对柱状图按降序排列:
ggplot(relig_summary, aes(tvhours, fct_reorder(relig, tvhours))) +
geom_col(width = .7, alpha = .7, color = "black")
当然,如果我们想让上边的柱子按升序排列,只需要在上边的代码中加一个负号-
:
ggplot(relig_summary, aes(tvhours, fct_reorder(relig, - tvhours))) +
geom_col(width = .7, alpha = .7, color = "black")
2.2 fct_relevel()
有时,我们需要将一个特殊的类别移到图的最前边作为参照,例如本案例中,我们特别想用“没有信仰”的None
和其他类型进行对比,所以需要把None
放在最前面,这时候可以用fct_relevel()
命令:
# 先排序,再把`None`放在因子顺序的最后
fct <- fct_reorder(relig_summary$relig, relig_summary$tvhours) %>%
fct_relevel("None", after = length(fct))
# 绘图
ggplot(relig_summary, aes(tvhours, fct)) +
geom_col(width = .7, alpha = .7, color = "black")
其中fct_relevel("None", after = length(fct))
的含义是将“None”放在第length(fct)
位的后面,也就是第length(fct)-1
的位次,对应在图中,就是最上方的位置。
如果想把"None"柱放在图的最下边,只需改写为after = 0
就可以了。
2.3 fct_reorder2
有时,我们需要基于两个变量对某一因子进行排序,特别是在绘制折线图的时候,这时可以用到fct_reorder2
命令,让标签排序更加便于观察:
# data
chks <- subset(ChickWeight, as.integer(Chick) < 10)
# Note that lines match order in legend
ggplot(chks, aes(Time, weight, colour = fct_reorder2(Chick, Time, weight))) +
geom_point() +
geom_line() +
labs(colour = "Chick")
2.5 fct_infreq() 和 fct_rev()
这两个命令主要是搭配geom_bar()
进行使用的,同样是对柱状图进行排序:
# 升序
increase_plot <-
gss_cat %>%
mutate(marital = marital %>% fct_infreq() %>% fct_infreq()) %>%
ggplot(aes(marital)) +
geom_bar()
# 降序
decrease_plot <-
gss_cat %>%
mutate(marital = marital %>% fct_infreq() %>% fct_rev()) %>%
ggplot(aes(marital)) +
geom_bar()
# 合并
pacman::p_load(cowplot)
plot_grid(increase_plot, decrease_plot, labels = c('fct_infreq', 'fct_rev'), label_size = 12)