ggplot boxplot - длина усов с логарифмической осью

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

Минимальный воспроизводимый пример:

Некоторые данные

library(ggplot2)
library(reshape2)
set.seed(1234)
my.df <- data.frame(a = rnorm(1000,150,50), b = rnorm(1000,500,150))
my.df$a[which(my.df$a < 5)] <- 5
my.df$b[which(my.df$b < 5)] <- 5

Если я построю это с использованием базы Rboxplot(), Все отлично

boxplot(my.df, log="x", horizontal=T)

Но с ggplot,

my.df.long <- melt(my.df, value.name = "vals")
ggplot(my.df.long, aes(x=variable, y=vals)) +
  geom_boxplot() +
  scale_y_log10(breaks=c(5,10,20,50,100,200,500,1000), limits=c(5,1000)) +
  theme_bw() + coord_flip()

Я получаю этот график, в котором усы имеют неправильную длину (см., Например, как много дополнительных выбросов ниже усов и ни одного выше).

Обратите внимание, что без учета бревен ggplot имеет правильную длину.

ggplot(my.df.long, aes(x=variable, y=vals)) +
  geom_boxplot() +
  theme_bw() + coord_flip()

Как создать горизонтальный логарифмический блок-график, используя ggplot с усиками правильной длины? Желательно, чтобы усы расширялись в 1,5 раза по IQR.

Обновить

Как объяснилВот, Можно использоватьcoord_trans(y = "log10") вместоscale_y_log10, что приведет к вычислению статистикидо преобразование данных.тем не мение, coord_trans нельзя использовать в сочетании сcoord_flip, Таким образом, это не решает проблему создания горизонтальных прямоугольников с осью журнала.

 dww03 авг. 2016 г., 23:19
@MikeyMike Спасибо - это приятно знать. Но даже в этом случае 2 версии ggplot - с осью бревна и без нее - размещают петли в разных положениях
 aosmith03 авг. 2016 г., 23:33
Может ли это быть трансформацией шкалы против трансформации системы координат? С помощьюscale_x_log10 так же, как использованиеlog(vals) в качестве переменной у.
 aosmith04 авг. 2016 г., 00:05
Этот вопрос выглядит актуально
 Mike H.03 авг. 2016 г., 23:18
смотреть на?geom_boxplot. ggplot а такжеboxplot использовать разные методы расчета "петли"

Ответы на вопрос(2)

Решение Вопроса

