R + ggplot: временной ряд с событиями - PullRequest
57 голосов
/ 30 ноября 2011

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

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

google chart with events

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

После некоторой проб и ошибок это примерно как можно ближе.Здесь я использую пример данных из наборов данных, которые поставляются с 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.Проблема заключается в том, что все аспекты должны быть получены из одного и того же data.frame (не уверен, что это правда).Если так, то это также кажется не идеальным (или, может быть, я просто пытаюсь избежать использования изменения формы?)

Ответы [ 3 ]

83 голосов
/ 30 ноября 2011

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

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

36 голосов
/ 30 ноября 2011

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

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

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

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

3 голосов
/ 09 августа 2017

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)

Itтребуется всего одна строка кода, чтобы превратить ggplot в сюжетный объект.

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