Reputation: 1345
I have an R Plotly subplot graph with the issue that the trace legends are duplicates:
This is a common problem:
Some of these have (ir)relevant answers, some don't.
The solution in essence is to force the first subplot to show the legend and disable it for all other subplots. However, the way to do this depends on the implementation, i.e. whether the subplots are generated using a list or a function. In my case I am using a function which makes it tricky to force one subplot to show the legends but not the others.
A minimum working example:
# clear env
rm(list = ls())
# libraries
library(plotly)
library(reshape2)
# prepare dataset
attach(mtcars)
mtcars$car <- rownames(mtcars)
mtcars <- melt(mtcars)
# generate plot of variable
pl <- . %>%
plot_ly(
x = ~car,
y = ~value,
type = 'scatter',
mode = 'markers',
color = I('blue'),
name = 'value',
legendgroup = 'batches',
showlegend = TRUE
) %>%
layout(
xaxis = list(
type = 'category'
),
yaxis = list(
title = ~unique(variable)
)
)
# generate subplot view
mtcars %>%
group_by(variable) %>%
do(
p = pl(.)
) %>%
subplot(
nrows = NROW(.),
shareX = TRUE,
titleY = TRUE
)
This generates the image above.
In my attempt I have been trying to use a closure with a global variable which is set to FALSE after the first subplot but it is not working as expected. All legend entries disappear despite seeing in the console it is setting the global variable correctly.
# set global showlegend variable
# we will set to FALSE after first plot
showlegend <- TRUE
# generate plot of variable
pl <- . %>%
plot_ly(
x = ~car,
y = ~value,
type = 'scatter',
mode = 'markers',
color = I('blue'),
name = 'value',
legendgroup = 'batches',
# use a closure to set showlegend
showlegend = (function(){
# echo to console
print(showlegend)
if(showlegend){
# at first plot this will run
# set to FALSE for subsequent plots
showlegend <<- FALSE
return(TRUE)
} else {
# runs for all except first
return(FALSE)
}
})()
) %>%
layout(
xaxis = list(
type = 'category'
),
yaxis = list(
title = ~unique(variable)
)
)
while the console outputs: TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE
based on this I expect there to be one legend entry, but the graph shows no legend entries. Why is this not working as expected?
Is there perhaps a more efficient way to toggle the showlegend variable without a closure and global variable?
Upvotes: 2
Views: 2616
Reputation: 1345
After thinking about the problem some more I realized that perhaps Plotly removes single legend entries, i.e. only legends are shown when more than one traces with a legend are plotted.
And indeed when adding an additional trace the graph shows the legends as expected.
Solution:
# set global showlegend variable
# we will set to FALSE after first plot
showlegend <- TRUE
# generate plot of variable
pl <- . %>%
plot_ly(
x = ~car,
y = ~value,
type = 'scatter',
mode = 'markers',
color = I('blue'),
name = 'value',
legendgroup = 'batches',
showlegend = showlegend
) %>%
add_trace(
y = ~value,
name = 'target',
type='scatter',
mode = 'lines',
line=list(
color='black',
dash='dash'
),
showlegend = (function(){
if(showlegend){
showlegend <<- FALSE
return(TRUE)
} else {
return(FALSE)
}
})()
) %>%
layout(
xaxis = list(
type = 'category'
),
yaxis = list(
title = ~unique(variable)
)
)
Note that the closure must be applied to the last trace plotted otherwise the global variable is set to FALSE too early.
Update: During testing i found that the following also works:
showlegend = (~unique(variable) == "mpg")
or if you do not want to hardcode the variable comparison:
showlegend = (~unique(variable) == unique(mtcars$variable)[1])
This is now my preferred method over the global variable closure
Upvotes: 2