Sovrapposizione di istogrammi con ggplot2 in R


124

Sono nuovo in R e sto cercando di tracciare 3 istogrammi sullo stesso grafico. Tutto ha funzionato bene, ma il mio problema è che non vedi dove 2 istogrammi si sovrappongono: sembrano piuttosto tagliati.

Quando creo grafici di densità, sembra perfetto: ogni curva è circondata da una linea di cornice nera e i colori hanno un aspetto diverso dove le curve si sovrappongono.

Qualcuno può dirmi se è possibile ottenere qualcosa di simile con gli istogrammi nella prima immagine? Questo è il codice che sto 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)

3
I collegamenti ipertestuali all'istogramma e al
grafico

Risposte:


115

Il tuo codice attuale:

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

sta dicendo ggplotdi costruire un istogramma usando tutti i valori in f0e poi colorare le barre di questo singolo istogramma in base alla variabile utt.

Quello che vuoi invece è creare tre istogrammi separati, con alpha blending in modo che siano visibili l'uno attraverso l'altro. Quindi probabilmente vorrai usare tre chiamate separate a geom_histogram, in cui ognuna ottiene il proprio frame di dati e riempimento:

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

Ecco un esempio concreto con qualche output:

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)

che produce qualcosa del genere:

inserisci qui la descrizione dell'immagine

Modificato per correggere errori di battitura; volevi riempimento, non colore.


7
Questo non funziona quando il sottoinsieme ha dimensioni diverse. Qualche idea su come affrontare questo? (Ad esempio, utilizzare dati con 100 punti su "a", 50 su "b").
Jorge Leitao

3
Uno svantaggio di questo approccio è che ho avuto difficoltà a far visualizzare una leggenda (anche se questo potrebbe essere dovuto solo alla mia mancanza di conoscenza). L'altra risposta sotto di @kohske mostrerà per impostazione predefinita una legenda che può quindi essere modificata (insieme ai colori specifici visualizzati sull'istogramma) con, ad es scale_fill_manual().
Michael Ohlrogge,

1
esattamente, come possiamo aggiungere una leggenda a questo?
shenglih

1
@shenglih Per una leggenda, la risposta di kohske di seguito è migliore. Anche la sua risposta è generalmente migliore.
joran

da dove viene f0?
Alan,

256

Utilizzando i dati di esempio di @ joran,

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

nota che la posizione predefinita di geom_histogramè "stack".

vedere "regolazione della posizione" di questa pagina:

docs.ggplot2.org/current/geom_histogram.html


30
Penso che questa dovrebbe essere la risposta migliore poiché evita di ripetere il codice
k per il

6
position = 'identity'non è solo una risposta più leggibile, ma si integra meglio con trame più complicate, come chiamate miste a aes()e aes_string().
rensa

2
Questa risposta mostrerà automaticamente anche una legenda per i colori, mentre la risposta di @joran no. La legenda può quindi essere modificata utilizzando, ad es scale_fill_manual(). Questa funzione può essere utilizzata anche per modificare i colori negli istogrammi.
Michael Ohlrogge,

4
Inoltre, assicurati che la variabile utilizzata in fillsia un fattore.
hhh

9
Personalmente penso che stackoverflow dovrebbe elencare prima la risposta più votata. La "risposta corretta" rappresenta solo l'opinione di una persona.
daknowles

25

Sebbene siano necessarie solo poche righe per tracciare istogrammi multipli / sovrapposti in ggplot2, i risultati non sono sempre soddisfacenti. Ci deve essere un uso corretto dei bordi e della colorazione per garantire che l'occhio possa distinguere tra gli istogrammi .

Le seguenti funzioni bilanciano i colori dei bordi, le opacità e i grafici di densità sovrapposti per consentire allo spettatore di differenziare le distribuzioni .

Istogramma singolo :

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

Istogramma multiplo :

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

Utilizzo :

Passa semplicemente il tuo frame di dati nelle funzioni precedenti insieme agli argomenti desiderati:

plot_histogram(iris, 'Sepal.Width')

inserisci qui la descrizione dell'immagine

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

inserisci qui la descrizione dell'immagine

Il parametro aggiuntivo in plot_multi_histogram è il nome della colonna contenente le etichette delle categorie.

Possiamo vederlo in modo più drammatico creando un dataframe con molti mezzi di distribuzione diversi :

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

Passaggio del frame di dati come prima (e ampliamento del grafico utilizzando le opzioni):

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

inserisci qui la descrizione dell'immagine


1
Questo è molto utile, si spera che riceva più attenzione.
Edward Tyler

2
@EdwardTyler Molto vero. Vorrei poter votare questo più di una volta!
ayePete
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.