R + ggplot: временные ряды с событиями

Я новичок R/ggplot. Я хотел бы создать график geom_line непрерывного переменного временного ряда, а затем добавить слой, состоящий из событий. Непрерывная переменная и ее временные метки хранятся в одних данных.фрейм, события и их временные метки хранятся в других данных.рамка.

что я действительно хотелось бы сделать что-то вроде диаграмм на finance.google.com - ... В них временной ряд-это цена акций, и есть "флаги", указывающие на новости-события. На самом деле я не планирую финансовые вещи, но тип графика похож. Я пытаюсь построить визуализацию данных файла журнала. Вот пример что я имею в виду...

google chart with events

Если целесообразно (?), Я хотел бы использовать отдельные данные.кадры для каждого слоя (один для наблюдений непрерывных переменных, другой для событий).

после некоторых проб и ошибок это примерно так же близко, как я могу получить. Здесь я использую примеры данных из наборов данных, которые поставляются с ggplot. "экономика "содержит некоторые данные временных рядов, которые я хотел бы построить, а" президентский " содержит несколько событий (президентские выборы).

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

вопросы:

  • это нормально для очень редких событий, но если есть кластер из них (как часто бывает в файле журнала), он становится беспорядочным. Есть ли какая-то техника, которую я могу использовать, чтобы аккуратно отобразить кучу событий, происходящих за короткий промежуток времени? Я думал о position_jitter, но это мне было очень трудно зайти так далеко. Google charts складывает эти "флаги" событий друг на друга, если их много.

  • мне на самом деле не нравится вставлять данные события в том же масштабе, что и дисплей непрерывного измерения. Я бы предпочел поместить его в facet_grid. Проблема в том, что все грани должны быть получены из одних и тех же данных.кадр (не уверен, что это правда). Если это так, это также кажется не идеальным (или, может быть, я просто пытаюсь избежать использования перекроить?)

3 ответов


насколько мне нравится ответ @JD Long, я поставлю тот, который находится только в R/ggplot2.

подход состоит в том, чтобы создать второй набор данных событий и использовать его для определения позиций. Начиная с того, что имел @Angelo:

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

вытащите данные события (президентские) и преобразуйте их. Вычислить baseline и offset в долях экономических данных будет обозначается. Установите дно (ymin) к базовой линии. Это где сложная часть приходит. Мы нужно уметь пошатывать этикетки, если они слишком близко друг к другу. Поэтому определите расстояние между соседними метками (предполагается, что события отсортированы). Если это меньше некоторой суммы (я выбрал около 4 лет для этой шкалы данных), то обратите внимание, что эта метка должна быть выше. Но он должен быть выше, чем после него, поэтому используйте rle чтобы получить длину TRUE(то есть должен быть выше) и вычислить вектор смещения, используя это (каждая строка TRUE должен отсчитывать от его длина до 2, то FALSEs находятся только на смещении 1). Используйте это, чтобы определить верхнюю часть баров (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

складывая это в сюжет:

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

вы можете фасет, но это сложно с разными масштабами. Другой подход состоит в составлении двух графиков. Существует некоторая дополнительная возня, которая должна быть сделана, чтобы убедиться, что участки имеют одинаковый X-диапазон, чтобы все метки вписывались в нижний участок и устраняли ось x на верхнем участке.

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


теперь мне нравится ggplot так же, как и следующий парень, но если вы хотите сделать диаграммы типа Google Finance, почему бы просто не сделать это с помощью API Google graphics?!? Вам понравится это:

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

и он производит эту фантастическую графику:

enter image description here


Plotly это простой способ сделать ggplots интерактивным. Чтобы отобразить события, принудите их к факторам, которые могут быть отображены как эстетические, такие как цвет.

конечным результатом является график, на который можно перетащить курсор. На участках отображаются данные, представляющие интерес:

enter image description here

вот код для создания 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)

требуется только одна строка кода, чтобы сделать ggplot плотным объект.

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