plotting 3D surface with plotly (matrix transformation with akima::interp) - r

In order to plot a surface in plotly with x, y, z, we can use the function interp to create the data (as input for the add_surface function in plotly)
This article give the solution.
I follow the different steps.
With the follow code, we can plotly a surface with markers.
library(akima)
library(plotly)
x=rep(seq(-1,5,0.2),time=31,each=1)
y=rep(seq(-1,5,0.2),time=1,each=31)
df=data.frame(x=x,y=y,
z=2*x+y-1.4)
fig <- plot_ly()%>% add_markers(data=df,x = ~x, y = ~y, z = ~z,
marker = list(color = "blue",
showscale = TRUE))
fig
We can see the following plot
Then I use interp to create the data for the surface, and I plot the surface together with the markers.
s = interp(x = df$x, y = df$y, z = df$z)
fig <- plot_ly()%>%
add_surface(x = s$x, y = s$y, z = s$z)%>%
add_markers(data=df,x = ~x, y = ~y, z = ~z,
marker = list(color = "blue",
showscale = TRUE))
fig
I have the following image.
We can see that the result is different. And I can't see why.
When I try to change the function to generate z, sometimes, the two surfaces are the same. For example, for this data.frame
df=data.frame(x=x,y=y,
z=x+y+1)
We have the following image. And we can see that this time, we get the same surfaces.

It appears the meanings of x and y are swapped in the add_surface versus the meanings in interp. The example that worked had x and y appear symmetrically. So swap them back by transposing the z matrix:
fig <- plot_ly()%>%
add_surface(x = s$x, y = s$y, z = t(s$z))%>%
add_markers(data=df,x = ~x, y = ~y, z = ~z,
marker = list(color = "blue",
showscale = TRUE))
fig
This is just a guess because the documentation in plotly is so weak. akima::interp clearly documents that rows of z correspond to different x values.

Related

How can I explicitly assign unique colors to every point in an R Plotly scatterplot?

I have some data like this:
data <- data.frame(x=runif(500), y=runif(500), z=runif(500))
I want a scatterplot with points colored independently/discretely in each dimension (X, Y, and Z) using RGB values.
This is what I have tried:
Code:
library(dplyr)
library(plotly)
xyz_colors <- rgb(data$x, data$y, data$z)
plot_ly(data = data,
x = ~x, y = ~y, z = ~z,
color= xyz_colors,
type = 'scatter3d',
mode='markers') %>%
layout(scene = list(xaxis = list(title = 'X'),
yaxis = list(title = 'Y'),
zaxis = list(title = 'Z')))
Plot:
RColorBrewer thinks I'm trying to create a continuous scale from 500 intermediate colors:
Warning messages:
1: In RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
2: In RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
What are some correct ways to color the points like this in R with Plotly?
Also, how can one generally assign colors to data points in R with Plotly, individually?
To clarify, I am trying to color each point where the color is of the format "#XXYYZZ" where 'XX' a value between 00 and FF linearly mapped to the value of data$x from 0 to 1. That is, the X dimension determines the amount of red, the Y dimension determines the amount of green, and the Z dimension determines the amount of blue. At 0,0,0 the point should be black and at 1,1,1 the point should be white. The reason for this is to make as easy to visualize the 3D position of the points as possible.
Updated answer after comments:
So, is there no way to color every point separately?
Yes, there is through the power and flexibility of add_traces(). And it's a lot less cumbersome than I first thought.
Just set up an empty plotly figure with some required 3D features:
p <-plot_ly(data = data, type = 'scatter3d', mode='markers')
And apply add_traces() in a loop over each defined color:
for (i in seq_along(xyz_colors)){
p <- p %>% add_trace(x=data$x[i], y=data$y[i], z=data$z[i],
marker = list(color = xyz_colors[i], opacity=0.6, size = 5),
name = xyz_colors[i])
}
And you can easily define single points with a color of your choice like this:
p <- p %>% add_trace(x=0, y=0, z=0,
marker = list(color = rgb(0, 0, 0), opacity=0.8, size = 20),
name = xyz_colors[i])
Plot:
Complete code:
library(dplyr)
library(plotly)
# data and colors
data <- data.frame(x=runif(500), y=runif(500), z=runif(500))
xyz_colors <- rgb(data$x, data$y, data$z)
# empty 3D plot
p <-plot_ly(data = data, type = 'scatter3d', mode='markers') %>%
layout(scene = list(xaxis = list(title = 'X'),
yaxis = list(title = 'Y'),
zaxis = list(title = 'Z')))
# one trace per color
for (i in seq_along(xyz_colors)){
p <- p %>% add_trace(x=data$x[i], y=data$y[i], z=data$z[i],
marker = list(color = xyz_colors[i], opacity=0.6, size = 5),
name = xyz_colors[i])
}
# Your favorite data point with your favorite color
p <- p %>% add_trace(x=0, y=0, z=0,
marker = list(color = rgb(0, 0, 0), opacity=0.8, size = 20),
name = xyz_colors[i])
p
Original answer:
In 3D plots you can use the same color for all of the points, discern different clusters or categories from each other using different colors, or you use individual colors for each point to illustrate a fourth value (or fourth dimension if you like, as described here) in your dataset. All these approaches are, as you put it, examples of '[...] correct ways to color the points [...]'. Have a look below and see if this suits your needs. I've included fourthVal <- data$x+data$y+data$z as an example for an extra dimension. What you end up using will depend entirely on your dataset and what you'd like to illustrate.
Code:
library(dplyr)
library(plotly)
data <- data.frame(x=runif(500), y=runif(500), z=runif(500))
xyz_colors <- rgb(data$x, data$y, data$z)
fourthVal <- data$x+data$y+data$z
plot_ly(data = data,
x = ~x, y = ~y, z = ~z,
color= fourthVal,
type = 'scatter3d',
mode='markers') %>%
layout(scene = list(xaxis = list(title = 'X'),
yaxis = list(title = 'Y'),
zaxis = list(title = 'Z')))
Plot:

