'R plotly with custom colorbar

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

enter image description here

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)

enter image description here

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)


Solution 1:[1]

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

enter image description here

enter image description here

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Kat