change - ggplot title center
R+ggplot: serie de tiempo con eventos (3)
Ahora me gusta ggplot tanto como el siguiente tipo, pero si quieres hacer los gráficos tipo Google Finance, ¿por qué no simplemente hacerlo con la API gráfica de Google?!? Te 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 esta fantástica carta:
Soy un novato 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.
Lo que realmente me gustaría 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. Aquí hay un ejemplo de lo que quiero decir ...
Si es aconsejable (?), Me gustaría usar data.frames separados para cada capa (uno para observaciones de variables continuas, otro para eventos).
Después de un poco 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
Preguntas:
Esto está bien para eventos muy dispersos, pero si hay un grupo de ellos (como sucede a menudo en un archivo de registro), se vuelve complicado. ¿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.
De hecho, 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í, eso tampoco parece ideal (¿o quizás solo estoy tratando de evitar el cambio de forma?)
Por mucho que me guste la respuesta de @JD Long, pondré una que esté justo en R / ggplot2.
El enfoque es crear un segundo conjunto de datos de eventos y usar eso para determinar posiciones. Comenzando con lo que tenía @Angelo:
library(ggplot2)
data(presidential)
data(economics)
Extraiga los datos del evento (presidencial) y transfórmelos. Calcule la baseline
y el offset
como fracciones de los datos económicos con los que se trazará. Establecer la parte inferior ( ymin
) a la línea de 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 compensación usando eso (cada cadena de TRUE
debe contar hacia abajo 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
Juntando esto en una trama:
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/]")
Podrías facetar, pero es complicado 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))
Plotly
es una manera fácil de hacer que ggplots sea interactivo. 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. Las parcelas muestran datos de interés:
Aquí está el código para hacer 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)
Solo se necesita una línea de código para convertir el ggplot en un objeto plotly.
# make it interactive!
#install.packages("plotly")
library(plotly)
ggplotly(p)