Проблема связана с тем, чтоscale_y_log10 преобразует данные перед вычислением статистики. Это не имеет значения для средних и процентильных точек, потому что, например, 10 ^ log10 (медиана) по-прежнему является медианным значением, которое будет нанесено в правильном месте. Но этоделает имеет значение для усов, которые рассчитываются с использованием 1,5 * IQR, потому что 10 ^ (1,5 * IQR (log10 (x)) не равно 1,5 * IQR (x). Таким образом, расчет не выполняется для усов.

Эта ошибка становится очевидной, если мы сравним

boxplot.stats(my.df$b)$stats
# [1] 117.4978 407.3983 502.0460 601.2937 873.0992
10^boxplot.stats(log10(my.df$b))$stats
# [1] 231.1603 407.3983 502.0459 601.2935 975.1906

В котором мы видим, что медианные и процентильные точки идентичны, но концы усов (1-й и последний элементы вектора статистики) отличаются

Этот подробный и полезный ответ от @ eipi10, показывает, как рассчитать статистику самостоятельно и заставить ggplot использовать эту статистику, определенную пользователем, а не ее внутренний (и неверный) алгоритм. Используя этот подход, становится относительно просто вычислить правильную статистику и использовать ее вместо этого.

# Function to use boxplot.stats to set the box-and-whisker locations  
mybxp = function(x) {
  bxp = log10(boxplot.stats(10^x)[["stats"]])
  names(bxp) = c("ymin","lower", "middle","upper","ymax")
  return(bxp)
}  

# Function to use boxplot.stats for the outliers
myout = function(x) {
  data.frame(y=log10(boxplot.stats(10^x)[["out"]]))
}

ggplot(my.df.long, aes(x=variable, y=vals)) + theme_bw() + coord_flip() +
  scale_y_log10(breaks=c(5,10,20,50,100,200,500,1000), limits=c(5,1000)) + 
  stat_summary(fun.data=mybxp, geom="boxplot") +
  stat_summary(fun.data=myout, geom="point") 

Который производит правильный сюжет

Примечание по использованиюcoord_trans в качестве альтернативного подхода:

С помощьюcoord_trans(y = "log10") вместоscale_y_log10, заставляет статистику рассчитываться (правильно) на нетрансформированных данных.тем не мение, coord_trans нельзя использовать в сочетании сcoord_flip, Таким образом, это не решает проблему создания горизонтальных прямоугольников с осью журнала. ПредложениеВот использоватьggdraw(switch_axis_position()) из пакета cowplot, чтобы перевернуть оси после использованияcoord_trans не работал, но выдает ошибку (cowplot v0.4.0 с ggplot2 v2.1.0)

Ошибка в Ops.unit (gyl $ x, grid :: unit (0.5, "npc")): оба операнда должны быть единицами

Дополнительно: предупреждающее сообщение:axis.ticks.margin устарела. Пожалуйста, установитеmargin собственностьюaxis.text вместо

 aosmith04 авг. 2016 г., 04:06
В дополнение к опции grid.draw, проверьте пакет ggstance для горизонтальных геомов.

Вы можете иметьggplot использованиеboxplot.stats (та же функция, используемая базойboxplot), чтобы установить значения у для ящиков и усов и выбросов. Например:

# Function to use boxplot.stats to set the box-and-whisker locations  
mybxp = function(x) {
  bxp = boxplot.stats(x)[["stats"]]
  names(bxp) = c("ymin","lower", "middle","upper","ymax")
  return(bxp)
}  

# Function to use boxplot.stats for the outliers
myout = function(x) {
  data.frame(y=boxplot.stats(x)[["out"]])
}

Теперь мы используем эти функции вstat_summary нарисовать коробку, как в примере ниже:

ggplot(my.df.long, aes(x=variable, y=vals)) +
  stat_summary(fun.data=mybxp, geom="boxplot") +
  stat_summary(fun.data=myout, geom="point") +
  theme_bw() + coord_flip()

Теперь о проблеме преобразования журнала: на графиках ниже показано, соответственно, отсутствие преобразования координат,scale_y_log10, а такжеcoord_trans(y="log10"), Кроме того, я использовалgeom_hline чтобы добавить пунктирные линии к каждому значению «ящик с усами», я добавил текст, чтобы показать фактические значения. Чтобы уменьшить беспорядок, я удалил точки выброса и немного потушил поля, чтобы другие компоненты были лучше видны.

# Set up common plot elements
p = ggplot(my.df.long, aes(x=variable, y=vals)) +
  geom_hline(yintercept=mybxp(my.df$a), colour="red", lty="11", size=0.3) +
  geom_hline(yintercept=mybxp(my.df$b), colour="blue", lty="11", size=0.3) +
  stat_summary(fun.data=mybxp, geom="boxplot", colour="#000000A0", fatten=0.5) +
  #stat_summary(fun.data=myout, geom="point") +
  theme_bw() + coord_flip()

br = c(5,10,20,50,100,200,500,1000)

## Create plots

# Without log transformation
p1 = p + scale_y_continuous(breaks=br, limits=c(5,1000)) + 
  stat_summary(fun.y=mybxp, aes(label=round(..y..)), geom="text", size=3, colour="red") +
  ggtitle("No Transformation")

# With scale_y_log10
p2 = p + scale_y_log10(breaks=br, limits=c(5,1000)) + ggtitle("scale_y_log10") +
  stat_summary(fun.y=mybxp, aes(label=round(..y..,2)), geom="text", size=3, colour="red") +
  stat_summary(fun.y=mybxp, aes(label=round(10^(..y..))), geom="text", size=3, 
               colour="blue", position=position_nudge(x=0.3)) 

# With coord_trans
p3 = p + scale_y_continuous(breaks=br, limits=c(5,1000)) +
  stat_summary(fun.y=mybxp, aes(label=round(..y..)), geom="text", size=3, colour="red") +
  coord_trans(y="log10") + ggtitle("coord_trans(y='log 10')")

Три участка показаны ниже. Обратите внимание, что последний сюжет, используяcoord_trans не переворачивается, потому чтоcoord_trans Переопределениеcoord_flip, Вы, вероятно, можете использовать что-то вроде кода вэтот так ответ перевернуть сюжет, но я не сделал этого здесь.

Первый график, без преобразований, показывает правильные значения.

Третий сюжет, используяcoord_trans также есть все в правильных местах. Обратите внимание, чтоcoord_trans фактически изменяет систему координат Y графика без изменения значений нанесенных точек. Это само пространство было «искажено» до логарифмического масштаба.

Теперь обратите внимание, что во втором сюжете, используяscale_y_log10Ящики находятся в правильных местах, но концы усов находятся в неправильных местах. С другой стороны, сравнение с двумя другими графиками показывает, что расположение всехgeom_hlineс правильно. Также обратите внимание, что в отличие отcoord_trans, scale_y_log10 берет журнал самих точек и просто перемаркирует разрывы оси y с незафиксированными значениями, оставляя "пространство", в котором точки отображаются без изменений. Вы можете увидеть это, посмотрев на значения в красном тексте. Значения, выделенные синим текстом, являются незафиксированными.

Увидеть@ dww's answer для объяснения того, почемуscale_y_log10 результаты только в том случае, когда концы усов неправильно преобразуются, а значения ячеек отображаются в нужном месте.

 eipi1004 авг. 2016 г., 06:23
Рад, что ты смог понять это. Хорошая работа!
 dww04 авг. 2016 г., 04:07
Спасибо @ eipi10, это было очень полезно. К сожалению, я не смог найти способ повернутьcoord_trans сюжет горизонтальный, удачно. Но я смог адаптировать ваши статистические функции к задаче и объяснить «тайну» того, почему статистика вискеров вычисляется неправильно ggplot. Смотрите мой ответ ниже.

Ваш ответ на вопрос