Есть ли способ манипулировать разрывами и метками шкалы ggplot?

ggplot в целом хорошо справляется с созданием разумных разрывов и меток на шкалах.

Однако я обнаружил, что на многогранном графике и, возможно, с выражением formatter=, метки имеют тенденцию становиться слишком "плотными" и накладываться друг на друга, например, на этой картинке:

df <- data.frame(
        fac=rep(LETTERS[1:10], 100),
        x=rnorm(1000)
)

ggplot(df, aes(x=x)) + 
  geom_bar(binwidth=0.5) + 
  facet_grid(~fac) + 
  scale_x_continuous(formatter="percent")

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

Я знаю, что могу явно указать разрывы и метки шкал, предоставив breaks= и scale= аргументы scale_x_continuous.

Однако я обрабатываю данные опроса с множеством вопросов и дюжиной перекрестных разрывов, поэтому мне нужно найти способ сделать это автоматически.

Есть ли способ указать ggplot, что нужно автоматически вычислять разрывы и метки, но при этом иметь меньше, скажем, минимум, максимум и нулевую точку?

РЕДАКТИРОВАТЬ: В идеале, я не хочу указывать минимальные и максимальные точки, а как-то задействовать встроенное обучение масштабов ggplot и использовать рассчитанные по умолчанию пределы шкалы.


person Andrie    schedule 21.03.2011    source источник


Ответы (2)


Вы можете передать аргументы, такие как min() и max() при вызове ggplot, чтобы динамически указывать разрывы. Похоже, вы собираетесь применить это к широкому спектру данных, поэтому вы можете подумать о том, чтобы обобщить это в функции и возиться с форматированием, но этот подход должен работать:

ggplot(df, aes(x=x)) + 
  geom_bar(binwidth=0.5) + 
  facet_grid(~fac) + 
  scale_x_continuous(breaks = c(min(df$x), 0, max(df$x))
    , labels = c(paste( 100 * round(min(df$x),2), "%", sep = ""), paste(0, "%", sep = ""), paste( 100 * round(max(df$x),2), "%", sep = ""))
    )

или поверните текст по оси x с помощью opts(axis.text.x = theme_text(angle = 90, hjust = 0)), чтобы получить что-то вроде:

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

Обновить

В последней версии ggplot2 аргументы breaks и labels для scale_x_continuous принимают функции, поэтому можно сделать что-то вроде следующего:

myBreaks <- function(x){
    breaks <- c(min(x),median(x),max(x))
    names(breaks) <- attr(breaks,"labels")
    breaks
}

ggplot(df, aes(x=x)) + 
  geom_bar(binwidth=0.5) + 
  facet_grid(~fac) + 
  scale_x_continuous(breaks = myBreaks,labels = percent_format()) + 
  opts(axis.text.x = theme_text(angle = 90, hjust = 1,size = 5))
