ggplot条形图与分面依赖的类别顺序

Pie*_*e D 18 r ggplot2 geom-bar

我已经看到很多问题(通常与ggplot2条形图中的订单栏相关)关于如何(重新)在条形图中对类别进行排序.

我所追求的只是一个不同的触摸,但我还没有找到一个好方法:我有一个多面条形图,我想根据另一个变量独立地为每个面定购x轴(在我的例子中,该变量只是y值本身,即我只希望条形在每个方面增加长度).

简单示例,遵循例如ggplot2条形图中的订单栏:

df <- data.frame(name=c('foo','bar','foo','bar'),period=c('old','old','recent','recent'),val=c(1.23,2.17,4.15,3.65))
p = ggplot(data = df, aes(x = reorder(name, val), y = val))
p = p + geom_bar(stat='identity')
p = p + facet_grid(~period)
p
Run Code Online (Sandbox Code Playgroud)

我们得到的是以下内容: 在此输入图像描述

而我想要的是: 在此输入图像描述

Pie*_*e D 20

好的,所以所有哲学都放在一边,如果有人感兴趣,这是一个丑陋的黑客做到这一点.我的想法是使用不同的标签(paste(period, name)除了我将句点替换为0空格,1空格等,以便它们不显示).我需要这个情节,我不想安排grobs等,因为我可能想分享一个共同的传说,等等.

前面给出的原子示例变为:

df <- data.frame(name=c('foo','bar','foo','bar'),
  period=c('old','old','recent','recent'),
  val=c(1.23,2.17,4.15,3.65),
  stringsAsFactors=F)
df$n = as.numeric(factor(df$period))
df = ddply(df,.(period,name),transform, x=paste(c(rep(' ',n-1), name), collapse=''))
df$x = factor(df$x, levels=df[order(df$val), 'x'])
p = ggplot(data = df, aes(x = x, y = val))
p = p + geom_bar(stat='identity')
p = p + facet_grid(~period, scale='free_x')
p
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述 另一个例子,仍然有点傻但更接近我的实际用例,将是:

df <- ddply(mpg, .(year, manufacturer), summarize, mixmpg = mean(cty+hwy))
df$manufacturer = as.character(df$manufacturer)
df$n = as.numeric(factor(df$year))
df = ddply(df, .(year,manufacturer), transform,
     x=paste(c(rep(' ',n-1), manufacturer), collapse=''))
df$x = factor(df$x, levels=df[order(df$mixmpg), 'x'])
p = ggplot(data = df, aes(x = x, y = mixmpg))
p = p + geom_bar(stat='identity')
p = p + facet_grid(~year, scale='free_x')
p = p + theme(axis.text.x=element_text(angle=90,hjust=1,vjust=.5,colour='gray50'))
p
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述 闭上眼睛,想起帝国,尽量享受.


Uwe*_*Uwe 8

这是一个老问题,但它被用作欺骗目标.所以建议一个利用最近的ggplot2包增强功能的解决方案可能是值得的,即labels参数scale_x_discrete().这避免了使用不推荐使用的重复级别通过预先设置不同数量的空格操纵因子标签.

准备数据

这里,mpg数据集用于与此答案进行比较.对于数据操作,data.table此处使用该包,但可以随意使用您喜欢的任何包.

library(data.table)   # version 1.10.4
library(ggplot2)      # version 2.2.1
# aggregate data
df <- as.data.table(mpg)[, .(mixmpg = mean(cty + hwy)), by = .(year, manufacturer)]
# create dummy var which reflects order when sorted alphabetically
df[, ord := sprintf("%02i", frank(df, mixmpg, ties.method = "first"))]
Run Code Online (Sandbox Code Playgroud)

创建情节

