0

I have a multi-line chart created using ggplot2 with autoplot and plotly in R code. I would like to add a single point on each line on the chart. The data frame I am plotting is of class xts. In the toy example below, I would like to add a point at 2019-12-22 on the "aa" line (red) and at 2019-12-24 on the "bb" line (blue). The dates for the points are in a named vector, 'my_points'. How do I do this??

library("xts")
library("ggplot2")
library("plotly")

my_dates <- as.Date(18250:18256)
## My points are in a named vector ...
my_points <- c(my_dates[3], my_dates[5])
names(my_points) <- c("aa", "bb")

## The toy data for the example created as an xts object
my_df <- data.frame(aa = c(14,12,23,14,15,26,17),
                    bb = c(14.2, 16.0, 12.3, 13.8, 10.1, 9.6, 8.9))
my_xts <- xts(my_df, order.by = my_dates)

## Plotted using autoplot and plotly to make it interactive
p <- autoplot(my_xts, facets = NULL)
pl <- ggplotly(p)
print(pl)
Ernie
  • 1,103
  • 1
  • 14
  • 25

2 Answers2

2

Perhaps a better and more general way would have been to melt the data into the long format. There may be better ways, but this is a flexible approach that allows for many data points and numerous curves, just as the "real" problem has.

## Prepare some data ... 2 straightline plots
a <- c(14,12,23,14,15,26,17)
b <- c(14.2, 16.0, 12.3, 13.8, 10.1, 9.6, 8.9)
my_dates <- as.Date(18250:18256)
my_df <- data.frame(aa = a,
                    bb = b)
my_df1 <- as.data.frame(cbind(my_dates, my_df))
## Construct a small df for points to be plotted
plot_df2 <- data.frame(my_dates = c(my_dates[3], my_dates[5]),
                       variable = c("pp", "pp"),
                       value = c(a[3], b[5]))

## Melt the data into the long form 
plot_df1 <- melt(my_df1, id.vars = "my_dates")

## Add the point information to the plot df
plot_df1 <- rbind(plot_df1, plot_df2)

p <- ggplot(data =  subset(plot_df1, variable == c("aa", "bb")),
             aes(x = my_dates, y = value,
             color = variable, group = variable)) +
    geom_line() +
    geom_point(data = subset(plot_df1, variable == "pp"),
  aes(x = my_dates, y = value), size = 2, color = "black")

pl <- ggplotly(p)
print(pl)
Ernie
  • 1,103
  • 1
  • 14
  • 25
1

While I would not recommend overloading the convenience functions offered by autoplot and xts you can get it done as follows:

my_xts_points_aa = my_xts[my_points[1],]
my_xts_points_bb = my_xts[my_points[2],]

p <- autoplot(my_xts, facets = NULL) + 
  geom_point(data=my_xts_points_aa,aes(y=aa)) +
  geom_point(data=my_xts_points_bb,aes(y=bb))
p

My personal reservation with this solution is that it feels a little hacky/manual because of the way your data is organized in wide format (aa and bb column instead of a value column with key aa or bb). Yet, autoplot on the xts object handles this automatically and silently introduces a Series categorical variable. Still, I hope this helps - potentially there is a direct way using the autoplot-xts facilities..

CMichael
  • 1,856
  • 16
  • 20
  • Thank you. I'm not wedded to autopiot and I think you are saying reorganize the data and add the point data with its own key. I can experiment with that as well. – Ernie May 16 '20 at 20:34