firmo23
firmo23

Reputation: 8454

Set the legend of a ggplotly() plot to have only the color and not the shape index

I have the dataframe below:

etf_id<-c("a","b","c","d","e","a","b","c","d","e","a","b","c","d","e")
factor<-c("A","A","A","A","A","B","B","B","B","B","C","C","C","C","C")
normalized<-c(-0.048436801,2.850578601,1.551666490,0.928625186,-0.638111793,
              -0.540615895,-0.501691539,-1.099239823,-0.040736139,-0.192048665,
              0.198915407,-0.092525810,0.214317734,0.550478998,0.024613778)
df<-data.frame(etf_id,factor,normalized)

and I create a ggplotly() boxplot with:

library(ggplot2)
library(plotly)
ggplotly(ggplot(data = df, aes(x = factor, y = normalized)) +
                   geom_boxplot(aes(fill = as.factor(factor)),outlier.colour = 'black') +
                   geom_point(data = df, position = position_dodge(0.75))+geom_point(data = df, 
                                                                                    aes(x = factor, y = normalized, shape = etf_id, color = etf_id), 
                                                                                     size = 2))

I take as a result a boxplot with this legend: enter image description here but I want my legend to have only the color distinction like below. Note that the factors wont be 3 every time but may vary from 1 to 8.

Upvotes: 1

Views: 2133

Answers (2)

lroha
lroha

Reputation: 34586

The recommended way to alter plotly elements is to use the style() function. You can identify the elements and traces by inspecting plotly_json().

I'm not sure if there's a more compact way, but you can achieve the desired result using:

p <- ggplotly(ggplot(data = df, aes(x = factor, y = normalized)) +
           geom_boxplot(aes(fill = as.factor(factor)),outlier.colour = 'black') +
           geom_point(data = df, position = position_dodge(0.75))+geom_point(data = df, 
                                                                             aes(x = factor, y = normalized, shape = etf_id, color = etf_id), 
                                                                             size = 2))

p <- style(p, showlegend = FALSE, traces = 5:9)
for (i in seq_along(levels(df$factor))) {
  p <- style(p, name = levels(df$factor)[i], traces = i)
}

p

Note that in this case the factor levels and traces align but that won't always be the case so you may need to adjust this (i.e. i + x).

enter image description here

Upvotes: 3

Ronak Shah
Ronak Shah

Reputation: 389175

One quick way would be to add show.legend = FALSE to supress the legend from showing.

library(ggplot2)

ggplot(data = df, aes(x = factor, y = normalized)) +
  geom_boxplot(aes(fill = as.factor(factor)),outlier.colour = 'black') +
  geom_point(position = position_dodge(0.75)) + 
  geom_point(aes(x = factor, y = normalized, shape = etf_id, color = etf_id), 
              size = 2, show.legend=FALSE)

enter image description here

Unfortunately, this does not work when this is passed to ggplotly. You can use theme(legend.position='none') which works but suppresses all the legends instead of specific ones. One dirty hack is to disable specific legend manually

temp_plot <- ggplotly(ggplot(data = df, aes(x = factor, y = normalized)) +
  geom_boxplot(aes(fill = as.factor(factor)),outlier.colour = 'black') +
  geom_point(position = position_dodge(0.75)) + 
  geom_point(aes(x = factor, y = normalized, shape = etf_id, color = etf_id),size = 2))

temp_plot[[1]][[1]][4:9] <- lapply(temp_plot[[1]][[1]][4:9], function(x) {x$showlegend <- FALSE;x})

temp_plot

enter image description here

Upvotes: 1

Related Questions