Search code examples
rplotlylegendr-plotlymarkers

Plot_ly in R: How to include a colorbar, symbols and the size of markers in a legend?


I have a scatter plot with data points at the coodinates "test_Xn" & "test_Yn".

Additional informations about those data points is stored in the columns "Item_1", "Item_2" and "Item_3" of the data frame "test_data":

library(plotly)
test_Xn <- c(13, 7, 12, -7, -9, 8)
test_Yn <- c(3, -0.5, 6, 3, 11, 5)
test_data <- data.frame("Item_1"= c(2.6, 2.6, 1.6, 3.2, NA, 1.8), # scale: 1 to 6
                        "Item_2"= c(2.7, 1.8, 2.2, 2.8, 3.2, 2), # scale: 1 to 4
                        "Item_3"= c(1, 2, 1, 2, 1, 1)) # values: 1 or 2

Apart from the hoverinfo, to visualize the additional informations different colors, symbols or sizes of the markers are being used:

    test <- plotly::plot_ly(x = ~test_Xn, y = ~test_Yn, mode = "markers",
                        text = paste("<b>Item_1: </b>", test_data$Item_1,
                                     "<b>\nItem2: </b>", test_data$Item_2,
                                     "<b>\nItem2: </b>", test_data$Item_3),
                        hoverinfo = "text", 
                        marker = list(sizemode = "diameter",
                                      color = test_data[["Item_1"]],
                                      cmin = 1, cmax = 6,
                                      colorbar = list(titel = "Item_1",
                                                      xanchor = "left",
                                                      yanchor = "middle"),
                                      colorscale = "Viridis",
                                      size = ~ test_data[["Item_2"]]*25,
                                      symbol = ~ test_data[["Item_3"]]))

test_axis <- list(titel="", showgrid=T, showticklabels=T, zeroline=F)

test_plot <- plotly::layout(test, xaxis=test_axis, yaxis=test_axis)

print(test_plot)

The code above produces the following plot:

test_plot

Unfortunatley I have only been able to include the colorbar (scaled) as part of the legend. In the last days I was unable to find a solution for simultaniously including the size of the markers (scaled) and the symbol of the markers as part of the legend and plot, but I am sure there must be a solucion.

Thank you in advance.


Solution

  • You'll need to use subplot for legends this way :

    library(plotly)
    library(dplyr)
    
    ### Data ----
    test_Xn <- c(13, 7, 12, -7, -9, 8)
    test_Yn <- c(3, -0.5, 6, 3, 11, 5)
    test_data <- data.frame("Item_1"= c(2.6, 2.6, 1.6, 3.2, NA, 1.8), # scale from 1 to 6
                            "Item_2"= c(2.7, 1.8, 2.2, 2.8, 3.2, 2), # scale from 1 to 4
                            "Item_3"= c(1, 2, 1, 2, 1, 1)) # values 1 or 2
    
    
    ### Main plot ----
    main.plot <-
      plot_ly(type='scatter',
              mode="markers",
              # X and Y
              x=~test_Xn,
              y=~test_Yn,
              # Text on hover
              text = paste("<b>Item_1: </b>", test_data$Item_1,
                           "<b>\nItem2: </b>", test_data$Item_2,
                           "<b>\nItem2: </b>", test_data$Item_3),
              hoverinfo = "text",
              # Marker
              marker=list(
                sizemode = "diameter",
                # Color scale
                color = test_data[["Item_1"]],
                cmin = 1, cmax = 6,
                colorbar = list(
                  title = list(text='<b>Item_1</b>'),
                  xanchor = "left",
                  yanchor = "middle"
                ),
                colorscale = "Viridis",
                size = ~ test_data[["Item_2"]]*25,
                symbol = ~ test_data[["Item_3"]]
              ),
              showlegend=T
      ) %>% 
      layout(
        xaxis=list(titel="", showgrid=T, showticklabels=T, zeroline = F, showline= T, linewidth=2, linecolor='grey', mirror = T),
        yaxis=list(titel="", showgrid=T, showticklabels=T, zeroline = F, showline= T, linewidth=2, linecolor='grey', mirror = T),
        legend = list(
          traceorder="grouped"
        )
      )
    
    main.plot
    
    
    
    ### Legend plots :
    
    ### For size ----
    # Number of different sizes to show in size legend :
    numbersize = 4
    
    size.legend.plot <- plot_ly() %>% 
      add_markers(
        x = 1, 
        y = 1:numbersize,
        # Choose symbol : You can keep it circle here if you want, or choose between : c('circle', 'square', 'x', 'triangle')
        symbol = 1:4,
        symbols = rep("square",length(1:numbersize)),
        size = 1:4,
        showlegend = F,
        # disable hover
        hoverinfo="none",
        marker = list(sizeref=0.1,sizemode="area",
                      color = "#7C7C7C")
      )%>%
      layout(
        annotations = 
          list(
            list(
              x = 1, 
              y = 1, 
              text = "<b> Item_2</b>", 
              showarrow = F, 
              xref='paper', 
              yref='paper')),
        xaxis = 
          list(
          zeroline=F,
          showline=F,
          showticklabels=F,
          showgrid=F),
        yaxis=
          list(
            showgrid=F,
            tickmode = "array",
            tickvals = 1:4,
            ticktext = 1:4
          )
      )
    
    # This legend looks like:
    size.legend.plot
    
    ## Now, we can merge the two legends
    subplot(main.plot, size.legend.plot, widths = c(0.90, 0.10), 
            titleX=TRUE, titleY=TRUE)
    
    # We go for the second legend in the same analogy
    
    ### Legend for symbols
    # Choose your vector of symbols:
    symbol = 1:2
    
    # plot for this legend : 
    symbol.legend.plot <- plot_ly() %>% 
      add_trace(type = "scatter",
                x = 1, 
                y = symbol,
                symbol = ~symbol,
                mode = 'markers',
                showlegend = F,
                # disable hover
                hoverinfo="none",
                # Marker
                marker=list(
                  sizemode = "diameter",
                  # size = 0.5,
                  symbol = ~symbol,
                  color = "#7C7C7C",
                  size = 28
                )
      )%>%
      layout(
             annotations = 
               list(
                 list(
                   # Localization of annotation : adjustment of x & y
                   x = 0.5, 
                   y = 1, 
                   text = paste0("<b>",symbol[1],"</b>"),
                   showarrow = F, 
                   xref='paper', 
                   yref='paper'),
                 list(
                   x = 0.5, 
                   y = 0, 
                   text = paste0("<b>",symbol[2],"</b>"), 
                   showarrow = F, 
                   xref='paper', 
                   yref='paper')
               ),
             xaxis = 
               list(
                 zeroline=F,
                 showline=F,
                 showticklabels=F,
                 showgrid=F
               ),
             yaxis=
               list(
                 zeroline=F,
                 showline=F,
                 showticklabels=F,
                 showgrid=F
               )
      )
    
    # looks like
    symbol.legend.plot
    
    ### Put all together
    
    # Adjust with parameters for the design you want
    subplot(main.plot, symbol.legend.plot, size.legend.plot, widths = c(0.85,0.1, 0.05), 
            titleX=TRUE, titleY=TRUE)