Можно с помощью ggplot2 вставить разрыв оси?

Я хочу создать гистограмму, на которой одно из значений намного больше, чем все другие значения. Есть ли способ получить прерывистую ось Y? Мои данные следующие:

df <- data.frame(a = c(1,2,3,500), b = c('a1', 'a2','a3', 'a4'))

p <- ggplot(data = df, aes(x = b, y = a)) + geom_bar() 
p <- p + opts(axis.text.x=theme_text(angle= 90, hjust=1))  + coord_flip()
p

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

Есть ли способ заставить мою ось двигаться от 1 до 10, а затем от 490 до 500? Я не могу придумать другого способа построения данных (кроме их преобразования, чего я не хочу делать)

[Изменить 2019-05-06]:

Спустя 8 лет необходимо изменить приведенный выше код для работы с версией 3.1.1 ggplot2, чтобы создать ту же диаграмму:

library(ggplot2)
ggplot(df) + 
  aes(x = b, y = a) +
  geom_col() +
  coord_flip()

person djq    schedule 25.08.2011    source источник
comment
Я не думаю, что вы можете вводить перерывы в ggplot2. альтернативой может быть использование шкалы log, которая упростит чтение графика.   -  person Ramnath    schedule 25.08.2011
comment
Я понимаю, что это упростит чтение в логарифмической шкале, но я не хочу показывать информацию таким образом, поскольку есть значительные различия между небольшими значениями, которые будут скрыты при преобразовании.   -  person djq    schedule 25.08.2011
comment
как насчет комбинации facet_wrap() с scales = "free_x"   -  person Chase    schedule 25.08.2011
comment
Мог бы также подойти к этой проблеме с кастомным преобразованием ... Я напишу ответ, когда у меня будет минутка   -  person Gregor Thomas    schedule 29.08.2019


Ответы (8)


Как отмечалось в другом месте, это не то, с чем ggplot2 хорошо справится, поскольку сломанные оси обычно считаются сомнительными.

Другие стратегии часто считаются лучшими решениями этой проблемы. Брайан упомянул несколько (фасетирование, два графика, ориентированные на разные наборы ценностей). Еще один вариант, который люди слишком часто упускают из виду, особенно в отношении гистограмм, - это создание таблицы:

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

Глядя на фактические значения, 500 не скрывает различий в других значениях! По какой-то причине таблицы не пользуются должным уважением как данные как метод визуализации. Вы можете возразить, что ваши данные имеют много-много категорий, что становится громоздким в таблице. Если это так, вероятно, на вашей гистограмме будет слишком много столбцов, чтобы быть разумным.

И я не спорю за таблицы все время. Но их определенно стоит учитывать, если вы создаете гистограммы с относительно небольшим количеством столбцов. И если вы делаете гистограммы с множеством столбцов, вам все равно придется это переосмыслить.

Наконец, в пакете plotrix есть функция axis.break, которая реализует сломанные оси. Однако из того, что я понял, вам придется вручную указать метки и позиции осей.

person joran    schedule 25.08.2011
comment
Джоран, у меня смешанные чувства по поводу использования этого типа сюжета. Вы правы - таблица, вероятно, лучший способ показать это. - person djq; 25.08.2011
comment
@celenius - Я не хотел казаться проповедником или как будто ругал вас. Я просто чувствую, что столы не вызывают особой любви, и иногда меня это волнует. ;) - person joran; 25.08.2011
comment
@joran, я согласен с тем, что для этих конкретных данных таблица является оптимальным представлением (и что я бы порекомендовал, если бы просто задал вопрос о том, как это представить лучше всего). В своем ответе я был слишком узко сфокусирован на конкретном вопросе, чтобы думать, чтобы ответить на более широкий вопрос, который следовало бы задать. - person Brian Diggs; 25.08.2011

Восемь лет спустя пакет ggforce предлагает расширение facet_zoom(), которое является реализацией предложения Хэдли Уикхема , чтобы показать два графика (как указано в ответе Брайана Диггса).

Фасет масштабирования

library(ggforce)
ggplot(df) + 
  aes(x = b, y = a) +
  geom_col() +
  facet_zoom(ylim = c(0, 10))

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

К сожалению, текущая версия ggforce 0.2.2 выдает ошибку с coord_flip(), поэтому могут отображаться только вертикальные полосы.

Увеличенный фасет показывает вариации малых значений, но по-прежнему содержит большую - теперь обрезанную - a4 полосу. Параметр zoom.data определяет, какие значения отображаются в увеличенном фасете:

library(ggforce)
ggplot(df) + 
  aes(x = b, y = a) +
  geom_col() +
  facet_zoom(ylim = c(0, 10), zoom.data = ifelse(a <= 10, NA, FALSE))

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

Два сюжета

