ggplot2 boxplot: горизонтальная полоса на медиане?

Я хотел бы сделать коробчатую диаграмму ggplot2 более значимой, добавив толстую полосу на медиане (чтобы, если медиана равна одному из нижних или верхних квартилей, можно было определить, чему она равна). Я наткнулся на недавнее сообщение Кохске: Могу ли я получить выемки на диаграммах в ggplot2? но я не знал, как придать «перекладине» «высоту». Затем я попытался использовать прямоугольник, но это тоже не сработало. Вот минимальный пример:

require(ggplot2) 
require(reshape2) 
require(plyr) 
set.seed(1) 
## parameters 
p1 <- c(5, 20, 100) 
p2 <- c("f1", "f2", "f3", "f4", "f5") 
p3 <- c("g1","g2","g3","g4","g5") 
N <- 1000 
## lengths 
l1 <- length(p1) 
l2 <- length(p2) 
l3 <- length(p3) 
## build result array containing the measurements 
arr <- array(rep(NA, l1*l2*l3*N), dim=c(l1, l2, l3, N), 
         dimnames=list( 
         p1=p1, 
         p2=p2, 
         p3=p3, 
         N=1:N)) 
for(i in 1:l1){ 
    for(j in 1:l2){ 
        for(k in 1:l3){ 
            arr[i,j,k,] <- i+j+k+runif(N, min=-4, max=4) 
        } 
    } 
} 

arr <- arr + rexp(3*5*5*N) 
## create molten data 
mdf <- melt(arr, formula = . ~ p1 + p2 + p3 + N) # create molten data frame 
## confidence interval calculated by `boxplot.stats` 
f <- function(x){ 
    ans <- boxplot.stats(x) 
    data.frame(x=x, y=ans$stats[3], ymin=ans$conf[1], ymax=ans$conf[2]) 
} 

## (my poor) trial 
ggplot(mdf, aes(x=p3, y=value)) + geom_boxplot(outlier.shape=1) + 
stat_summary(fun.data=f, geom="rectangle", colour=NA, fill="black", 
xmin=x-0.36, xmax=x+0.36, ymin=max(y-0.2, ymin), ymax=min(y+0.2, 
ymax)) + facet_grid(p2 ~ p1, scales = "free_y") 


**SOLUTION** (after the discussion with Kohske below):
f <- function(x, height){
    ans <- median(x)
    data.frame(y=ans, ymin=ans-height/2, ymax=ans+height/2)
}
p <- ggplot(mdf, aes(x=p3, y=value)) + geom_boxplot(outlier.shape=1) +
stat_summary(fun.data=f, geom="crossbar", height=0.5, colour=NA,
         fill="black", width=0.78) +
facet_grid(p2 ~ p1, scales = "free_y")
pdf()
print(p)
dev.off()

**UPDATE** Hmmm... it's not that trivial. The following example shows that the "height" of the crossbar should be adapted to the y-axis scale, otherwise it might be overseen.

require(ggplot2)
require(reshape2)
require(plyr)
set.seed(1)
## parameters
p1 <- c(5, 20, 100)
p2 <- c("f1", "f2", "f3", "f4", "f5")
p3 <- c("g1","g2","g3","g4","g5")
N <- 1000
## lengths
l1 <- length(p1)
l2 <- length(p2)
l3 <- length(p3)
## build result array containing the measurements
arr <- array(rep(NA, l1*l2*l3*N), dim=c(l1, l2, l3, N),
     dimnames=list(
     p1=p1,
     p2=p2,
     p3=p3,
     N=1:N))
for(i in 1:l1){
    for(j in 1:l2){
        for(k in 1:l3){
            arr[i,j,k,] <- i+j^4+k+runif(N, min=-4, max=4)
        }
    } 
}
arr <- arr + rexp(3*5*5*N)
arr[1,2,5,] <- arr[1,2,5,]+30
arr[1,5,3,] <- arr[1,5,3,]+100

## create molten data
mdf <- melt(arr, formula = . ~ p1 + p2 + p3 + N) # create molten data frame

f <- function(x, height){
    ans <- median(x)
    data.frame(y=ans, ymin=ans-height/2, ymax=ans+height/2)
}

## plot
p <- ggplot(mdf, aes(x=p3, y=value)) + geom_boxplot(outlier.shape=1) +
stat_summary(fun.data=f, geom="crossbar", height=0.7, colour=NA,
         fill="black", width=0.78) +
facet_grid(p2 ~ p1, scales = "free_y")
pdf()
print(p)
dev.off()

