Adding color and bubble size legend in R plotly

2019-06-12 22:19发布

Probably an easy one.

I have an xy dataset I'd like to plot using R's plotly. Here are the data:

set.seed(1)
df <- data.frame(x=1:10,y=runif(10,1,10),group=c(rep("A",9),"B"),group.size=as.integer(runif(10,1,10)))

I'd like to color the data by df$group and have the size of the points follow df$group.size (i.e., a bubble plot). In addition, I'd like to have both legends added.

This is my naive attempt:

require(plotly)  
require(dplyr)  

    main.plot <-
 plot_ly(type='scatter',mode="markers",color=~df$group,x=~df$x,y=~df$y,size=~df$group.size,marker=list(sizeref=0.1,sizemode="area",opacity=0.5),data=df,showlegend=T) %>%
     layout(title="Title",xaxis=list(title="X",zeroline=F),yaxis=list(title="Y",zeroline=F))

which comes out as: enter image description here

and unfortunately messes up the legend, at least how I want it to be: a point for each group having the same size but different colors.

Then to add a legend for the group.size I followed this, also helped by aocall's answer:

legend.plot <- plot_ly() %>% add_markers(x = 1, y = unique(df$group.size),
                                size = unique(df$group.size),
                                showlegend = T, 
                                marker = list(sizeref=0.1,sizemode="area")) %>%
   layout(title="TITLE",xaxis = list(zeroline=F,showline=F,showticklabels=F,showgrid=F),
          yaxis=list(showgrid=F))

which comes out as: enter image description here

Here my problem is that the legend is including values that do not exist in my data.

then I combine them using subplot:

subplot(legend.plot, main.plot, widths = c(0.1, 0.9))

I get this: enter image description here

where the legend title is eliminated

So I'd be helpful for some help.

标签: r plotly legend
2条回答
爱情/是我丢掉的垃圾
2楼-- · 2019-06-12 22:45

Firstly, you are only passing in the unique values to the legend. If you pass in all possible values (ie, seq(min(x), max(x), by=1), or in this case seq_len(max(x))) the legend will show the full range.

Secondly, sizeref and sizemode in the marker argument alter the way that point size is calculated. The following example should produce a more consistent plot:

set.seed(1)
df <- data.frame(x=1:10,y=runif(10,1,10),group=c(rep("A",9),"B"),group.size=as.integer(runif(10,1,10)))

require(plotly)  
require(dplyr)  

a <- plot_ly(type='scatter',mode="markers",
    color=~df$group,
    x=~df$x,
    y=~df$y,
    size=df$group.size,
    marker = list(sizeref=0.1, sizemode="area"),
    data=df,
    showlegend=F) %>%
    layout(title="Title",
        xaxis=list(title="X",zeroline=F),
        yaxis=list(title="Y",zeroline=F))

b <- plot_ly() %>% add_markers(x = 1, y = seq_len(max(df$group.size)),
    size = seq_len(max(df$group.size)), 
    showlegend = F, 
    marker = list(sizeref=0.1, sizemode="area")) %>%
    layout(
        xaxis = list(zeroline=F,showline=F,showticklabels=F,showgrid=F),
        yaxis=list(showgrid=F))


subplot(b, a, widths = c(0.1, 0.9))
查看更多
【Aperson】
3楼-- · 2019-06-12 23:01

Based on the updated request:

Note the changes in legend.plot (mapping values to a sequence of integers, then manually changing the axis tick text), and the use of annotations to get a legend title. As explained in this answer, only one title may be used, regardless of how many subplots are used.

The circle on the plot legend seems to correspond to the minimum point size of each trace. Thus, I've added a point at (12, 12), and restricted the range of the axes to ensure it isn't shown.

titleX and titleY control the display of axis labels, as explained here.

set.seed(1)
df <- data.frame(x=1:10,y=runif(10,1,10),group=c(rep("A",9),"B"),group.size=as.integer(runif(10,1,10)))
require(plotly)  
require(dplyr)  


## Take unique values before adding dummy value
unique_vals <- unique(df$group.size)
df <- rbind(c(12, 12, "B", 1), df)
df[c(1, 2, 4)] <- lapply(df[c(1, 2, 4)], as.numeric)


main.plot <-
  plot_ly(type='scatter',
    mode="markers",
    color=~df$group,
    x=~df$x,
    y=~df$y,
    size=~df$group.size,
    marker=list(
        sizeref=0.1,
        sizemode="area",
        opacity=0.5),
        data=df,
        showlegend=T) %>%
  layout(title="Title",
    xaxis=list(title="X",zeroline=F, range=c(0, 11)),
    yaxis=list(title="Y",zeroline=F, range=c(0, 11)))

legend.plot <- plot_ly() %>% 
    add_markers(x = 1, 
    y = seq_len(length(unique_vals)),
    size = sort(unique_vals),
    showlegend = F, 
    marker = list(sizeref=0.1,sizemode="area")) %>%
    layout(
        annotations = list(
            list(x = 0.2, 
                y = 1, 
                text = "LEGEND TITLE", 
                showarrow = F, 
                xref='paper', 
                yref='paper')),
         xaxis = list(
            zeroline=F,
            showline=F,
            showticklabels=F,
            showgrid=F),
         yaxis=list(
            showgrid=F,
            tickmode = "array",
            tickvals = seq_len(length(unique_vals)),
            ticktext = sort(unique_vals)))


subplot(legend.plot, main.plot, widths = c(0.1, 0.9), 
    titleX=TRUE, titleY=TRUE)
查看更多
登录 后发表回答