r time-series gradient

Cómo hacer un diagrama de series de tiempo lleno de color degradado en R



time-series gradient (4)

¿Cómo llenar el área debajo y arriba (sp) de la línea con degradado de color ?

Este ejemplo se ha dibujado en Inkscape, PERO NECESITO gradiente vertical , NO horizontal.

Intervalo de cero a positivo == de blanco a rojo .

Intervalo de cero a negativo == de blanco a rojo .

¿Hay algún paquete que pueda hacer esto?

He fabricado algunos datos fuente ...

set.seed(1) x<-seq(from = -10, to = 10, by = 0.25) data <- data.frame(value = sample(x, 25, replace = TRUE), time = 1:25) plot(data$time, data$value, type = "n") my.spline <- smooth.spline(data$time, data$value, df = 15) lines(my.spline$x, my.spline$y, lwd = 2.5, col = "blue") abline(h = 0)


Aquí hay un enfoque, que se basa en gran medida en varios paquetes espaciales R.

La idea básica es:

  • Trace una parcela vacía, el lienzo sobre el que se colocarán los elementos posteriores. (Hacer esto primero también le permite recuperar las coordenadas de usuario de la trama, necesarias en los pasos posteriores).

  • Use una llamada vectorizada a rect() para establecer un lavado de color de fondo. Obtener los detalles complicados del gradiente de color es en realidad la parte más difícil de hacer esto.

  • Use las funciones de topología en rgeos para encontrar primero los rectángulos cerrados en su figura, y luego su complemento. Trazar el complemento con un relleno blanco sobre el lavado de fondo cubre el color en todas partes, excepto dentro de los polígonos, justo lo que desea.

  • Finalmente, use plot(..., add=TRUE) , lines() , abline() , etc. para establecer cualquier otro detalle que desee que muestre el gráfico.

library(sp) library(rgeos) library(raster) library(grid) ## Extract some coordinates x <- my.spline$x y <- my.spline$y hh <- 0 xy <- cbind(x,y) ## Plot an empty plot to make its coordinates available ## for next two sections plot(data$time, data$value, type = "n", axes=FALSE, xlab="", ylab="") ## Prepare data to be used later by rect to draw the colored background COL <- colorRampPalette(c("red", "white", "red"))(200) xx <- par("usr")[1:2] yy <- c(seq(min(y), hh, length.out=100), seq(hh, max(y), length.out=101)) ## Prepare a mask to cover colored background (except within polygons) ## (a) Make SpatialPolygons object from plot''s boundaries EE <- as(extent(par("usr")), "SpatialPolygons") ## (b) Make SpatialPolygons object containing all closed polygons SL1 <- SpatialLines(list(Lines(Line(xy), "A"))) SL2 <- SpatialLines(list(Lines(Line(cbind(c(0,25),c(0,0))), "B"))) polys <- gPolygonize(gNode(rbind(SL1,SL2))) ## (c) Find their difference mask <- EE - polys ## Put everything together in a plot plot(data$time, data$value, type = "n") rect(xx[1], yy[-201], xx[2], yy[-1], col=COL, border=NA) plot(mask, col="white", add=TRUE) abline(h = hh) plot(polys, border="red", lwd=1.5, add=TRUE) lines(my.spline$x, my.spline$y, col = "red", lwd = 1.5)


Esta es una forma terrible de engañar a ggplot para que haga lo que quiera. Esencialmente, hago una cuadrícula gigante de puntos que están debajo de la curva. Como no hay forma de establecer un gradiente dentro de un solo polígono, debe crear polígonos separados, de ahí la cuadrícula. Será lento si configura los píxeles demasiado bajos.

gen.bar <- function(x, ymax, ypixel) { if (ymax < 0) ypixel <- -abs(ypixel) else ypixel <- abs(ypixel) expand.grid(x=x, y=seq(0,ymax, by = ypixel)) } # data must be in x order. find.height <- function (x, data.x, data.y) { base <- findInterval(x, data.x) run <- data.x[base+1] - data.x[base] rise <- data.y[base+1] - data.y[base] data.y[base] + ((rise/run) * (x - data.x[base])) } make.grid.under.curve <- function(data.x, data.y, xpixel, ypixel) { desired.points <- sort(unique(c(seq(min(data.x), max(data.x), xpixel), data.x))) desired.points <- desired.points[-length(desired.points)] heights <- find.height(desired.points, data.x, data.y) do.call(rbind, mapply(gen.bar, desired.points, heights, MoreArgs = list(ypixel), SIMPLIFY=FALSE)) } xpixel = 0.01 ypixel = 0.01 library(scales) grid <- make.grid.under.curve(data$time, data$value, xpixel, ypixel) ggplot(grid, aes(xmin = x, ymin = y, xmax = x+xpixel, ymax = y+ypixel, fill=abs(y))) + geom_rect()

Los colores no son lo que deseabas, pero de todos modos es demasiado lento para un uso serio.


Otra posibilidad que utiliza funciones de paquetes grid y gridSVG .

Comenzamos generando puntos de datos adicionales por interpolación lineal, de acuerdo con los métodos descritos por @ kohske here . La gráfica básica consistirá en dos polígonos separados, uno para valores negativos y otro para valores positivos.