предложила Хэдли Уикхэм

Я думаю, что гораздо более уместно показать два графика - один для всех данных и один только для небольших значений.

Этот код создает два графика

library(ggplot2)
g1 <- ggplot(df) + 
  aes(x = b, y = a) +
  geom_col() +
  coord_flip()
g2 <- ggplot(df) + 
  aes(x = b, y = a) +
  geom_col() +
  coord_flip() +
  ylim(NA, 10)

которые можно объединить в один сюжет

cowplot::plot_grid(g1, g2) # or ggpubr::ggarrange(g1, g2)

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

or

gridExtra::grid.arrange(g1, g2) # or egg::ggarrange(g1, g2)

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

Две грани

Это было предложено в комментарии Чейза, а также Брайаном Диггсом в его ответе, который интерпретировал предложение Хэдли использовать

фасетные графики, один со всеми данными, один увеличенный в определенном регионе

но до сих пор не было предоставлено кода для этого подхода.

Поскольку нет простого способа масштабировать фасеты по отдельности (см., Например, связанный вопрос), данными необходимо управлять:

library(dplyr)
library(ggplot2)
ggplot() + 
  aes(x = b, y = a) +
  geom_col(data = df %>% mutate(subset = "all")) +
  geom_col(data = df %>% filter(a <= 10) %>% mutate(subset = "small")) +
  coord_flip() + 
  facet_wrap(~ subset, scales = "free_x")

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

person Uwe    schedule 06.05.2019
comment
Об ошибке с facet_zoom(), geom_col() и coord_flip() было сообщено на github.com/thomasp85/ggforce/issues / 143. - person Uwe; 06.05.2019
comment
спасибо, мне очень нравится функция масштабирования граней ggforce! Вы знаете, можно ли увеличить масштаб до двух диапазонов, по одному с каждой стороны графика? Или просто иметь вертикальную линию только с осью y и по одному графику с обеих сторон с графиками в двух разных диапазонах значений y? - person charlesdarwin; 10.11.2019

Нет, без использования ggplot. См. Обсуждение в ветке на http://groups.google.com/group/ggplot2/browse_thread/thread/8d2acbfc59d2f247, где Хэдли объясняет, почему это невозможно, но дает предлагаемую альтернативу (фасетированные графики, один со всеми данными, один увеличенный в определенной области).

person Brian Diggs    schedule 25.08.2011

Не с помощью ggplot, но с помощью plotrix вы легко можете это сделать:

library(plotrix)
gap.barplot(df$a, gap=c(5,495),horiz=T)
person Wouter    schedule 06.06.2012

Нет, к сожалению, нет

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

Например, если ось усечена, но обычно лежит в пределах некоторого интервала (скажем, [0,1]), аудитория может не заметить усечения и сделать искаженные выводы о данных. В этом случае более подходящей и прозрачной была бы явная прерывистая ось.

Сравнивать:

Пример правильного использования непрерывной и прерывистой оси

person milo    schedule 23.02.2016

Я сомневаюсь, что в R есть что-нибудь готовое, но вы могли бы показать данные как серию частичных трехмерных кубов. 500 - это всего лишь 5 * 10 * 10, поэтому он хорошо масштабируется. Точное значение может быть меткой.

Вероятно, это следует использовать только в том случае, если по какой-то причине вам необходимо иметь графическое представление.

person Ed Staub    schedule 30.09.2011

умное решение ggplot предоставляется Йорг Стейнкамп, используя facet_grid. В упрощенном виде это примерно так:

library("tidyverse")
df <- data.frame(myLetter=LETTERS[1:4], myValue=runif(12) + rep(c(4,0,0),2))  # cluster a few values well above 1
df$myFacet <- df$myValue > 3
(ggplot(df, aes(y=myLetter, x=myValue)) 
  + geom_point() 
  + facet_grid(. ~ myFacet, scales="free", space="free")
  + scale_x_continuous(breaks = seq(0, 5, .25)) # this gives both facets equal interval spacing.
  + theme(strip.text.x = element_blank()) # get rid of the facet labels
)

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

person user3799203    schedule 10.12.2020
comment
Есть ли способ контролировать соотношение левой и правой панели? - person Miao Cai; 14.12.2020
comment
@MiaoCai - Один из способов управления пропорциями - использование пакета сетки, как показано в хорошо подробном примере на stackoverflow.com/a/49225527/3799203 - person user3799203; 31.01.2021

Одна из стратегий - изменить ось для построения шкалы журнала. Таким образом вы уменьшите экспоненциально более высокое значение в 10 раз.

person webscale    schedule 20.10.2018
comment
Хороший вариант для некоторых графиков, но он не подойдет для гистограмм, начинающихся с 0. - person Gregor Thomas; 29.08.2019