Упорядочить дискретную шкалу х по частоте / значению

137

Я делаю точечную гистограмму, используя ggplot с дискретной шкалой x, ось x теперь расположена в алфавитном порядке, но мне нужно изменить ее так, чтобы она упорядочивалась по значению оси y (т. Е. Самая высокая полоса будет располагаться слева).

Я попытался упорядочить или отсортировать, но в результате отсортировать ось X, но не столбцы соответственно.

Что я сделал не так?

lokheart
источник

Ответы:

105

Попробуйте вручную установить уровни коэффициента по оси X. Например:

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

ggplot набора данных автомобилей с автоматическими уровнями факторов

# 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 набора данных автомобилей с уровнями факторов, упорядоченными вручную

Как указал Джеймс в своем ответе, reorderэто идиоматический способ переупорядочения уровней факторов.

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

ggplot набора данных автомобилей с уровнями факторов, переупорядоченными с помощью функции переупорядочения

Ричи Коттон
источник
197

Лучшим способом для меня было использование вектора с категориями в порядке, который мне нужен в качестве limitsпараметра scale_x_discrete. Я думаю, что это довольно простое и понятное решение.

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

введите описание изображения здесь

Юрий Петровский
источник
1
@HendyIrawan нет легенды, если у вас нет других измерений (цвет, заливка), также сопоставленных с той же переменной.
Грегор Томас
5
Я думаю, что это лучший ответ. Он контролирует порядок значений оси X и не трансформирует и не влияет на фрейм данных. Использование factorи reorderизменение характеристик данных, хотя и в рамках ggplot()вызова, и это делает больше, чем нужно для решения проблемы.
mjandrews
2
Это должен быть принятый ответ !! Зачем усложнять ситуацию, написав 2-3 строки кода для того, что вы можете сделать в одной элегантной (предопределенной) строке кода?
SilSur
1
Это также scale_x_discrete(limits = DT$x[order(-DT$y)])+
помогло
38

Вы можете использовать reorder:

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

Редактировать:

Чтобы иметь самый высокий бар слева, вы должны использовать немного клуджа:

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

Я ожидал бы, что у этого также будут отрицательные высоты, но это не так, это работает!

Джеймс
источник
5
Я в шоке, у этого ответа больше нет голосов, 90% времени это правильный способ сделать это.
Грегор Томас
1
Я думаю, что оба факторных вызова излишни. Существует неявный вызов фактора для первого аргумента, а второй аргумент считается числовым.
IRTFM
Объяснение, которое помогло мне понять, что эти решения делали под капотом: rstudio-pubs-static.s3.amazonaws.com/…
keithpjolley
30

Хэдли разрабатывает пакет под названием forcats. Этот пакет делает задачу намного проще. Вы можете использовать, fct_infreq()когда вы хотите изменить порядок оси X на частоту фактора. В случае mtcarsпримера в этом посте вы хотите изменить порядок уровней cylпо частоте каждого уровня. Уровень, который появляется чаще всего, остается слева. Все, что вам нужно, это fct_infreq().

library(ggplot2)
library(forcats)

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

Если вы хотите пойти другим путем, вы можете использовать fct_rev()вместе с fct_infreq().

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

введите описание изображения здесь

jazzurro
источник
2

Я понимаю, что это старая, но, может быть, эта функция, которую я создал, будет полезна кому-то там:

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

Теперь с помощью этой функции вы можете интерактивно построить график с помощью ggplot2, например так:

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

Как можно видеть, order_axisфункция создает другой фрейм данных с новым столбцом, названным так же, но с _oконцом в конце. Этот новый столбец имеет уровни в порядке возрастания, поэтому ggplot2 автоматически строит графики в этом порядке.

Это несколько ограничено (работает только для символьных или факторных и числовых комбинаций столбцов и в порядке возрастания), но я все еще считаю его очень полезным для построения графиков на ходу.

eflores89
источник
Я думаю, я не вижу преимущества этого по сравнению с простым использованием reorder. Разве не ggplot(df, aes(x = reorder(AXIS_X, COLUMN_Y), y = COLUMN_Y)) + ...делает то же самое, примерно так же кратко и без вспомогательной функции?
Грегор Томас