I am somewhat new to plotly and I am trying to make an before-after dot plot in which you can switch variables by dropdown menu. I actually achieved this, but I want to have a color legend feature that categorizes the direction of the before-after differences into "Before > After", "Before < After" etc. In the example I named this variable dir_y. The updatemenus updates the variables (in my example y and z) but I dont know how to update dir_y and dir_z while maintaining only the 2 dropdown options ("Var y" and "Var z"). Needless to say, I need to update dir_y and dir_z in oder to select only one category ("Before > After", "Before < After" etc) from the legend and that category needs to correspond to either y or z depending on which one is selected from the dropdown. I added 2 comments where I thought dir_y and dir_z updating should go, but nothing I tried worked.

Thank you. Any help is greatly appreciated.

Here is my code:

library(plotly)
library(tidyverse)

set.seed(81)
df <- data.frame(id = rep(1:100, 2),
                 x = c(rep("pre", 100), rep("post", 100)), 
                 y = runif(200), 
                 z = rnorm(200, mean = 50, sd = 10))
df <- df[-sample(1:nrow(df), size = 20) , ]                               # delete some rows at random to simulate missing values


df_plotly <- 
  df %>%
  mutate(x = forcats::fct_relevel(x, "pre", "post")) %>%                  # relevel Pre Post for plot
  mutate(jit_x = jitter(as.numeric(x))) %>%                               # add jitter to x discrete var before piping to plotly
  mutate(y = round(y, 2),
         z = round(z, 2)) %>%                                             # round y & z
  group_by(id) %>%                                                        # group by id
  mutate(dif_y = coalesce(lag(y) - y, y - lead(y)),                       # do Pre - Post by id for y
         dif_z = coalesce(lag(z) - z, z - lead(z))) %>%                   # do Pre - Post by id for z
  mutate(dir_y = case_when(dif_y != 0 && dif_y > 0 ~ "Pre > Post",
                           dif_y != 0 && dif_y < 0 ~ "Pre < Post",
                           dif_y == 0              ~ "Pre = Post",
                           TRUE                    ~ "Unpaired"),
         dir_z = case_when(dif_z != 0 && dif_z > 0 ~ "Pre > Post",
                           dif_z != 0 && dif_z < 0 ~ "Pre < Post",
                           dif_z == 0              ~ "Pre = Post",
                           TRUE                    ~ "Unpaired"))



p1 <-
  df_plotly %>%
  plot_ly(x = ~jit_x, y = ~y) %>%  
  add_trace(x = ~jit_x, y = ~y, color = ~dir_y, colors = c("red", "lightgrey", "green", "black"), 
            mode = 'markers+lines', type = 'scatter', hoverinfo = 'text+y',   
            text = ~paste("ID: ", id, "<br>") 
            ) %>% 
  layout(
    title = "",
    xaxis = list(title = "",
                 tickvals = list(1, 2),                       # jitter(1:2) from 2 levels factor produces values around 1 & 2, should be fine
                 ticktext = list("Pre", "Post") ),
    yaxis = list(title = "",
                 hoverformat = '.2f',            
                 zeroline = F),
    updatemenus = list(
      list(
        buttons = list(
          list(method = "restyle",
               args = list("y", list(df_plotly$y)  # , "dir_y", list(df_plotly$dir_y)
                           ),  
               label = "Var Y"),
          list(method = "restyle",
               args = list("y", list(df_plotly$z)  # ,  "dir_y", list(df_plotly$dir_z)
                           ),  
               label = "Var Z")))
    ))
p1

enter image description here

0 Answers