# `ord` is plotted on x-axis instead of `manufacturer`
ggplot(df, aes(x = ord, y = mixmpg)) +
  # geom_col() is replacement for geom_bar(stat = "identity")
  geom_col() +
  # independent x-axis scale in each facet, 
  # drop absent factor levels (actually not required here)
  facet_wrap(~ year, scales = "free_x", drop = TRUE) +
  # use named character vector to replace x-axis labels
  scale_x_discrete(labels = df[, setNames(as.character(manufacturer), ord)]) + 
  # replace x-axis title
  xlab(NULL) +
  # rotate x-axis labels
  theme(axis.text.x = element_text(angle = 90, hjust=1, vjust=.5))
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述


Tun*_*ung 5

根据这个答案,有几种不同的方法可以实现 OP 的目标

(1)在facet内reorder_within()重新排序的函数。nameperiod

library(tidyverse)
library(forcats)

df <- data.frame(
  name = c("foo", "bar", "foo", "bar"),
  period = c("old", "old", "recent", "recent"),
  val = c(1.23, 2.17, 4.15, 3.65)
)

reorder_within <- function(x, by, within, fun = mean, sep = "___", ...) {
  new_x <- paste(x, within, sep = sep)
  stats::reorder(new_x, by, FUN = fun)
}

scale_x_reordered <- function(..., sep = "___") {
  reg <- paste0(sep, ".+$")
  ggplot2::scale_x_discrete(labels = function(x) gsub(reg, "", x), ...)
}

ggplot(df, aes(reorder_within(name, val, period), val)) +
  geom_col() +
  scale_x_reordered() +
  facet_grid(period ~ ., scales = "free", space = "free") +
  coord_flip() +
  theme_minimal() +
  theme(panel.grid.major.y = element_blank()) 
Run Code Online (Sandbox Code Playgroud)

或(2)类似的想法

### https://trinkerrstuff.wordpress.com/2016/12/23/ordering-categories-within-ggplot2-facets/
df %>% 
  mutate(name = reorder(name, val)) %>%
  group_by(period, name) %>% 
  arrange(desc(val)) %>% 
  ungroup() %>% 
  mutate(name = factor(paste(name, period, sep = "__"), 
                       levels = rev(paste(name, period, sep = "__")))) %>%
  ggplot(aes(name, val)) +
  geom_col() +
  facet_grid(period ~., scales = "free", space = 'free') +
  scale_x_discrete(labels = function(x) gsub("__.+$", "", x)) +
  coord_flip() +
  theme_minimal() +
  theme(panel.grid.major.y = element_blank()) + 
  theme(axis.ticks.y = element_blank())
Run Code Online (Sandbox Code Playgroud)

或者 (3) 对整个数据框进行排序,并对period每个构面组内的类别 ( ) 进行排序!

  ### https://drsimonj.svbtle.com/ordering-categories-within-ggplot2-facets
  # 
  df2 <- df %>% 
  # 1. Remove any grouping
  ungroup() %>% 
  # 2. Arrange by
  #   i.  facet group (period)
  #   ii. value (val)
  arrange(period, val) %>%
  # 3. Add order column of row numbers
  mutate(order = row_number())
df2
#>   name period  val order
#> 1  foo    old 1.23     1
#> 2  bar    old 2.17     2
#> 3  bar recent 3.65     3
#> 4  foo recent 4.15     4

ggplot(df2, aes(order, val)) +
  geom_col() +
  facet_grid(period ~ ., scales = "free", space = "free") +
  coord_flip() +
  theme_minimal() +
  theme(panel.grid.major.y = element_blank()) 
Run Code Online (Sandbox Code Playgroud)

# To finish we need to replace the numeric values on each x-axis 
# with the appropriate labels
ggplot(df2, aes(order, val)) +
  geom_col() +
  scale_x_continuous(
    breaks = df2$order,
    labels = df2$name) +
  # scale_y_continuous(expand = c(0, 0)) +
  facet_grid(period ~ ., scales = "free", space = "free") +
  coord_flip() +
  theme_minimal() +
  theme(panel.grid.major.y = element_blank()) + 
  theme(legend.position = "bottom",
        axis.ticks.y = element_blank())
Run Code Online (Sandbox Code Playgroud)

reprex 包(v0.2.1.9000)于 2018 年 11 月 5 日创建