Preencher área entre duas linhas, com alta / baixa e datas

Prefácio: dou uma resposta razoavelmente satisfatória à minha própria pergunta. Entendo que essa é uma prática aceitável. Naturalmente, minha esperança é convidar sugestões e melhorias.

Meu objetivo é plotar duas séries temporais (armazenadas em um quadro de dados com datas armazenadas como classe 'Data') e preencher a área entre os pontos de dados com duas cores diferentes, dependendo se uma está acima da outra. Por exemplo, plotar um índice de títulos e um índice de ações e preencher a área em vermelho quando o índice de ações estiver acima do índice de títulos e preencher a área em azul caso contrário.

Eu tenho usadoggplot2 para esse fim, porque estou razoavelmente familiarizado com o pacote (autor: Hadley Wickham), mas fique à vontade para sugerir outras abordagens. Eu escrevi uma função personalizada com base nogeom_ribbon() função doggplot2 pacote. No início, enfrentei problemas relacionados à minha falta de experiência no manuseio dogeom_ribbon() função e objetos de classe'Date'. A função abaixo representa meu esforço para resolver esses problemas, quase certamente é rotatória, desnecessariamente complicada, desajeitada, etc. Então, minha pergunta é:Por favor, sugerir melhorias e / ou abordagens alternativas. Por fim, seria ótimo ter uma função de uso geral disponibilizada aqui.

Dados:

set.seed(123456789)
df <- data.frame(
    Date  = seq.Date(as.Date("1950-01-01"), by = "1 month", length.out = 12*10),
    Stocks = 100 + c(0, cumsum(runif(12*10-1, -30, 30))),
    Bonds = 100 + c(0, cumsum(runif(12*10-1, -5, 5))))
library('reshape2')
df <- melt(df, id.vars = 'Date')

Função personalizada:

## Function to plot geom_ribbon for class Date
geom_ribbon_date <- function(data, group, N = 1000) {
    # convert column of class Date to numeric
    x_Date <- as.numeric(data[, which(sapply(data, class) == "Date")])
    # append numeric date to dataframe
    data$Date.numeric <- x_Date
    # ensure fill grid is as fine as data grid
    N <- max(N, length(x_Date))
    # generate a grid for fill
    seq_x_Date <- seq(min(x_Date), max(x_Date), length.out = N)
    # ensure the grouping variable is a factor
    group <- factor(group)
    # create a dataframe of min and max
    area <- Map(function(z) {
        d <- data[group == z,];
        approxfun(d$Date.numeric, d$value)(seq_x_Date);
    }, levels(group))
    # create a categorical variable for the max
    maxcat <- apply(do.call('cbind', area), 1, which.max)
    # output a dataframe with x, ymin, ymax, is. max 'dummy', and group
    df <- data.frame(x = seq_x_Date, 
        ymin = do.call('pmin', area), 
        ymax = do.call('pmax', area), 
        is.max = levels(group)[maxcat],
        group = cumsum(c(1, diff(maxcat) != 0))
    )
    # convert back numeric dates to column of class Date
    df$x <- as.Date(df$x, origin = "1970-01-01")
    # create and return the geom_ribbon
    gr <- geom_ribbon(data = df, aes(x, ymin = ymin, ymax = ymax, fill = is.max, group = group), inherit.aes = FALSE)
    return(gr)
}

Uso:

ggplot(data = df, aes(x = Date, y = value, group = variable, colour = variable)) + 
    geom_ribbon_date(data = df, group = df$variable) +
    theme_bw() +
    xlab(NULL) +
    ylab(NULL) +
    ggtitle("Bonds Versus Stocks (Fake Data!)") +
    scale_fill_manual('is.max', breaks = c('Stocks', 'Bonds'), 
                        values = c('darkblue','darkred')) +
    theme(legend.position = 'right', legend.direction = 'vertical') +
    theme(legend.title = element_blank()) +
    theme(legend.key = element_blank())

Resultado:

Embora existam perguntas e respostas relacionadas ao stackoverflow, não encontrei uma que fosse suficientemente detalhada para o meu propósito. Aqui está uma seleção de trocas úteis:

create-geom-ribbon-for-min-max-range: Faz uma pergunta semelhante, mas fornece menos detalhes do que eu estava procurando.possível-bug-in-geom-ribbon: Faltam etapas estreitamente relacionadas, mas intermediárias, sobre como calcular o máximo / min.preencher-região-entre-duas-loess-suavizou-linhas-em-r-com-ggplot: Estreitamente relacionado, mas se concentra nas linhas loess. Excelente.ggplot-coloração-áreas-entre-densidade-linhas-de acordo com a posição relativa : Estreitamente relacionado, mas se concentra em densidades. Este post me inspirou muito.

questionAnswers(2)

yourAnswerToTheQuestion