Uporządkuj dyskretną skalę x według częstotliwości / wartości

137

Robię unikany wykres słupkowy za pomocą ggplot z dyskretną skalą x, osie x są teraz ułożone w kolejności alfabetycznej, ale muszę to zmienić tak, aby był uporządkowany według wartości osi y (tj. Najwyższy słupek będzie być umieszczone po lewej stronie).

Próbowałem uporządkować lub posortować, ale w rezultacie posortowałem oś X, ale nie odpowiednio słupki.

Co zrobiłem źle?

lokheart
źródło

Odpowiedzi:

105

Spróbuj ręcznie ustawić poziomy współczynnika na osi X. Na przykład:

library(ggplot2)
# Automatic levels
ggplot(mtcars, aes(factor(cyl))) + geom_bar()    

ggplot zbioru danych samochodów z automatycznie określanymi poziomami współczynników

# Manual levels
cyl_table <- table(mtcars$cyl)
cyl_levels <- names(cyl_table)[order(cyl_table)]
mtcars$cyl2 <- factor(mtcars$cyl, levels = cyl_levels)
# Just to be clear, the above line is no different than:
# mtcars$cyl2 <- factor(mtcars$cyl, levels = c("6","4","8"))
# You can manually set the levels in whatever order you please. 
ggplot(mtcars, aes(cyl2)) + geom_bar()

ggplot zbioru danych samochodów z ręcznie zmienioną kolejnością poziomów czynników

Jak zauważył James w swojej odpowiedzi, reorderjest idiomatyczny sposób zmiany kolejności poziomów czynników.

mtcars$cyl3 <- with(mtcars, reorder(cyl, cyl, function(x) -length(x)))
ggplot(mtcars, aes(cyl3)) + geom_bar()

ggplot zbioru danych samochodów z poziomami współczynników uporządkowanymi za pomocą funkcji zmiany kolejności

Richie Cotton
źródło
197

Najlepszym sposobem dla mnie było użycie wektora z kategoriami w kolejności, której potrzebuję jako limitsparametru scale_x_discrete. Myślę, że jest to całkiem proste i nieskomplikowane rozwiązanie.

ggplot(mtcars, aes(factor(cyl))) + 
  geom_bar() + 
  scale_x_discrete(limits=c(8,4,6))

wprowadź opis obrazu tutaj

Yuriy Petrovskiy
źródło
1
@HendyIrawan nie ma legendy, chyba że masz inne wymiary (kolor, wypełnienie) również zmapowane na tę samą zmienną.
Gregor Thomas
5
Myślę, że to najlepsza odpowiedź. Kontroluje kolejność wartości na osi X i nie przekształca ani nie wpływa na ramkę danych. Użycie factori reorderzmiana charakterystyki danych, aczkolwiek w ramach ggplot()połączenia, robi więcej, niż jest to konieczne dla danego problemu.
mjandrews
2
To powinna być akceptowana odpowiedź !! Po co komplikować sprawę, pisząc od 2 do 3 linii kodu dla czegoś, co można zrobić, w jednej eleganckiej (predefiniowanej) linii kodu?
SilSur
1
To również zadziałało, gdy scale_x_discrete(limits = DT$x[order(-DT$y)])+
zamówiłem
38

Możesz użyć reorder:

qplot(reorder(factor(cyl),factor(cyl),length),data=mtcars,geom="bar")

Edytować:

Aby mieć najwyższy słupek po lewej stronie, musisz użyć trochę kludge:

qplot(reorder(factor(cyl),factor(cyl),function(x) length(x)*-1),
   data=mtcars,geom="bar")

Spodziewałbym się, że będzie to również miało ujemne wysokości, ale tak nie jest, więc działa!

James
źródło
5
Jestem zszokowany, że ta odpowiedź nie ma więcej głosów pozytywnych, w 90% przypadków jest to właściwy sposób.
Gregor Thomas
1
Myślę, że oba wywołania czynników są zbędne. Istnieje niejawne wywołanie czynnika dla pierwszego argumentu i zakłada się, że drugi argument jest liczbowy.
IRTFM
Wyjaśnienie, które pomogło mi dowiedzieć się, co te rozwiązania robią pod maską: rstudio-pubs-static.s3.amazonaws.com/…
keithpjolley
30

Hadley rozwijał pakiet o nazwie forcats. Ten pakiet znacznie ułatwia zadanie. Możesz to wykorzystać, fct_infreq()gdy chcesz zmienić kolejność osi X o częstotliwość czynnika. W przypadku mtcarsprzykładu w tym poście chcesz zmienić kolejność poziomów cylwedług częstotliwości każdego poziomu. Poziom, który pojawia się najczęściej, pozostaje po lewej stronie. Wszystko, czego potrzebujesz, to fct_infreq().

library(ggplot2)
library(forcats)

ggplot(mtcars, aes(fct_infreq(factor(cyl)))) +
geom_bar() +
labs(x = "cyl")

Jeśli chcesz przejść na odwrót, możesz użyć fct_rev()razem z fct_infreq().

ggplot(mtcars, aes(fct_rev(fct_infreq(factor(cyl))))) +
geom_bar() +
labs(x = "cyl") 

wprowadź opis obrazu tutaj

jazzurro
źródło
2

Zdaję sobie sprawę, że to jest stare, ale może ta funkcja, którą stworzyłem, przyda się komuś:

order_axis<-function(data, axis, column)
{
  # for interactivity with ggplot2
  arguments <- as.list(match.call())
  col <- eval(arguments$column, data)
  ax <- eval(arguments$axis, data)

  # evaluated factors
  a<-reorder(with(data, ax), 
             with(data, col))

  #new_data
  df<-cbind.data.frame(data)
  # define new var
  within(df, 
         do.call("<-",list(paste0(as.character(arguments$axis),"_o"), a)))
}

Teraz dzięki tej funkcji możesz interaktywnie kreślić za pomocą ggplot2, na przykład:

ggplot(order_axis(df, AXIS_X, COLUMN_Y), 
       aes(x = AXIS_X_o, y = COLUMN_Y)) +
        geom_bar(stat = "identity")

Jak widać, order_axisfunkcja tworzy kolejną ramkę danych z nową kolumną o tej samej nazwie, ale z _okońcówką. Ta nowa kolumna ma poziomy w kolejności rosnącej, więc ggplot2 automatycznie kreśli w tej kolejności.

Jest to nieco ograniczone (działa tylko dla kombinacji znaków lub czynników i liczb w kolejności rosnącej), ale nadal uważam, że jest bardzo przydatne do kreślenia w ruchu.

eflores89
źródło
Myślę, że nie widzę korzyści z tego w porównaniu do reorderbezpośredniego używania . Czy nie ggplot(df, aes(x = reorder(AXIS_X, COLUMN_Y), y = COLUMN_Y)) + ...robi tego samego, mniej więcej tak zwięźle i bez funkcji pomocnika?
Gregor Thomas