0

Let's say I have a saved plot named my_plot, produced with ggplot. Also, let's say that the column in my_plot[[1]] data frame used for horizontal axis is named my_dates

Now, I want to add some vertical lines to the plot, which, of course, can be done by something like that:

my_plot + 
    geom_vline(aes(xintercept = my_dates[c(3, 8)]))

Since I perform this task quite on a regular basis, I want to write a function for that -- something like that:

ggplot.add_lines <- function(given_plot, given_points) {
    finale <- given_plot + 
        geom_vline(aes(xintercept = given_plot[[1]]$my_dates[given_points]))
    return(finale)
}

Which, as it's probably obvious to everyone, doesn't work:

> ggplot.add_lines(my_plot, c(3, 5))
Error in eval(expr, envir, enclos) : object 'given_plot' not found

So, my question would be what am I doing wrong, and how can it be fixed? Below is some data for a reproducible example:

> dput(my_plot)
structure(list(data = structure(list(my_dates = c(1, 2, 3, 4, 
5, 6, 7, 8, 9, 10), my_points = c(-2.20176409422924, -1.12872396340683, 
-0.259703895194354, 0.634233385649338, -0.678983982973015, -1.83157126614836, 
1.33360095418957, -0.120455389285709, -0.969431974863616, -1.20451262626184
)), .Names = c("my_dates", "my_points"), row.names = c(NA, -10L
), class = "data.frame"), layers = list(<environment>), scales = <S4 object of class structure("Scales", package = "ggplot2")>, 
mapping = structure(list(x = my_dates, y = my_points), .Names = c("x", 
"y"), class = "uneval"), theme = list(), coordinates = structure(list(
    limits = structure(list(x = NULL, y = NULL), .Names = c("x", 
    "y"))), .Names = "limits", class = c("cartesian", "coord"
)), facet = structure(list(shrink = TRUE), .Names = "shrink", class = c("null", 
"facet")), plot_env = <environment>, labels = structure(list(
    x = "my_dates", y = "my_points"), .Names = c("x", "y"
))), .Names = c("data", "layers", "scales", "mapping", "theme", 
"coordinates", "facet", "plot_env", "labels"), class = c("gg", 
"ggplot"))
A S
  • 1,195
  • 2
  • 12
  • 26

2 Answers2

2

According to this post, below is my solution to this problem. The environment issue in the **ply and ggplot is annoying.

ggplot.add_lines <- function(given_plot, given_points) {
    finale <- eval(substitute( expr = {given_plot + 
        geom_vline(aes(xintercept = my_dates[given_points]))}, env = list(given_points = given_points)))
    return(finale)
}

The following code runs well on my machine. (I cannot make your reproducible work on my machine...)

df <- data.frame(my_dates = 1:10, val = 1:10)
my_plot <- ggplot(df, aes(x = my_dates, y = val)) + geom_line()
my_plot <- ggplot.add_lines(my_plot, c(3, 5))
print(my_plot)

Update: The above solution fails when more than two points are used.

It seems that we can easily solve this problem by not including the aes (subsetting together with aescauses problems):

ggplot.add_lines <- function(given_plot, given_points) {        
    finale <- given_plot + geom_vline(xintercept = given_plot[[1]]$my_dates[given_points])
    return(finale)
}

enter image description here

Community
  • 1
  • 1
Ping Jin
  • 520
  • 4
  • 8
  • thank you for your help and interest. But do you know, why does it throws an error if more than two points are used, like `c(3, 5, 7)`: `Error in data.frame(xintercept = c(3L, 5L, 6L), PANEL = c(1L, 1L, 1L, : arguments imply differing number of rows: 3, 10` – A S Aug 21 '15 at 19:04
  • 1
    I am not quite certain about the problem of the first answer, but your provided code `my_plot + + geom_vline(aes(xintercept = my_dates[c(3, 7,8)]))` does not work either for more than three points... The problem may be due to using subsetting in `aes()`. – Ping Jin Aug 22 '15 at 02:13
1

I would take the following approach: extract the data.frame of interest, and pass it to the new layer,

df <- data.frame(my_dates = 1:10, val = rnorm(10))
my_plot <- ggplot(df, aes(x = my_dates, y = val)) + geom_line()

add_lines <- function(p, given_points=c(3,5), ...){
  d <- p[["data"]][given_points,]
  p + geom_vline(data = d, aes_string(xintercept="my_dates"), ...)
}

add_lines(my_plot, c(3,5), lty=2)

enter image description here

baptiste
  • 75,767
  • 19
  • 198
  • 294