Scatterplot over time with traces conneting each dot

Hello everyone,

I am trying to create a scatter plot with some custom specifications. I want the x and y axis to present log10 intensities. Each dot is supposed represent one sample. Each frame is supposed to present a measure point.

I want to see how the dots move in the 2D space over different measure points. Also, I want lines to be drawn when the dots move, which allow to track the entire sequence of the dots moving around over all measure points.

This is how far I got:

library(tidyverse)
library(ggplot2)
library(plotly)

id <- c("drill_1", "drill_2", "drill_3", "drill_1", "drill_2", "drill_2", "drill_3", "drill_2", "drill_3", "drill_2", "drill_2", "drill_1", "drill_2", "drill_3", "drill_1", "drill_3")
signal_1 <- c(6663, 5914, 8471, 7474, 5509, 6206, 17174, 4876, 15243, 5256, 5405, 7094, 5166, 12709, 6838, 12597)
signal_2 <- c(3589, 3733, 5597, 4374, 4000, 4083, 7671, 3864, 6438, 3868, 3817, 4583, 3853, 5033, 4427, 5219)
measure.point <- c(0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 5, 6, 6, 6, 8, 8)

df <- data.frame(ID = id,
                 signal_1 = signal_1,
                 signal_2 = signal_2,
                 measure.point = measure.point)

df %>%
  
  plot_ly(
    x = ~log10(signal_1),
    y = ~log10(signal_2),
    color = ~ID,
    frame = ~measure.point,
    text = ~ID,
    hoverinfo = "text",
    type = 'scatter',
    mode = 'markers+text'
  ) %>% 
  
  layout(
  xaxis = list(
    type = "log"
  )
  
)

Oddly, the dots change their color while they are moving. And for hours I do not get these “traces” of each dot projected into the plot.

Maybe you have an idea to solve this problem.

Thanks a lot!

You get colour switch behaviour because your ID's dont all exist across all frames/measure points, so plotly gets confused about continuity I guess.
This can be solved by putting every id in every frame.

library(tidyverse)
library(ggplot2)
library(plotly)

id <- c("drill_1", "drill_2", "drill_3", "drill_1", "drill_2", "drill_2", "drill_3", "drill_2", "drill_3", "drill_2", "drill_2", "drill_1", "drill_2", "drill_3", "drill_1", "drill_3")
signal_1 <- c(6663, 5914, 8471, 7474, 5509, 6206, 17174, 4876, 15243, 5256, 5405, 7094, 5166, 12709, 6838, 12597)
signal_2 <- c(3589, 3733, 5597, 4374, 4000, 4083, 7671, 3864, 6438, 3868, 3817, 4583, 3853, 5033, 4427, 5219)
measure.point <- c(0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 5, 6, 6, 6, 8, 8)

df <- data.frame(ID = id,
                 signal_1 = signal_1,
                 signal_2 = signal_2,
                 measure.point = measure.point)

# http://www.cookbook-r.com/Manipulating_data/Filling_in_NAs_with_last_non-NA_value/
fillNAgaps <- function(x, firstBack=FALSE) {
  ## NA's in a vector or factor are replaced with last non-NA values
  ## If firstBack is TRUE, it will fill in leading NA's with the first
  ## non-NA value. If FALSE, it will not change leading NA's.
  
  # If it's a factor, store the level labels and convert to integer
  lvls <- NULL
  if (is.factor(x)) {
    lvls <- levels(x)
    x    <- as.integer(x)
  }
  
  goodIdx <- !is.na(x)
  
  # These are the non-NA values from x only
  # Add a leading NA or take the first good value, depending on firstBack   
  if (firstBack)   goodVals <- c(x[goodIdx][1], x[goodIdx])
  else             goodVals <- c(NA,            x[goodIdx])
  
  # Fill the indices of the output vector with the indices pulled from
  # these offsets of goodVals. Add 1 to avoid indexing to zero.
  fillIdx <- cumsum(goodIdx)+1
  
  x <- goodVals[fillIdx]
  
  # If it was originally a factor, convert it back
  if (!is.null(lvls)) {
    x <- factor(x, levels=seq_along(lvls), labels=lvls)
  }
  
  x
}


df2 <- df %>% arrange(ID,measure.point) %>% 
  complete(ID,measure.point) %>%
  mutate(across(starts_with("signal"),~fillNAgaps(.x, firstBack = TRUE)))

df2 %>% 
  plot_ly(
    x = ~log10(signal_1),
    y = ~log10(signal_2),
    color = ~ID,
    frame = ~measure.point,
    text = ~ID,
    hoverinfo = "text",
    type = 'scatter',
    mode = 'markers+text'
  ) %>% 
  
  layout(
    xaxis = list(
      type = "log"
    )
    
  )