Related
I have a plot_ly 3D scatter plot that uses three traces, and I want to use a different symbol and color for each trace. My code looks like this
library(plotrix)
library(plotly)
library(processx)
x <- c(1, 2, 3, 4)
y <- c(2, 4, 6, 8)
z <- c(1, 2, 3, 4)
df <- data.frame(x, y, z)
z1 <- z + 1.5
df1 <- data.frame(x, y, z1)
z2 <- z + 3
df2 <- data.frame(x, y, z2)
symbols <- c("circle", "diamond", 'triangle-down')
colors <- c("gray", "lightgray", "darkslategray")
plot<- plot_ly()%>%
add_trace(data = df, x = ~x, y = ~y, z = ~z,type = "scatter3d",
mode = 'markers', marker = list(size = 8, symbol = 1, symbols = symbols, color = 1, colors = colors)) %>%
add_trace(data = df1, x = ~x, y = ~y, z = ~z1,type = "scatter3d",
mode = 'markers', marker = list(size = 8, symbol = 2, symbols = symbols, color = 2, colors = colors)) %>%
add_trace(data = df2, x = ~x, y = ~y, z = ~z2,type = "scatter3d",
mode = 'markers', marker = list(size = 8, symbol = 8, symbols = symbols, color = 3, colors = colors)) %>%
layout(title = 'Explore Options')
plot
which I would like to have the first trace to use circle markers, the second diamond and the third triangles, each with a different gray scale color, but instead I just get colored circles i.e.
One option would be to add a column to your dataframes which could then be mapped on the color and symbol attributes. Additionally I use named vectors of colors and symbols to assign colors and symbols to categories of the new column. Also note that colors and symbols should not to be placed inside the list for the marker specifications. Finally I simplified your code a bit.
The "triangle-down" symbol does not work, according to this reference, only ( "circle" | "circle-open" | "cross" | "diamond" | "diamond-open" | "square" | "square-open" | "x" ) are accepted.
library(plotly)
x <- c(1, 2, 3, 4)
y <- c(2, 4, 6, 8)
z <- c(1, 2, 3, 4)
df <- data.frame(x, y, z)
z1 <- z + 1.5
df1 <- data.frame(x, y, z = z1)
z2 <- z + 3
df2 <- data.frame(x, y, z = z2)
df$color <- "a"
df1$color <- "b"
df2$color <- "c"
symbols <- c("circle", "diamond", 'square')
colors <- c("gray", "lightgray", "darkslategray")
names(colors) <- names(symbols) <- c("a", "b", "c")
plot<- plot_ly(x = ~x, y = ~y, z = ~z, color = ~color, symbol = ~color, colors = colors, symbols = symbols, marker = list(size = 8)) %>%
add_trace(data = df, type = "scatter3d", mode = 'markers') %>%
add_trace(data = df1, type = "scatter3d", mode = 'markers') %>%
add_trace(data = df2, type = "scatter3d", mode = 'markers') %>%
layout(title = 'Explore Options')
plot
The dynamic hoverlabel background color in R plotly does not seem to work when using scattergl instead of scatter as depicted in the example below.
Works as intended with type = "scatter":
library(plotly)
X <- data.frame(x = 1:6,
y = 1:6,
z = 1:6)
plot_ly(data = X, x = ~x, y = ~y,
type = "scatter", mode = "markers",
marker = list(color = ~x,
colorscale = list(c(0, .5, 1), c('#0d71db', "#dbc00d", "#db220d"))))
The hoverlabel background color becomes black for all data points with type = "scattergl":
plot_ly(data = X, x = ~x, y = ~y,
type = "scattergl", mode = "markers",
marker = list(color = ~x,
colorscale = list(c(0, .5, 1), c('#0d71db', "#dbc00d", "#db220d"))))
I guess a solution could be to pass the same color array used in colorscale to the bgcolor argument via hoverlabel = list(bgcolor = ???). However I have no idea how to do so.
Edit
Tried this based on #Quinten's answer, without success. As can be seen the colors are the default plot_ly colors and do not correspond to what is specified in cols.
library(plotly)
n <- 5000
X <- data.frame(x = sample(1:100, n, replace = TRUE),
y = sample(1:100, n, replace = TRUE),
z = sample(1:500, n, replace = TRUE))
length_unique_vals <- length(unique(X$z))
cols <- colorRampPalette(c('#0d71db', "#dbc00d", "#db220d"))(length_unique_vals)
cols <- cols[factor(X$z)]
plot_ly(data = X, x = ~x, y = ~y,
type = "scattergl", mode = "markers",
marker = list(color = ~z,
colorscale = cols,
colorbar = list(title = "Colorbar")),
hoverlabel = list(bgcolor = cols)) %>%
toWebGL()
You can create a vector of 6 different colors using RColorBrewer. These colors you assign to the color of your marker and to the bgcolor of your hoverlabel which will show the right color. You can use the following code:
library(plotly)
X <- data.frame(x = 1:6,
y = 1:6,
z = 1:6)
library(RColorBrewer)
cols <- brewer.pal(n = 6, name = "Set3")
plot_ly(data = X, x = ~x, y = ~y,
type = "scattergl", mode = "markers",
marker = list(color = cols),
hoverlabel = list(bgcolor = cols))
Output:
As you can see from the plot, the label is the same color as the marker.
library(dplyr)
library(plotly)
library(plyr)
df <- data.frame(
Category = c('foo', 'bar', 'bar', 'foo'),
x = c(2.1, 3.4, 4, 4),
y = c(16, 21, 10, 17)
)
palette <- c("green", "red")
fig <- plot_ly(
data = df, x = ~x, y = ~y, size = 10, color = ~Category, colors = palette,
symbol = ~Category, hoverinfo = 'y', symbols = c(15, 17)
)
fig
That's what I have so far. What I want to do is to make the foo plot, and only the foo plot, visible in the legend. I've tried using add_trace() with showlegend = F, but that sets bar invisible in the legend as well.
Isn't it better to use ggplot2?
library(tidyverse)
df <- tibble(
Category = c('foo', 'bar', 'bar', 'foo'),
x = c(2.1, 3.4, 4, 4),
y = c(16, 21, 10, 17)
)
df %>% ggplot(aes(x, y))+
geom_point(data = df %>% filter(Category=='foo'), aes(x, y, col=Category, shape=Category))+
geom_point(data = df %>% filter(Category=='bar'), aes(x, y), col="green", shape=1)
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
I am trying to plot line charts from two data frames where first columns of both data frames are to be plotted in one frame and so forth. And finally all the plots are to be put under one subplot. But I am getting multiple legends with same symbols. The data frames are-
d1 <- data.frame(x = 1:5,
y = c(2, 3, 4, 1, 5),
z = c(2, 1, 4, 6, 8))
d2 <- data.frame(x = 1:5,
y = c(1, 5, 8, 9, 11),
z = c(3, 5, 8, 13, 11))
The code I am trying to generate the subplot is-
py <-
plot_ly(
x = d1$x,
y = d1$y,
type = "scatter",
mode = "lines",
name = names(d1)[2],
line = list(color = "#56B4E9")
) %>% add_trace(y = d2$y,
name = names(d1)[3],
line = list(color = "#D55E00"))
pz <-
plot_ly(
x = d1$x,
y = d1$z,
type = "scatter",
mode = "lines",
name = names(d1)[2],
line = list(color = "#56B4E9")
) %>% add_trace(y = d2$z,
name = names(d1)[3],
line = list(color = "#D55E00"))
subplot(py, pz)
The output is-
Is there any way to get rid of the duplicate legends?
Thanks in advance.
This can be achieved by first bringing the data in the right shape which also simplifies the plotting. Simply row bind your dfs e.g. via dplyr::bindrows and you have the variable you need for setting up the legendgroup. Also, your colors don't reflect the variables y and z but the datasets. Try this:
library(dplyr)
library(plotly)
d1 <- data.frame(x = 1:5,
y = c(2, 3, 4, 1, 5),
z = c(2, 1, 4, 6, 8))
d2 <- data.frame(x = 1:5,
y = c(1, 5, 8, 9, 11),
z = c(3, 5, 8, 13, 11))
# Bind the dfs
d3 <- bind_rows(list(d1 = d1, d2 = d2), .id = "id")
py <- d3 %>%
plot_ly(x = ~x, y = ~y, color = ~id, legendgroup= ~id) %>%
add_lines(colors = c("#D55E00", "#56B4E9"))
pz <- d3 %>%
plot_ly(x = ~x, y = ~z, color = ~id, legendgroup= ~id) %>%
add_lines(colors = c("#D55E00", "#56B4E9"), showlegend = FALSE)
subplot(py, pz) %>%
layout(legend=list(title=list(text='<b> Dataset </b>')))
Created on 2020-04-10 by the reprex package (v0.3.0)