Plotting add_trace from within a function: Plotly - r

I am trying to "functionize" my plot statements. If i want to add an additional trace from another dataframe, i am getting an error that the values on the y axis do not equal the first number of values in the first dataframe. I am not certain why this is relevant.
library(tidyverse)
library(plotly)
library(lubridate)
Date <- seq(as.Date("2016-10-1"), as.Date("2018-09-01"), by="month")
Values <- c(2,3,4,3,4,5,6,4,5,6,7,8,9,10,8,9,10,11,12,13,11,12,13,14)
Date2 <- seq(as.Date("2018-07-1"), as.Date("2018-09-01"), by="month")
Values2 <- c(16,17,18)
df <- tibble::tibble(Date, Values)
df2 <- tibble::tibble(Date2, Values2)
testfunction <- function(x, y, y2){
p <- plot_ly(df,x = ~x, y = ~y, colors = "Blues", type = 'scatter', mode = 'lines') %>%
add_trace(data = df2, y = ~y2, line = list(color = 'rgb(255, 36,1)', width = 2.25)) %>%
layout(xaxis = list(tickformat = "%b %e"))
p
}
testfunction(Date, Values, Values2)
#Error: Column `y` must be length 1 or 24, not 3

Notice that Date, Values, and Values2 are objects that exist in your global environment. So, testfunction is actually using those objects in the call to plot_ly. To demonstrate this, try removing df in the plot_ly call -- you should still be able to get a plot (i.e. plot_ly isn't actually using the values in the dataframe). However, I suspect what you're trying to do is to specify variable names in your dataframe in the arguments to your function. In which case, try
testfunction <- function(x, y, x2, y2) {
x <- enquo(x)
y <- enquo(y)
x2 <- enquo(x2)
y2 <- enquo(y2)
plot_ly(df, x = x, y = y, type = "scatter", mode = "lines") %>%
add_trace(x = x2, y = y2, data = df2)
}
testfunction(Date, Values, Date2, Values2)
with a hat tip to this question and answer: Pass variables as parameters to plot_ly function

Related

How can I successively add multiple lines to a graph in a plotly animation?

I want to show multiple lines being added to a plotly plot (as an animation) using R. For example, I have the following plotly line graphs (p, p2, p3):
library(plotly)
set.seed(3)
x = 1:10
y = 1:10
y2 = y^2
y3 = y^3
p = plot_ly(data = data.frame(x = x, y = y), x = ~ x, y = ~y, type = "scatter", mode = "lines")
p2 = plot_ly(data = data.frame(x = x, y = y2), x = ~ x, y = ~y2, type = "scatter", mode = "lines")
p3 = plot_ly(data = data.frame(x = x, y = y3), x = ~ x, y = ~y3, type = "scatter", mode = "lines")
Here p, p2, p3 are different plots but they all have the same x axis and different y axis. I want to be able to make an animation where the lines y, y2, y3 will successively appear in the plotly graph.
P.S: It does not strictly have to be done using plotly, but strongly preferred.
An idea might be to create a 'dataset' for each frame.
The first frame contains all values for y and all values for y2 and y3 are located outside the y-axis limits. For the second frame all values from y and y2 are shown and just the values from y3 are beyond the limit. In frame 3 all values are included.
library(tidyverse)
library(plotly)
# transform dataframe into a long format
df <- data.frame(x = 1:10,
y = 1:10) %>%
mutate(y2 = y^2,
y3 = y^3) %>%
pivot_longer(cols = -x,
names_to = "line",
values_to = "value")
# set the values for each frame and line
# (all lines not shown, need to hidden outside the plot limits - NA won't work)
df_plot <- map_df(1:3, ~ mutate(df, frame = .)) %>%
mutate(value = case_when(frame == 1 & line %in% c("y2", "y3") ~ -10,
frame == 2 & line %in% c("y3") ~ -10,
TRUE ~ value))
# create plot
plot_ly(data = df_plot,
x = ~x,
y = ~value,
color = ~line,
type = "scatter",
mode = "line",
frame = ~frame) %>%
layout(yaxis=list(range = c(0, 1000))) %>%
animation_opts(easing = "bounce")

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

plotly adding colorbar to mesh3d without using intensity (using facecolor)

I have a need to place a colorbar to a mesh3d plot that consists of several traces. Each mesh3d trace has a single color, but I need the colorbar to span all the trace-colors.
I am trying to combine a scatter3d with visible="legendonly" with the mesh3d, so achieve this. But when the mesh is plotted, the legend is removed.
Using the helicopter-example:
library(plotly)
library(geomorph)
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, ShowSpecimen = F)
# 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")(9)
)(rescale(x=zmean))
plot_ly() %>%
# Creates the legend, and also the plotting space
add_trace(
x = x, y = y, z = z,
color = x,
colors = c("#ffffff", "#000000"),
# visible="legendonly",
type = "scatter3d",
mode="markers"
) %>%
# Adds the mesh, but removes the legend
add_trace(
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"
)
After a lot of hacking, I finally have a working solution.
In this case, by plotting a mesh3d area, with points that are "inside" the helicopter and will not be visible later, and then plot the actual helicopter later.
It seems that "visible='legendonly'" does not apply to mesh3d, as this option removes both the plot and legend.
library(plotly)
library(geomorph)
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, ShowSpecimen = F)
# 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])})
# Get colors you want
cols = brewer_pal(palette="RdBu")(9)
# Ramp to add to facecolor
library(scales)
facecolor = colour_ramp(cols)(rescale(x=zmean))
# Create data.frame of colours and breakpoints.
# Must go from 0 to 1, plotly scales it based on values it self.
colz = data.frame(seq(0,1,length.out = length(cols)),
cols)
# Make stupid pointcloud to fool the colorbar
xx = c(min(x), max(x))
yy = c(min(y), max(y))
zz = c(min(z), max(z))
plot_ly() %>%
# Creates the legend, and also the plotting space
add_trace(
x = xx, y = yy, z = zz,
intensity = x,
colorscale = colz,
# visible="legendonly",
type = "mesh3d"
) %>%
# Adds the mesh
add_trace(
x = x, y = y, z = z,
i = mesh$it[1,]-1, j = mesh$it[2,]-1, k = mesh$it[3,]-1,
facecolor = facecolor,
showscale=FALSE,
type = "mesh3d"
)