person Marius Hofert    schedule 25.11.2011    source источник
comment
Не то чтобы минимально, но, что более важно, это не воспроизводимо. Попробуйте запустить это в чистом сеансе - значение x не найдено.   -  person Andrie    schedule 25.11.2011
comment
Это является воспроизводимым. Я должен был сказать следующее: он не работает (именно по этой причине). Если бы это работало, я бы не стал спрашивать :-)   -  person Marius Hofert    schedule 25.11.2011
comment
Я особенно не понимаю, почему x не найден, поскольку я специально возвращаю его в data.frame в функции f ...   -  person Marius Hofert    schedule 25.11.2011
comment
ошибка возникает потому, что вы не используете mapping=aes(...). попробуйте stat_summary(..., mapping = aes(xmin = x-0.36, ...)). но я не думаю, что это решит ваш вопрос.   -  person kohske    schedule 25.11.2011
comment
кроме того, горизонтальная линия, которую вы видите на диаграмме, является просто средней.   -  person kohske    schedule 25.11.2011
comment
Привет, Kohske, спасибо за помощь. Я знаю, что это просто медиана. Моя цель - сделать медиану более заметной, сделав линию шире. Проблема со значением по умолчанию заключается в том, что если у вас есть данные, в которых медиана равна верхнему квартилю, вы не можете определить, равно ли оно верхнему или нижнему квартилю, потому что столбец имеет тот же размер, что и столбец для квартили. С более широкой полосой можно заметить разницу. Некоторое время назад это также было введено в коробчатую диаграмму базовой графики.   -  person Marius Hofert    schedule 25.11.2011
comment
Хорошо, но теперь я получаю сообщение об ошибке: no geom под названием rectangle ... хммм .. что за geom можно здесь использовать? Я не мог найти аргумент высоты для перекладины. ggplot(mdf, aes(x=p3, y=value)) + geom_boxplot(outlier.shape=1) + stat_summary(fun.data=f, geom="rectangle", colour=NA, fill="black", mapping=aes(xmin=x-0.36, xmax=x+0.36, ymin=max(y-0.2, ymin), ymax=min(y+0.2, ymax))) + facet_grid(p2 ~ p1, scales = "free_y")   -  person Marius Hofert    schedule 25.11.2011
comment
Тогда не могли бы вы привести пример базовой графической версии сюжета? Одна картинка стоит тысячи слов :)   -  person kohske    schedule 25.11.2011
comment
Я поставил ответ, но буду рад, если вы предоставите пример базовой графической версии. Будет полезно и другим читателям.   -  person kohske    schedule 25.11.2011
comment
Базовая диаграмма вышеизложенного довольно сложна (поэтому я использую ggplot2 :-)), но вы можете прекрасно понять, что я имею в виду, посмотрев на boxplot(count ~ spray, data = InsectSprays) [это первый пример в? Boxplot]. Вы можете ясно видеть, что медиана представлена ​​более толстой горизонтальной линией, чем нижний и верхний квартили (или весь прямоугольник, если хотите). Если вы посмотрите на группу D, вы увидите, что в этом случае медиана равна верхнему квартилю. Это было бы неотличимо от случая, когда медиана равна нижнему квартилю, если бы у медианы не было более толстой линии.   -  person Marius Hofert    schedule 25.11.2011
comment
Хорошо спасибо. Теперь я думаю, что это будет полезным вариантом, если можно будет изменить стиль линии медианы.   -  person kohske    schedule 25.11.2011


Ответы (1)


вот пример:

f <- function(x, height) {
 ans <- median(x)
 data.frame(ymin = ans-height/2, ymax = ans+height/2, y = ans)
}

df <- data.frame(x=gl(2,6), y=c(1,1,1,1,3,3, 1,1,3,3,3,3))
ggplot(df, aes(x, y)) + geom_boxplot() + 
 stat_summary(fun.data = f, geom = "crossbar", height = 0.1,
  colour = NA, fill = "skyblue", width = 0.8, alpha = 0.5)

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

если вы просто хотите изменить внешний вид, то вот быстрый совет, хотя я не рекомендую,

df <- data.frame(x=gl(2,6), y=c(c(1,1,1,1,3,3), c(1,1,3,3,3,3)*10))
ggplot(df, aes(x, y)) + geom_boxplot() + facet_grid(x~.)

gs <- grid.gget("geom_boxplot", grep = T)
if (inherits(gs, "grob")) gs <- list(gs)
gss <- llply(gs, function(g) g$children[[length(g$children)]])

l_ply(gss, function(g) grid.edit(g$name, grep=T, just = c("left", "center"), height = unit(0.05, "native"), gp = gpar(fill = "skyblue", alpha = 0.5, col = NA)))

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

person kohske    schedule 25.11.2011
comment
Забавно, я пробовал это перед тем, как опубликовать вопрос, но высота перекладины не найдена ... Спасибо! width должен быть 0,78, в противном случае полоса шире, чем прямоугольник. Кроме того, height должен зависеть от фактического выхода. Мне пришлось выбрать большую высоту в опубликованном выше решении, чтобы сделать медианы видимыми. - person Marius Hofert; 25.11.2011
comment
height передается f, а не перекладине. Я изменил f, чтобы он отображал медианное значение с указанным height. - person kohske; 25.11.2011
comment
Как именно я могу получить обновленную версию? У меня всегда возникают проблемы с установкой из репозитория github ... Это просто install_github("ggplot2") или надо указывать ветку ...? - person Marius Hofert; 25.11.2011
comment
Еще один момент: я бы рекомендовал использовать outlier.shape=1 по умолчанию. Причина в том, что как только у вас есть пара выбросов, вы больше ничего не видите (например, информация о том, сколько точек нарисовано более или менее друг над другом, больше не отображается [в отличие от outlier.shape=1, который производит незакрашенные кружки]) - person Marius Hofert; 25.11.2011
comment
Последний комментарий к коробчатым диаграммам: мне всегда было интересно, почему ggplot2 не дает усов по умолчанию. Медиана и квартили показаны горизонтальными линиями. Глазу было бы намного легче обнаружить концы усов, если бы они тоже были обозначены горизонтальными линиями (?) Есть ли для этого причина? С типографской точки зрения предпочтительнее классический способ. - person Marius Hofert; 25.11.2011
comment
Уважаемый Kohske, пожалуйста, не ОБНОВЛЕНИЕ выше. Как видите, указание фиксированной высоты (т. Е. Не зависящей от строки и столбца) может быть неподходящим. В строке 2 и строке 5 столбики недостаточно толстые, тогда как в первом ряду они довольно толстые ... Вы знаете, как это исправить? - person Marius Hofert; 25.11.2011
comment
@MariusHofert ответ был обновлен. Я так не рекомендую. Не уверен, что будет работать в будущей версии. Также я рекомендую вам предоставить минимальный пример с маленьким набором данных. - person kohske; 26.11.2011