Полая гистограмма или биннинг для geom_step
Я хотел бы нарисовать полую гистограмму, в которой нет вертикальных полос, внутри которой она находится, а всего лишь контур. Я не мог найти способ сделать это с помощью geom_histogram
. Комбинация geom_step
+ stat_bin
выглядела так, будто она могла выполнять эту работу. Тем не менее, бины geom_step
+ stat_bin
сдвигаются на половину бина вправо или влево, в зависимости от значения параметра шага direction=
. Похоже, он делает свои "шаги" в центрах WRT. Есть ли способ изменить это поведение, чтобы он выполнял "шаги" на краях корзины?
Вот иллюстрация:
d <- data.frame(x=rnorm(1000))
qplot(x, data=d, geom="histogram",
breaks=seq(-4,4,by=.5), color=I("red"), fill = I("transparent")) +
geom_step(stat="bin", breaks=seq(-4,4,by=.5), color="black", direction="vh")
![enter image description here]()
Ответы
Ответ 1
Я предлагаю создать новую Geom так:
library(ggplot2)
library(proto)
geom_stephist <- function(mapping = NULL, data = NULL, stat="bin", position="identity", ...) {
GeomStepHist$new(mapping=mapping, data=data, stat=stat, position=position, ...)
}
GeomStepHist <- proto(ggplot2:::Geom, {
objname <- "stephist"
default_stat <- function(.) StatBin
default_aes <- function(.) aes(colour="black", size=0.5, linetype=1, alpha = NA)
reparameterise <- function(., df, params) {
transform(df,
ymin = pmin(y, 0), ymax = pmax(y, 0),
xmin = x - width / 2, xmax = x + width / 2, width = NULL
)
}
draw <- function(., data, scales, coordinates, ...) {
data <- as.data.frame(data)[order(data$x), ]
n <- nrow(data)
i <- rep(1:n, each=2)
newdata <- rbind(
transform(data[1, ], x=xmin, y=0),
transform(data[i, ], x=c(rbind(data$xmin, data$xmax))),
transform(data[n, ], x=xmax, y=0)
)
rownames(newdata) <- NULL
GeomPath$draw(newdata, scales, coordinates, ...)
}
guide_geom <- function(.) "path"
})
Это также работает для неравномерных разрывов. Чтобы проиллюстрировать использование:
d <- data.frame(x=runif(1000, -5, 5))
ggplot(d, aes(x)) +
geom_histogram(breaks=seq(-4,4,by=.5), color="red", fill=NA) +
geom_stephist(breaks=seq(-4,4,by=.5), color="black")
![plot]()
Ответ 2
Это не идеально, но это лучшее, что я могу придумать:
h <- hist(d$x,breaks=seq(-4,4,by=.5))
d1 <- data.frame(x = h$breaks,y = c(h$counts,NA))
ggplot() +
geom_histogram(data = d,aes(x = x),breaks = seq(-4,4,by=.5),
color = "red",fill = "transparent") +
geom_step(data = d1,aes(x = x,y = y),stat = "identity")
![enter image description here]()
Ответ 3
Еще один. Используйте ggplot_build
для построения объекта графика гистограммы для рендеринга. Из этого объекта выделяются значения x
и y
, которые будут использоваться для geom_step
. Используйте by
для смещения значений x
.
by <- 0.5
p1 <- ggplot(data = d, aes(x = x)) +
geom_histogram(breaks = seq(from = -4, to = 4, by = by),
color = "red", fill = "transparent")
df <- ggplot_build(p1)$data[[1]][ , c("x", "y")]
p1 +
geom_step(data = df, aes(x = x - by/2, y = y))
![enter image description here]()
Изменить следующий комментарий от @Vadim Khotilovich (Спасибо!)
Вместо этого можно использовать xmin
из объекта сюжета (- > нет необходимости в настройке смещения)
df <- ggplot_build(p1)$data[[1]][ , c("xmin", "y")]
p1 +
geom_step(data = df, aes(x = xmin, y = y))
Ответ 4
Альтернатива, также менее идеальная:
qplot(x, data=d, geom="histogram", breaks=seq(-4,4,by=.5), color=I("red"), fill = I("transparent")) +
stat_summary(aes(x=round(x * 2 - .5) / 2, y=1), fun.y=length, geom="step")
Отсутствие некоторых бункеров, которые вы, вероятно, можете добавить обратно, если вы немного потрудитесь. Только (несколько бессмысленно) преимущество заключается в том, что больше в ggplot
чем @Joran ответ, хотя даже это спорно.
![enter image description here]()
Ответ 5
Я отвечу на свой собственный комментарий ранее: вот измененная версия ответа @RosenMatev, обновленная для v2 (ggplot2_2.0.0) с помощью ggproto:
GeomStepHist <- ggproto("GeomStepHist", GeomPath,
required_aes = c("x"),
draw_panel = function(data, panel_scales, coord, direction) {
data <- as.data.frame(data)[order(data$x), ]
n <- nrow(data)
i <- rep(1:n, each=2)
newdata <- rbind(
transform(data[1, ], x=x - width/2, y=0),
transform(data[i, ], x=c(rbind(data$x-data$width/2, data$x+data$width/2))),
transform(data[n, ], x=x + width/2, y=0)
)
rownames(newdata) <- NULL
GeomPath$draw_panel(newdata, panel_scales, coord)
}
)
geom_step_hist <- function(mapping = NULL, data = NULL, stat = "bin",
direction = "hv", position = "stack", na.rm = FALSE,
show.legend = NA, inherit.aes = TRUE, ...) {
layer(
data = data,
mapping = mapping,
stat = stat,
geom = GeomStepHist,
position = position,
show.legend = show.legend,
inherit.aes = inherit.aes,
params = list(
direction = direction,
na.rm = na.rm,
...
)
)
}
Ответ 6
простой способ сделать что-то похожее на @Rosen Matev (это не работает с ggplot2_2.0.0, как упоминалось @julou), я бы просто
1) вычислить вручную значение бункеров (используя небольшую функцию, как показано ниже)
2) использовать geom_step()
Надеюсь, это поможет!
geom_step_hist<- function(d,binw){
dd=NULL
bin=min(d$y) # this enables having a first value that is = 0 (to have the left vertical bar of the plot when using geom_step)
max=max(d$y)+binw*2 # this enables having a last value that is = 0 (to have the right vertical bar of the plot when using geom_step)
xx=NULL
yy=NULL
while(bin<=max){
n=length(temp$y[which(temp$y<bin & temp$y>=(bin-binw))])
yy=c(yy,n)
xx=c(xx,bin-binw)
bin=bin+binw
rm(n)
}
dd=data.frame(xx,yy)
return(dd)
}
hist=ggplot(dd,aes(x=xx,y=yy))+
geom_step()