2011-11-29 32 views
56

Soy un novato en R/ggplot. Me gustaría crear un diagrama geom_line de una serie temporal variable continua y luego agregar una capa compuesta de eventos. La variable continua y sus marcas de tiempo se almacenan en un data.frame, los eventos y sus marcas de tiempo se almacenan en otro data.frame.R + ggplot: serie de tiempo con eventos

Lo que haría realmente me gusta hacer es algo así como los gráficos en finance.google.com. En esos, las series de tiempo son acciones-precio y hay "banderas" para indicar noticias-eventos. En realidad, no estoy tramando cosas de finanzas, pero el tipo de gráfico es similar. Estoy tratando de trazar visualizaciones de datos de archivo de registro. He aquí un ejemplo de lo que quiero decir ...

google chart with events

Si recomendable (?), Me gustaría utilizar data.frames separadas para cada capa (uno para las observaciones continuas variables, otro para eventos).

Después de algunos intentos de prueba y error, esto es lo más cerca que puedo llegar. Aquí, estoy usando datos de ejemplo de conjuntos de datos que vienen con ggplot. "economía" contiene algunos datos de series temporales que me gustaría trazar y "presidencial" contiene algunos eventos (elecciones presidenciales).

library(ggplot2) 
data(presidential) 
data(economics) 

presidential <- presidential[-(1:3),] 
yrng <- range(economics$unemploy) 
ymin <- yrng[1] 
ymax <- yrng[1] + 0.1*(yrng[2]-yrng[1]) 

p2 <- ggplot() 
p2 <- p2 + geom_line(mapping=aes(x=date, y=unemploy), data=economics , size=3, alpha=0.5) 
p2 <- p2 + scale_x_date("time") + scale_y_continuous(name="unemployed [1000's]") 
p2 <- p2 + geom_segment(mapping=aes(x=start,y=ymin, xend=start, yend=ymax, colour=name), data=presidential, size=2, alpha=0.5) 
p2 <- p2 + geom_point(mapping=aes(x=start,y=ymax, colour=name), data=presidential, size=3) 
p2 <- p2 + geom_text(mapping=aes(x=start, y=ymax, label=name, angle=20, hjust=-0.1, vjust=0.1),size=6, data=presidential) 
p2 

my attempt

Preguntas:

  • Esto está bien para eventos muy escasas, pero si hay un grupo de ellos (como sucede a menudo en un archivo de registro), que se complica. ¿Hay alguna técnica que pueda usar para mostrar prolijamente un grupo de eventos que ocurren en un corto intervalo de tiempo? Estaba pensando en position_jitter, pero fue muy difícil para mí llegar tan lejos. Los gráficos de Google acumulan estos "indicadores" de eventos uno encima del otro si hay muchos de ellos.

  • En realidad, no me gusta pegar los datos del evento en la misma escala que la pantalla de medición continua. Preferiría ponerlo en facet_grid. El problema es que todas las facetas deben provenir del mismo data.frame (no estoy seguro si eso es cierto). Si es así, que también parece que no es ideal (o tal vez sólo estoy tratando de evitar el uso de remodelar?)

+6

Plan de interés: ¡no espere conseguir un trabajo después de que un presidente republicano asuma el poder! – James

+0

Fue solo la información más útil y disponible para usar como ejemplo-- pero sí, te hace pensar :-) – Angelo

Respuesta

36

Por mucho que me gusta la respuesta de @JD largo, voy a poner uno que sea justo R/ggplot2.

El enfoque consiste en crear un segundo conjunto de datos de eventos y utilizarlos para determinar las posiciones. A partir de lo que tenía @Angelo:

library(ggplot2) 
data(presidential) 
data(economics) 

Tire de los datos del evento (presidenciales), y transformarlo. Calcule baseline y offset como fracciones de los datos económicos con los que se trazará. Establezca la parte inferior (ymin) en la línea base. Aquí es donde viene la parte difícil. Necesitamos ser capaces de escalonar las etiquetas si están demasiado juntas.Por lo tanto, determine el espacio entre las etiquetas adyacentes (se supone que los eventos están ordenados). Si es menor que cierta cantidad (elegí unos 4 años para esta escala de datos), tenga en cuenta que esa etiqueta debe ser más alta. Pero tiene que ser más alto que el siguiente, así que use rle para obtener la longitud de TRUE (es decir, debe ser mayor) y calcule un vector de desplazamiento usando eso (cada cadena de TRUE debe contar hacia atrás desde su longitud hasta 2, los FALSE s están justo en un desplazamiento de 1). Use esto para determinar la parte superior de las barras (ymax).

events <- presidential[-(1:3),] 
baseline = min(economics$unemploy) 
delta = 0.05 * diff(range(economics$unemploy)) 
events$ymin = baseline 
events$timelapse = c(diff(events$start),Inf) 
events$bump = events$timelapse < 4*370 # ~4 years 
offsets <- rle(events$bump) 
events$offset <- unlist(mapply(function(l,v) {if(v){(l:1)+1}else{rep(1,l)}}, l=offsets$lengths, v=offsets$values, USE.NAMES=FALSE)) 
events$ymax <- events$ymin + events$offset * delta 

Poner esto juntos en una parcela:

