I am trying to have a dropdown button within plotly that enables to use different columns of my dataframe for traces to be drawn. However, switching from the first trace to another, arbitrary values gets plotted (not sure what values plotly uses after the first change, but they don't match the dataframe values), the legend gets screwed up (colors are not unique anymore, labels are out of order, not all of the values are shown on the legend, etc.). You can see the plot in action at the link below on R-pubs.
https://rpubs.com/Mdoubledash/testplotlydropdown
What do I mean by not the right traces are drawn? Simply switching to A2 and going back to A1, you see that the plot looks different from the first render and there are duplicated colors/labels on the plot and the legend.
Here's the code I have used (see the reproducible data at the bottom). Here, I am adding 7 traces and then within the layout
argument I assign these 7 traces to the dropdown button.
ex_df %>%
plot_ly(x = ~Date, color = ~Model) %>%
add_lines(y = ~`A1`) %>%
add_lines(y = ~`A2`, visible = F) %>%
add_lines(y = ~`A3`, visible = F) %>%
add_lines(y = ~`B1`, visible = F) %>%
add_lines(y = ~`B2`, visible = F) %>%
add_lines(y = ~`C1`, visible = F) %>%
add_lines(y = ~`C2`, visible = F) %>%
layout(
title = "Plotly Dropdown Menus",
xaxis = list(domain = c(1, 1)),
yaxis = list(title = "Value"),
updatemenus = list(
list(y = 10,
buttons = list(
list(method = "restyle",
args = list("visible", list(T, F, F, F, F, F, F)),
label = "A1"),
list(method = "restyle",
args = list("visible", list(F, T, F, F, F, F, F)),
label = "A2"),
list(method = "restyle",
args = list("visible", list(F, F, T, F, F, F, F)),
label = "A3"),
list(method = "restyle",
args = list("visible", list(F, F, F, T, F, F, F)),
label = "B1"),
list(method = "restyle",
args = list("visible", list(F, F, F, F, T, F, F)),
label = "B2"),
list(method = "restyle",
args = list("visible", list(F, F, F, F, F, T, F)),
label = "C1"),
list(method = "restyle",
args = list("visible", list(F, F, F, F, F, F, T)),
label = "C2")
)
)
)
)
The code runs fine, and looks OK with the first render.
#dput(ex_df)
ex_df <- structure(list(Model = c("M_0", "M_1", "M_2", "M_3", "M_4", "M_5",
"M_0", "M_1", "M_2", "M_3", "M_4", "M_5",
"M_0", "M_1", "M_2", "M_3", "M_4", "M_5"),
Date = structure(c(1630512000, 1630512000, 1630512000,
1630512000, 1630512000, 1630512000,
1630512900, 1630512900, 1630512900,
1630512900, 1630512900, 1630512900,
1630513800, 1630513800, 1630513800,
1630513800, 1630513800, 1630513800),
tzone = "", class = c("POSIXct", "POSIXt")),
A1 = c(4.3924, 2.77967, 3.23016, 3.23016, 4.3924, 4.3924,
4.45712, 2.8175, 3.27791, 3.27789, 4.45715, 4.43708,
4.87661, 3.10666, 3.61006, 3.61005, 4.8779, 4.79372),
A2 = c(0.19052, 0.19052, 0.19052, 0.19052, 0.19052, 0.19052,
0.43156, 0.43156, 0.43156, 0.43163, 0.43156, 0.43156,
0.6055, 0.6055, 0.6055, 0.60551, 0.6055, 0.6055),
A3 = c(NA, 4.33173, 3.88124, 3.88124, 2.719, 2.719,
NA, 4.33173, 3.96342, 3.9293, 2.719, 2.719,
NA, 4.34133, 2.46357, 4.12238, 2.719, 2.719),
B1 = c(13.03056, 11.41784, 11.86833, 11.86833, 13.03056,13.03056,
13.02643, 11.41376, 11.86428, 11.86428,13.02643, 13.02643,
13.01181, 11.3972, 11.84812, 11.84812, 13.01181, 13.01093),
B2 = c(15.90011, 18.61912, 14.73789, 18.61912, 18.6191, 18.6191,
20.56435, 21.78546, 20.17156, 21.78857, 21.78544, 21.78544,
18.05423, 19.96631, 17.51721, 19.96667, 19.96629, 19.96629),
C1 = c(116.84061, 116.84061, 120.72184, 116.84061, 116.84061, 116.84062,
35.50683, 35.50684, 36.85026, 35.56428, 35.50684, 35.50679,
162.67923, 162.67924, 168.46906, 162.67662, 162.67924, 162.67929),
C2 = c(106.3359, 106.3359, 106.33588, 106.33589, 106.3359, 106.33603,
-24.20234, -24.20234, -25.43058, -24.17748, -24.20234, -24.20229,
345.84013, 345.84011, 332.59987, 345.83915, 345.84011, 345.84026)),
class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA, -18L))
The reason you're not seeing what you expect is because of how Plotly handles your data. Typically, Plotly will make a separate trace for each color. You created 7 traces; you have 6 unique values in Model
. You need around 42 T or F, but around doesn't work.
How many traces?
plt <- ex_df %>%
plot_ly(x = ~Date, color = ~Model) %>%
add_lines(y = ~A1) %>%
add_lines(y = ~A2, visible = F) %>%
add_lines(y = ~A3, visible = F) %>%
add_lines(y = ~B1, visible = F) %>%
add_lines(y = ~B2, visible = F) %>%
add_lines(y = ~C1, visible = F) %>%
add_lines(y = ~C2, visible = F)
plt <- plotly_build(plt)
length(plt$x$data)
# [1] 41
To determine which column doesn't have all colors, sometimes you can look at the name
and legendgroup
for the traces. However, when I looked, there were no legendgroup
designations. The Model
is the trace name.
You can look at this like so:
x <- invisible(lapply(1:length(plt$x$data),
function(i){
plt$x$data[[i]]$name
})) %>% unlist()
table(x)
# x
# M_0 M_1 M_2 M_3 M_4 M_5
# 6 7 7 7 7 7
I tried a few more things to determine which trace was missing a color.
funModeling::df_status(ex_df)
# A3 as has NA's; that's probably the one that's missing a color
ex_df[ , c(1, 5)] %>% na.omit() %>% select(Model) %>% unique()
# # A tibble: 5 × 1
# Model
# <chr>
# 1 M_1
# 2 M_2
# 3 M_3
# 4 M_4
# 5 M_5 # A3 is missing M_0
The layout, armed with the right info.
plt %>%
layout(
title = "Plotly Dropdown Menus",
xaxis = list(domain = c(1, 1)),
yaxis = list(title = "Value"),
updatemenus = list(
list(y = 10,
buttons = list(
list(method = "restyle",
args = list("visible", c(rep(T, 6), rep(F, 35))),
label = "A1"),
list(method = "restyle",
args = list("visible", c(rep(F, 6), rep(T, 6), rep(F, 29))),
label = "A2"),
list(method = "restyle",
args = list("visible", c(rep(F, 12), rep(T, 5), rep(F, 24))),
label = "A3"),
list(method = "restyle",
args = list("visible", c(rep(F, 17), rep(T, 6), rep(F, 18))),
label = "B1"),
list(method = "restyle",
args = list("visible", c(rep(F, 23), rep(T, 6), rep(F, 12))),
label = "B2"),
list(method = "restyle",
args = list("visible", c(rep(F, 33), rep(T, 6), rep(F, 6))),
label = "C1"),
list(method = "restyle",
args = list("visible", c(rep(F, 35), rep(T, 6))),
label = "C2")
) # end buttons list
)) # end updatemenus list
) # end layout
Looks good.
I ran another plot just to check.
ex_df %>%
plot_ly(x = ~Date, color = ~Model) %>%
add_lines(y = ~C2) %>%
layout(
title = "Plotly Dropdown Menus",
xaxis = list(domain = c(1, 1)),
yaxis = list(title = "Value"))