Plotly - Surface - Text hoverinfo not working - r

I have build a surface chart with plotly and I am trying to have hoverinfo based on my own text. Curiously it is not working anymore.
library(plotly)
x <- rnorm(10)
y <- rnorm(10)
z <- outer(y, x)
p <- plot_ly(x = ~x, y = ~y, z = ~z, type = "surface",
text = ~paste0("My X = ", x, "\n My Y = ", y, "\n My Z = ", z),
hoverinfo = "text") %>% layout(dragmode = "turntable")
print(p)
Although
p <- plot_ly(x = ~x, y = ~y, z = ~z, type = "surface") %>% layout(dragmode = "turntable")
works well.
I have also tried to substitute \n by <br /> with no effect.
I am using R 3.4.0 and plotly 4.7.0 on macOS Sierra.
Any suggestions?

Plotly's labeling seems finicky with custom labels using the ~paste() syntax because it is trying to build a new data structure with your inputs (three vectors and one matrix), but if you pass in custom labels as a matrix with the same dimensions it will work.
custom_txt <- paste0("My X = ", rep(x, times = 10),
"</br> My Y = ", rep(y, each = 10), # correct break syntax
"</br> My Z = ", z) %>%
matrix(10,10) # dim must match plotly's under-the-hood? matrix
plot_ly(x = ~x, y = ~y, z = ~z, type = "surface",
text = custom_txt,
hoverinfo = "text") %>%
layout(dragmode = "turntable")

Related

Making a predefined layout for plotly in R

