R - shade area between two crossing lines with different colors

我是研究僧i 提交于 2019-12-01 21:18:05
pickle rick

If you find the intersections between the curves, then you can draw the polygons between the intersections. Here is a modification of a previous post where they find intersections between curves, and a function to draw the polygons.

## Some sample data
set.seed(0)
dat <- data.frame(x1=3*sin(3*(x=seq(0,10,len=100)))+rnorm(100),
                  x2=2*cos(x)+rnorm(100))

## https://stackoverflow.com/questions/20519431/finding-point-of-intersection-in-r
intersects <- function(x1, x2) {
    seg1 <- which(!!diff(x1 > x2))                            # location of first point in crossing segments
    above <- x2[seg1] > x1[seg1]                              # which curve is above prior to crossing
    slope1 <- x1[seg1+1] - x1[seg1]
    slope2 <- x2[seg1+1] - x2[seg1]
    x <- seg1 + ((x2[seg1] - x1[seg1]) / (slope1 - slope2))
    y <- x1[seg1] + slope1*(x - seg1)
    data.frame(x=x, y=y, pindex=seg1, pabove=(1:2)[above+1L])  # pabove is greater curve prior to crossing
}

ichimoku <- function(data, addLines=TRUE) {
    ## Find points of intersections
    ints <- intersects(data[,1], data[,2])
    intervals <- findInterval(1:nrow(data), c(0, ints$x))

    ## Make plot
    matplot(data, type="n", col=2:3, lty=1, lwd=4)
    legend("topright", c("A", "B"), col=3:2, lty=1, lwd=2)

    ## Draw the polygons
    for (i in seq_along(table(intervals))) {
        xstart <- ifelse(i == 1, 0, ints$x[i-1])
        ystart <- ifelse(i == 1, dat[1,ints$pindex[1]], ints$y[i-1])
        xend <- ints$x[i]
        yend <- ints$y[i]
        x <- seq(nrow(data))[intervals == i]
        polygon(c(xstart, x, xend, rev(x)), c(ystart, data[x,1], yend, rev(data[x,2])),
                col=ints$pabove[i]%%2+2)
    }

    ## Add lines for curves
    if (addLines)
        invisible(lapply(1:2, function(x) lines(seq(nrow(data)), data[,x], col=x%%2+2, lwd=2)))
}

## Plot the data
ichimoku(dat)

Here is some code that works for a simple version of your problem, in which the lines only cross once. I haven't tested it for repeated crossings, however.

# Make toy data
ichimoku <- data.frame(senkouA = rep(10, 10), senkouB = c(3, 5, 4, 7, 10, 11, 15, 12, 13, 14))

# Make indices for the conditions that define the fill colors. They need to intersect for the polygons to connect.
index.green = with(ichimoku, as.logical(senkouA >= senkouB))
index.red = with(ichimoku, as.logical(senkouA <= senkouB))

# Make the line plot
matplot(ichimoku, lty=1, lwd=1, pch=20, type="l", col=c("red","blue"))

# Now add polygons with fill color based on those conditions by subsetting the task using the indices.
with(ichimoku, polygon(x = c(seq(length(senkouA))[index.green], rev(seq(length(senkouA))[index.green])),
    y = c(senkouB[index.green], senkouA[index.green]), col = "green"))
with(ichimoku, polygon(x = c(seq(length(senkouA))[index.red], rev(seq(length(senkouA))[index.red])),
    y = c(senkouB[index.red], senkouA[index.red]), col = "red"))

Here's my result:

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!