los - superponer graficas en r ggplot
Diagrama de barra de ggplot con orden de categorÃas dependiente de facetas (4)
Esta es una pregunta antigua, pero está siendo utilizada como un objetivo para engañar. Por lo tanto, podría valer la pena sugerir una solución que utilice las mejoras recientes del paquete ggplot2
, a saber, el parámetro de labels
para scale_x_discrete()
. Esto evita usar niveles duplicados que están en desuso o manipular las etiquetas de factores al anteponer un número variable de espacios .
Preparar datos
Aquí, el conjunto de datos mpg
se usa para hacer una comparación con esta respuesta . Para la manipulación de datos, el paquete data.table
se usa aquí, pero puede usar el paquete que prefiera para este propósito.
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"))]
Crear trama
# `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))
He visto muchas preguntas (a menudo vinculadas a Barras de orden en el gráfico de barras ggplot2 ) sobre cómo (re) ordenar categorías en un diagrama de barra.
Lo que busco es solo un toque diferente, pero no he encontrado una buena manera de hacerlo: tengo un gráfico de barras multifacético, y quiero ordenar el eje x para cada faceta de forma independiente, de acuerdo con otra variable ( en mi caso, esa variable es solo el valor y en sí, es decir, solo quiero que las barras vayan en longitud creciente en cada faceta).
Ejemplo simple, siguiendo, por ejemplo, Barras de orden en el gráfico de barras 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
Lo que obtenemos es lo siguiente:
Mientras que lo que quiero es:
Hay varias maneras diferentes de lograr el objetivo de OP para esta respuesta
(1) reorder_within()
funciona para reordenar el name
dentro de las facetas del period
.
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())
O (2) idea similar
### 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())
O (3) ordena todo el marco de datos y también ordena las categorías ( period
) dentro de cada grupo de facetas
### 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())
# 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())
Creado en 2018-11-05 por el paquete reprex (v0.2.1.9000)
Ok, así que deja de lado la filosofía, y en caso de que alguien esté interesado, aquí hay un feo truco para hacerlo. La idea es usar etiquetas diferentes (piense en paste(period, name)
excepto que reemplacé el período en espacio 0, espacio 1, etc. para que no aparezcan). Necesito esta trama y no quiero organizar grobs y similares, porque tal vez quiera compartir una leyenda común, etc.
El ejemplo atómico dado anteriormente se convierte en:
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
Otro ejemplo, aún un poco tonto pero más cercano a mi caso de uso real, sería:
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
Cierra los ojos, piensa en el Imperio y trata de disfrutar.
Prueba esto, es muy simple (solo ignora las advertencias)
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))
d1 <- df[order(df$period, df$val), ]
sn <- factor(x = 1:4, labels = d1$name)
d1$sn <- sn
p <- ggplot(data = d1, aes(x = sn, y = val))
p <- p + geom_bar(stat = ''identity'')
p <- p + facet_wrap(~ period, scale = ''free_x'')
p