Superposition d'histogrammes avec ggplot2 dans R


124

Je suis nouveau sur R et j'essaye de tracer 3 histogrammes sur le même graphique. Tout a bien fonctionné, mais mon problème est que vous ne voyez pas où 2 histogrammes se chevauchent - ils semblent plutôt coupés.

Lorsque je crée des graphiques de densité, cela semble parfait: chaque courbe est entourée d'une ligne de cadre noire et les couleurs sont différentes là où les courbes se chevauchent.

Quelqu'un peut-il me dire si quelque chose de similaire peut être réalisé avec les histogrammes de la première image? Voici le code que j'utilise:

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)

3
Les hyperliens vers l'histogramme et le graphique de densité sont rompus
Daghan ---

Réponses:


115

Votre code actuel:

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

indique ggplotde construire un histogramme en utilisant toutes les valeurs de f0, puis de colorier les barres de cet histogramme unique en fonction de la variable utt.

Ce que vous voulez à la place est de créer trois histogrammes séparés, avec un mélange alpha afin qu'ils soient visibles les uns à travers les autres. Vous souhaitez donc probablement utiliser trois appels distincts à geom_histogram, où chacun obtient sa propre trame de données et se remplit:

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) +

Voici un exemple concret avec une sortie:

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)

qui produit quelque chose comme ceci:

entrez la description de l'image ici

Édité pour corriger les fautes de frappe; vous vouliez un remplissage, pas une couleur.


7
Cela ne fonctionne pas lorsque le sous-ensemble a une taille différente. Une idée de comment résoudre ce problème? (Par exemple, utilisez des données avec 100 points sur "a", 50 sur "b").
Jorge Leitao

3
Un inconvénient de cette approche est que j'ai eu du mal à lui faire afficher une légende (bien que cela puisse simplement être dû à mon manque de connaissances). L'autre réponse ci-dessous par @kohske affichera par défaut une légende qui pourra ensuite être modifiée (avec les couleurs spécifiques affichées sur l'histogramme) avec, par exemple scale_fill_manual().
Michael Ohlrogge du

1
exactement, comment pouvons-nous ajouter une légende à cela ??
shenglih

1
@shenglih Pour une légende, la réponse de kohske ci-dessous est meilleure. Sa réponse est également généralement meilleure.
joran

d'où vient f0?
Alan

256

En utilisant les exemples de données de @ joran,

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

notez que la position par défaut de geom_histogramest "pile".

voir "réglage de la position" de cette page:

docs.ggplot2.org/current/geom_histogram.html


30
Je pense que cela devrait être la meilleure réponse car cela évite de répéter le code
k pour

6
position = 'identity'n'est pas seulement une réponse plus lisible, elle se gélifie mieux avec des tracés plus compliqués, tels que des appels mixtes à aes()et aes_string().
rensa

2
Cette réponse affichera également automatiquement une légende des couleurs, contrairement à la réponse de @joran. La légende peut ensuite être modifiée en utilisant, par exemple scale_fill_manual(). Cette fonction peut également être utilisée pour modifier les couleurs dans les histogrammes.
Michael Ohlrogge

4
Assurez-vous également que la variable utilisée dans fillest un facteur.
hhh

9
Personnellement, je pense que stackoverflow devrait d'abord lister la réponse la plus votée. La «bonne réponse» ne représente que l'opinion d'une personne.
daknowles

25

Alors que seules quelques lignes sont nécessaires pour tracer des histogrammes multiples / superposés dans ggplot2, les résultats ne sont pas toujours satisfaisants. Il faut utiliser correctement les bordures et la coloration pour s'assurer que l'œil peut différencier les histogrammes .

Les fonctions suivantes équilibrent les couleurs de bordure, les opacités et les graphiques de densité superposés pour permettre au spectateur de différencier les distributions .

Histogramme unique :

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)
}

Histogramme multiple :

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))
}

Utilisation :

Passez simplement votre bloc de données dans les fonctions ci-dessus avec les arguments souhaités:

plot_histogram(iris, 'Sepal.Width')

entrez la description de l'image ici

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

entrez la description de l'image ici

Le paramètre supplémentaire dans plot_multi_histogram est le nom de la colonne contenant les étiquettes de catégorie.

Nous pouvons voir cela de manière plus spectaculaire en créant un dataframe avec de nombreux moyens de distribution différents :

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))

Passer le bloc de données comme avant (et élargir le graphique à l'aide d'options):

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

entrez la description de l'image ici


1
Ceci est très utile et, espérons-le, attire plus l'attention.
Edward Tyler

2
@EdwardTyler Très vrai. J'aurais aimé pouvoir voter plus d'une fois!
ayePete
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.