2013-09-04 17 views
9

Ho visto molte domande (spesso collegate a Order Bars in ggplot2 bar graph) su come riordinare le categorie in un grafico a barre.ggplot bar plot con ordine di categorie facet-dipendente

Quello che sto cercando è solo un tocco diverso, ma non ho trovato un buon modo per farlo: ho un grafico a barre sfaccettato, e voglio ordinare l'asse x per ogni sfaccettatura in modo indipendente, secondo ad un'altra variabile (nel mio caso, quella variabile è solo il valore y stesso, cioè voglio solo che le barre vadano ad aumentare di lunghezza in ogni sfaccettatura).

Semplice esempio, seguito per es. Order Bars in ggplot2 bar graph:

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 

Quello che otteniamo è la seguente: enter image description here

Mentre quello che voglio è: enter image description here

+4

Oh mio Dio! Stai scrivendo un seguito a * How to Lie with Statistics *? – John

+1

L'unico modo per farlo sarebbe quello di creare grafici separati e usare 'grid.arrange' dal pacchetto' gridExtra'. Ma sono d'accordo sul fatto che in genere non si traduce in una trama molto bella. (Lo troverai molto in ggplot, se qualcosa è davvero difficile da fare, probabilmente è perché sta cercando di impedirti di fare qualcosa di stupido.Non sempre, ma molto ...) – joran

+0

Sì, grazie, non super utile, ma grazie comunque. Nel contesto in cui lo stiamo usando, è una trama importante e l'ordine delle categorie è molto deliberato. Qui ho riportato questo esempio a un esempio minimo, ma nella nostra applicazione, ordiniamo una dozzina di segnali in funzione della loro additività realizzata, e il fatto che le barre vadano dappertutto in qualche aspetto sarebbe inaccettabile. –

risposta

18

Ok, in modo che tutti filosofare a parte, e nel caso in cui qualcuno è interessato, qui è un brutto trucco per farlo. L'idea è di usare etichette diverse (pensa allo paste(period, name) eccetto che sostituisco il periodo in 0-spazio, 1-spazio, ecc. In modo che non vengano mostrate). Ho bisogno di questo complotto e non voglio per organizzare grobs e simili, perché potrei voler condividere una leggenda comune, ecc

L'esempio dato in precedenza atomica diventa:

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 

enter image description here altro esempio, ancora un po 'stupido, ma più vicino al mio caso d'uso effettivo, sarebbe:

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 

enter image description here Chiudi gli occhi, pensare dell'Impero, e cercare di godere.

+0

Ho aggiunto la risposta perché penso che sia bello che si possa fare senza 'grid.arrange', ma ancora una volta credo che questo potrebbe essere molto complicato in quanto le nostre aspettative su un grafico sfaccettato sono che le categorie saranno disposte nello stesso modo attraverso sfaccettature. Questa potrebbe essere un'aspettativa innata o storica, ma l'aspettativa è ancora lì e la violazione potrebbe essere fuorviante. –

+0

Sono d'accordo con @TylerRinker su entrambi i conteggi e ho votato di conseguenza. Un'altra opzione che (IMHO) potrebbe essere meno confusa potrebbe essere quella di sopprimere completamente le etichette degli assi e utilizzare solo l'estetica di riempimento (se ci sono solo poche barre) o etichettarle all'interno della trama sopra ogni barra. – joran

+0

Grazie. In sostanza, stai proponendo che x sia il rango (che è un valore numerico coerente) e traccia il testo della categoria da qualche parte all'interno di ogni barra invece che come un'etichetta. Questo potrebbe essere un problema se una barra è piccola per alcune categorie, ma sono sempre aperto alla diversità di opinioni. Forse puoi dare un esempio, ad es. usando i dati 'mpg', in modo che possiamo vedere come sarebbe. Essere un devoto di Tufte, usare i barattoli non sarebbe comunque la mia prima scelta, ma si adatta a ciò che Tyler chiamerebbe "aspettative storiche" (in questo caso, quelle della mia compagnia) ... –

1

Prova questa, è davvero semplice (basta ignorare gli avvertimenti)

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

Per completezza: Gli avvertimenti da ignorare leggere: "i livelli duplicati nei fattori sono deprecati". – Uwe

4

Questa è una vecchia questione, ma è in uso come bersaglio vittima. Pertanto potrebbe essere utile proporre una soluzione che utilizzi i recenti miglioramenti del pacchetto ggplot2, ovvero il parametro labels su scale_x_discrete(). Ciò evita a use duplicate levels che è deprecato o a manipulate factor labels by prepending a varying number of spaces.

preparare i dati

Qui, il set di dati mpg viene usato per avere un confronto per this answer. Per la manipolazione dei dati, qui viene utilizzato il pacchetto data.table ma non esitate a utilizzare il pacchetto che preferite per questo scopo.

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

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

enter image description here