combining plot3D , plotly and ggplot visualization - r

Can we combine multiple type of 3d visuals.
I want to combine
3d scatterplot using plot3d package
3d scatterplot using plotly package
3d scatterplot using ggplot package
library(plotly)
mtcars$am[which(mtcars$am == 0)] <- 'Automatic'
mtcars$am[which(mtcars$am == 1)] <- 'Manual'
mtcars$am <- as.factor(mtcars$am)
pltly <- plot_ly(mtcars, x = ~wt, y = ~hp, z = ~qsec, color = ~am, colors = c('#BF382A', '#0C4B8E'))
pltly <- pltly %>% add_markers()
pltly <- pltly %>% layout(scene = list(xaxis = list(title = 'Weight'),
yaxis = list(title = 'Gross horsepower'),
zaxis = list(title = '1/4 mile time')))
pltly
x <- sep.l <- iris$Sepal.Length
y <- pet.l <- iris$Petal.Length
z <- sep.w <- iris$Sepal.Width
s3d <-scatter3D(x, y, z, clab = c("Sepal", "Width (cm)"))
gg <- ggplot(mtcars, aes(x = mpg, y = drat)) +
geom_point(aes(color = factor(gear)))
#I want to combine all 3.
All three can be rendered individually but fails when combined.
Any help/direction will be appreciated.

Related

boxplot annotation to outliers using r plotly

Using the iris dataset below how do I get the ID of the flower on hover of the outliers
library(plotly)?
I've tried something like:
iris_ids <- iris %>%
mutate(id = rownames(iris))
plot_ly(iris, y = ~Sepal.Length, x= ~Species, type = 'box') %>%
layout(title = 'Box Plot',
xaxis = list(title = "cond", showgrid = F),
yaxis = list(title = "rating"),
annotations = list(
x = boxplot.stats(Species)$out,
# use boxplot.stats() to get the outlier's y coordinate
y = boxplot.stats(Sepal.Length)$out,
# I want the ID of the flower
# of the outliers
text = c("ID:", id),
showarrow = FALSE,
xanchor = "right"
)
) %>%
config(displayModeBar = FALSE)
And also tried using the ggplotly wrapper:
ggplotly(
ggplot(iris_id, aes(x = Species, y = Sepal.Length)) +
geom_boxplot()
) %>%
#....what goes here....
I prefer the second way because I'm more comfortable with theming in ggplot2 but I'm open to any and all suggestions!! Thank you.
Try this approach, for sure you can customize further:
library(ggplot2)
library(plotly)
library(dplyr)
#Data
iris_ids <- iris %>%
mutate(id = rownames(iris))
#Plot
gg <- ggplotly(
ggplot(iris_ids, aes(x = Species, y = Sepal.Length)) +
geom_boxplot()
)
hoverinfo <- with(iris_ids, paste0("id: ", id, "</br></br>",
"Sepal.Length: ", Sepal.Length, "</br>"))
gg$x$data[[1]]$text <- hoverinfo
gg$x$data[[1]]$hoverinfo <- c("text", "boxes")
gg
Output:

R Plotly - Plotting Multiple Regression Lines

How do I add multiple regression lines to the same plot in plotly?
I want to graph the scatter plot, as well as a regression line for each CATEGORY
The scatter plot plots fine, however the graph lines are not graphed correctly (as compared to excel outputs, see below)
df <- as.data.frame(1:19)
df$CATEGORY <- c("C","C","A","A","A","B","B","A","B","B","A","C","B","B","A","B","C","B","B")
df$x <- c(126,40,12,42,17,150,54,35,21,71,52,115,52,40,22,73,98,35,196)
df$y <- c(92,62,4,23,60,60,49,41,50,76,52,24,9,78,71,25,21,22,25)
df[,1] <- NULL
fv <- df %>%
filter(!is.na(x)) %>%
lm(x ~ y + y*CATEGORY,.) %>%
fitted.values()
p <- plot_ly(data = df,
x = ~x,
y = ~y,
color = ~CATEGORY,
type = "scatter",
mode = "markers"
) %>%
add_trace(x = ~y, y = ~fv, mode = "lines")
p
Apologies for not adding in all the information beforehand, and thanks for adding the suggestion of "y*CATEGORY" to fix the parallel line issue.
Excel Output
https://i.imgur.com/2QMacSC.png
R Output
https://i.imgur.com/LNypvDn.png
Try this:
library(plotly)
df <- as.data.frame(1:19)
df$CATEGORY <- c("C","C","A","A","A","B","B","A","B","B","A","C","B","B","A","B","C","B","B")
df$x <- c(126,40,12,42,17,150,54,35,21,71,52,115,52,40,22,73,98,35,196)
df$y <- c(92,62,4,23,60,60,49,41,50,76,52,24,9,78,71,25,21,22,25)
df[,1] <- NULL
df$fv <- df %>%
filter(!is.na(x)) %>%
lm(y ~ x*CATEGORY,.) %>%
fitted.values()
p <- plot_ly(data = df,
x = ~x,
y = ~y,
color = ~CATEGORY,
type = "scatter",
mode = "markers"
) %>%
add_trace(x = ~x, y = ~fv, mode = "lines")
p

