用于 ggplot2 背景的带有 rasterGrob R 的水平渐变

Horizontal gradient with rasterGrob R for ggplot2 background

我正在尝试向绘图添加背景以显示 24 小时内的光照条件(即夜间、日出、白天、日落)。我想使用渐变来表示光的过渡期(日出时为上午 8 点至上午 9 点,日落时为晚上 8 点至晚上 9 点),以及白天和夜晚的纯色。

我已经很接近了,但是渐变是垂直方向的,我需要它是水平的。

如有任何帮助,我们将不胜感激!

当前工作代码

library(ggplot2)
library(scales)

## date, start and stop time

datestart <- as.POSIXct(strptime('2017-06-20 00:00:00', format = "%Y-%m-%d %H:%M:%S"))
datestop <- as.POSIXct(strptime('2017-06-20 23:59:59', format = "%Y-%m-%d %H:%M:%S"))

## sunrise

risestart <- as.POSIXct(strptime('2017-06-20 08:00:00', format = "%Y-%m-%d %H:%M:%S"))
risestop <- as.POSIXct(strptime('2017-06-20 09:00:00', format = "%Y-%m-%d %H:%M:%S"))

## sunset

setstart <- as.POSIXct(strptime('2017-06-20 20:00:00', format = "%Y-%m-%d %H:%M:%S"))
setstop <- as.POSIXct(strptime('2017-06-20 21:00:00', format = "%Y-%m-%d %H:%M:%S"))

## data limits

lims <- c(datestart, datestop)

## generate some random data

timelist <- seq(datestart, datestop, by = '15 mins')
act <- runif(length(timelist), min = 0, max = 50)

data <- data.frame(timelist, act)

## colours

nightColour <- c("#9ea5ff")
sunriseColour <- c("#9ea5ff", "#fcffbd")
testColour <- c(c("#9ea5ff"), c("#fcffbd"))

dayColour <- c("#fcffbd")
sunsetColour <- c("#fcffbd","#9ea5ff")

## add background

nightGrob <- rasterGrob(nightColour, width = unit(1,"npc"), height = unit(1,"npc"),
                        interpolate = TRUE)

sunriseGrob <- rasterGrob(sunriseColour, width = unit(1,"npc"), height = unit(1,"npc"),
                          interpolate = TRUE)

dayGrob <- rasterGrob(dayColour, width = unit(1,"npc"), height = unit(1,"npc"),
                      interpolate = TRUE)

sunsetGrob <- rasterGrob(sunsetColour, width = unit(1,"npc"), height = unit(1,"npc"),
                         interpolate = TRUE)

## plot

ggplot(data = data, aes(x = timelist, y = act)) +
  annotation_custom(nightGrob, xmin = as.numeric(datestart), xmax = as.numeric(risestart) + 100, ymin = -Inf, ymax = Inf) +
  annotation_custom(sunriseGrob, xmin = as.numeric(risestart), xmax = as.numeric(risestop), ymin = -Inf, ymax = Inf) +
  annotation_custom(dayGrob, xmin = as.numeric(risestop), xmax = as.numeric(setstart), ymin = -Inf, ymax = Inf) +
  annotation_custom(sunsetGrob, xmin = as.numeric(setstart), xmax = as.numeric(setstop), ymin = -Inf, ymax = Inf) +
  annotation_custom(nightGrob, xmin = as.numeric(setstop), xmax = as.numeric(datestop), ymin = -Inf, ymax = Inf) +
  geom_bar(stat = "identity", colour = "black", fill = "white") +
  scale_x_datetime(limits = lims, expand = c(0,0), breaks = date_breaks('1 hour'), labels = date_format(format = "%H", tz = "Europe/London")) +
  scale_y_continuous(expand = c(0,0))

Current progress

如果你愿意,你也可以用很多 geom_rect 代替 rasterGrob 来制作渐变。

这是一个函数,它 returns 一个 data.frame 的渐变背景绘图数据,您可以使用 geom_rect 绘图。

GenerateGradientData <- function(start_hour,
                                 stop_hour,
                                 start_colour,
                                 stop_colour,
                                 x_resolution = 100) {

    # define the colour palette
    colour_function <- colorRampPalette(
        c(start_colour, stop_colour),
        alpha = TRUE)

    # set up the rect coordinates
    x_range <- seq(start_hour,
                      stop_hour,
                      length.out = x_resolution + 1)
    grad_xmin <- x_range[-length(x_range)]
    grad_xmax <- x_range[c(1:x_resolution + 1)]

    # define colours
    grad_colours <- colour_function(x_resolution)

    # return data.frame
    data.frame(
        xmin = grad_xmin,
        xmax = grad_xmax,
        ymin = -Inf,
        ymax = Inf,
        grad_colours = grad_colours
    )
}

这是一个使用数字 x 轴的示例:

# dummy data
set.seed(1)
plot_data <- data.frame(
    hours = c(1:24),
    value = rnorm(24, 100, 30)
)

# day/night colours
night_colour <- c("#9ea5ff")
day_colour <- c("#fcffbd")

# generate data for a one-hour sunrise gradient
sunrise_pd <- GenerateGradientData(start_hour = 8,
                                   stop_hour = 9,
                                   start_colour = night_colour,
                                   stop_colour = day_colour,
                                   x_resolution = 1000)

# generate data for a one-hour sunset gradient
sunset_pd <- GenerateGradientData(start_hour = 20,
                                  stop_hour = 21,
                                  start_colour = day_colour,
                                  stop_colour = night_colour,
                                  x_resolution = 1000)

# setup plot
ggplot(plot_data, aes(x = hours, y = value)) +
    scale_x_continuous(expand = c(0, 0)) +
    scale_y_continuous(expand = c(0, 0)) +

    # day background
    geom_rect(xmin = 9,
              xmax = 20,
              ymin = -Inf,
              ymax = Inf,
              fill = day_colour) +

    # night background
    geom_rect(xmin = -Inf,
              xmax = 8,
              ymin = -Inf,
              ymax = Inf,
              fill = night_colour) +
    geom_rect(xmin = 21,
              xmax = Inf,
              ymin = -Inf,
              ymax = Inf,
              fill = night_colour) +

    # gradient backgrounds for sunrise and sunset
    geom_rect(data = sunrise_pd,
              mapping = aes(xmax = xmax,
                            xmin = xmin,
                            ymax = ymax,
                            ymin = ymin),
              fill = sunrise_pd$grad_colours,
              inherit.aes = FALSE) +
    geom_rect(data = sunset_pd,
              mapping = aes(xmax = xmax,
                            xmin = xmin,
                            ymax = ymax,
                            ymin = ymin),
              fill = sunset_pd$grad_colours,
              inherit.aes = FALSE) +

    # finally, plot your data on top
    geom_col(fill = NA, colour = "black")

这是输出:

根据 x_resolution、您保存时使用的图形设备和图像查看器,这可能看起来有点块状。