person Chase    schedule 21.03.2011
comment
@Chase Спасибо. Да, я думал об этом, но это не идеально. Причина в том, что данные могут быть процентами, подсчетом респондентов, оценками t-stat или чем-то еще. Вычисление ближайшей звездной величины может быть вариантом, но на самом деле я хочу использовать масштаб, на котором тренировался ggplot, а затем скрыть метки между конечными точками. Другими словами, иногда я хочу, чтобы верхний предел шкалы был (например) 60%. Я надеюсь это имеет смысл. - person Andrie; 21.03.2011
comment
@Andrie - понял. Итак, что вам действительно нужно, так это функция, которая интерпретирует тип данных, отображаемых на оси x (проценты, числа и т. Д.), И соответствующим образом изменяет масштаб, верно? Можете ли вы использовать class() в столбцах, чтобы проинформировать об этом? Или какие-то другие данные / метданные, которые информируют о том, что именно вы рисуете? Не должно быть слишком сложно написать небольшую функцию для генерации вектора разрывов и меток для передачи в scale_x_continuous(), если у вас есть некоторая информация, чтобы сообщить, что и как форматировать. - person Chase; 21.03.2011
comment
@Chase Я надеюсь, что кто-то предложит более общий подход. Например, при работе с фасетами и свободными масштабами, например facet_grid (~ fac, scale = free), верхняя и нижняя точки разрыва в целом будут разными для каждого аспекта. Итак, что мне действительно нужно, так это подавить метки без указания перерывов. - person Andrie; 21.03.2011
comment
@Andrie, может быть, вы можете предоставить обновленный набор образцов данных, который лучше иллюстрирует вашу проблему? Насколько я могу судить, у вас есть как минимум две разные проблемы. 1. Наложение графика оси шкалы, 2. Использование одного и того же фрагмента кода для представления одних и тех же данных в разных источниках света. Вы можете решить проблему перекрытия графика с помощью чего-то вроде ... + opts(axis.text.x = theme_text(angle = 90, hjust = 0)). Если вы хотите выйти за рамки проблем с форматированием, я думаю, вам придется написать свою собственную функцию для передачи параметров в labels() и breaks(). - person Chase; 22.03.2011
comment
+1 за предложение изменить угол наклона и размер текста. Это поможет с моими непосредственными потребностями в презентации. - person Andrie; 22.03.2011
comment
+1,5 за принятие. К вашему сведению, Хэдли Уикхэм ответила на другом форуме, что то, что я хочу сделать, на данный момент сделать непросто, но в ближайшем будущем выпуске у каждого будет больше контроля над перерывами и отметками. - person Andrie; 22.03.2011

Пакет scales содержит несколько функций breaks_* и label_*, которые возвращают функции (замыкания), используемые ggplot. Итак, вы можете написать для них оболочки, которые изменяют вывод.

Например:

library(ggplot2)

# Compute the list of breaks using original_func,
# then remove any of these that occur in remove_list
remove_breaks <- function(original_func, remove_list = list()) {
  function(x) {
    original_result <- original_func(x)
    original_result[!(original_result %in% remove_list)]
  }
}

# Compute the list of labels using original_func,
# then remove any of these that occur in remove_list
remove_labels <- function(original_func, remove_list = list()) {
  function(x) {
    original_result <- original_func(x)
    replace(original_result, original_result %in% remove_list, '')
  }
}

# Original plot
ggplot(data.frame(x=c(1,2,3,4,5,6,7,8), y = c(1,4,9,16,25,36,49,64))) + geom_line(aes(x, y)) +
  scale_x_continuous(breaks       = scales::breaks_pretty(9),
                     minor_breaks = scales::breaks_pretty(18),
                     labels       = scales::label_number_auto()) +
  scale_y_continuous(breaks       = scales::breaks_pretty(9),
                     minor_breaks = scales::breaks_pretty(18),
                     labels       = scales::label_number_auto())

# Remove some breaks from the x-axis, and remove some labels from the y-axis
ggplot(data.frame(x=c(1,2,3,4,5,6,7,8), y = c(1,4,9,16,25,36,49,64))) + geom_line(aes(x, y)) +
  scale_x_continuous(breaks       = remove_breaks(scales::breaks_pretty(9), seq(3,6)),
                     minor_breaks = remove_breaks(scales::breaks_pretty(18), seq(3,6,0.5)),
                     labels       = scales::label_number_auto()) +
  scale_y_continuous(breaks       = scales::breaks_pretty(9),
                     minor_breaks = scales::breaks_pretty(18),
                     labels       = remove_labels(scales::label_number_auto(), seq(20, 30)))

Конечно, с моими простыми функциями remove_breaks и remove_labels вам все равно нужно указать, какие значения следует удалить, но вы можете легко изменить их на что-то, что удаляет максимальное и минимальное значение, удаляет любое значение в указанном диапазоне и т. Д.

person Tim Goodman    schedule 18.03.2020
comment
Написал ответ, прежде чем заметил, сколько лет было вопросу ????. - person Tim Goodman; 18.03.2020