Show 3d axes in Plotly, R

Using plotly in R, how do I make a 3d plot that shows the axes, like this:
instead of a plot that shows a bounding box, like this:
?
R code for the second is
t <- seq(0,2*pi,by =1)
r <- seq(0,1,by = .1)
x <- as.vector(outer(t,r,function(t,r).5*r*cos(t)))
y <- as.vector(outer(t,r,function(t,r)r*sin(t)))
z <- 4*x^2+y^2
plot_ly(x = ~x, y = ~y, z = ~z, type = "mesh3d", opacity=.5)

Movable lines in Plotly R

I have a scatter plot with numeric values on both the axis. I want to add two draggable lines, one horizontal and one vertical. Also, I would like to change the color of points in the top-right quadrant formed by the two lines. I could not find any way to do this in R.
My question is similar to Horizontal/Vertical Line in plotly
Two things I want to add is
Ability to drag vertical and horizontal lines
Return values on which the two lines intersect the x and y axis, so that I can use those values as an input for another UI.
My code sample
data <- data.frame(y = sample(0:50, 100, replace = TRUE),
x = round(runif(100),2)
)
plot_ly(data, x = ~x, y = ~y)
(1) You can add draggable lines as follows:
plot_ly(data, x = ~x, y = ~y, type = 'scatter') %>%
layout(shapes = list(
#vertical line
list(type = "line", x0 = 0.4, x1 = 0.4,
y0 = 0, y1 = 1, yref = "paper"),
#horizontal line
list(type = "line", x0 = 0, x1 = 1,
y0 = 30, y1 = 30, xref = "paper"))) %>%
# allow to edit plot by dragging lines
config(edits = list(shapePosition = TRUE))
Similar to https://stackoverflow.com/a/54777145/5840900
(2) In an interactive environment, you can extract the values of the last dragged line with:
# Only within reactive shiny context
newData <- plotly::event_data("plotly_relayout")
Hopefully this is still helpful!

Plot ellipse3d in R plotly?

Package rgl includes a very useful function ellipse3d, which can return an ellipsoid that cover like 95% percent of the points in 3D. Then this object can be used in rgl::plot3d to plot it out. My question is that is it possible to convert the output of ellipse3d to something that can be plotted through js plotting packages like plotly?
library(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)
Then what can I do to plot the ellipsoid through plotly?
You can extract the coordinates of the ellipse from the ellipse$vb. Then plot these. Something like:
p <- plot_ly() %>%
add_trace(type = 'scatter3d', size = 1,
x = ellipse$vb[1,], y = ellipse$vb[2,], z = ellipse$vb[3,],
opacity=0.01) %>%
add_trace(data=dt, type = 'scatter3d', x=~x, y=~y, z=~z)

Adding a Vertical / Horizontal Reference Line using Plotly

I'm working with a proportional bar chart and I'd like to draw a vertical line at a particular X value. I'd prefer to accomplish this using the plotly package, but it doesn't seem to be easily done.
The solution found at Horizontal/Vertical Line in plotly doesn't seem to get the job done.
I've provided some sample code below that could be used to draw the vertical line at X = 3.
library(plotly)
library(ggplot2)
plot_ly(diamonds[1:1000, ], x = ~x, y = ~cut, color = ~color) %>% add_bars()
I'd appreciate any help in this matter.
I found some information about lines in plotly from Zappos Engineering here. The range -0.5 to 4.5 is because there are five categories in the data provided, each centered on a whole number. The y range creates the line, while the x constant (at 3) keeps the line vertical.
p <- plot_ly(diamonds[1:1000, ], x = ~x, y = ~cut, color = ~color) %>% add_bars()
p <- layout(p, shapes = list(type = "line", fillcolor = "red",
line = list(color = "red"),
opacity = 1,
x0 = 3, x1 = 3, xref = 'x',
y0 = -0.5, y1 = 4.5, yref = 'y'))

Resources