R + ggplot: szereg czasowy z wydarzeniami

Jestem nowicjuszem R / ggplot. Chciałbym utworzyć wykres geom_line ciągłej zmiennej szeregi czasowe, a następnie dodać warstwę złożoną ze zdarzeń. Zmienna ciągła i jej znaczniki czasu są przechowywane w jednej danych.ramka, zdarzenia i ich znaczniki czasu są przechowywane w innych danych.rama.

To, co chciałbym naprawdę zrobić, to coś takiego jak wykresy na finance.google.com. w tych, szereg czasowy jest cena akcji i istnieją "flagi", aby wskazać wiadomości-wydarzenia. Nie jestem wykresy finansowe, ale typ wykresu jest podobny. Próbuję wykreślić wizualizacje danych z pliku dziennika. Oto przykład tego, co mam na myśli...

Wykres google z wydarzeniami

Jeśli wskazane (?), Chciałbym użyć osobnych danych.ramki dla każdej warstwy (jedna dla ciągłych obserwacji zmiennych, druga dla zdarzeń).

Po próbach i błędach jest to tak blisko, jak tylko mogę. Tutaj używam przykładowych danych z zestawów danych, które są dostarczane z ggplot. "Ekonomia" zawiera dane szeregów czasowych że chciałbym spiskować i "prezydencki" zawiera kilka wydarzeń (wybory prezydenckie).

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

moja próba

Pytania:

  • Jest to w porządku dla bardzo rzadkich zdarzeń, ale jeśli jest ich klaster (jak to często bywa w pliku dziennika), robi się bałagan. Czy jest jakaś technika, której mogę użyć, aby starannie wyświetlić kilka zdarzeń występujących w krótkim odstępie czasu? Myślałem o position_jitter, ale naprawdę ciężko mi było zajść tak daleko. Google charts układa te wydarzenia "flagi" na sobie, jeśli jest ich dużo.

  • Właściwie nie lubię trzymać danych o zdarzeniach w tej samej skali, co wyświetlacz ciągłego pomiaru. Wolałbym umieścić go w facet_grid. Problem polega na tym, że wszystkie aspekty muszą pochodzić z tych samych danych.frame (Nie wiem czy to prawda). Jeśli tak, to również nie wydaje się to idealne (a może po prostu staram się uniknąć używania zmiany kształtu?)

Author: joran, 2011-11-30

3 answers

Jak najbardziej podoba mi się odpowiedź @ JD Long, to wrzucę taką, która jest właśnie w R / ggplot2.

Podejście polega na stworzeniu drugiego zbioru danych zdarzeń i wykorzystaniu go do określania pozycji. Zaczynając od tego co @ Angelo miał:

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

Wyciągnij dane zdarzenia (Prezydenckiego) i przekształć je. Oblicz baseline i offset jako ułamki danych ekonomicznych, które zostaną wykreślone. Ustaw bottom (ymin) na linię bazową. Tutaj przychodzi najtrudniejsza część. Musimy być w stanie zataczać etykiety, jeśli są zbyt blisko siebie. Więc określ odstępy między sąsiednimi etykietami (zakłada, że zdarzenia są sortowane). Jeśli jest to mniej niż pewna kwota (wybrałem około 4 lat dla tej skali danych), to należy pamiętać, że etykieta musi być wyższa. Ale musi być wyższy niż ten po nim, więc użyj rle, aby uzyskać długość TRUE'S (to znaczy musi być wyższa) i Oblicz wektor przesunięcia za pomocą tego (każdy ciąg TRUE musi odliczać od swojej długości do 2, FALSE S są tylko na przesunięcie 1). Użyj tego do określenia górnej części pasków (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

Układanie tego w fabułę:

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

Można ująć, ale jest to trudne w różnych skalach. Innym podejściem jest skomponowanie dwóch wykresów. Istnieje pewne dodatkowe zmiany, które muszą być wykonane, aby upewnić się, że działki mają ten sam zakres X, aby etykiety pasowały do dolnej działki i wyeliminować oś x w górnej powierzchni.

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

 36
Author: Brian Diggs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-29 22:47:01

Teraz lubię ggplot tak samo jak następny facet, ale jeśli chcesz zrobić wykresy typu Google Finance, dlaczego nie po prostu zrobić to z Google graphics API?!? Pokochasz to:

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

I tworzy ten fantastyczny wykres:

Tutaj wpisz opis obrazka

 82
Author: JD Long,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-29 22:35:01

Plotly to łatwy sposób na interaktywność ggplots. Aby wyświetlać zdarzenia, zmuszaj je do czynników, które mogą być wyświetlane jako estetyczne, takie jak kolor.

Efektem końcowym jest wykres, nad którym można przeciągnąć kursor. Wykresy wyświetlają interesujące dane:

Tutaj wpisz opis obrazka

Oto kod do robienia 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)

Wystarczy tylko jedna linijka kodu, aby zrobić z ggplot obiekt plotly.

# make it interactive!
#install.packages("plotly")
library(plotly)
ggplotly(p)
 2
Author: Rich Pauloo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-21 07:13:34