R: plot 3d interaction model and observations using plotly - r

I start from a simple interaction model z = 0.5*x*y. The goal is to plot simulated observations with add_markers() as well as the model with add_surface() using the plotly library.
So far I have manage to simulate the data and plot it:
library(plotly)
library(magrittr)
x <- rnorm(10000)
y <- rnorm(10000)
z <- 0.5 * x * y
plot_ly() %>% add_markers(x = x, y = y, z = z, marker = list(size = 1))
This is what the plot looks like:
I then tried to surface plot the model:
plot_ly() %>%
add_markers(x = x, y = y, z = z, marker = list(size = 1)) %>%
add_surface(z = matrix(z, 100, 100))
But it produces something completely different to what it would be expected. This is approximately the result that would be expect from the surface plot:
What am I doing wrong?

An easy workaround is to use:
plot_ly(x = x, y = y, z= z, type = 'mesh3d')
Or using surface plot:
library(tidyverse)
grid <- expand.grid(x = seq(from = -3, to = 3, length.out = 100),
y = seq(from = -3, to = 3, length.out = 100))
grid %>%
mutate(z = 0.5 * x * y) %>%
spread(key = y, value = z) %>%
as.matrix() -> z
plot_ly() %>%
add_surface(z = z, x = unique(grid$x), y = unique(grid$y)) %>%
layout(scene = list(xaxis = list(range = c(-2.5, 2.5)),
yaxis = list(range = c(-2.5, 2.5)))) #odd artifact if all values are plotted - check without layout call
or:
model = lm(z ~ x * y)
grid <- expand.grid(x = seq(from = -3, to = 3, length.out = 100),
y = seq(from = -3, to = 3, length.out = 100))
grid$z = predict(model, grid)
and proceed as above
grid %>%
spread(key = y, value = z) %>%
as.matrix() -> z

Related

How can I plot a sphere with plotly in R?

I would like to plot a sphere in the following plot:
And that is the code for it:
library(plotly)
fig <- plot_ly(mtcars, x = ~wt, y = ~hp, z = ~qsec,
marker = list(color = ~mpg, colorscale = c('#FFE1A1', '#683531'), showscale = TRUE))
fig <- fig %>% add_markers()
fig <- fig %>% layout(scene = list(xaxis = list(title = 'Weight'),
yaxis = list(title = 'Gross horsepower'),
zaxis = list(title = '1/4 mile time')),
annotations = list(
x = 1.13,
y = 1.05,
text = 'Miles/(US) gallon',
xref = 'paper',
yref = 'paper',
showarrow = FALSE
)) %>% add_markers(x = 2.8, y = 120, z = 20, color="red", marker=list(size=30,
opacity = .65,
line=list(width=2,
color='black')))
fig
At the moment my best version only contains a 2D circle. How could I integrate a 3d/wireframe sphere into it using plotly R-version?
A sphere is an isosurface. You can plot an isosurface with plotly but it is a bit slow, I prefer to use the misc3d package.
library(plotly)
f <- function(x, y, z){
x^2 + y^2 + z^2
}
R <- 2 # radius
x <- y <- z <- seq(-R, R, length.out = 100)
g <- expand.grid(x = x, y = y, z = z)
voxel <- array(with(g, f(x, y, z)), dim = c(100, 100, 100))
library(misc3d)
cont <- computeContour3d(voxel, level = R^2, x = x, y = y, z = z)
idx <- matrix(0:(nrow(cont)-1), ncol=3, byrow=TRUE)
plot_ly(
x = cont[, 1], y = cont[, 2], z = cont[, 3],
i = idx[, 1], j = idx[, 2], k = idx[, 3],
type = "mesh3d"
) %>% layout(scene = list(aspectmode = "data"))

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)?
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

How fill a plot to a given y0 value

I'm using Plotly in R and I want to create a plot like this:
But when trying with fill = "tozeroy" the plot looks like this:
Ignoring the value of y0
So, I want to fill the area from the lines to y0 value, instead to absolute zero.
A code example:
library(plotly)
library(magrittr)
x <- seq.Date(as.Date("2017/01/01"), as.Date("2017/12/31"), by = 1)
y1 <- rnorm(365, 100, 10)
y2 <- rnorm(365, 100, 10)
dat <- data.frame(x, y1, y2)
plot_ly(dat, x = ~x, y = ~y1, mode = "lines", type = "scatter", fill = "tozeroy", y0 = 80, name = "y1") %>%
add_trace(dat, x = ~x, y = ~y2, fill = 'tozeroy', y0 = 80, name = "y2")%>%
layout(xaxis = list(title = ""), yaxis = list(title = ""))
produces:
Ignoring the y0 = 80 parameter.
If I understood correctly you want the range to begin in y0.
To that end, you have to change the yaxis' range in the layout.
This should suffice:
library(plotly)
library(magrittr)
set.seed(19)
x <- seq.Date(as.Date("2017/01/01"), as.Date("2017/12/31"), by = 1)
y1 <- rnorm(365, 100, 10)
y2 <- rnorm(365, 100, 10)
y0 <- 80
ymax <- max(y1,y2)
dat <- data.frame(x, y1, y2)
plot_ly(dat, x = ~x, y = ~y1, mode = "lines", type = "scatter", fill = "tozeroy", y0 = 80, name = "y1") %>%
add_trace(dat, x = ~x, y = ~y2, fill = 'tozeroy', name = "y2")%>%
layout(xaxis = list(title = ""), yaxis = list(range = c(y0, ymax),title = ""))
The range options in plotly are explained here

