Reputation:
I have data of sales by year and model, which is visualized via Sankey chart and plotly (Previous question). However, I have some issues concerning hover which I want to handle. More precisely hover only shows model but not sales information each year:
If we turn the hover to the second mode, it traces everything together but model: F is accidentally shown on the chart for no reason:
Code:
df <- data.frame (model = c("A","B","C","D","E","F","G","H","I","J","A","B","C","D","E","F","G","H","I","J","A","B","C","D","E","F","G","H","I","J","A","B","C","D","E","F","G","H","I","J","A","B","C","D","E","F","G","H","I","J","A","B","C","D","E","F","G","H","I","J"),
Year = c(2015,2015,2015,2015,2015,2015,2015,2015,2015,2015,2016,2016,2016,2016,2016,2016,2016,2016,2016,2016,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2018,2018,2018,2018,2018,2018,2018,2018,2018,2018,2019,2019,2019,2019,2019,2019,2019,2019,2019,2019,2020,2020,2020,2020,2020,2020,2020,2020,2020,2020),
sales = c(450,678,456,344,984,456,234,244,655,789,234,567,234,567,232,900,1005,1900,450,345,567,235,456,345,144,333,555,777,111,444,222,223,445,776,331,788,980,1003,456,434,345,2222,3456,456,678,8911,4560,4567,4566,5555,6666,7777,8888,1233,1255,5677,3411,2344,6122,4533))
##################################################################################################
library(ggsankey)
library(tidyverse)
library(plotly)
# df from the question is unchanged
# visualize the original
(plot <- ggplot(df,
aes(Year, node = model, fill = model, value = sales)) +
geom_sankey_bump(space = 0, type = "alluvial",
color = "transparent", smooth = 15) +
scale_fill_viridis_d(option = "A", alpha = .8) +
theme_sankey_bump(base_size = 16))
ggplotly(plot) -> plp
plp
#-------- colors --------
# collect the 10 colors
cols <- map_dfr(1:10, function(k){
nm <- plp$x$data[[k]]$name
filler <- plp$x$data[[k]]$fillcolor
c(nm = nm, filler = filler)
})
##################################################################################################
#--------------- collect values for hovertext positions ----------
x <- plp$x$data[[1]]$x
inds <- which(x %in% 2015:2020, arr.ind = T)
yrs <- x[inds]
tellMe <- invisible(
map(1:length(plp$x$data),
function(m) {
y <- plp$x$data[[m]]$y
y[inds]
}) %>% setNames(sort(unique(df$model))) %>% # changed from LETTERS[1:10]
as.data.frame() %>%
mutate(yr = yrs %>% as.integer()) %>%
pivot_longer(names_to = "model", values_to = "sales",
cols = sort(unique(df$model))) %>%
distinct() %>%
group_by(yr, model) %>%
summarise(val = mean(sales)) %>%
left_join(df, by = c("yr" = "Year", "model" = "model")) %>%
as.data.frame() # drop groups
)
#-------------- create data trace for hovertext --------------
plot_ly(tellMe, x = ~yr, y = ~val, split = ~model,
customdata = ~sales, text = ~model,
line = list(width = .01, shape = "spline", smoothing = 1.3),
hovertemplate = "Year: %{x}<br>Model: %{text}<br>Sales: %{customdata}<extra></extra>",
type = "scatter", mode = "lines", showlegend = F) -> pp2
pp2
##################################################################################################
# change colors to match sankey
pp2 <- plotly_build(pp2)
invisible(
map(1:10,
function(z) {
nm <- pp2$x$data[[z]]$name
# collect and assign the color
cr <- unlist(cols[cols$nm == nm, "filler"], use.names = F)
pp2$x$data[[z]]$line$color <<- cr
})
)
#################################################################################################################################
#-------------- consolidate the traces (subplot won't work) -----------
# collect data one more time!
dx <- plp$x$data
yx <- pp2$x$data
yx <- append(yx, dx) # put plt on top
# replace data
plp$x$data <- yx
# lines are small, increase the distance searched for matches
plp %>% layout(hoverdistance = 40)
Upvotes: 2
Views: 525
Reputation: 18714
Right before you call the plot, you could use this to remove the hover data that only includes "Model ..."
It seems that if you do it and then do a bunch of manipulation, you get some odd results, like Plotly re-adding this information. So this has to be done towards the end.
invisible(map(
1:length(plp$x$data),
function(k){
x <- length(plp$x$data[[k]]$x)
if(x > 3000) {
plp$x$data[[k]]$text <<- NULL
plp$x$data[[k]]$hoverinfo <<- "none"
}
}
))
Without the other label, you could improve the hover response with a larger increase in hoverdistance
.
plp %>% layout(hoverdistance = 80)
Upvotes: 2