I want to make a stacked bar chart with a slider in plotly
.
I took inspiration from the plotly website.
I can't manage to insert the legend, maybe because I didn't use the legendgroup
argument correctly.
summary <- structure(list(Language = c("English", "English", "English", "English", "English", "English", "English", "English", "English", "English", "English", "English", "English", "German", "German", "German", "German", "German", "German", "German", "German", "German", "German", "German", "German", "German", "German"), category = structure(c(1L, 1L, 1L, 1L, 2L, 3L, 3L, 3L, 3L, 4L, 4L, 4L, 4L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 4L, 4L, 4L), levels = c("A", "B", "C", "D"), class = "factor"), Year = c(2000, 2001, 2002, 2003, 2002, 2000, 2001, 2002, 2003, 2000, 2001, 2002, 2003, 2000, 2001, 2002, 2003, 2000, 2001, 2003, 2000, 2001, 2002, 2003, 2001, 2002, 2003), n = c(20L, 39L, 41L, 53L, 1L, 3L, 12L, 8L, 22L, 2L, 11L, 17L, 18L, 44L, 29L, 38L, 46L, 1L, 3L, 3L, 2L, 1L, 2L, 4L, 1L, 3L, 3L)), row.names = c(NA, -27L), class = "data.frame")
library(plotly)
# Create data for different traces
traces <- list()
unique_years <- unique(summary$Year) %>% sort
unique_disciplines <- unique(summary$category)
n_colors <- length(unique_disciplines)
colors <- rainbow(n_colors)
for (i in 1:length(unique_years)) {
year <- unique_years[i]
trace <- list(
visible = FALSE,
name = paste0('Year = ', year),
x = summary$Language[summary$Year == year],
y = summary$n[summary$Year == year],
color = summary$category[summary$Year == year]
)
traces[[i]] <- trace
}
traces[[1]]$visible <- TRUE # Make the first trace visible by default
# Create steps for the slider
steps <- list()
for (i in 1:length(unique_years)) {
step <- list(
method = "restyle",
args = list("visible", rep(FALSE, length(traces))),
label = paste0('Year = ', unique_years[i])
)
step$args[[2]][i] <- TRUE
steps[[i]] <- step
}
# Create the graph
fig <- plot_ly()
for (i in 1:length(traces)) {
fig <- fig %>% add_bars(
type = 'bar',
x = traces[[i]]$x,
y = traces[[i]]$y,
visible = traces[[i]]$visible,
marker = list(color = colors[traces[[i]]$color]),
# The problem comes from the following line probably:
legendgroup = traces[[i]]$color
)
}
# Add the slider to the graph
fig <- fig %>% layout(
sliders = list(list(active = 1, currentvalue = list(prefix = "Year: "), steps = steps)),
yaxis = list(title = "Count"),
barmode = "stack"
)
# Display the graph
fig
I started going down the path of breaking down your code. I can still do that if this answer is not satisfying.
This does not use your code (just your data); however, it does accomplish your objective. You'll notice that there isn't much to it. With the code you're written and the knowledge needed to put that code together, I think you'll understand what I've done without any explanation. I've added comments in the code and you an always comment on my answer if you have any questions.
At the end of the code I used plt$x$layout$updatemenus = list()
. I did this because using frame
adds and populates the slider, but it also adds animation (which you were not asking for). This line of code removes the animation while keeping the slider.
library(plotly)
plt <- plot_ly(summary, type = "bar", color = ~category,
colors = ~setNames(rainbow(4), unique(category)), # colors by category
frame = ~Year, x = ~Language, y = ~n) %>%
layout(barmode = "stack") # stack bars
plt <- plotly_build(plt) # build plot to remove animation
plt$x$layout$updatemenus = list() # remove animation (keep slider)
plt