使用ggplot2' s geom_bar(stat="identity")
绘制计数是一种可视化计数的有效方法。我想使用这种方法来显示我观察到的计数,并将它们与我希望通过使用geom_step
在条形图上覆盖阶梯步骤图层的预期计数进行比较。
然而,当我这样做时,我遇到的问题是,默认情况下,条形图的位置被躲避但geom_step
没有。例如,使用连续和离散因变量:
library(tidyverse)
test <- data_frame(a = 1:10, b = runif(10, 1, 10))
test_plot <- ggplot(test, aes(a, b)) +
geom_bar(stat="identity") +
geom_step(color = 'red')
test2 <- data_frame(a = letters[1:10], b = runif(10, 1, 10))
test2_plot <- ggplot(test2, aes(a, b, group = 1)) +
geom_bar(stat="identity") +
geom_step(color = 'red'))
gridExtra::grid.arrange(test_plot, test2_plot, ncol = 2)
正如您所看到的那样,这两层是偏移的,这是不可取的。
阅读文档后,我看到geom_path
有一个position =
选项,但尝试类似geom_step(color = 'red', position = position_dodge(width = 0.5))
的内容并不能达到我想要的效果,而是将条形和阶梯线压缩到中心。另一种选择是像这样geom_step(aes(a-0.5, b), color = 'red')
直接调整数据,这对于具有连续因变量的数据产生接近可接受的结果。您还可以将stairstep行计算为函数,并使用stat_function()
绘制它。
然而,这些方法不适用于具有离散因变量的数据,而我的实际数据具有离散的因变量,因此我需要另一个答案。
此外,当移动时,阶梯线将不会覆盖最后一根柱,如上图所示。是否有一种简单优雅的方式来扩展它以覆盖最后一个栏?
如果geom_step()
是错误的方法,而我想要获得的东西可以用另一种方式实现,我也对此感兴趣。
答案 0 :(得分:2)
我认为解决此问题的最有效方法是以下列方式定义自定义geom:
library(tidyverse)
geom_step_extend <- function(data, extend = 1, nudge = -0.5,
...) {
# Function for computing the last segment data
get_step_extend_data <- function(data, extend = 1, nudge = -0.5) {
data_out <- as.data.frame(data[order(data[[1]]), ])
n <- nrow(data)
max_x_y <- data_out[n, 2]
if (is.numeric(data_out[[1]])) {
max_x <- data_out[n, 1] + nudge
} else {
max_x <- n + nudge
}
data.frame(x = max_x,
y = max_x_y,
xend = max_x + extend,
yend = max_x_y)
}
# The resulting geom
list(
geom_step(position = position_nudge(x = nudge), ...),
geom_segment(
data = get_step_extend_data(data, extend = extend, nudge = nudge),
mapping = aes(x = x, y = y,
xend = xend, yend = yend),
...
)
)
}
set.seed(111)
test <- data_frame(a = 1:10, b = runif(10, 1, 10))
test2 <- data_frame(a = letters[1:10], b = runif(10, 1, 10))
test_plot <- ggplot(test, aes(a, b, group = 1)) +
geom_bar(stat = "identity") +
geom_step_extend(data = test, colour = "red")
test2_plot <- ggplot(test2, aes(a, b, group = 1)) +
geom_bar(stat = "identity") +
geom_step_extend(data = test2, colour = "red")
gridExtra::grid.arrange(test_plot, test2_plot, ncol = 2)
基本上这个解决方案由三部分组成:
position_nudge
步长曲线按所需值(在本例中为-0.5); get_step_extend_data
计算缺席(右侧的)段数据。它的行为受ggplot2:::stairstep
的启发,这是geom_step
; geom_step
在geom_segment
的单独geom中撰写list
。答案 1 :(得分:1)
这是一个相当粗略的解决方案,但在这种情况下应该有用。
创建一个替代数据框,扩展每一行以将x轴扩展-0.5和0.5:
test2 <- data.frame(a = lapply(1:nrow(test), function(x) c(test[x,"a"]-.5, test[x,"a"], test[x, "a"]+0.5)) %>% unlist,
b = lapply(1:nrow(test), function(x) rep(test[x,"b"], 3)) %>% unlist)
使用geom_line参数绘制轮廓:
ggplot(test, aes(a,b)) + geom_bar(stat="identity", alpha=.7) + geom_line(data=test2, colour="red")
如果将geom_bar宽度设置为1,则显示更整洁:
ggplot(test, aes(a,b)) + geom_bar(width=1, stat="identity", alpha=.7) + geom_line(data=test2, colour="red")
答案 2 :(得分:1)
由于ggplot2 version 3.3.0现已由geom_step
使用direction = "mid"
支持此选项:
library(tidyverse)
test <- data_frame(a = 1:10, b = runif(10, 1, 10))
test_plot <- ggplot(test, aes(a, b)) +
geom_bar(stat="identity") +
geom_step(color = 'red', direction = "mid", size = 2)
test_plot
答案 3 :(得分:0)
我喜欢 molx 在 ggplot2 3.3.0 版中对 direction = 'mid'
使用 geom_step()
的回答。但是,对于时间序列,我建议移动用于 geom_bar()
或 geom_col()
图的 x 轴的数据:
data.frame(time = seq(as.POSIXct('2020-10-01 05:00'),
as.POSIXct('2020-10-01 14:00'), by = 'hour'),
value = runif(10, 0, 100)) %>%
mutate(time_shift_bars = times + 30*60) %>%
ggplot(df, mapping = aes(y = value)) +
geom_step(color = 'red', mapping = aes(x = time)) +
geom_col(width = 60*60, mapping = aes(x = time_shift_bars))
![resulting plot](https://i.stack.imgur.com/fJBac.png)
The reason I prefer this is because for example 09:00 occurs at a specific instance, and the data represents the average for the following hour. If your time-series data is not averaged like this, use the `direction` method.