Search code examples
r3dplotlygroupingline-plot

How to do 3D line plots grouped by two factors with the Plotly package in R?


I have checked up the official webpage of Plotly, but how to plot the following task still escapes me:

id <- c(rep(1,5), rep(2,5), rep(3,5), rep(4,5))
t <- rep(seq(50,75,length.out=5), 4)
x <- runif(20) + sin(t) 
y <- rnorm(20) + cos(t)
gender <- c(rep("F",10), rep("M",10))
smoke <- c(rep("Y",5), rep("N",10), rep("Y",5))

DATA <- data.frame(ID, t, x, y, gender, smoke)

fig <- plot_ly(DATA, x = ~t, y = ~y, z = ~x, .......)

Suppose I have 4 groups of patients (grouped by 2 factors, Female/Male and Smokers/Non-smokers), each associated with 5 observations $(x_i, y_i)$ along the timestamps $t_i$. So I need to draw a 3D line plot $${(t_i, x_i, y_i)}_{i=1}^{i=5}$ for each patient, but all in one plotting canvas. If I want to represent genders by red/blue, smokers by solid and non-smokers by dash lines, and specify these in the legend, what should I do (ideally using R)?


Solution

  • The kind of 3D plot you have in mind can be achievd like so:

    library(plotly)
    
    id <- c(rep(1,5), rep(2,5), rep(3,5), rep(4,5))
    t <- rep(seq(50,75,length.out=5), 4)
    x <- runif(20) + sin(t) 
    y <- rnorm(20) + cos(t)
    gender <- c(rep("F",10), rep("M",10))
    smoke <- c(rep("Y",5), rep("N",10), rep("Y",5))
    
    DATA <- data.frame(id, t, x, y, gender, smoke)
    
    col_gender <- c(M = "red", F = "blue")
    lt_smoke <- c(Y = "solid", N = "dash")
    sym_id <- c(`1` = "circle", `2` = "square", `3` = "diamond", `4` = "cross")
    
    fig <- plot_ly(DATA, 
                   x = ~x, y = ~y, z = ~t, symbol = ~id, color = ~gender, linetype = ~smoke, type = 'scatter3d', mode = 'lines+markers',
                   line = list(width = 6),
                   marker = list(size = 3.5, cmin = -20, cmax = 50),
                   colors = col_gender,
                   linetypes = lt_smoke,
                   symbols = sym_id)
    fig
    

    Edit:

    In case of more patients the best option is to map id on color and additonally group by id using transform groupby

    library(plotly)
    
    id <- c(rep(1,5), rep(2,5), rep(3,5), rep(4,5), rep(5,5), rep(6,5), rep(7,5), rep(8,5))
    t <- rep(seq(50,75,length.out=5), 8)
    x <- runif(40) + sin(t) 
    y <- rnorm(40) + cos(t)
    gender <- c(rep("F",10), rep("M",10), rep("F",10), rep("M",10))
    smoke <- c(rep("Y",5), rep("N",10), rep("Y",5), rep("Y",5), rep("N",10), rep("Y",5))
    
    lt_smoke <- c(Y = "solid", N = "dash")
    sym_id <- c(M = "circle", F = "square")
    
    fig <- plot_ly(DATA, 
                   x = ~x, y = ~y, z = ~t, symbol = ~gender, color = ~id, linetype = ~smoke, type = 'scatter3d', mode = 'lines+markers',
                   line = list(width = 6),
                   marker = list(size = 3.5, cmin = -20, cmax = 50),
                   linetypes = lt_smoke,
                   symbols = sym_id,
                   transforms = list(
                     list(
                       type = 'groupby',
                       groups = ~id)
                   ))
    fig