R plotly dynamic line width

I have multiple paths in my data, separated by NAs to build separated bar data, for which I'm trying to implement dynamic widths based on another value in that observation (column z below).
Reproducible Example:
index <- c(1,1,NA,2,2)
value <- c(50,51,NA,51,52)
width <- c(3,3,NA,5,5)
data <- data.frame(x = index,
y = value,
z = width)
p <- plot_ly(data, x = x, y = y, mode = "lines",
marker = list(color = '#ff2626'),
line = list(width = data$z))
Where I am trying to reference column z for the line = list(width = data$z) paramter.
Can this be done in the Plotly for R package, or does the line width need to be fixed?
index <- c(1,1,NA,2,2)
value <- c(50,51,NA,51,52)
width <- c(3,3,NA,5,5)
data <- data.frame(x = index, y = value, z = width)
# first, create an empty plotly object
p <- plot_ly(type = "scatter", mode = "lines+markers", marker = list(color = '#ff2626'))
# second, every third line a new lines definition begins. Loop through lines in steps of 3 and add lines
for (i in seq(1, nrow(data), by = 3)){
p <- p %>% add_trace(x=data[i,"x"], y=data[i:(i+1), "y"], line=list(width=data[i,"z"]))
}

how to use a numeric variable as character in plot_ly r graphs

I am quite new to plotly so this is probably a basic question, I have a simple data frame :
id = c("01","02","03","04","05")
value = c(1:5)
data=data.frame(id,value)
When I plot it using plot_ly :
require(plotly)
plot_ly(data,x=id,y=value)
plot_ly think my id variable is a numeric variable, so on the x axis, I get graduation 1, 1.5, 2, 2.5 ... which makes no sense.
If I want that plot_ly understand my variable is a character, I have to add some non-numeric character :
data$id = paste0("n",id)
plot_ly(data,x=id,y=value)
This code gives me what I want, but whith a disgracious "n" before my id.
Any ideas ?
Useless to say I have no problem using ggplot.
Based on this github issue one needs to explicitly specify the axis type.
Hope this helps. Disregard my misinformed comment earlier.
library(plotly)
df <- data.frame(x = c("A", "B", "C"),
y = 1:3)
# Works fine
plot_ly(df, x = x, y = y, mode = "markers")
# Treated as numeric
df <- data.frame(x = c("1000", "2000", "3000"),
y = 1:3)
plot_ly(df, x = x, y = y, mode = "markers")
# Force as a categorical axis
plot_ly(df, x = x, y = y, mode = "markers") %>% layout(xaxis = list(type = "category"))
# Treated as categorical
df <- data.frame(x = c("1000A", "2000B", "3000C"),
y = 1:3)
plot_ly(df, x = x, y = y, mode = "markers")

Resources