Change Legend Titles in R Plotly

I am using the following code to generate a 3D scatter plot with vectors in Plotly - R studio. Currently, the legend labels are displayed as "trace 1, trace 2, etc", but I'd like to change that with my own text. Any idea how to achieve this?
#Define the data from df to be plotted, basically three columns of a data frame
x = df[,1]
y = df[,2]
z = df[,3]
#Scatter and Axis Labels
p <- plot_ly() %>%
add_trace(x=x, y=y, z=z,
type="scatter3d", mode="markers",
marker = list(color=y,
colorscale = 'Viridis',
opacity = 0.02,showscale = F)) %>%
layout(title = "TITLE",
scene = list(
xaxis = list(title = "LABEL 1"),
yaxis = list(title = "LABEL 2"),
zaxis = list(title = "LABEL 3")))
#Add Vectors to the Plot
for (k in 1:nrow(df_vector)) {
x <- c(0, df_vector[k,1])
y <- c(0, df_vector[k,2])
z <- c(0, df_vector[k,3])
p <- p %>% add_trace(x=x, y=y, z=z,
type="scatter3d", mode="lines",
line = list(width=8),
opacity = 1)
}
Use the name argument to add_trace. I've mocked up some data below, but in future bear in mind that it's helpful to include easily-readable example data using (eg) dput.
library(plotly)
## Reproducible by setting RND seed
set.seed(42)
## Define the data from df to be plotted, basically three columns of a data frame
df <- data.frame(x = rnorm(100), y = rnorm(100), z = rnorm(100))
## Scatter and Axis Labels
p <- plot_ly(df) %>%
add_trace(x=~x, y=~y, z=~z,
type="scatter3d", mode="markers",
name = "markers"
# ,
# marker = list(
# colorscale = 'Viridis',
# opacity = 0.02,showscale = F)
) %>%
layout(title = "TITLE",
scene = list(
xaxis = list(title = "LABEL 1"),
yaxis = list(title = "LABEL 2"),
zaxis = list(title = "LABEL 3")))
#Add Vectors to the Plot
for (k in 1:nrow(df[1:3, ])) {
x <- c(0, df[k, 1])
y <- c(0, df[k, 2])
z <- c(0, df[k, 3])
p <- p %>% add_trace(x=x, y=y, z=z,
name = paste("my trace name", k),
type="scatter3d", mode="lines",
line = list(width=8),
opacity = 1)
}

Plotting Ellipse3d in R Plotly with surface ellipse

