2016-08-03 5 views
2

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

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

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

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 

Если я сюжет это с помощью базы R boxplot(), все нормально

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

enter image description here

Но с 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() 

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

enter image description here

Обратите внимание, что, без осей бревенчатых, ggplot имеет усы правильной длину

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

enter image description here

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

Update

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

+0

Посмотрите на '? Geom_boxplot'. 'ggplot' и' boxplot' используют разные методы расчета «шарниров» –

+0

@MikeyMike Спасибо - это хорошо знать. Но даже в этом случае 2 версии ggplot - с осью журнала и без нее - помещают петли в разных положениях. – dww

+1

Может ли это быть трансформированием шкал против трансформации системы координат? Использование 'scale_x_log10' такое же, как использование' log (vals) 'как переменной y. – aosmith

ответ

1

Проблема состоит в связи с тем, что 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 

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

This detailed and useful answer by @eipi10 , показывает, как рассчитать статистику самостоятельно и заставить ggplot использовать эти определяемые пользователем статистические данные rath чем его внутренний (и некорректный) алгоритм. Используя этот подход, становится относительно простым рассчитать правильную статистику и использовать их вместо этого.

# 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") 

Который производит правильный участок

enter image description here

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

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

Ошибка в Ops.unit (GYL $ х, сетки :: блок (0,5, "НПЦ")): оба операнда должен быть блоками

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

+0

В дополнение к опции grid.draw, проверьте ggstance для горизонтальных геометрий. – aosmith

2

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

# 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 обратить boxplot, как в примере ниже:

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, чтобы добавить пунктирные линии в каждом из значений box-and-whisker, и я добавил текст, чтобы показать фактические значения. Чтобы уменьшить беспорядок, я удалил точки выброса, и я немного потупил ящики, чтобы другие компоненты отображались лучше.

# 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. Вероятно, вы можете использовать что-то вроде кода в this SO answer, чтобы перевернуть сюжет, но я этого не делал.

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

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

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

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

enter image description here

+0

Спасибо @ eipi10, это была действительно отличная помощь. К сожалению, я не смог найти способ превратить график 'coord_trans' горизонтально, успешно. Но я смог приспособить ваши функции статистики к задаче и объяснить «тайну», почему статистика вискеров вычисляется неправильно ggplot. См. Мой ответ ниже. – dww

+0

Рад, что ты смог это понять. Хорошая работа! – eipi10

Смежные вопросы