Re: Drawing multiple vertical lines on time series line plots

5,434 views
Skip to first unread message

Allan Just

unread,
Feb 6, 2013, 11:42:43 AM2/6/13
to ggp...@googlegroups.com
Hi Jennifer,
 your issue would be clearer with a reproducible example (explained here).
Coercing text, as in:  as.numeric("2012-09-08") will only produce NA values. But using Date formatted xintercept for geom_vline brings up a scale error for me as demonstrated below which perhaps someone else can help with (so that you can keep the nice scale_x_date options). This may be the same as in this incomplete previous thread that went off topic: https://groups.google.com/d/msg/ggplot2/M7ngIrcaxOU/W7avAikaMmAJ

# reproducible example code
library(ggplot2)
x <- data.frame(mydate = seq(as.Date("2012-08-28"),
  by = "days", length.out = 10), myvar = rnorm(10))

# generate line plot with dates - works fine
ggplot(x, aes(mydate, myvar)) +
  geom_line()

# adding geom_vline with dates throws an error
last_plot() + geom_vline(aes(xintercept = mydate))
# Error: Discrete value supplied to continuous scale

-Allan
R version 2.15.1 (2012-06-22)
Platform: x86_64-pc-mingw32/x64 (64-bit)

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] ggplot2_0.9.3

loaded via a namespace (and not attached):
 [1] colorspace_1.2-1   dichromat_2.0-0    digest_0.6.2       grid_2.15.1        gtable_0.1.2       labeling_0.1      
 [7] MASS_7.3-23        munsell_0.4        plyr_1.8           proto_0.3-10       RColorBrewer_1.0-5 reshape2_1.2.2    
[13] scales_0.2.3       stringr_0.6.2      tools_2.15.1      


On Tuesday, 5 February 2013 17:20:55 UTC-5, Jennifer Krauel wrote:
I'm trying to draw vertical lines on my line plots.  They're all plots of weather-related time series data, with the date column generated in R as a series based on a start date (see data snipped below).  The vertical lines will represent passage of cold fronts, and there's a column (ncep.front) in the same data frame with 1 in cells on dates where the front passed, otherwise zero.    What I want to do is extract an array of front dates for each season, then apply that as a vline layer to each plot.  I've got this working intermittently which is very frustrating; I think there's something fundamental I don't understand.

In the simplest example, I have a set of dates, the column of 0/1 for cold fronts, and one of my time series variables: 
         date ncep.front hrs.foraging
1  2012-08-28          0        11.12
2  2012-08-29          0        11.37
3  2012-08-30          0        10.87
4  2012-08-31          0        10.62 ....

I can generate a list of the frontal dates for the 2012 fall season from the main data frame with this code:

>fronts <- which(few.cols[few.front] == 1)
>frontdates <- few.cols[fronts,1]
> frontdates
[1] "2012-09-08" "2012-09-13" "2012-09-28" "2012-10-06" "2012-10-10" "2012-10-14" "2012-10-17" "2012-10-25"
[9] "2012-11-04"

I've tried a bunch of variations on the following calls to draw the actual plot.  This particular one generates the graph but not the lines, and I get warning messages.

>ggplot (data = fewest, aes(x = date,y = hrs.foraging) ) +

         geom_line() +

        geom_vline (aes (xintercept = as.numeric("2012-09-08","2012-09-13","2012-09-28","2012-10-06","2012-10-10","2012-10-14","2012-10-17","2012-10-25","2012-11-04")

          )))

Warning messages:

1: In eval(expr, envir, enclos) : NAs introduced by coercion

2: Removed 1 rows containing missing values (geom_segment). 

Based on what I've read in the ggplot Springer book and online in various forums, using the date format with the as.numeric call should be at least close to what would work.  Why can't I just say "xintercept = frontdates" or "xintercept = as.numeric(frontdates)"? Those also give me errors.

