1

When I run the following code (source : embed image: ggplot to plotly date issue):

library(ggplot2)
library(png)
library(RCurl)
library(plotly)
mydf <- data.frame(date = 
                   as.Date(c("01/01/1998", "10/01/1998", "15/01/1998", 
                             "25/01/1998", "01/02/1998", "12/02/1998", "20/02/1998"), "%d/%m/%Y"),
                 counts = c(12, 10, 2, 24, 15, 1, 14),
                 image = c(NA, "https://www.r-project.org/logo/Rlogo.png", NA, NA, 
                           "https://www.r-project.org/logo/Rlogo.png", NA, NA))
mydf

# You should find some way to compute your desired image height and image width
yHeight <- (max(mydf$counts) - min(mydf$counts)) * 0.05
xWidth <- (max(as.numeric(mydf$date)) - min(as.numeric(mydf$date))) * 0.05

# create the base plot
gg2 <- ggplot(mydf, aes(date, counts)) + 
  geom_line()

# for each row in the df
for (x in 1:nrow(mydf)) {
  row <- mydf[x, ]
  if(!is.na(row$image)){
    # read the image
    img <- readPNG(getURLContent(row$image))
    # add the image with annotation_raster
    gg2 <- gg2 + annotation_raster(img, 
                            xmin = as.numeric(row$date) - xWidth/2, 
                            xmax = as.numeric(row$date) + xWidth/2, 
                            ymin = row$counts - yHeight/2, 
                            ymax = row$counts + yHeight/2)
  }
}

ggplotly(gg2)

I have this error message:

Error in if (RasterGeom/length(geoms) > 0.5) "above" else "below" : 
  the condition has length > 1

(I cannot comment on an answer so I'm making a new question)

Thanks a lot

Juliette
  • 71
  • 5

1 Answers1

1

I couldn't find a way to resolve this problem, so I came up with a new solution to your original problem. There are two different ways to go about this, either with ggplot() and ggplotly() or just with plotly().

This doesn't use the packages png or RCurl. It does use the package magick, though.

First I changed the dates to POSIXct in your dataframe, so they work better with Plotly (which is to say so they work with Javascript). I only used the first part of your original graph, as well.

library(tidyverse)
library(plotly)
library(magick)

mydf$date <- as.POSIXct(mydf$date)

# create the base plot
gg2 <- ggplot(mydf, aes(date, counts)) + 
  geom_line()

Then I set up the image traces for the ggplotly object. First I wrote a function to find the number of days between dates, then I created the data formatted for Plotly.

# for the x domain; difference in days + 1
dt = function(d1 = min(mydf$date), d2){
  x = length(seq(d1, d2, by = "day"))
  return(x)
}
mdf = mydf %>%        # image rows only
  filter(!is.na(mydf$image))

ig = lapply(1:nrow(mdf),
            function(i){
              # get and setup image
              img = image_read(mdf[i,]$image) %>% as.raster()
              # get domain splitter for the x-axis (whole weeks)
              ds = ceiling(dt(d2 = max(mydf$date))/7) * 7
              # get position of current date on the x-axis
              cs = dt(d2 = mdf[i, ]$date) + 2
              list(source = raster2uri(img),
                   xref = "paper", yref = "y",
                   xanchor = "center", yanchor = "middle",
                   x = 1/ds * cs,
                   y = mdf[i, ]$counts,
                   sizex = 1.5, sizey = 1.5)
            })

You can add this list of lists to the ggplotly object now.

ggplotly(gg2) %>% 
  layout(images = ig)

enter image description here

Alternatively, you could use Plotly directly.

plot_ly(data = mydf, x = ~date, y = ~counts, 
        mode = "lines+markers", type = "scatter") %>% 
  layout(images = ig)

enter image description here

Or if you don't want the markers (along with the line) in Plotly...

ig2 = lapply(1:nrow(mdf),
            function(i){
              # get and setup image
              img = image_read(mdf[i,]$image) %>% as.raster()
              # get domain splitter
              ds = dt(d2 = max(mydf$date)) - 1 # exact fit
              # get position of current date on the x-axis
              cs = dt(d2 = mdf[i, ]$date) - 1  # exact fit
              list(source = raster2uri(img),
                   xref = "paper", yref = "y",
                   xanchor = "center", yanchor = "middle",
                   x = 1/ds * cs,
                   y = mdf[i, ]$counts,
                   sizex = 1.5, sizey = 1.5)
            })
plot_ly(data = mydf, x = ~date, y = ~counts, 
        mode = "lines", type = "scatter") %>% 
  layout(images = ig2)

enter image description here

Kat
  • 15,669
  • 3
  • 18
  • 51