2011-11-29 27 views
56

Sono un novizio R/ggplot. Vorrei creare un diagramma geom_line di una serie temporale variabile continua e quindi aggiungere un livello composto da eventi. La variabile continua e i suoi timestamp sono memorizzati in un data.frame, gli eventi e i loro timestamp sono memorizzati in un altro data.frame.R + ggplot: Serie storica con eventi

Quello che vorrei fare veramente è qualcosa come i grafici su finance.google.com. In quelli, le serie temporali sono quotazioni di borsa e ci sono "bandiere" per indicare notizie-eventi. In realtà non sto tracciando materiale finanziario, ma il tipo di grafico è simile. Sto cercando di tracciare visualizzazioni dei dati del file di registro. Ecco un esempio di ciò che intendo ...

google chart with events

Se consigliabile (?), Vorrei utilizzare data.frames separate per ogni strato (uno per le osservazioni variabili continue, un altro per gli eventi).

Dopo alcune prove ed errori questo è il più vicino possibile. Qui, sto usando dati di esempio dai set di dati forniti con ggplot. "economia" contiene alcuni dati di serie temporali che mi piacerebbe tracciare e "presidenziale" contiene alcuni eventi (elezioni presidenziali).

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

Domande:

  • Questo va bene per gli eventi molto scarsa, ma se c'è un gruppo di loro (come spesso accade in un file di log), essa diventa disordinato. C'è qualche tecnica che posso usare per mostrare in modo ordinato una serie di eventi che si verificano in un breve intervallo di tempo? Stavo pensando a position_jitter, ma è stato davvero difficile per me arrivare così lontano. i grafici di google impilano questi "flag" di eventi uno sopra l'altro se ce ne sono molti.

  • In realtà non mi piace incollare i dati dell'evento nella stessa scala del display di misurazione continua. Preferirei inserirlo in un facet_grid. Il problema è che tutti i facet devono essere tutti provenienti dallo stesso data.frame (non è sicuro che sia vero). Se è così, che sembra anche non ideali (o forse sto solo cercando di evitare l'uso di rimodellare?)

+6

Trama interessante: non aspettarti di trovare un lavoro dopo che un presidente repubblicano è salito al potere! – James

+0

E 'stato solo il più pratico e disponibile da usare come esempio - ma sì, ti fa pensare :-) – Angelo

risposta

36

Per quanto mi piace la risposta di @JD lungo, metterò uno che si trova proprio di R/ggplot2.

L'approccio consiste nel creare un secondo set di dati di eventi e utilizzarlo per determinare le posizioni. A partire da ciò che aveva @Angelo:

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

Estrarre i dati dell'evento (presidenziali) e trasformarli. Calcola baseline e offset come frazioni dei dati economici con cui verrà tracciato. Impostare il fondo (ymin) sulla linea di base. È qui che arriva la parte difficile. Dobbiamo essere in grado di scaglionare le etichette se sono troppo vicine tra loro.Quindi determina la spaziatura tra etichette adiacenti (si presuppone che gli eventi siano ordinati). Se è inferiore a una certa quantità (ho scelto circa 4 anni per questa scala di dati), allora nota che quella etichetta deve essere più alta. Ma deve essere superiore a quello successivo, quindi utilizzare rle per ottenere la lunghezza di TRUE (ovvero deve essere maggiore) e calcolare un vettore di offset usando quello (ogni stringa di TRUE deve contare alla rovescia dalla sua lunghezza a 2, il FALSE s sono solo su un offset di 1). Utilizzare questo per determinare la parte superiore delle barre (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 

aver realizzato tutto questo in 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\]") 

Si potrebbe sfaccettatura, ma è difficile con diverse scale. Un altro approccio è la composizione di due grafici. C'è un po 'di giochetto supplementare da fare per assicurarsi che i grafici abbiano lo stesso intervallo x, per far sì che le etichette si adattino perfettamente al grafico inferiore e per eliminare l'asse x nel grafico superiore.

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

questa è un'ottima risposta e una buona illustrazione ggplot. –

+3

Woohoo! tra te e @JDLong, ho imparato un bel kung fu R oggi! – Angelo

+0

Molto utile, grazie a @Brian Diggs. Un po 'deprecato. Ecco una versione aggiornata del codice: http://pastebin.com/sVAACtQe (ha dovuto giocare con i margini, noioso - sentiti libero di copiare e incollare, naturalmente). – PatrickT

81

Ora mi piace ggplot tanto quanto la persona accanto, ma se si vuole fare il tipo di Google Finance grafici, perché non farlo solo con l'API grafica di Google?!? Si sta andando ad amare questo:

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") 

e produce questo fantastico grafico:

enter image description here

+1

WOW! Non sapevo nemmeno che esistesse un pacchetto googleVis per R. – Angelo

+10

hai sentito aumentare la felicità, vero? Vedi, i grafici non mentono! :) –

+0

Pronostico: Avrai un rep bump serio da quella demo. –

1

Plotly è un modo semplice per fare ggplots interattivo. Per visualizzare eventi, costringerli a fattori che possono essere visualizzati come estetici, come il colore.

Il risultato finale è un grafico su cui è possibile trascinare il cursore. I dati di visualizzazione trame di interesse:

enter image description here

Ecco il codice per rendere il 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) 

Ci vuole solo una riga di codice per rendere la ggplot in un oggetto plotly.

# make it interactive! 
#install.packages("plotly") 
library(plotly) 
ggplotly(p) 
Problemi correlati