2014-10-07 12 views
10

Ich versuche reorder in einem facet-Wrapped-Diagramm zu verwenden, das auch scales = free_x in ggplot2 verwendet, aber die Reorder-Funktion ist nicht richtig umordnen der X-Achse. Hier ist, was ich laufen:R: Reorder facet_wrapped x-Achse mit free_x in ggplot2

library(ggplot2) 

df <- read.table("speaking_distribution_by_play.txt", 
       header = F, 
       sep = "\t") 

ggplot(df, aes(x=reorder(V2, V3), y=V3)) + 
    geom_bar(stat = "identity") + 
    facet_wrap(~V1, ncol = 4, scales = "free_x") + 
    opts(title = "Distribution of Speakers in Shakespearean Drama") + 
    xlab("Speaking Role") + 
    ylab("Words Spoken") + 
    opts(axis.text.x=theme_text(angle=90, hjust=1)) 

ausgeführt wird, der Code auf dem Datenrahmen gelesen von this tab-separated file ergibt sich ein Plot, in dem die x-Achse jedes facettierten Grundstück ist nur teilweise geordnet. Someone else on SO fragte eine sehr ähnliche Frage, aber die einzige vorgeschlagene Lösung war, Raster anzuordnen. Da mein Datensatz jedoch ein wenig größer ist als der Datensatz in dieser Frage, ist dies keine besonders schnelle Operation. Daher wollte ich fragen: Gibt es eine Möglichkeit, die x-Achse jedes facettierten Diagramms neu anzuordnen? um die Balken in zunehmender (oder abnehmender) Reihenfolge der Größe zu zeigen? Ich wäre sehr dankbar für jede Hilfe, die andere in dieser Frage anbieten können.

+1

Whoa ... 'opts' veraltet ist seit 2012 ich, es ist Zeit, die Sie Ihre' ggplot2' Paket aktualisiert denken. Ihr erstes 'opts()' mit dem Titel kann dann durch 'labs()' ersetzt werden (und Ihr 'xlab' und' ylab' können hineingehen), und Ihr zweites 'opts' wird durch ein' theme() ersetzt '. – Gregor

+0

Danke, Gregor! Irgendwelche Gedanken zur Nachbestellungsfrage? – duhaime

+1

Wenn Sie verschiedene Aufträge in verschiedenen Facetten wünschen, denke ich, dass 'grid.arrange' Ihre beste Wahl ist. – Gregor

Antwort

6

Das Problem ist, dass ggplot behandelt V2 als Einzelfaktor; es enthält keine Untermenge V2 für jede Facette (Wert V1) und behandle dann jede dieser Faktoren als unabhängige Faktoren (leider). Da einige der Rollen ("Messenger 1" usw.) in mehreren Spielen enthalten sind, werden diese Ebenen basierend auf ihrer Wichtigkeit in der ersten Wiedergabe angeordnet, in der sie vorkommen.

Es gibt eine Problemumgehung, aber es ist ein bisschen ein Hack: Sie müssen die Rollen einzigartig machen, indem Sie den Namen des Spiels mit jedem verketten und dann den x-Wert verwenden. Um die ursprünglichen Rollen zurück zu erhalten, deaktivieren Sie den Achstext und verwenden Sie stattdessen geom_text(...) für die Balkenbeschriftungen. Hier ein Beispiel:

gg  <- df[order(df$V1,-df$V3),] # reorder by play and lines 
gg$lvl <- with(df,paste(V2,V1,sep=".")) 

ggplot(gg[gg$V1 %in% unique(df$V1)[1:4],], 
     aes(x=factor(lvl,levels=unique(lvl)), y=V3)) + 
    geom_text(aes(y=5,label=V2),angle=90,size=3,hjust=-0)+ 
    geom_bar(stat = "identity", fill="blue",alpha=0.2) + 
    facet_wrap(~V1, ncol = 2, scales="free_x") + 
    labs(title="Distribution of Speakers in Shakespearean Drama", 
     x="Speaking Role", y="Words Spoken") + 
    theme(axis.text.x=element_blank(),axis.ticks.x=element_blank()) 

Das sieht schrecklich auf einen so geringen Umfang (nicht so schlecht, wie Ihre ursprüngliche Handlung, obwohl ...). Aber wenn du es größer machst (wie du es mit 38 Spielen tun musst, nein ??), dann kannst du die Beschriftungen und die Balken sehen. Wenn Sie wirklich die Etiketten unter den Bars möchten, verwenden Sie so etwas wie dieses:

ggplot(gg[gg$V1 %in% unique(df$V1)[1:4],], 
     aes(x=factor(lvl,levels=unique(lvl)), y=V3)) + 
    geom_text(aes(y=-5,label=V2),angle=90,size=3,hjust=1)+ 
    ylim(-500,NA)+ 
    geom_bar(stat = "identity", fill="lightblue") + 
    facet_wrap(~V1, ncol = 2, scales="free_x") + 
    labs(title="Distribution of Speakers in Shakespearean Drama", 
     x="Speaking Role", y="Words Spoken") + 
    theme(axis.text.x=element_blank(),axis.ticks.x=element_blank()) 

Auch in diesem kleinen Maßstab schrecklich aussieht, aber besser vergrößert. In jedem Fall müssen Sie wahrscheinlich den Parameter in geom_text(...) optimieren.

+1

Clever Hack! Enthusiastisch +1 – Gregor

+0

Du bist ein Gelehrter, @jlhoward! Vielen Dank für diese clevere Workaround :) – duhaime

9

Mit einem etwas anderen Ansatz können Sie die Beschriftungen im Bereich unter den Diagrammen beibehalten. Diese Version erstellt eindeutige x-Unterbrechungen, indem V1 und V2 ähnlich wie jlhowards Methode verkettet werden, stellt dann aber V2 als x-Beschriftungen wieder her, indem die Funktionsrollen im folgenden Code in der scale_x_drecte-Anweisung verwendet werden.

library(ggplot2) 
df <- read.table("speaking_distribution_by_play.txt", 
      header = F, 
      sep = "\t") 

# Creates a small test subset; remove for complete set 
df <- df[df$V1 %in% c("Mac.xml","MM.xml","MND.xml","MV.xml"),] 

# used to create x-axis label restoring original name of role 
roles <- function(x) sub("[^_]*_","",x) 

ggplot(cbind(df, V4=paste(df$V1,df$V2,sep="_")), aes(x=reorder(V4,V3), y=V3)) + 
geom_bar(stat = "identity") + 
facet_wrap(~ V1, ncol=4, scales = "free_x") + 
labs(title = "Distribution of Speakers in Shakespearean Drama") + 
xlab("Speaking Role") + 
ylab("Words Spoken") + 
scale_x_discrete(labels=roles) + 
theme(axis.text.x=element_text(angle=90, hjust=1)) 

enter image description here

+0

Das ist wunderbar, @Walts! Was für eine einfache Lösung!Danke :) – duhaime

+2

Froh, dass es dir geholfen hat. Ich bemerkte, dass ich eine kleine Änderung an der Rollenfunktion vornehmen musste, um alle Werte von V1 richtig zu behandeln. Die bearbeitete Version oben hat dieses Update. Das tut mir leid. – WaltS

+0

Ich wünschte, ich könnte das zweimal aufwerten. Das rettete mich nur auf etwas, mit dem ich stundenlang zu kämpfen hatte. –