2013-03-05 9 views
8

Vorrei un po 'di aiuto per colorare un istogramma ggplot2 generato da dati di conteggio già riepilogati.Istogramma impilato da conteggi già riepilogati utilizzando ggplot2

I dati sono qualcosa come i conteggi di # maschi e # femmine che vivono in una serie di aree diverse. E 'abbastanza facile da tracciare l'istogramma per i conteggi totali (cioè i maschi + femmine):

set.seed(1) 
N=100; 
X=data.frame(C1=rnbinom(N,15,0.1), C2=rnbinom(N,15,0.1),C=rep(0,N)); 
X$C=X$C1+X$C2; 
ggplot(X,aes(x=C)) + geom_histogram() 

Tuttavia, mi piacerebbe per colorare ogni barra in funzione del contributo relativo dalla C1 e C2, in modo che ho la stesso istogramma (cioè altezza complessiva della barra) come nell'esempio sopra, in più vedo la proporzione di individui tipo "C1" e "C2" come in un grafico a barre sovrapposto.

Suggerimenti per un modo pulito di farlo con ggplot2, utilizzando dati come "X" nell'esempio?

risposta

9

Molto rapidamente, si può fare ciò che il PO vuole utilizzando l'opzione stat="identity" e il pacchetto plyr calcolare manualmente l'istogramma, in questo modo:

library(plyr) 

X$mid <- floor(X$C/20)*20+10 
X_plot <- ddply(X, .(mid), summarize, total=length(C), split=sum(C1)/sum(C)*length(C)) 

ggplot(data=X_plot) + geom_histogram(aes(x=mid, y=total), fill="blue", stat="identity") + geom_histogram(aes(x=mid, y=split), fill="deeppink", stat="identity") 

Abbiamo praticamente basta creare una colonna 'medi' per sapere come posizionare le colonne e quindi creare due grafici: uno con il conteggio per il totale (C) e uno con le colonne adattato al conteggio di una delle colonne (C1). Dovresti essere in grado di personalizzare da qui.

histogram demo

Update 1: mi sono reso conto che ho fatto un piccolo errore nel calcolo dei medi. Risolto ora. Inoltre, non so perché ho usato una dichiarazione 'ddply' per calcolare i medi. Era sciocco. Il nuovo codice è più chiaro e più conciso.

Aggiornamento 2: sono tornato per visualizzare un commento e ho notato qualcosa di leggermente orripilante: stavo usando le somme come le frequenze dell'istogramma. Ho ripulito un po 'il codice e ho anche aggiunto suggerimenti dai commenti riguardanti la sintassi della colorazione.

+0

questo è buono tranne che la tua leggenda è stravagante. Inizia con 'geom_histogram (aes (x = mid, y = total), fill =" blue ")' (ad esempio, inserisci la specifica 'fill' al di fuori della mappatura); quindi dovrai capire come aggiungere manualmente la guida (legenda). –

+0

@BenBolker Sì, è solo una soluzione rapida per visualizzare i dati correttamente. Ora, l'OP deve solo personalizzare da qui. – Dinre

0

ne dite:

library("reshape2") 
mm <- melt(X[,1:2]) 
ggplot(mm,aes(x=value,fill=variable))+geom_histogram(position="stack") 
+0

non credo che le opere, purtroppo. La distribuzione generale è diversa. Vorrei conservare i conteggi di, ad esempio, 100 individui nel contenitore 100, ma colorare la ripartizione complessiva di M e F in quel contenitore. –

+0

@PaulJHurtado Penso che tu abbia frainteso il codice di Ben. I conteggi totali saranno esattamente gli stessi per ogni contenitore, dal momento che saranno impilati. La funzione 'fusione' condensa solo i dati e quindi l'opzione istogramma 'position =" stack "' mette le variabili una sopra l'altra. L'altezza totale sarà la stessa. Aggiungerò qualche dettaglio alla risposta di Ben per renderlo più chiaro. – Dinre

+0

Grazie per lo sforzo @Dinre. Assicurati di eseguire l'esempio di codice che ho postato e confronta. L'esempio di Ben offre una distribuzione generale diversa. –

6

Ecco un trucco utilizzando ggplot_build. L'idea è di ottenere prima il vostro vecchio trama originale /:

p <- ggplot(data = X, aes(x=C)) + geom_histogram() 

memorizzato in p. Quindi, utilizzare ggplot_build(p)$data[[1]] per estrarre i dati, in particolare, le colonne xmin e xmax (per ottenere gli stessi pause/binwidths di istogramma) e count colonna (per normalizzare la percentuale in count Ecco il codice:.

# get old plot 
p <- ggplot(data = X, aes(x=C)) + geom_histogram() 
# get data of old plot: cols = count, xmin and xmax 
d <- ggplot_build(p)$data[[1]][c("count", "xmin", "xmax")] 
# add a id colum for ddply 
d$id <- seq(nrow(d)) 

Come per generare dati ora Quello che ho capito dal tuo post è questo Prendiamo ad esempio il primo bar nel vostro diagramma ha un conteggio di 2 e si estende da xmin = 147 a xmax = 156.8 Quando controlliamo X per questi valori:?...

X[X$C >= 147 & X$C <= 156.8, ] # count = 2 as shown below 
# C1 C2 C 
# 19 91 63 154 
# 75 86 70 156 

Qui computo (91+86)/(154+156)*(count=2) = 1.141935 e (63+70)/(154+156) * (count=2) = 0.8580645 come i due valori normalizzati per ogni barra che genereremo.

require(plyr) 
dd <- ddply(d, .(id), function(x) { 
    t <- X[X$C >= x$xmin & X$C <= x$xmax, ] 
    if(nrow(t) == 0) return(c(0,0)) 
    p <- colSums(t)[1:2]/colSums(t)[3] * x$count 
}) 

# then, it just normal plotting 
require(reshape2) 
dd <- melt(dd, id.var="id") 
ggplot(data = dd, aes(x=id, y=value)) + 
     geom_bar(aes(fill=variable), stat="identity", group=1) 

E questa è la trama originale:

original_ggplot2_plot

E questo è ciò che ottengo:

ggplot2_weird_histogram_plot

Edit: Se anche voi volete ottenere il interruzioni corrette, quindi, è possibile ottenere le corrispondenti coordinate x da la trama vecchio e usarlo qui invece di id:

p <- ggplot(data = X, aes(x=C)) + geom_histogram() 
d <- ggplot_build(p)$data[[1]][c("count", "x", "xmin", "xmax")] 
d$id <- seq(nrow(d)) 

require(plyr) 
dd <- ddply(d, .(id), function(x) { 
    t <- X[X$C >= x$xmin & X$C <= x$xmax, ] 
    if(nrow(t) == 0) return(c(x$x,0,0)) 
    p <- c(x=x$x, colSums(t)[1:2]/colSums(t)[3] * x$count) 
}) 

require(reshape2) 
dd.m <- melt(dd, id.var="V1", measure.var=c("V2", "V3")) 
ggplot(data = dd.m, aes(x=V1, y=value)) + 
     geom_bar(aes(fill=variable), stat="identity", group=1) 

enter image description here

+0

Cosa sta facendo la tua soluzione 'require (reshape2); ggplot (melt (X, id.vars =" C "), aes (x = C, fill = variable)) + geom_histogram()' non funziona? – russellpierce

Problemi correlati