ggplot2 - 如何使用 geom_bar 绘制时间长度?
ggplot2 - How to plot length of time using geom_bar?
我试图通过显示多个地区的作物种植和收获日期来显示不同的生长季节长度。
我的最终目标是一个看起来像这样的图表:
摘自对 this question 的回答。请注意,日期以儒略日(一年中的某天)为单位。
我第一次尝试重现类似的情节是:
library(data.table)
library(ggplot2)
mydat <- "Region\tCrop\tPlanting.Begin\tPlanting.End\tHarvest.Begin\tHarvest.End\nCenter-West\tSoybean\t245\t275\t1\t92\nCenter-West\tCorn\t245\t336\t32\t153\nSouth\tSoybean\t245\t1\t1\t122\nSouth\tCorn\t183\t336\t1\t153\nSoutheast\tSoybean\t275\t336\t1\t122\nSoutheast\tCorn\t214\t336\t32\t122"
# read data as data table
mydat <- setDT(read.table(textConnection(mydat), sep = "\t", header=T))
# melt data table
m <- melt(mydat, id.vars=c("Region","Crop"), variable.name="Period", value.name="value")
# plot stacked bars
ggplot(m, aes(x=Crop, y=value, fill=Period, colour=Period)) +
geom_bar(stat="identity") +
facet_wrap(~Region, nrow=3) +
coord_flip() +
theme_bw(base_size=18) +
scale_colour_manual(values = c("Planting.Begin" = "black", "Planting.End" = "black",
"Harvest.Begin" = "black", "Harvest.End" = "black"), guide = "none")
但是,这个情节有一些问题:
因为条形是堆叠的,所以 x 轴上的值是聚合的并且最终太高了 - 超出了代表一年中某天的 1-365 范围。
我需要将Planting.Begin
和Planting.End
组合成相同的颜色,对Harvest.Begin
和Harvest.End
做同样的事情。
此外,需要在 Planting.Begin
和 Harvest.End
之间创建一个“空白”(或完全没有颜色的条)。
也许图表 可以 用 geom_rect
或 geom_segment
实现,但我真的想坚持使用 geom_bar
,因为它更可定制(例如,它接受 scale_colour_manual
以便向条形图添加黑色边框)。
关于如何创建此类图表的任何提示?
我认为这是 geom_bar
或 geom_col
无法做到的事情。更通用的方法是使用 geom_rect
绘制矩形。为此,我们需要稍微重塑数据
plotdata <- mydat %>%
dplyr::mutate(Crop = factor(Crop)) %>%
tidyr::pivot_longer(Planting.Begin:Harvest.End, names_to="period") %>%
tidyr::separate(period, c("Type","Event")) %>%
tidyr::pivot_wider(names_from=Event, values_from=value)
# Region Crop Type Begin End
# <chr> <fct> <chr> <int> <int>
# 1 Center-West Soybean Planting 245 275
# 2 Center-West Soybean Harvest 1 92
# 3 Center-West Corn Planting 245 336
# 4 Center-West Corn Harvest 32 153
# 5 South Soybean Planting 245 1
# ...
我们已使用 tidyr
重塑数据,因此我们要绘制的每个矩形都有一行,我们还使裁剪成为一个因素。然后我们可以这样绘制它
ggplot(plotdata) +
aes(ymin=as.numeric(Crop)-.45, ymax=as.numeric(Crop)+.45, xmin=Begin, xmax=End, fill=Type) +
geom_rect(color="black") +
facet_wrap(~Region, nrow=3) +
theme_bw(base_size=18) +
scale_y_continuous(breaks=seq_along(levels(plotdata$Crop)), labels=levels(plotdata$Crop))
这里有点乱的部分是我们对 y
使用离散比例,但是 geom_rect
更喜欢数值,所以由于这些值现在是因子,所以我们使用数值作为创建 ymin 和 ymax 位置的因素。然后我们需要用因子水平的名称替换 y 轴。
如果您还想在 x
轴上获取月份名称,您可以执行类似
的操作
dateticks <- seq.Date(as.Date("2020-01-01"), as.Date("2020-12-01"),by="month")
# then add this to you plot
... +
scale_x_continuous(breaks=lubridate::yday(dateticks),
labels=lubridate::month(dateticks, label=TRUE, abbr=TRUE))
我试图通过显示多个地区的作物种植和收获日期来显示不同的生长季节长度。
我的最终目标是一个看起来像这样的图表:
摘自对 this question 的回答。请注意,日期以儒略日(一年中的某天)为单位。
我第一次尝试重现类似的情节是:
library(data.table)
library(ggplot2)
mydat <- "Region\tCrop\tPlanting.Begin\tPlanting.End\tHarvest.Begin\tHarvest.End\nCenter-West\tSoybean\t245\t275\t1\t92\nCenter-West\tCorn\t245\t336\t32\t153\nSouth\tSoybean\t245\t1\t1\t122\nSouth\tCorn\t183\t336\t1\t153\nSoutheast\tSoybean\t275\t336\t1\t122\nSoutheast\tCorn\t214\t336\t32\t122"
# read data as data table
mydat <- setDT(read.table(textConnection(mydat), sep = "\t", header=T))
# melt data table
m <- melt(mydat, id.vars=c("Region","Crop"), variable.name="Period", value.name="value")
# plot stacked bars
ggplot(m, aes(x=Crop, y=value, fill=Period, colour=Period)) +
geom_bar(stat="identity") +
facet_wrap(~Region, nrow=3) +
coord_flip() +
theme_bw(base_size=18) +
scale_colour_manual(values = c("Planting.Begin" = "black", "Planting.End" = "black",
"Harvest.Begin" = "black", "Harvest.End" = "black"), guide = "none")
但是,这个情节有一些问题:
因为条形是堆叠的,所以 x 轴上的值是聚合的并且最终太高了 - 超出了代表一年中某天的 1-365 范围。
我需要将
Planting.Begin
和Planting.End
组合成相同的颜色,对Harvest.Begin
和Harvest.End
做同样的事情。此外,需要在
Planting.Begin
和Harvest.End
之间创建一个“空白”(或完全没有颜色的条)。
也许图表 可以 用 geom_rect
或 geom_segment
实现,但我真的想坚持使用 geom_bar
,因为它更可定制(例如,它接受 scale_colour_manual
以便向条形图添加黑色边框)。
关于如何创建此类图表的任何提示?
我认为这是 geom_bar
或 geom_col
无法做到的事情。更通用的方法是使用 geom_rect
绘制矩形。为此,我们需要稍微重塑数据
plotdata <- mydat %>%
dplyr::mutate(Crop = factor(Crop)) %>%
tidyr::pivot_longer(Planting.Begin:Harvest.End, names_to="period") %>%
tidyr::separate(period, c("Type","Event")) %>%
tidyr::pivot_wider(names_from=Event, values_from=value)
# Region Crop Type Begin End
# <chr> <fct> <chr> <int> <int>
# 1 Center-West Soybean Planting 245 275
# 2 Center-West Soybean Harvest 1 92
# 3 Center-West Corn Planting 245 336
# 4 Center-West Corn Harvest 32 153
# 5 South Soybean Planting 245 1
# ...
我们已使用 tidyr
重塑数据,因此我们要绘制的每个矩形都有一行,我们还使裁剪成为一个因素。然后我们可以这样绘制它
ggplot(plotdata) +
aes(ymin=as.numeric(Crop)-.45, ymax=as.numeric(Crop)+.45, xmin=Begin, xmax=End, fill=Type) +
geom_rect(color="black") +
facet_wrap(~Region, nrow=3) +
theme_bw(base_size=18) +
scale_y_continuous(breaks=seq_along(levels(plotdata$Crop)), labels=levels(plotdata$Crop))
这里有点乱的部分是我们对 y
使用离散比例,但是 geom_rect
更喜欢数值,所以由于这些值现在是因子,所以我们使用数值作为创建 ymin 和 ymax 位置的因素。然后我们需要用因子水平的名称替换 y 轴。
如果您还想在 x
轴上获取月份名称,您可以执行类似
dateticks <- seq.Date(as.Date("2020-01-01"), as.Date("2020-12-01"),by="month")
# then add this to you plot
... +
scale_x_continuous(breaks=lubridate::yday(dateticks),
labels=lubridate::month(dateticks, label=TRUE, abbr=TRUE))