首页 文章

R ggplot:包含事件的时间序列

提问于
浏览
57

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

我真正想做的是像finance.google.com上的图表 . 其中,时间序列是股票价格,有"flags"表示新闻事件 . 我'm not actually plotting finance stuff, but the type of graph is similar. I am trying to plot visualizations of log file data. Here'是我的意思的一个例子......

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,但这对我来说真的很难 . 谷歌图表将这些事件“标志”叠加在一起,如果它们有很多的话 .

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

3 回答

  • 83

    尽管我喜欢@JD Long的答案,但我会把它放在R / ggplot2中 .

    该方法是创建第二个事件数据集并使用它来确定位置 . 从@Angelo开始:

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

    拉出事件(总统)数据并进行转换 . 计算 baselineoffset 作为其绘制的经济数据的一部分 . 将底部( 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

    现在我和下一个人一样喜欢ggplot,但是如果你想制作Google财经类型的图表,为什么不用Google图形API呢?你会喜欢这个:

    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

    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 only takes one line of code to make the ggplot into a plotly object.

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

相关问题