I would like to make a predefined layout that I can use for my plot functions that I have created so as not to repeat myself everytime I make a plot. For example, I tried to do sth like the following which doesn't work and gives an error:
custom_layout <- function(){
plotly::layout(
xaxis = list(title = ""),
yaxis = list(title = ""),
title = list(text = title, y = 0.98)
)
}
plot_bar <- function(title, dt, x, y, fill){
plot_ly(dt, x = ~x, y = ~y, type = "bar",
color = ~ fill, split = ~ fill) %>%
custom_layout()}
plot_line <- function(title, dt, x, y, fill){
plot_ly(dt, x = ~x, y = ~y, type="scatter",
split = ~fill, mode="lines+markers") %>%
custom_layout()}
I call these 2 plotting functions multiple times in my code. I have also other predefined plotting functions like plot_line and plot_bar and I use the same layout for them as well but now manually adding the layout like in the following:
plot_bar <- function(title, dt, x, y, fill){
plot_ly(dt, x = ~x, y = ~y, type = "bar",
color = ~ fill, split = ~ fill) %>%
layout(
xaxis = list(title = ""),
yaxis = list(title = ""),
title = list(text = title, y = 0.98)
Ideally, I would like to define it like in the first scenario with a predefined layout that I could use later for every plotting function which is not working for me. Is there a way to do it with native plotly and not ggplot2?
You need to make the custom_layout() function take p as its first argument (just like layout() does).
library(tibble)
dt <- tibble(x=1:4, y=3:6, fill=1:4)
custom_layout <- function(p, title){
plotly::layout(p,
xaxis = list(title = ""),
yaxis = list(title = ""),
title = list(text = title, y = 0.98)
)
}
plot_bar <- function(title, dt, x, y, fill){
plot_ly(dt, x = ~x, y = ~y, type = "bar",
color = ~ fill, split = ~ fill) %>%
custom_layout(title=title)}
plot_bar(title="myplot", dt, "x", "y", "fill")

Modifying labels (x,y,z) in heatmap on plotly?

I want to rename labels in a heatmap. for example:
instead of the label says "x:", I want the label to say "Hour:"
instead of the label says "y:", I want the label to say "Day:"
Library(plotly)
p <- plot_ly(z = volcano, colors = colorRamp(c("red", "green")), type = "heatmap")
furthermore, it would be useful, for example if we use a transformation of data in order to intensify contrast, still the html interactive label show real data.
Example
What about
library(plotly)
dat <- expand.grid(x = 1:nrow(volcano), y = 1:ncol(volcano))
dat$z <- c(volcano)
plot_ly(height = 500) %>%
layout(autosize = FALSE,
xaxis=list(title = "Hour", titlefont = list(size=20)),
yaxis=list(title = "Day", titlefont = list(size=20))) %>%
add_trace(data = dat, x = ~x, y = ~y, z = ~z, type = "heatmap",
hoverinfo = 'text',
text = ~paste("Hour:", dat$x,
"<br> Day:", dat$y,
"<br> z:", dat$z))

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

I want to increase the maximum magnification of the graph in R in plotly

For graphs drawn with R in the R package(Plotly), there is a limit to enlarging the graph. After zooming to a certain size, I can not zoom in anymore, but I want to zoom in. Do you have any code or arguments that circumvent these restrictions?
If you want to go to the bottom of the link, please check the limit of enlargement with the last example 'Map'.
https://plot.ly/r/trisurf/
I need help!
// additional information
The following code shows the graph and I want to zoom in on the helicopter more than the image! Is there a way?
(Zooming is done using the tools of plotly or using the mouse wheel.)
Click graph image (Maximum magnification)
library(plotly)
library(geomorph)
data <- read.csv('https://raw.githubusercontent.com/plotly/datasets/master/_3d-line-plot.csv')
plyFile <- 'http://people.sc.fsu.edu/~jburkardt/data/ply/chopper.ply'
dest <- basename(plyFile)
if (!file.exists(dest)) {
download.file(plyFile, dest)
}
mesh <- read.ply(dest)
# see getS3method("shade3d", "mesh3d") for details on how to plot
# plot point cloud
x <- mesh$vb["xpts",]
y <- mesh$vb["ypts",]
z <- mesh$vb["zpts",]
m <- matrix(c(x,y,z), ncol=3, dimnames=list(NULL,c("x","y","z")))
# now figure out the colormap
zmean <- apply(t(mesh$it),MARGIN=1,function(row){mean(m[row,3])})
library(scales)
facecolor = colour_ramp(
brewer_pal(palette="RdBu")(10)
)(rescale(x=zmean))
p <- plot_ly(data, x = ~x1, y = ~y1, z = ~z1, type = 'scatter3d', mode = 'lines',
line = list(color = '#1f77b4', width = 1)) %>%
add_trace(x = ~x2, y = ~y2, z = ~z2,
line = list(color = 'rgb(44, 160, 44)', width = 1)) %>%
add_trace(x = ~x3, y = ~y3, z = ~z3,
line = list(color = 'bcbd22', width = 1))
add_trace(p, x = x, y = y, z = z,
i = mesh$it[1,]-1, j = mesh$it[2,]-1, k = mesh$it[3,]-1,
facecolor = facecolor,
type = "mesh3d")

R plotly specifying custom legend name with color parameter

I am trying to plot using color coding on a value, and changing default legend names. Can't seem to get it to work.
This code plots what I mainly want:
df <- data.frame(x = 1:10, y = 1:10)
plot_ly(df, x = x, y = y, color = y > 5, mode = 'markers')
Now, I am trying to change the default legend names so they are more explanatory:
plot_ly(df, x = x, y = y, color = y > 5, mode = 'markers', name = c('Y <= 5', 'y > 5'))
Does not do anything, even though plotly documentation says name is the right way to change the legend name.
I just want the legend names to be more descriptive than simple true and false as they are shown in the plot.
Color by third variable, here added with dplyr.
df <- data.frame(x = 1:10, y = 1:10)
df %>%
dplyr::mutate(col = ifelse(y >= 5, ">= 5", "< 5")) %>%
plot_ly(x = ~x, color = ~col, mode = 'markers') %>%
add_markers(y = ~y)

Resources