I have tried passing an array of integer offsets for the correct dates ("fronts" as calculated above), but it will only print 5 lines; asking for more than that gives me a different error message.  But I'm afraid ggplot doesn't want offsets here (so why did it work for 5 but not 6 or more?); it wants the actual dates to match to the dates on the x-axis, no?  So how do I get it to accept multiple dates?

Any suggestions greatly appreciated.

Jennifer Krauel

University of Tennessee, Knoxville


Jennifer Krauel

unread,
Feb 6, 2013, 2:14:28 PM2/6/13
to ggp...@googlegroups.com
OK great link on how to assemble reproducible code!  Here's what I have.


library(ggplot2)

fewest2<- structure(list(date = structure(15580:15653, class = "Date"), 

    ncep.front = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 

    1L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 

    0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 

    0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 

    0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 

    0L, 0L, 0L), hrs.foraging = c(11.12, 11.37, 10.87, 10.62, 

    11.38, 11.3, 11.58, 11.28, 11.78, 12.05, 14.13, 11.12, 10.85, 

    10.65, 12.2, 12.78, 14.05, 11.55, 12.22, 11.73, 11.55, 11.1, 

    12.22, 10.57, 11.43, 11.8, 11.9, 11.68, 11.62, 11.85, 12.17, 

    11.98, 12.52, 11.87, 11.53, 11.37, 11.67, 11.52, 11.6, 11.92, 

    11.95, 12.2, 12.65, 12.15, 12.52, 11.92, 12.27, 11.9, 12.28, 

    11.97, 12.32, 11.1, 12.67, 12.12, 12.03, 12.22, 12.17, 11.97, 

    12.28, 12.03, 11.85, 11.77, 11.37, 12.33, 12.15, 11.7, 11.85, 

    12.02, 12.32, 12.27, 11.58, 11.7, 12.18, 12.3)), .Names = c("date", 

"ncep.front", "hrs.foraging"), class = "data.frame", row.names = c(NA, 

-74L))

#create an array of rows representing frontal passages for the season

fronts <- which(fewest2[,2] == 1)

frontdates <- fewest2[fronts,1]

#try a simple line plot, with vertical bars representing fronts

ggplot (data = fewest2, aes(x = date,y = hrs.foraging)) +

        geom_line()+

        geom_vline(aes(xintercept = as.numeric(frontdates)))

#this returns an error: Error in data.frame(xintercept = c(15591, 15596, 15611, 15619, 15623,  : 

#  arguments imply differing number of rows: 9, 74

#Try it brute force by entering the dates directly:

ggplot (data = fewest2, aes(x = date,y = hrs.foraging)) +

        geom_line()+

geom_vline(aes(xintercept = as.numeric("2012-09-08","2012-09-13","2012-09-28","2012-10-06","2012-10-10","2012-10-14","2012-10-17","2012-10-25","2012-11-04")

                   ))  

#now I get a plot, but some warning messages and no vlines:

#Warning messages:

#1: In eval(expr, envir, enclos) : NAs introduced by coercion

#2: Removed 1 rows containing missing values (geom_segment). 


Hopefully someone can point out what I'm doing wrong, and how to make this work.  I have the attributes included in the ggplot command because I intend for this to work with facets, but I could move them if that would make the difference.

Thanks,

Jennifer

Dennis Murphy

unread,
Feb 6, 2013, 9:12:56 PM2/6/13
to Jennifer Krauel, ggp...@googlegroups.com
Hi:

Try this:

# Need to pass data frames into ggplot()...
front <- data.frame(fdates = frontdates)

ggplot (data = fewest2, aes(x = date,y = hrs.foraging)) +
geom_line(size = 1, color = "firebrick") +
geom_vline(data = front, aes(xintercept = as.numeric(fdates)),
color = "blue")

Thanks for the reproducible example, BTW...