Similar to the question here but this didn't give me excatly what I needed and I couldn't figure it out: Plot ellipse3d in R plotly?. I want to recreate rgl's ellipse3d and surface ellipsoid in plotly. I know there there was an anwer which allowed plotting of an ellipse but as individual opaque markers, I need to get it as a surface ellipsoid that's slightly opaque so I can still see the data points in the ellipsoid.
I tried to figure out how dww's comment for "add_surface" instead works but couldn't figure it out.... Can anyone help please?
if (!require("rgl")) install.packages("rgl")
dt <- cbind(x = rnorm(100), y = rnorm(100), z = rnorm(100))
ellipse <- ellipse3d(cov(dt))
plot3d(dt)
plot3d(ellipse, add = T, color = "red", alpha = 0.5)
dww's answer was:
if (!require("plotly")) install.packages("plotly")
if (!require("rgl")) install.packages("rgl")
dt <- cbind(x = rnorm(100), y = rnorm(100), z = rnorm(100))
ellipse <- ellipse3d(cov(dt))
p <- plot_ly(mode = 'markers') %>%
add_trace(type = 'scatter3d', size = 1,
x = ellipse$vb[1,], y = ellipse$vb[2,], z = ellipse$vb[3,],
opacity=0.01) %>%
add_trace(type = 'scatter3d', x = dt[,1], y = dt[,2], z = dt[,3])
p
# shows more obviously what dww's code does to create the visual ellipsoid
w <- plot_ly(mode = 'markers') %>%
add_trace(type = 'scatter3d',
x = ellipse$vb[1,], y = ellipse$vb[2,], z = ellipse$vb[3,],
opacity=0.5) %>%
add_trace(type = 'scatter3d', x = dt[,1], y = dt[,2], z = dt[,3])
w
Their comment on how to use add_surface was
Note that for simplicity, I plotted the ellipse as a cloud using markers. If you want to use add_surface instead, you will have to first convert the ellipse into a different format, with a vector of x locations, a vector of y locations, z as a matrix (dimensions equal to x by y). You'll also need to split the z values into two separate surface layers one for the top half of the ellipsoid and one for the bottom. I don't have time right now to do all this, but if you get stuck I can work this out later
This is my solution if anyone is interested in it. This allows using of the buttons in plotly to toggle the ellipsoid on and off so that you can still hover over and select data points inside the ellipsoid when desired:
if (!require("rgl")) install.packages("rgl", dependencies=TRUE, repos="http://cran.rstudio.com/")
if (!require("plotly")) install.packages("plotly", dependencies=TRUE, repos="http://cran.rstudio.com/")
dt <- cbind(x = rnorm(100), y = rnorm(100), z = rnorm(100))
ellipse <- ellipse3d(cov(dt))
updatemenus <- list(
list(
active = 0,
type= 'buttons',
buttons = list(
list(
label = "Ellipsoid",
method = "update",
args = list(list(visible = c(TRUE, TRUE)))),
list(
label = "No Ellipsoid",
method = "update",
args = list(list(visible = c(TRUE, FALSE)))))
)
)
plot<- plot_ly()%>%
# Plot raw scatter data points
add_trace(data = dt, x = dt[,1], y = dt[,2], z = dt[,3],
type = "scatter3d", mode = 'markers', marker = list(size = 3)) %>%
# Plot ellipsoid
add_trace(x=ellipse$vb [1,], y=ellipse$vb [2,], z=ellipse$vb [3,],
type='mesh3d', alphahull = 0, opacity = 0.4)%>%
# Axes Titles
layout(updatemenus = updatemenus)
plot
Here is a possibility, using the mesh3d type, and with the help of the misc3d package.
pts <- cbind(x = rnorm(10), y = rnorm(10), z = rnorm(10))
C <- chol(cov(pts))
SVD <- svd(t(C))
A <- solve(t(SVD$u)) %*% diag(SVD$d)
cr <- colMeans(pts)
r <- sqrt(qchisq(0.95,3))
fx <- function(u,v){
cr[1] + r*(A[1,1]*cos(u)*cos(v) + A[1,2]*cos(u)*sin(v) + A[1,3]*sin(u))
}
fy <- function(u,v){
cr[2] + r*(A[2,1]*cos(u)*cos(v) + A[2,2]*cos(u)*sin(v) + A[2,3]*sin(u))
}
fz <- function(u,v){
cr[3] + r*(A[3,1]*cos(u)*cos(v) + A[3,2]*cos(u)*sin(v) + A[3,3]*sin(u))
}
library(misc3d)
tris <- parametric3d(fx, fy, fz,
umin=-pi/2, umax=pi/2, vmin=0, vmax=2*pi,
n=100, engine="none")
n <- nrow(tris$v1)
cont <- matrix(NA_real_, ncol=3, nrow=3*n)
cont[3*(1:n)-2,] <- tris$v1
cont[3*(1:n)-1,] <- tris$v2
cont[3*(1:n),] <- tris$v3
idx <- matrix(0:(3*n-1), ncol=3, byrow=TRUE)
library(plotly)
p <- plot_ly() %>%
add_trace(type = "mesh3d",
x = cont[,1], y = cont[,2], z = cont[,3],
i = idx[,1], j = idx[,2], k = idx[,3],
opacity = 0.3) %>%
add_trace(type = "scatter3d", mode = "markers",
data = as.data.frame(pts),
x = ~x, y = ~y, z = ~z,
marker = list(size = 5)) %>%
layout(scene = list(aspectmode = "data"))
To add some colors:
midpoints <- (tris$v1 + tris$v2 + tris$v3)/3
distances <- apply(midpoints, 1, function(x) crossprod(x-cr))
intervals <- cut(distances, 256)
colorsPalette <- viridisLite::viridis(256)
colors <- colorsPalette[as.integer(intervals)]
p <- plot_ly() %>%
add_trace(type = "mesh3d",
x = cont[,1], y = cont[,2], z = cont[,3],
i = idx[,1], j = idx[,2], k = idx[,3],
facecolor = colors,
opacity = 0.3) %>%
add_trace(type = "scatter3d", mode = "markers",
data = as.data.frame(pts),
x = ~x, y = ~y, z = ~z,
marker = list(size = 5)) %>%
layout(scene = list(aspectmode = "data"))
Another solution with the Rvcg package. We use the vcgSphere function which generates a triangulated sphere.
sphr <- Rvcg::vcgSphere() # triangualted sphere
library(rgl) # to use scale3d and transform3d
ell <- scale3d(transform3d(sphr, A), r, r, r)
vs <- ell$vb[1:3,] + cr
idx <- ell$it - 1
p <- plot_ly() %>%
add_trace(type="mesh3d",
x = vs[1,], y = vs[2,], z = vs[3,],
i = idx[1,], j = idx[2,], k = idx[3,],
opacity = 0.3) %>%
add_trace(type = "scatter3d", mode = "markers",
data = as.data.frame(pts),
x = ~x, y = ~y, z = ~z,
marker = list(size = 5)) %>%
layout(scene = list(aspectmode = "data"))

