Related
I'm trying to set the colour in R for "points" or markers in plotly with a custom palette. It doesn't work. I'm also trying to add a title to the graph, but it won't appear. In addition, I'd like to remove some elements of the legend (like the extra "z") and add a title to the legend elements. Nothing seems to work, even if it is present in the code.
library(plotly)
library(tidyverse)
set.seed(123456)
pal <- c("black", "orange", "darkgreen", "pink")
pal <- setNames(pal, levels(as.factor(c("gr1","gr2","gr3","gr4"))))
linedat = data.frame(x = rep(mean(1:50),2),
y = rep(mean(1:50),2),
z = c(0,1))
zoom = 3
pg = plotly::plot_ly(x = 1:50,
y = 1:50,
z = outer(1:50,1:50,"+")/100) %>%
add_surface(contours = list(
z = list(show = TRUE, start = 0, end = 1, size = 0.05)),
opacity = 1) %>%
add_markers(x = rnorm(50,25,5),
y = rnorm(50,25,5),
marker = list(opacity = 0.9),
type="scatter3d",
mode = "markers",inherit = FALSE,
colors = pal,
color = as.factor(sample(1:4,50,replace = T)),
z = rbinom(50,1,.5)) %>%
layout(scene=list(title = "Title won't show up????",
xaxis = list(title = 'trait1'),
yaxis = list(title = 'trait1',autorange = "reversed"),
camera = list(eye = list(x = cos(0.8*pi)*zoom, y = sin(pi*1.3)*zoom, z= 2.00)),
legend = list(title=list(text='<b> Groups </b>')))) %>%
add_trace(data=linedat, x=~x, y=~y, z=~z,
type="scatter3d", mode="lines",
line = list(color = pal[1],
width = 14),name = "Avg. data1")%>%
add_trace(data=linedat, x=~x+20, y=~y+20, z=~z,
type="scatter3d", mode="lines",
line = list(color = pal[4],
width = 14),name = "Avg. data2")
pg
See how here I'm able to set the colour of the points, but I'm not able to get the names of the colours to show in the legend (I modified the code to match what #Kat suggested):
library(plotly)
library(tidyverse)
set.seed(123456)
pal <- c("black", "orange", "darkgreen", "pink")
pal <- setNames(pal, levels(as.factor(c("gr1","gr2","gr3","gr4"))))
linedat = data.frame(x = rep(mean(1:50),2),
y = rep(mean(1:50),2),
z = c(0,1))
zoom = 3
pg = plotly::plot_ly(x = 1:50,
y = 1:50,
z = outer(1:50,1:50,"+")/100) %>%
add_surface(contours = list(
z = list(show = TRUE, start = 0, end = 1, size = 0.05)),
opacity = 1, colorbar = list(title = "Only one Z")) %>%
add_markers(x = rnorm(50,25,5),
y = rnorm(50,25,5),
marker = list(color = pal[as.factor(sample(1:4,50,replace = T))],opacity = 0.9),
type="scatter3d",
mode = "markers",inherit = FALSE,
colors = pal,
z = rbinom(50,1,.5)) %>%
layout(title = "Title that won't show",
margin = list(t = 40),
legend = list(title = list(
text = "<br>Legends deserve names, too")),
scene=list(xaxis = list(title = 'trait1'),
yaxis = list(title = 'trait1',autorange = "reversed"),
camera = list(eye = list(x = cos(0.8*pi)*zoom,
y = sin(pi*1.3)*zoom, z= 2.00)))) %>%
add_trace(data=linedat, x=~x, y=~y, z=~z,
type="scatter3d", mode="lines",
line = list(color = pal[1],
width = 14),name = "Avg. data1")%>%
add_trace(data=linedat, x=~x+20, y=~y+20, z=~z,
type="scatter3d", mode="lines",
line = list(color = pal[4],
width = 14),name = "Avg. data2");pg
Your original plot_ly call and add_trace calls can remain as is. I've included the changes needed for the layout call and added the call needed for colorbar.
The layout first.
layout(title = "Title that won't show", # <------ give my plot a name
margin = list(t = 40), # don't smash that title, either
legend = list(title = list(
text = "<br>Legends deserve names, too")), # <--- name my legend
scene=list(title = "Title won't show up????", # <- this can go away
xaxis = list(title = 'trait1'),
yaxis = list(title = 'trait1',autorange = "reversed"),
camera = list(eye = list(x = cos(0.8*pi)*zoom,
y = sin(pi*1.3)*zoom, z= 2.00)),
legend = list(title=list(text='<b> Groups </b>')))) %>%
colorbar(title = "Only one Z") # <--- give me one z colorbar title
(Some colors are different in the image; I didn't realize I had the pal object...sigh)
Update
This addresses your additional questions.
First, I'm not getting an error from the method in which I title the color bar. You'll have to share what error you're getting.
I didn't realize that it was ignoring the colors you set in markers, either. The easiest way to address this is to call that trace first. Since nothing else was declared within markers, I called opacity outside of the list, but it's fine the way you have it.
First, I commented out the setNames call, because that won't work for the marker's trace and it doesn't matter to the other traces.
library(plotly)
set.seed(123456)
pal <- c("black", "orange", "darkgreen", "pink")
# pal <- setNames(pal, levels(as.factor(c("gr1","gr2","gr3","gr4"))))
linedat = data.frame(x = rep(mean(1:50),2),
y = rep(mean(1:50),2),
z = c(0,1))
zoom = 3
I made plot_ly() empty and put all the data for the surface in that trace. I also added inherit = false so that the layout could go at the end without the data errors.
set.seed(123456)
pg = plotly::plot_ly() %>%
add_trace(inherit = F,
x = rnorm(50,25,5),
y = rnorm(50,25,5),
type="scatter3d",
mode = "markers",
opacity = .8,
colors = pal,
color = as.factor(sample(1:4, 50, replace = T)),
z = rbinom(50,1,.5)) %>%
add_surface(x = 1:50,
y = 1:50,
z = outer(1:50,1:50,"+")/100,
colorscale = "Viridis",
contours = list(
z = list(show = TRUE, start = 0, end = 1, size = 0.05)),
opacity = 1) %>%
add_trace(data=linedat, x=~x, y=~y, z=~z,
type="scatter3d", mode="lines",
line = list(color = pal[1],
width = 14),name = "Avg. data1", inherit = F) %>%
add_trace(data=linedat, x=~x+20, y=~y+20, z=~z,
type="scatter3d", mode="lines",
line = list(color = pal[4],
width = 14),name = "Avg. data2", inherit = F) %>%
The last part is the layout, but this is not different than my original answer.
layout(title = "Title that won't show", # <------ give my plot a name!
margin = list(t = 40), # don't smash that title, either
legend = list(title = list(
text = "<br>Legends deserve names, too"),
tracegroupgap = 350), # <--- name my legend!
scene=list(title = "Title won't show up????", # <--- this can go away!
xaxis = list(title = 'trait1'),
yaxis = list(title = 'trait1',autorange = "reversed"),
camera = list(eye = list(x = cos(0.8*pi)*zoom,
y = sin(pi*1.3)*zoom, z= 2.00)),
legend = list(title=list(text='<b> Groups </b>')))) %>%
colorbar(title = "Only one Z") # <--- give me one z for the title!
pg
I am trying to reproduce a graph generated via ggplotly with plot_ly. I am struggling however with the colorbar.
This is the ggploty plot that I would like to reproduce, and in particular the colorbar:
library(plotly)
X <- data.frame(w = rep(c("a", "b"), each = 8),
x = 1:16,
y = 1:16,
z = c(1, 1:13, 13, 13))
X$z_scaled <- (X$z-min(X$z))/(max(X$z)-min(X$z)) # scale to 0-1
# ggplot
gg <- ggplot(X) +
geom_point(aes(x, y, color = z_scaled, alpha = w, text = paste0(x, ", ", y))) +
scale_color_gradient2(low = '#0d71db', mid = "#dbc00d", high = '#db220d',
midpoint = .5, breaks = 0:1, limits = 0:1) +
scale_alpha_manual(name = " ", values = rep(1, nrow(X))) +
labs(color = "Z", x = "", y = "")
ggplotly(gg, type = "scattergl", tooltip = "text") %>% toWebGL()
This is what I have with plot_ly:
length_unique_vals <- length(unique(X$z))
.colors <- colorRampPalette(c('#0d71db', "#dbc00d", "#db220d"))(length_unique_vals)
.colors <- .colors[factor(X$z)]
plot_ly() %>%
add_markers(
data = X, x = ~x, y = ~y,
split = ~w,
text = ~paste0(x, ", ", y),
hoverinfo = "text",
type = "scattergl",
mode = "markers",
marker = list(
# color = ~z_scaled,
color = .colors,
# colorscale = list(c(0, .5, 1), c("#0d71db", "#dbc00d", "#db220d")),
colorscale = .colors,
hoverlabel = list(bgcolor = .colors),
colorbar = list(
title = list(text = "Z"),
len = .5,
x = 1,
y = .7
)
)
) %>%
layout(
legend = list(x = 1, y = .4, bgcolor = 'rgba(255,255,255,0.6)')
) %>% toWebGL() %>% partial_bundle(local = FALSE)
As you can see, the colorbar is not displaying correctly. I have tried multiple possibilities (commented above) without success. What am I missing?
Edit
#Kat's answer solves the colorbar issue. However, if you want to use scattergl or toWebGl you will need to fix the hoverlabel background so it remains dynamic. Here is a solution for that below building on her answer.
length_unique_vals <- length(unique(X$z))
.colors <- colorRampPalette(c('#0d71db', "#dbc00d", "#db220d"))(length_unique_vals)
.colors <- .colors[factor(X$z)]
plot_ly() %>%
add_trace(x = ~x,
y = ~y,
split = ~w, # instead of alpha or opacity
data = X,
type = "scattergl",
mode = "markers",
color = ~z_scaled, # color = var and colors = literal colors
colors = c('#0d71db', "#dbc00d", '#db220d'),
hoverlabel = list(bgcolor = .colors)) %>% # Fix hovercolor bg
layout(xaxis = list(title = "",
dtick = 4,
zeroline = F,
gridcolor = "white"), # white on gray
yaxis = list(title = "",
dtick = 4,
zeroline = F,
gridcolor = "white"), # white on gray
plot_bgcolor = "#eeeeee") %>% # gray background
colorbar(title = "Z", # colorbar title
dtick = c(0, 1), # colorbar ticks
thickness = 25) %>% # width
toWebGL() %>% partial_bundle(local = FALSE)
Edit 2
The hoverlabel bgcolor breaks down then the split factor is not ordered. This is why it needs to be ordered first.
library(plotly)
library(data.table)
X <- data.table(w = rep(c("a", "b"), 8), #not ordered
x = 1:16,
y = 1:16,
z = c(1, 1:13, 13, 13))
X[, z_scaled := (X$z-min(X$z))/(max(X$z)-min(X$z))] # scale to 0-1
# Get colors for hoverlabel bgcolor
X <- X[order(w)]
length_unique_vals <- length(unique(X$z))
.colors <- colorRampPalette(c('#0d71db', "#dbc00d", "#db220d"))(length_unique_vals)
.colors <- .colors[factor(X$z)]
plot_ly() %>%
add_trace(x = ~x,
y = ~y,
split = ~w, # instead of alpha or opacity
data = X,
type = "scattergl",
mode = "markers",
color = ~z_scaled, # color = var and colors = literal colors
colors = c('#0d71db', "#dbc00d", '#db220d'),
hoverlabel = list(bgcolor = .colors),
marker = list(size = 10)) %>% # Fix hovercolor bg
layout(xaxis = list(title = "",
dtick = 4,
zeroline = F,
gridcolor = "white"), # white on gray
yaxis = list(title = "",
dtick = 4,
zeroline = F,
gridcolor = "white"), # white on gray
plot_bgcolor = "#eeeeee") %>% # gray background
colorbar(title = "Z", # colorbar title
dtick = c(0, 1), # colorbar ticks
thickness = 25) %>% # width
toWebGL() %>% partial_bundle(local = FALSE)
Assuming you even wanted the gray background, this should work. If something isn't clear or not what you were looking for, let me know.
You don't even need the text, because you specified the default hover content.
plot_ly() %>%
add_trace(x = ~x,
y = ~y,
split = ~w, # instead of alpha or opacity
data = X,
type = "scatter",
mode = "markers",
color = ~z_scaled, # color = var and colors = literal colors
colors = c('#0d71db', "#dbc00d", '#db220d')) %>%
layout(xaxis = list(title = "",
dtick = 4,
zeroline = F,
gridcolor = "white"), # white on gray
yaxis = list(title = "",
dtick = 4,
zeroline = F,
gridcolor = "white"), # white on gray
plot_bgcolor = "#eeeeee") %>% # gray background
colorbar(title = "Z", # colorbar title
dtick = c(0, 1), # colorbar ticks
thickness = 25) # width
How can I reproduce the following graph in plotly
library(dplyr)
library(ggplot2)
tibble(x =1:10, y = 1:10) %>%
ggplot(aes(x,y)) +
geom_line() +
scale_y_continuous(sec.axis = ~.*2)
I tried the following code based on this answer here
library(dplyr)
library(plotly)
tibble(x =1:10, y = 1:10) %>%
mutate(y2 = y*2) %>%
plot_ly() %>%
add_lines(x =~x, y =~y) %>%
add_lines(x= ~x, y=~y2,
yaxis = "y2", color = I("transparent"),
hoverinfo='skip', showlegend=FALSE) %>%
layout(yaxis2 = list(side = "right", overlaying = "y", showgrid = FALSE),
margin = list(r = 50))
While at first glance it appears to work, it only provides a partial solution, since if I interactively try to change the scale of the main (left) y axis on the produced graph (by dragging it up or down), the right axis does not move with the graph (because it is linked only to the second invisible graph). This of course is not acceptable as it does not allow using any of interactive features of plotly reliably which is the reason I wanted to use it to begin with instead of ggplot.
Edit: Just realized that this plotly solution does not seem to work at all in the case of non linear transformation between the axes (while ggplot handles it beautifully).
You just need to set up dtick and tick0 for plotly to have the same graph as ggplot2 one. See below;
library(plotly)
library(dplyr)
tibble(x =1:10, y = 1:10) %>%
mutate(y2 = y*2) -> df1
n0 <- 4
y0 <- max(df1$y)/n0
x0 <- max(df1$x)/n0
df1 %>%
plot_ly(data = . , x = ~x, y = ~y,
type = "scatter", mode = "lines", width = 800,
color = I("red"), name = "") %>%
add_trace(x = ~x, y = ~y2, yaxis = "y2",
color = I("red"), name = "") %>%
layout(yaxis = list(showline = FALSE, side = "left",
title = "", color = "red",
dtick = y0, tick0 = y0, fixedrange=TRUE),
yaxis2 = list(showline = FALSE, side = "right", overlaying = "y", position = 1,
title = "", anchor = "free", color = "blue",
dtick = 2*y0, tick0 = 2*y0, fixedrange=TRUE),
xaxis = list(showline = FALSE, zeroline = FALSE, title = "",
dtick = x0, tick0 = x0),
showlegend = FALSE,
margin = list(l = 50, r = 50, b = 50, t = 50, pad = 4)
)
Created on 2020-06-19 by the reprex package (v0.3.0)
I have the following code producing a scatter plot and I would like to add both vertical and horizontal lines representing the mean values of the y axis and x axis, how could I do that?
f <- list(
family = "Courier New, monospace",
size = 18,
color = "#7f7f7f"
)
x <- list(
title = "Age of Buildings",
titlefont = f,
zeroline = FALSE,
showline = FALSE,
showticklabels = TRUE,
showgrid = TRUE
)
y <- list(
title = "Total Violations",
titlefont = f,
zeroline = FALSE,
showline = FALSE,
showticklabels = TRUE,
showgrid = TRUE
)
fig2 <- plot_ly(final, x=~agebuilding, y=~violationstotal, mode= "markers", color = ~INdexrehabless6, size = ~totalvalue)
fig2 <- fig2 %>% layout(xaxis = x, yaxis = y, legend=list(title=list(text='<b> Housing Conditions </b>'))) #chaging name legend
fig2
Here is the plot I get
Using some random data for your df final. I don't know whether plotly provides some kind of geom_h/vline ... Instead I constructed the lines using dataframes which contain the start and the end point of the lines. Have a look:
set.seed(50)
final <- data.frame(
agebuilding = 150 * runif(50),
violationstotal = 30 * runif(50),
INdexrehabless6 = factor(sample(0:1, 50, replace = TRUE)),
totalvalue = 100 * runif(50)
)
mean_x <- data.frame(x = rep(mean(final$agebuilding), 2), y = c(0, ceiling(10* max(final$violationstotal))/10))
mean_y <- data.frame(y = rep(mean(final$violationstotal), 2), x = c(0, ceiling(10* max(final$agebuilding))/10))
library(plotly)
fig2 <- plot_ly(final) %>%
add_markers(x=~agebuilding, y=~violationstotal, color = ~INdexrehabless6, size = ~totalvalue) %>%
add_lines(x = ~x, y = ~y, data = mean_x, name = "Mean x") %>%
add_lines(x = ~x, y = ~y, data = mean_y, name = "Mean y")
fig2 <- fig2 %>% layout(xaxis = x, yaxis = y, legend=list(title=list(text='<b> Housing Conditions </b>'))) #chaging name legend
fig2
I have a list of figures created with R's plotly, just as an example:
library(plotly)
library(dplyr)
set.seed(1)
data.df <- data.frame(val = c(rnorm(100,0,1),rnorm(100,1,1)), group = c(rep("A",100),rep("B",100)))
density.df <- do.call(rbind,lapply(levels(data.df$group),function(g){
dens <- density(dplyr::filter(data.df,group == g)$val)
data.frame(x = dens$x, y = dens$y, group = g)
}))
plot.list <- lapply(1:5,function(x)
plot_ly(x = density.df$x, y = density.df$y, type = 'scatter', mode = 'lines',color = density.df$group, showlegend = (x == 5)) %>%
layout(xaxis = list(title= "Value", zeroline = F), yaxis = list(title = "Density", zeroline = F))
)
Which I'd like to put together horizontally, where there will be only a single shared x-axis label and a single shared y-axis label.
I'm using:
plotly::subplot(plot.list, nrows = 1, shareX = T, shareY = T, titleX = T, titleY = T)
And getting:
Is it not possible to get a single x-axis label in a horizontal plot?
The same occurs for the y-axis label if I change the nrows argument value from 1 to 5.
You can manually add an annotation
https://community.plot.ly/t/subplots-how-to-add-master-axis-titles/13927/5
myplotly(df) %>%
add_annotations(
text = "my x title",
x = 0.5,
y = 0,
yref = "paper",
xref = "paper",
xanchor = "center",
yanchor = "bottom",
yshift = -35,
showarrow = FALSE,
font = list(size = 15)
)