It looks like you've got some great information so far. This addresses all of the things you identified. Although, at this point, it would be a LOT easier to just make the plot in Plotly!
The first thing I did is comment out the call for geom_text
and geom_label
. Plotly doesn't tend to play well here. It is going back into the plot, but not here.
Next, I built your plot and looked at the names and legend groups that were assigned by the conversion. This doesn't change anything—this is just looking.
plt2 <- plotly_build(plt)
invisible(
lapply(1:length(plt2$x$data),
function(j) {
message(j, " ", plt2$x$data[[j]]$name, " & ",
plt2$x$data[[j]]$legendgroup)
})
)
# 1 (sale,1) & (sale,1)
# 2 (share,1) & (share,1)
# 3 (cost,1) & (cost,1)
@Quinten addressed this issue, but this is how you can just look. Once I saw what Plotly "made", I was sure I knew what I needed to change.
This code changes these strings. It also prints the update to the console so that you can inspect what you expect.
invisible(
lapply(1:length(plt2$x$data),
function(j) {
x <- plt2$x$data[[j]]$name # find the name
y <- str_extract(x, "[a-z]+") # remove anything that's not a letter
plt2$x$data[[j]]$name <<- y # put it back
plt2$x$data[[j]]$legendgroup <<- y
message(j, " ", plt2$x$data[[j]]$name, " & ",
plt2$x$data[[j]]$legendgroup)
})
)
# 1 sale & sale
# 2 share & share
# 3 cost & cost
You can use this sort of look/change/check to validate the information that ends up in the tooltips, as well. Instead of $name
or $legendgroup
, you'll look at $text
.
This next chunk of code doesn't check the input and print it out (I figured that would be redundant). This just changes it. (I did use that process to build this though.)
tx = " "
invisible(
lapply(1:length(plt2$x$data),
function(k){
tx <<- plt2$x$data[[k]]$text # tooltip for each trace
lapply(1:length(tx),
function(m) {
tr <- strsplit(tx[[m]], "<br />") # tooltip for each point
tr2 <- unique(tr[[1]]) # remove redundancy
str <- paste0(tr2, collapse = "<br />")
tx[[m]] <<- str # put it back together
})
plt2$x$data[[k]]$text <<- tx # change the plot
})
)
Now on to the labels-if you want a background or border, you have to use annotations
in Plotly. Like annotation
in the ggplot package, annotations
in Plotly has less 'rules' per se.
You have an odd order for the model
, so that has to be addressed, as well. When data moves between ggplot and Plotly, things tend to be awry. So it's unlikely that you'd be able to connect to the original data.
One thing to keep in mind, I used paper space for the x-axis. The default paper space (domain) in Plotly is [0,1]. Your graph is evenly spaced along the x, with your values in the middle of each of the six categories, so everything on the x is in terms of 1/6th space.
So first, put the data in order as it needs to appear in the plot. Then add the annotations (labels) to the plot. I've also removed the name of the legend here.
# to add labels, we need to have the order the data appears on the plot
df2 <- df_long %>%
arrange(desc(value)) %>%
filter(name == "cost")
plt2 %>%
layout(legend = list(title = "")) %>% # remove legend name
add_annotations(x = c(1/12, 1/6 + 1/12, 1/3 + 1/12, # using domain for x-axis
1/2 + 1/12, 2/3 + 1/12, 5/6 + 1/12),
y = df2$value,
text = df2$value,
xshift = 20, # shift right 20 px
yshift = 15, # shift up 15 px
hoverinfo = "skip",
bgcolor = "white",
bordercolor = "black",
xref = "paper", yref = "y", # cat x, use domain for annot x
showarrow = F)
After all of that, here's your plot.


This is straight plotly. I think the labels would look a bit better with padding (which can be added).
df_long %>%
filter(name != "cost") %>%
plot_ly(x = ~model, y = ~value, color = ~name, type = "bar",
customdata = ~name, colors = c("blue", "gray"),
hovertemplate = paste0("Model: %{x}<br>Value: %{y}<br>",
"Name: %{customdata}<extra></extra>")) %>%
add_lines(inherit = F, data = df, x = ~model,
y = ~cost, color = I("red"),
name = "cost",
hovertemplate = paste0("Model: %{x}<br>Value: %{y}<br>",
"Name: cost<extra></extra>")) %>%
add_annotations(data = df, x = ~model, y = ~cost, text = ~cost,
bgcolor = "white", bordercolor = "black",
xshift = 15, yshift = 15, showarrow = F) %>%
layout(barmode = "group")
Pretty much the same as the converted plot.
