Используя 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
![enter image description here]()
Есть ли способ заставить мою ось работать от 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()
Ответы
Ответ 1
Как уже упоминалось в другом месте, это не то, что ggplot2
будет хорошо работать, поскольку сломанные оси обычно считаются сомнительными.
Другие стратегии часто считаются лучшими решениями этой проблемы. Брайан упомянул несколько (огранки, два сюжета, посвященные различным наборам ценностей). Еще один вариант, который люди слишком часто пропускают, особенно для штрих-кодов, - это сделать таблицу:
![enter image description here]()
Глядя на фактические значения, 500 не скрывает различия в других значениях! По какой-то причине таблицы не получают достаточного уважения в качестве метода визуализации. Вы можете возразить, что ваши данные имеют много и много категорий, которые становятся громоздкими в таблице. Если это так, вероятно, ваша гистограмма будет иметь слишком много баров, чтобы быть разумным.
И я не спорю о таблицах все время. Но они определенно должны что-то учитывать, если вы создаете баррикады с относительно небольшим количеством баров. И если вы делаете барчарты с множеством баров, вам может потребоваться переосмыслить это в любом случае.
Наконец, в пакете plotrix
есть функция axis.break
, которая реализует сломанные оси. Однако из того, что я собираюсь, вам придется вручную указать метки и позиции оси.
Ответ 2
Нет, не используйте ggplot. См. Обсуждение в разделе http://groups.google.com/group/ggplot2/browse_thread/thread/8d2acbfc59d2f247, где Хэдли объясняет, почему это невозможно, но дает предложенную альтернативу (граненый график, один со всеми данными, один увеличенный конкретный регион).
Ответ 3
Не с ggplot, но с помощью графика вы можете легко сделать это:
library(plotrix)
gap.barplot(df$a, gap=c(5,495),horiz=T)
Ответ 4
нет, к сожалению нет
Страх в том, что возможность прерывистых осей приведет к обману аудитории. Однако бывают случаи, когда отсутствие прерывистой оси приводит к искажению.
Например, если ось усечена, но обычно лежит в пределах некоторого интервала (скажем [0,1]), аудитория может не заметить усечение и сделать искаженные выводы о данных. В этом случае явная прерывистая ось будет более подходящей и прозрачной.
Для сравнения:
![Example of good use of continuous vs discontinuous axis]()
Ответ 5
Я сомневаюсь, что что-нибудь с полки в R, но вы можете показать данные как серию 3D частичных кубов. 500 составляет всего 5 * 10 * 10, поэтому он будет хорошо масштабироваться. Точным значением может быть метка.
Это, вероятно, следует использовать только в том случае, если по какой-то причине вы должны иметь графическое представление.
Ответ 6
Одна стратегия состоит в том, чтобы изменить ось, чтобы построить масштаб журнала. Таким образом, вы можете уменьшить экспоненциально более высокое значение в 10 раз
Ответ 7
Восемь лет спустя пакет ggforce
предлагает расширение facet_zoom()
которое является реализацией предложения Хэдли Уикхема, чтобы показать два графика (как указано в ответе Брайана Диггса).
Увеличить грань
library(ggforce)
ggplot(df) +
aes(x = b, y = a) +
geom_col() +
facet_zoom(ylim = c(0, 10))
![enter image description here]()
К сожалению, текущая версия 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))
![enter image description here]()
Два участка
Хэдли Уикхем предложил
Я думаю, что гораздо более уместно показать два графика - один из всех данных, а другой - только небольшие значения.
Этот код создает два участка
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)
![enter image description here]()
или же
gridExtra::grid.arrange(g1, g2) # or egg::ggarrange(g1, g2)
![enter image description here]()
Две грани
Это было предложено в комментарии Чейза, а также Брайана Диггса в его ответе, который интерпретировал предложение Хэдли использовать
граненые участки, один со всеми данными, один увеличенный в определенном регионе
но пока не было предоставлено никакого кода для этого подхода.
Поскольку не существует простого способа отдельно масштабировать фасеты (см., Например, связанный вопрос), необходимо манипулировать данными:
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")
![enter image description here]()