ggplot() + 
    geom_line(mapping=aes(x=date, y=unemploy), data=economics , size=3, alpha=0.5) + 
    geom_segment(data = events, mapping=aes(x=start, y=ymin, xend=start, yend=ymax)) + 
    geom_point(data = events, mapping=aes(x=start,y=ymax), size=3) + 
    geom_text(data = events, mapping=aes(x=start, y=ymax, label=name), hjust=-0.1, vjust=0.1, size=6) + 
    scale_x_date("time") + 
    scale_y_continuous(name="unemployed \[1000's\]") 

Se podría faceta, pero es difícil con diferentes escalas. Otro enfoque es componer dos gráficos. Hay que hacer algunos ajustes adicionales para asegurarse de que las parcelas tengan el mismo rango x, para que todas las etiquetas quepan en la gráfica inferior, y para eliminar el eje x en la gráfica superior.

xrange = range(c(economics$date, events$start)) 

p1 <- ggplot(data=economics, mapping=aes(x=date, y=unemploy)) + 
    geom_line(size=3, alpha=0.5) + 
    scale_x_date("", limits=xrange) + 
    scale_y_continuous(name="unemployed [1000's]") + 
    opts(axis.text.x = theme_blank(), axis.title.x = theme_blank()) 

ylims <- c(0, (max(events$offset)+1)*delta) + baseline 
p2 <- ggplot(data = events, mapping=aes(x=start)) + 
    geom_segment(mapping=aes(y=ymin, xend=start, yend=ymax)) + 
    geom_point(mapping=aes(y=ymax), size=3) + 
    geom_text(mapping=aes(y=ymax, label=name), hjust=-0.1, vjust=0.1, size=6) + 
    scale_x_date("time", limits=xrange) + 
    scale_y_continuous("", breaks=NA, limits=ylims) 

#install.packages("ggExtra", repos="http://R-Forge.R-project.org") 
library(ggExtra) 

align.plots(p1, p2, heights=c(3,1)) 

+0

esa es una muy buena respuesta y una buena ilustración de ggplot. –

+3

¡Woohoo! entre tú y @JDLong, ¡hoy aprendí un poco de R kung fu muy bonito! – Angelo

+0

Muy útil, gracias @Brian Diggs. Un poco obsoleto. Aquí hay una versión actualizada del código: http://pastebin.com/sVAACtQe (tuvo que jugar con los márgenes, tedioso, no dude en copiar y pegar, naturalmente). – PatrickT

81

Ahora me gusta ggplot tanto como el que más, pero si quiero hacer el tipo de Google Finance gráficos, ¿por qué no solo hacerlo con Google graphics API?!? Usted va a encantar esto:

install.packages("googleVis") 
library(googleVis) 

dates <- seq(as.Date("2011/1/1"), as.Date("2011/12/31"), "days") 
happiness <- rnorm(365)^ 2 
happiness[333:365] <- happiness[333:365] * 3 + 20 
Title <- NA 
Annotation <- NA 
df <- data.frame(dates, happiness, Title, Annotation) 
df$Title[333] <- "Discovers Google Viz" 
df$Annotation[333] <- "Google Viz API interface by Markus Gesmann causes acute increases in happiness." 

### Everything above here is just for making up data ### 
## from here down is the actual graphics bits  ### 
AnnoTimeLine <- gvisAnnotatedTimeLine(df, datevar="dates", 
             numvar="happiness", 
             titlevar="Title", annotationvar="Annotation", 
             options=list(displayAnnotations=TRUE, 
                legendPosition='newRow', 
                width=600, height=300) 
             ) 
# Display chart 
plot(AnnoTimeLine) 
# Create Google Gadget 
cat(createGoogleGadget(AnnoTimeLine), file="annotimeline.xml") 

y produce este fantástico cuadro:

enter image description here

+1

¡WOW! Ni siquiera sabía que había un paquete de googleVis para R. – Angelo

+10

que sentiste que la felicidad aumentaba, ¿no? ¡Mira, los gráficos no mienten! :) –

+0

Predicción: Obtendrás un golpe de representante serio de esa demostración. –

1

Plotly es una manera fácil de hacer ggplots interactiva. Para mostrar eventos, cópielos en factores que pueden mostrarse como estéticos, como el color.

El resultado final es un diagrama sobre el que puede arrastrar el cursor. Los datos de visualización parcelas de interés:

enter image description here

Este es el código para hacer que el ggplot:

# load data  
data(presidential) 
data(economics) 

# events of interest 
events <- presidential[-(1:3),] 

# strip year from economics and events data frames 
economics$year = as.numeric(format(economics$date, format = "%Y")) 

# use dplyr to summarise data by year 
#install.packages("dplyr") 
library(dplyr) 
econonomics_mean <- economics %>% 
    group_by(year) %>% 
    summarise(mean_unemployment = mean(unemploy)) 

# add president terms to summarized data frame as a factor 
president <- c(rep(NA,14), rep("Reagan", 8), rep("Bush", 4), rep("Clinton", 8), rep("Bush", 8), rep("Obama", 7)) 
econonomics_mean$president <- president 

# create ggplot 
p <- ggplot(data = econonomics_mean, aes(x = year, y = mean_unemployment)) + 
    geom_point(aes(color = president)) + 
    geom_line(alpha = 1/3) 

Sólo se necesita una línea de código para hacer que el ggplot en un objeto argumentalmente.

# make it interactive! 
#install.packages("plotly") 
library(plotly) 
ggplotly(p) 
Cuestiones relacionadas