Search code examples
rplotlylegend

How to customize the legend order for a 3D scatter plot?


I'm trying to generate a 3D scatter plot and the shapes of markers correspond to 'Treatment' (IC, IT, YS), whilst, the colors correspond to 'Time' (0, 2, 4, 6, 12, 24, 48, 72). Everything went well except the legend order was like: automatically generated legend order

enter image description here

This order would be confusing and I wand it to go in the order from 0 to 72. I guess this automatically generated legend order was caused as Time was converted from numeric to factor. However, I failed to find a good way to set the order manually. Could anyone help?

And here is my code:

# PCA Plot - 3D
pca_data_3D <- data.frame(Sample = rownames(pca$x),
                          PC1 = pca$x[,1],
                          PC2 = pca$x[,2],
                          PC3 = pca$x[,3],
                          Treatment = pca_data_2D$Treatment,   # already converted to factor
                          Time = pca_data_2D$Time)             # already converted to factor

treatment_groups <- c("YS" = "square", "IT" = "cross", "IC" = "circle")
time_groups <- c("0" = "#BC3C29", "2" = "#0072B5", "4" = "#E18727", "6" = "#20854E", 
                 "12" = "#7876B1", "24" = "#6F99AD", "48" = "#FFDC91", "72" = "#EE4C97")

hover_info <- pca_data_3D$Sample

pca_data_3D %>%
  plot_ly(
    type = "scatter3d", mode = "markers",
    x = ~PC1, y = ~PC2, z = ~PC3,
    symbol = ~Treatment, symbols = treatment_groups, 
    color = ~Time, colors = time_groups,
    hovertext = ~hover_info
  ) %>%
  layout(
    title = "PCA Graph PC1,2,3"
  )

I've tried to set legendgroup = ~Time and traceorder = "normal"/"grouped" (separately), but it didn't seem to work. Yet I'm not sure if I did these in the right way.


Solution

  • Next time, please give a reprodcible example.

    The legend orders are set alphabetically. So, a way to set the legend order correctly is just put a zero in front of variable "time".

    # Number of samples
    num_samples <- 100
    
    # Generating PC values
    pc1 <- rnorm(num_samples, mean = 0, sd = 1)
    pc2 <- rnorm(num_samples, mean = 0, sd = 1)
    pc3 <- rnorm(num_samples, mean = 0, sd = 1)
    
    # Generating treatment and time information
    treatment <- sample(c("YS", "IT", "IC"), num_samples, replace = TRUE)
    time <- sample(c("00", "02", "04", "06", "12", "24", "48", "72"), num_samples, replace = TRUE)
    
    # Combining into a data frame
    pca_data_3D <- data.frame(
      Sample = paste0("Sample", 1:num_samples),
      PC1 = pc1,
      PC2 = pc2,
      PC3 = pc3,
      Treatment = as.factor(treatment),
      Time = as.factor(time)
    )
    
    # Checking the first few rows of the dataset
    head(pca_data_3D)
    
    treatment_groups <- c("YS" = "square", "IT" = "cross", "IC" = "circle")
    time_groups <- c("00" = "#BC3C29", "02" = "#0072B5", "04" = "#E18727", "06" = "#20854E", 
                     "12" = "#7876B1", "24" = "#6F99AD", "48" = "#FFDC91", "72" = "#EE4C97")
    #time_groups <- factor(time_groups, levels = names(time_groups))
    hover_info <- pca_data_3D$Sample
    
    pca_data_3D %>%
      plot_ly(
        type = "scatter3d", mode = "markers",
        x = ~PC1, y = ~PC2, z = ~PC3,
        symbol = ~Treatment, symbols = treatment_groups, 
        color = ~Time, colors = time_groups,
        hovertext = ~hover_info
      ) %>%
      layout(
        title = "PCA Graph PC1,2,3"
      )
    
    

    enter image description here