Una vez que se ha procesado la trama, grid.ls se usa para mostrar una lista de grob s, es decir, todos los componentes grob de la trama. En la lista encontraremos (entre otras cosas) dos geom_area.polygon s; uno que representa el polígono para valores <= 0 y otro para valores >= 0 .

El relleno de los grobs polígono se manipula utilizando gridSVG funciones gridSVG : los gradientes de color personalizados se crean con linearGradient , y el relleno de los grobs se reemplaza con grid.gradientFill .

La manipulación de gradientes grob se describe muy bien en el capítulo 7 de la tesis de maestría de Simon Potter, uno de los autores del paquete gridSVG .

library(grid) library(gridSVG) library(ggplot2) # create a data frame of spline values d <- data.frame(x = my.spline$x, y = my.spline$y) # create interpolated points d <- d[order(d$x),] new_d <- do.call("rbind", sapply(1:(nrow(d) -1), function(i){ f <- lm(x ~ y, d[i:(i+1), ]) if (f$qr$rank < 2) return(NULL) r <- predict(f, newdata = data.frame(y = 0)) if(d[i, ]$x < r & r < d[i+1, ]$x) return(data.frame(x = r, y = 0)) else return(NULL) }) ) # combine original and interpolated data d2 <- rbind(d, new_d) d2 # set up basic plot ggplot(data = d2, aes(x = x, y = y)) + geom_area(data = subset(d2, y <= 0)) + geom_area(data = subset(d2, y >= 0)) + geom_line() + geom_abline(intercept = 0, slope = 0) + theme_bw() # list the name of grobs and look for relevant polygons # note that the exact numbers of the grobs may differ grid.ls() # GRID.gTableParent.878 # ... # panel.3-4-3-4 # ... # areas.gTree.834 # geom_area.polygon.832 <~~ polygon for negative values # areas.gTree.838 # geom_area.polygon.836 <~~ polygon for positive values # create a linear gradient for negative values, from white to red col_neg <- linearGradient(col = c("white", "red"), x0 = unit(1, "npc"), x1 = unit(1, "npc"), y0 = unit(1, "npc"), y1 = unit(0, "npc")) # replace fill of ''negative grob'' with a gradient fill grid.gradientFill("geom_area.polygon.832", col_neg, group = FALSE) # create a linear gradient for positive values, from white to red col_pos <- linearGradient(col = c("white", "red"), x0 = unit(1, "npc"), x1 = unit(1, "npc"), y0 = unit(0, "npc"), y1 = unit(1, "npc")) # replace fill of ''positive grob'' with a gradient fill grid.gradientFill("geom_area.polygon.836", col_pos, group = FALSE) # generate SVG output grid.export("myplot.svg")

Puede crear fácilmente diferentes gradientes de color para polígonos positivos y negativos. Por ejemplo, si desea que los valores negativos se ejecuten de blanco a azul, reemplace col_pos arriba con:

col_pos <- linearGradient(col = c("white", "blue"), x0 = unit(1, "npc"), x1 = unit(1, "npc"), y0 = unit(0, "npc"), y1 = unit(1, "npc"))


Y aquí hay un enfoque en la base R, donde llenamos el área de la trama completa con rectángulos de color graduado, y luego rellenamos el inverso del área de interés con blanco.

shade <- function(x, y, col, n=500, xlab=''x'', ylab=''y'', ...) { # x, y: the x and y coordinates # col: a vector of colours (hex, numeric, character), or a colorRampPalette # n: the vertical resolution of the gradient # ...: further args to plot() plot(x, y, type=''n'', las=1, xlab=xlab, ylab=ylab, ...) e <- par(''usr'') height <- diff(e[3:4])/(n-1) y_up <- seq(0, e[4], height) y_down <- seq(0, e[3], -height) ncolor <- max(length(y_up), length(y_down)) pal <- if(!is.function(col)) colorRampPalette(col)(ncolor) else col(ncolor) # plot rectangles to simulate colour gradient sapply(seq_len(n), function(i) { rect(min(x), y_up[i], max(x), y_up[i] + height, col=pal[i], border=NA) rect(min(x), y_down[i], max(x), y_down[i] - height, col=pal[i], border=NA) }) # plot white polygons representing the inverse of the area of interest polygon(c(min(x), x, max(x), rev(x)), c(e[4], ifelse(y > 0, y, 0), rep(e[4], length(y) + 1)), col=''white'', border=NA) polygon(c(min(x), x, max(x), rev(x)), c(e[3], ifelse(y < 0, y, 0), rep(e[3], length(y) + 1)), col=''white'', border=NA) lines(x, y) abline(h=0) box() }

Aquí hay unos ejemplos:

xy <- curve(sin, -10, 10, n = 1000) shade(xy$x, xy$y, c(''white'', ''blue''), 1000)

O con el color especificado por una paleta de rampa de color:

shade(xy$x, xy$y, heat.colors, 1000)

Y aplicado a sus datos, aunque primero interpolamos los puntos a una resolución más fina (si no hacemos esto, el gradiente no sigue de cerca la línea donde cruza cero).

xy <- approx(my.spline$x, my.spline$y, n=1000) shade(xy$x, xy$y, c(''white'', ''red''), 1000)