Hi all,
I produced a graph using geom_smooth() function and I want to identify the point that there is a change in trend from upwards to downwards. Does someone has an idea how this happens?
Many thanks in advance.
Panos
I don't think geom_smooth() can give you that directly. Under the hood, geom_smooth() is actually using a type of loess() smoothing, so you could use that directly:
library(tidyverse)
dat <- tibble(x = 1:100,
y = ifelse(x<50, 2*x, -2*x + 200) + rnorm(100, sd = 10))
ggplot(dat, aes(x, y)) +
geom_point() +
geom_smooth()
#> `geom_smooth()` using method = 'loess' and formula = 'y ~ x'
mod <- loess(y ~ x, data = dat)
predict(mod, 1:100) |>
diff() |>
sign() |>
diff()
#> [1] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
#> [26] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -2 0 0
#> [51] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
#> [76] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Created on 2023-06-19 with reprex v2.0.2
But for more advanced methods, I suggest you look up "R time series changepoint detection", there is a lot of resources that exist!
Thanks Alex! However still I cannot find the point where the trend is changing
Of the steps to follow that Alex laid out, which one trips you up ?
What Alex suggested leads to a graph with a smooth_line. However I want (say in his graph) to see the coordinates where the smooth_line changes inclination (from upwards to dowanwards)
Alex's example went as far as to detect the difference in sign as x is traversed. we can find the location by adding a little more
predict(mod, 1:100) |>
diff() |>
sign() |>
diff() |> which.min()
this gives me '49'
the 49th position of 1:100 is itself '49'
Here's a further example adapted from Alex, where the correspondence with x is less obvious, but still retreivable.
library(tidyverse)
dat <- tibble(x = 25:60,
y = ifelse(x<50, 2*x, -2*x + 200) + rnorm(36, sd = 10))
ggplot(dat, aes(x, y)) +
geom_point() +
geom_smooth()
#> `geom_smooth()` using method = 'loess' and formula = 'y ~ x'
mod <- loess(y ~ x, data = dat)
predict(mod, 25:60) |>
diff() |>
sign() |>
diff() |> which.min()
#24
(25:60)[24]
# x=48
in this example x is from 25:60 , the point of sign change is the 24th entry of x, which is the value x=48
I suppose your question may be simply how to annotate a chart ?
+ geom_vline(xintercept = 48)
will add a vertical line at the x value you choose
My question includes how to annotate the chart but I don't want all points to be shown. Moreover, how do you know that xintercept=48? It makes sense after the piece of work that you added.
Many thanks for your help!