R + ggplot:带有事件的时间序列

我是R / ggplot新手。 我想创build一个连续variables时间序列的geom_line图,然后添加一个由事件组成的图层。 连续variables及其时间戳存储在一个data.frame中,事件和时间戳存储在另一个data.frame中。

真正想要做的就是像finance.google.com上的图表。 其中,时间序列是股票价格,有“旗”来表示新闻事件。 我实际上不是在绘制财务资料,但是图表的types是相似的。 我试图绘制日志文件数据的可视化。 这里是我的意思的例子…

谷歌图表与事件

如果build议(?),我想为每个图层使用不同的数据框架(一个用于连续variables观察,另一个用于事件)。

经过一些试验和错误,这是尽可能接近我可以得到的。 在这里,我正在使用来自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 

我的企图

问题:

  • 对于非常稀疏的事件来说,这是可以的,但是如果它们有一个集群(就像在一个日志文件中经常发生的那样),就会变得混乱。 是否有一些技巧可以用来整齐地显示一小段时间内发生的事件? 我正在考虑position_jitter,但是我真的很难得到这个。 谷歌图表堆叠这些事件“标志”在彼此的顶部,如果有很多。

  • 实际上,我不喜欢用连续测量显示的相同比例来粘贴事件数据。 我宁愿把它放在facet_grid中。 问题是,方面都必须来自相同的data.frame(不知道如果是这样)。 如果是这样,那也似乎不理想(或者我只是想避免使用重塑?)

尽pipe我喜欢@JD Long的回答,但我会把它放在R / ggplot2中。

方法是创build第二个事件数据集,并使用它来确定职位。 从@Angelo开始:

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

拉出事件(总统)的数据,并将其转换。 将baselineoffset计算为将绘制的​​经济数据的一部分。 将底部( ymin )设置为基线。 这是棘手的部分来的地方。 如果标签太靠近,我们需要交错。 因此,确定相邻标签之间的间距(假设事件已sorting)。 如果它小于一定数量(我select了大约4年的数据),那么请注意,标签需要更高。 但是它必须高于后面的那个,所以使用rle来获得TRUE的长度(也就是必须更高),并使用它来计算偏移向量(每个TRUEstring必须从其长度倒数到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)) 

现在我和ggplot一样喜欢下一个人,但是如果你想制作Google Financetypes图表,那么为什么不用GooglegraphicsAPI呢? 你会喜欢这个:

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

它产生了这个奇妙的图表:

在这里输入图像说明

Plotly是一个简单的方法来使ggplots互动。 为了显示事件,强迫它们成为可以作为审美performance的因素,如颜色。

最终结果是一个可以拖动光标的graphics。 这些图显示感兴趣的数据:

在这里输入图像说明

这是制作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)