Encomende escala x discreta por frequência / valor

137

Estou fazendo um gráfico de barras esquivado usando ggplot com escala x discreta, o eixo x agora está organizado em ordem alfabética, mas preciso reorganizá-lo para que seja ordenado pelo valor do eixo y (ou seja, a barra mais alta será posicionado à esquerda).

Eu tentei ordenar ou classificar, mas resultar na classificação do eixo x, mas não nas barras, respectivamente.

O que eu fiz errado?

lokheart
fonte

Respostas:

105

Tente definir manualmente os níveis do fator no eixo x. Por exemplo:

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

ggplot do conjunto de dados de carros com níveis de fator determinados automaticamente

# 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 do conjunto de dados de carros com níveis de fator reordenados manualmente

Como James apontou em sua resposta, reorderé a maneira idiomática de reordenar os níveis dos fatores.

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

ggplot do conjunto de dados de carros com níveis de fator reordenados usando a função reordenar

Richie Cotton
fonte
197

A melhor maneira para mim foi usar vetor com categorias para que eu precise como limitsparâmetro scale_x_discrete. Eu acho que é uma solução bastante simples e direta.

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

insira a descrição da imagem aqui

Yuriy Petrovskiy
fonte
1
@HendyIrawan, não há legenda, a menos que você tenha outras dimensões (cor, preenchimento) também mapeadas para a mesma variável.
Gregor Thomas
5
Eu acho que essa é a melhor resposta. Ele controla a ordem dos valores do eixo x e não transforma ou afeta o quadro de dados. O uso factore reorderalterações das características dos dados, embora dentro da ggplot()chamada, e mais do que o necessário para o problema em questão.
Mjandrews #
2
Esta deve ser a resposta aceita !! Por que complicar as coisas, escrevendo 2 a 3 linhas de código para algo que você pode fazer em uma única linha de código elegante (predefinida)?
26419 SilSur
1
Isso também trabalhou para mim a fim x pelo valor de y: scale_x_discrete(limits = DT$x[order(-DT$y)])+
armipunk
38

Você pode usar reorder:

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

Editar:

Para ter a barra mais alta à esquerda, você deve usar um pouco de clareza:

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

Eu esperaria que isso também tivesse alturas negativas, mas não tem, então funciona!

James
fonte
5
Estou chocado que esta resposta não tenha mais votos positivos, 90% das vezes é a maneira correta de fazê-lo.
Gregor Thomas
1
Eu acho que as duas chamadas de fator são supérfluas. Há uma chamada implícita ao fator para o primeiro argumento e o segundo argumento é assumido como numérico.
IRTFM 16/09
Uma explicação que me ajudou a descobrir o que essas soluções estavam fazendo sob o capô: rstudio-pubs-static.s3.amazonaws.com/...
keithpjolley
30

Hadley está desenvolvendo um pacote chamado forcats. Este pacote facilita muito a tarefa. Você pode explorar fct_infreq()quando quiser alterar a ordem do eixo x pela frequência de um fator. No caso do mtcarsexemplo nesta postagem, você deseja reordenar os níveis cylpela frequência de cada nível. O nível que aparece com mais frequência fica no lado esquerdo. Tudo que você precisa é o fct_infreq().

library(ggplot2)
library(forcats)

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

Se você quiser fazer o contrário, pode usar fct_rev()junto fct_infreq().

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

insira a descrição da imagem aqui

jazzurro
fonte
2

Sei que isso é antigo, mas talvez essa função que criei seja útil para alguém por aí:

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

Agora, com esta função, você pode plotar interativamente com o ggplot2, assim:

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

Como pode ser visto, a order_axisfunção cria outro quadro de dados com uma nova coluna denominada igual, mas com a _ono final. Esta nova coluna possui níveis em ordem crescente, portanto o ggplot2 é automaticamente plotado nessa ordem.

Isso é um pouco limitado (funciona apenas para combinações de caracteres ou fatores e numéricos de colunas e em ordem crescente), mas ainda acho muito útil para plotagem em movimento.

eflores89
fonte
Acho que não vejo a vantagem disso em comparação ao uso reorderdireto. Não ggplot(df, aes(x = reorder(AXIS_X, COLUMN_Y), y = COLUMN_Y)) + ...faz a mesma coisa de maneira concisa e sem a função auxiliar?
Gregor Thomas