R: Plot_ly 3d graph with trace line

I am using plotly 4.7.0. I am trying to add a 3d line to a 3d plot_ly surface plot. When I don't add the add_lines() function inside of the plot_ly call it looks fine. As soon as I do add the add_lines, the graph gets all messed up and doesn't add the 3d line graph.
library(plotly)
m_x = seq(-2, 2, .01)
m_y = seq(-2, 2, .01)
df = expand.grid(m_x, m_y)
df['matrix'] = exp(-(df$Var1^2+df$Var2^2))
m_z = matrix(df$matrix, nrow = length(m_x), ncol = length(m_y))
m_df = list(m_x, m_y, m_z)
x1 = seq(-2, 0, by=0.0202)
y1 = runif(100, min=-0.03,max=0.03)
z1 = exp(-(x1^2+y1^2))
df = data.frame(x1, y2, z2)
names(df) <- c("df_x", "df_y", "df_z")
colors = c( "Blue", "Cyan", "Green", "Yellow", "Orange", "Red")
p1 <- plot_ly(x = m_df[[1]], y = m_df[[2]], z = m_df[[3]],
colors = colors, color = m_df[[3]]) %>% add_surface() %>%
add_lines(x = df$df_x, y = df$df_y, z = df$df_z, data = df,
line = list(color = 'red', width = 1)) %>%
layout(title = "Hike_Example",
scene = list(aspectratio = list(x = 4, y = 4, z = 1)))
p1
Here is the code of the surface plot with the 3D line.
I plotted the 3D line using add_trace in place of add_lines.
library(plotly)
m_x = seq(-2, 2, .01)
m_y = seq(-2, 2, .01)
df = expand.grid(m_x, m_y)
df['matrix'] = exp(-(df$Var1^2+df$Var2^2))
m_z = matrix(df$matrix, nrow = length(m_x), ncol = length(m_y))
m_df = list(m_x, m_y, m_z)
x1 = seq(-2, 0, by=0.0202)
y1 = runif(100, min=-0.03,max=0.03)
z1 = exp(-(x1^2+y1^2))
df = data.frame(x1, y1, z1)
names(df) <- c("df_x", "df_y", "df_z")
colors = c( "Blue", "Cyan", "Green", "Yellow", "Orange", "Red")
p1 <- plot_ly(x = m_df[[1]], y = m_df[[2]], z = m_df[[3]],
colors = colors, color = m_df[[3]]) %>% add_surface() %>%
add_trace(x = ~df_x, y = ~df_y, z = ~df_z, data = df,
type="scatter3d", mode="lines",
line = list(color = "red", width = 4)) %>%
layout(title = "Hike_Example",
scene = list(aspectratio = list(x = 4, y = 4, z = 1)))
p1

how to plot lines in 3d graph in R

I have these two 3d graphs made in R, with two different functions:
x <- c(0,50,100,150,200,250,300,350,400,450)
y <- c(0,50,100,150,200,250,300,350,400,450)
z <- c(1,2,1,1,2,1,2,1,2,1)
plot_ly(x=x,y=y,z=z)
scatterplot3d(x, y, z)
I would like to plot in these two graphs, the following lines and the intersection area between them:
Lines plotted in both graphs
As per the lines and intersection with plotly, something like this will do:
library(scatterplot3d)
library(plotly)
x <- c(0,50,100,150,200,250,300,350,400,450)
y <- c(0,50,100,150,200,250,300,350,400,450)
z <- c(1,2,1,1,2,1,2,1,2,1)
data <- data.frame(x=x,y=y,z=z)
line <- data.frame(x = rep(200,5), y = seq(0,500,length.out = 5), z = rep(1,5))
line2 <- data.frame(x = rep(300,5), y = seq(0,500,length.out = 5), z = rep(1,5))
rect <- data.frame(expand.grid(x= c(200,300), y =c(200,300)),z = rep(1,4) )
plot_ly() %>%
add_trace(data=data, x=x, y=y, z=z, type="scatter3d", mode="markers") %>%
add_trace(line, x = line$x, y = line$y, z = line$z, type = 'scatter3d', mode = 'lines', line = list(color = 'rgb(1, 1, 1)', width = 1 , dash = 'dash', width = 4)) %>%
add_trace(line2, x = line2$x, y = line2$y, z = line2$z, type = 'scatter3d', mode = 'lines', line = list(color = 'rgb(1, 1, 1)', width = 1, dash = 'dash', width = 4)) %>%
add_trace(line, x = line$y, y = line$x, z = line$z, type = 'scatter3d', mode = 'lines', line = list(color = 'rgb(1, 1, 1)', width = 1 , dash = 'dash', width = 4)) %>%
add_trace(line2, x = line2$y, y = line2$x, z = line2$z, type = 'scatter3d', mode = 'lines', line = list(color = 'rgb(1, 1, 1)', width = 1, dash = 'dash', width = 4))%>%
add_trace(rect, x=rect$x, y=rect$y, z=rect$z, type="mesh3d" )
Result with plotly:

Resources