Dennis
> --
> --
> You received this message because you are subscribed to the ggplot2 mailing
> list.
> Please provide a reproducible example:
> https://github.com/hadley/devtools/wiki/Reproducibility
>
> To post: email ggp...@googlegroups.com
> To unsubscribe: email ggplot2+u...@googlegroups.com
> More options: http://groups.google.com/group/ggplot2
>
> ---
> You received this message because you are subscribed to the Google Groups
> "ggplot2" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to ggplot2+u...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>

Allan Just

unread,
Feb 7, 2013, 10:30:29 AM2/7/13
to ggp...@googlegroups.com, Jennifer Krauel
Thanks Dennis,
That works! I couldn't find anywhere that explained that geom_vline xintercept values should be coerced to numeric for date scales. Is there a place to suggest additional examples for the documentation? For example here: http://docs.ggplot2.org/current/geom_vline.html
-Allan

Dennis Murphy

unread,
Feb 7, 2013, 2:03:26 PM2/7/13
to Allan Just, ggp...@googlegroups.com, Jennifer Krauel
Hi:

On Thu, Feb 7, 2013 at 7:30 AM, Allan Just <Alla...@gmail.com> wrote:
> Thanks Dennis,
> That works! I couldn't find anywhere that explained that geom_vline
> xintercept values should be coerced to numeric for date scales. Is there a
> place to suggest additional examples for the documentation? For example
> here: http://docs.ggplot2.org/current/geom_vline.html

I would have thought that if the data frame used for geom_vline() had
a variable of class Date to pass to xintercept, and the plot code
contained a call to scale_x_date(), things would be copacetic, but
that is apparently not the case:

front <- as.data.frame(frontdates)
names(front) <- "date"

> str(front)
'data.frame': 9 obs. of 1 variable:
$ date: Date, format: "2012-09-08" "2012-09-13" ...
> str(fewest2)
'data.frame': 74 obs. of 3 variables:
$ date : Date, format: "2012-08-28" "2012-08-29" ...
$ ncep.front : int 0 0 0 0 0 0 0 0 0 0 ...
$ hrs.foraging: num 11.1 11.4 10.9 10.6 11.4 ...

I set it up so that the x and xintercept aesthetics had the same name
and same class in both data frames.

# Doesn't work:
> ggplot(data = fewest2, aes(x = date,y = hrs.foraging)) +
+ geom_line(aes(group = 1), size = 1, color = "firebrick") +
+ geom_vline(data = front, aes(xintercept = date,
+ color = "blue")) +
+ scale_x_date()
Error: Discrete value supplied to continuous scale

# Works:
> ggplot(data = fewest2, aes(x = date,y = hrs.foraging)) +
+ geom_line(aes(group = 1), size = 1, color = "firebrick") +
+ geom_vline(data = front, aes(xintercept = as.numeric(date)),
+ color = "blue") +
+ scale_x_date()

Maybe the scale training process doesn't check that the xintercept
variable has the same class as the x aesthetic in the base layer...I
don't know offhand. You or Jennifer could always raise this as an
issue at https://github.com/hadley/ggplot2/issues (look for the button
"New Issue" towards the upper right corner) or make a comment in the
documentation feedback at http://docs.ggplot2.org/current/

Dennis

Allan Just

unread,
Feb 9, 2013, 11:38:23 AM2/9/13
to ggp...@googlegroups.com, Allan Just, Jennifer Krauel
Looks like this has been previously logged as an issue:
geom_vline should work with non-numeric scales (e.g. date and character)
https://github.com/hadley/ggplot2/issues/84

Jennifer Krauel

unread,
Feb 14, 2013, 11:44:27 AM2/14/13
to ggp...@googlegroups.com
I just wanted to say that Dennis' suggestion worked really well and I'm now able to plot vertical lines on all kinds of plots, faceted or not, using either actual date (coerced) or julian date.  I made a separate data object with a data frame containing the dates of interest from each year that I load, and stick the same geom_vline code in my plots and it works like a charm.  Since it goes on pretty much every one of my plots, this is a huge win.  Thanks so much for your help.
Jennifer
Reply all
Reply to author
Forward
0 new messages