How do I add surfaces such a planes as traces generated mathematical formulas in a 3D scatter plot in plotly in r?

I'm trying to learn how to draw surfaces in a 3D scatter plot in Plotly using R.
I tried to extend the example give in this questions: Add Regression Plane to 3d Scatter Plot in Plotly
Except I changed the example from using a standard Iris data set to using to random clusters separated by a 2D plane with the formula: Z = -X -Y
I get the error:
Error in traces[[i]][[obj]] :
attempt to select less than one element in get1index
So I set up my data to be divided by the plane
rm(list=ls())
library(plotly)
library(reshape2)
x <- rnorm(100,1,1)
y <- rnorm(100,1,1)
z <- rnorm(100,1,1)
col <- rep("red",100)
df.1 <- data.frame(x,y,z,col)
x <- rnorm(100,-1,1)
y <- rnorm(100,-1,1)
z <- rnorm(100,-1,1)
col <- rep("blue",100)
df.2 <- data.frame(x,y,z,col)
df<- rbind(df.1,df.2)
Next, I want to calculate a surface for a plane whose formula is x + y + z = 0
graph_reso <- 0.1
#Setup Axis
axis_x <- seq(min(df$x), max(df$x), by = graph_reso)
axis_y <- seq(min(df$x), max(df$x), by = graph_reso)
surface <- expand.grid(x = axis_x,y = axis_y,KEEP.OUT.ATTRS = F)
Here I compute the surface - in the cited example they use linear regression
surface$z <- 0 - surface$x - surface$y
surface2 <- acast(surface, y ~ x, value.var = "z") #y ~ x
Next, I use plot_ly to create the 3D scatter plot -- which works fine
p <- plot_ly(df, x = ~x, y = ~y, z = ~z, color = ~col, colors = c('#BF382A', '#0C4B8E')) %>%
add_markers() %>%
layout(scene = list(xaxis = list(title = 'X'),
yaxis = list(title = 'Y'),
zaxis = list(title = 'Z')))
So this is the step where I get stuck -- I guess I'm not creating my surface correctly. Tried google and troubleshooting -- it seems I'm stuck.
add_trace(p,z=surface2,x=axis_x,y=axis_y,type="surface")
The error I get is:
Error in traces[[i]][[obj]] :
attempt to select less than one element in get1index
Add inherit=FALSE inside add_trace:
p <- plot_ly(df, x = ~x, y = ~y, z = ~z, color = ~col, colors=c('#BF382A', '#0C4B8E')) %>%
add_markers() %>%
add_trace(z=surface2, x=axis_x, y=axis_y, type="surface", inherit=FALSE) %>%
layout(scene = list(xaxis = list(title = 'X'), yaxis = list(title = 'Y'),
zaxis = list(title = 'Z'), aspectmode='cube'))
print(p)

Resources