Superposición de histogramas con ggplot2 en R

124

Soy nuevo en R y estoy tratando de trazar 3 histogramas en el mismo gráfico. Todo funcionó bien, pero mi problema es que no ves dónde se superponen 2 histogramas, se ven bastante cortados.

Cuando hago gráficos de densidad, se ve perfecto: cada curva está rodeada por una línea de marco negra, y los colores se ven diferentes donde las curvas se superponen.

¿Alguien puede decirme si se puede lograr algo similar con los histogramas de la primera imagen? Este es el código que estoy usando:

lowf0 <-read.csv (....)
mediumf0 <-read.csv (....)
highf0 <-read.csv(....)
lowf0$utt<-'low f0'
mediumf0$utt<-'medium f0'
highf0$utt<-'high f0'
histogram<-rbind(lowf0,mediumf0,highf0)
ggplot(histogram, aes(f0, fill = utt)) + geom_histogram(alpha = 0.2)
Florido
fuente
3
Los hipervínculos al histograma y la gráfica de densidad están rotos
Daghan ---

Respuestas:

115

Tu código actual:

ggplot(histogram, aes(f0, fill = utt)) + geom_histogram(alpha = 0.2)

le dice ggplota construir un histograma usando todos los valores f0y luego colorear las barras de este histograma individual de acuerdo con la variable utt.

En cambio, lo que desea es crear tres histogramas separados, con una combinación alfa para que sean visibles entre sí. Por lo tanto, es probable que desee utilizar tres llamadas separadas para geom_histogram, donde cada uno obtiene su propio marco de datos y relleno:

ggplot(histogram, aes(f0)) + 
    geom_histogram(data = lowf0, fill = "red", alpha = 0.2) + 
    geom_histogram(data = mediumf0, fill = "blue", alpha = 0.2) +
    geom_histogram(data = highf0, fill = "green", alpha = 0.2) +

Aquí hay un ejemplo concreto con algo de salida:

dat <- data.frame(xx = c(runif(100,20,50),runif(100,40,80),runif(100,0,30)),yy = rep(letters[1:3],each = 100))

ggplot(dat,aes(x=xx)) + 
    geom_histogram(data=subset(dat,yy == 'a'),fill = "red", alpha = 0.2) +
    geom_histogram(data=subset(dat,yy == 'b'),fill = "blue", alpha = 0.2) +
    geom_histogram(data=subset(dat,yy == 'c'),fill = "green", alpha = 0.2)

que produce algo como esto:

ingrese la descripción de la imagen aquí

Editado para corregir errores tipográficos; Querías rellenar, no colorear.

joran
fuente
77
Esto no funciona cuando el subconjunto tiene un tamaño diferente. ¿Alguna idea de cómo abordar esto? (Por ejemplo, use datos con 100 puntos en "a", 50 en "b").
Jorge Leitao
3
Una desventaja de este enfoque es que tuve dificultades para que mostrara una leyenda (aunque esto podría deberse a mi falta de conocimiento). La otra respuesta a continuación por @kohske mostrará por defecto una leyenda que luego se puede modificar (junto con los colores específicos que se muestran en el histograma) con, por ejemplo scale_fill_manual().
Michael Ohlrogge
1
exactamente, ¿cómo podemos agregar leyenda a esto?
shenglih
1
@shenglih Para una leyenda, la respuesta de kohske a continuación es mejor. Su respuesta también es generalmente mejor.
joran
de donde viene f0?
Alan
256

Usando los datos de muestra de @ joran,

ggplot(dat, aes(x=xx, fill=yy)) + geom_histogram(alpha=0.2, position="identity")

tenga en cuenta que la posición predeterminada de geom_histogrames "apilar".

ver "ajuste de posición" de esta página:

docs.ggplot2.org/current/geom_histogram.html

kohske
fuente
30
Creo que esta debería ser la respuesta principal, ya que evita la repetición de código
kpara el
66
position = 'identity'no es solo una respuesta más fácil de leer, se gela mejor con tramas más complicadas, como llamadas mixtas a aes()y aes_string().
rensa
2
Esta respuesta también mostrará automáticamente una leyenda de los colores, mientras que la respuesta de @joran no. La leyenda puede entonces ser modificada utilizando, por ejemplo scale_fill_manual(). Esta función también se puede utilizar para modificar los colores en los histogramas.
Michael Ohlrogge
44
Además, asegúrese de que la variable utilizada fillsea ​​un factor.
hhh
9
Personalmente, creo que stackoverflow debería enumerar primero la respuesta más votada. La "respuesta correcta" solo representa la opinión de una persona.
daknowles
25

Si bien solo se requieren unas pocas líneas para trazar histogramas múltiples / superpuestos en ggplot2, los resultados no siempre son satisfactorios. Debe haber un uso adecuado de los bordes y la coloración para garantizar que el ojo pueda diferenciar entre histogramas .

Las siguientes funciones equilibran los colores del borde, las opacidades y los gráficos de densidad superpuestos para permitir al espectador diferenciar entre distribuciones .

Histograma único :

plot_histogram <- function(df, feature) {
    plt <- ggplot(df, aes(x=eval(parse(text=feature)))) +
    geom_histogram(aes(y = ..density..), alpha=0.7, fill="#33AADE", color="black") +
    geom_density(alpha=0.3, fill="red") +
    geom_vline(aes(xintercept=mean(eval(parse(text=feature)))), color="black", linetype="dashed", size=1) +
    labs(x=feature, y = "Density")
    print(plt)
}

Múltiple histograma :

plot_multi_histogram <- function(df, feature, label_column) {
    plt <- ggplot(df, aes(x=eval(parse(text=feature)), fill=eval(parse(text=label_column)))) +
    geom_histogram(alpha=0.7, position="identity", aes(y = ..density..), color="black") +
    geom_density(alpha=0.7) +
    geom_vline(aes(xintercept=mean(eval(parse(text=feature)))), color="black", linetype="dashed", size=1) +
    labs(x=feature, y = "Density")
    plt + guides(fill=guide_legend(title=label_column))
}

Uso :

Simplemente pase su marco de datos a las funciones anteriores junto con los argumentos deseados:

plot_histogram(iris, 'Sepal.Width')

ingrese la descripción de la imagen aquí

plot_multi_histogram(iris, 'Sepal.Width', 'Species')

ingrese la descripción de la imagen aquí

El parámetro adicional en plot_multi_histogram es el nombre de la columna que contiene las etiquetas de categoría.

Podemos ver esto más dramáticamente creando un marco de datos con muchos medios de distribución diferentes :

a <-data.frame(n=rnorm(1000, mean = 1), category=rep('A', 1000))
b <-data.frame(n=rnorm(1000, mean = 2), category=rep('B', 1000))
c <-data.frame(n=rnorm(1000, mean = 3), category=rep('C', 1000))
d <-data.frame(n=rnorm(1000, mean = 4), category=rep('D', 1000))
e <-data.frame(n=rnorm(1000, mean = 5), category=rep('E', 1000))
f <-data.frame(n=rnorm(1000, mean = 6), category=rep('F', 1000))
many_distros <- do.call('rbind', list(a,b,c,d,e,f))

Pasando el marco de datos como antes (y ampliando el gráfico usando las opciones):

options(repr.plot.width = 20, repr.plot.height = 8)
plot_multi_histogram(many_distros, 'n', 'category')

ingrese la descripción de la imagen aquí

Cibernético
fuente
1
Esto es muy útil, ojalá reciba más atención.
Edward Tyler
2
@EdwardTyler Muy cierto. ¡Ojalá pudiera votar esto más de una vez!
ayePete