Color code a scatter plot by group with a gradient

爷,独闯天下 提交于 2020-01-02 07:11:16

问题


I have XY data which I'd like to graph using a scatter plot, with R's plotly package.

set.seed(1)
df <- data.frame(x=c(rnorm(30,1,1),rnorm(30,5,1),rnorm(30,9,1)),
                 y=c(rnorm(30,1,1),rnorm(30,5,1),rnorm(30,9,1)),
                 group=c(rep("A",30),rep("B",30),rep("C",30)),score=runif(90,0,1))

Each point is assigned to one of three groups (df$group) and has a score in the [0,1] range.

I'm looking for a way to graph the data such that each group is colored with a different color but the shade of that color (or intensity) reflects the score.

So I thought this would work:

library(dplyr)
library(plotly)

    plot_ly(marker=list(size=10),type='scatter',mode="markers",x=~df$x,y=~df$y,color=~df$score,colors=c("#66C2A5","#FC8D62","#8DA0CB")) %>%
  layout(xaxis=list(title="X",zeroline=F,showticklabels=F),yaxis=list(title="Y",zeroline=F,showticklabels=F))

But I get:

If I just color code by group:

plot_ly(marker=list(size=10),type='scatter',mode="markers",x=~df$x,y=~df$y,color=~df$group,colors=c("#66C2A5","#FC8D62","#8DA0CB")) %>%
      layout(xaxis=list(title="X",zeroline=F,showticklabels=F),yaxis=list(title="Y",zeroline=F,showticklabels=F))

I get:

So it looks like it is mixing the group colors and the score gradient.

What I'm looking for is to have the bottom left group colored in shades of green (say from gray to darkgreen) that correspond to score (low to high), and the same for the two other groups in orange and blue, respectively.


回答1:


Using scales::colour_ramp you can create the colours yourself with a quick function. I'm not sure how else to get different gradients happening within each group. Note I'm using df$score = df$x + df$y here to make the mapping more obvious.

make_colour_gradient = function(x, brewer_palette = "Greens") {
    min_x = min(x)
    max_x = max(x)
    range_x = max_x - min_x
    x_scaled = (x - min_x) / range_x

    # Chopping out first colour as it's too light to work well as a
    #   point colour
    colours = scales::brewer_pal("seq", brewer_palette)(5)[2:5]

    colour_vals = scales::colour_ramp(colours)(x_scaled)
    colour_vals
}

df$score = df$x + df$y

df = df %>%
    # Assign a different gradient to each group, these are the names
    #   of different palettes in scales::brewer_pal
    mutate(group_colour = case_when(
        group == "A" ~ "Greens",
        group == "B" ~ "Oranges",
        group == "C" ~ "Purples"
    )) %>%
    group_by(group) %>%
    mutate(point_colour = make_colour_gradient(score, first(group_colour)))


plot_ly(marker=list(size=10),type='scatter',mode="markers",
        x=~df$x,y=~df$y,color=~ I(df$point_colour)) %>%
    hide_colorbar() %>%
    layout(xaxis=list(title="X",zeroline=F,showticklabels=F),
           yaxis=list(title="Y",zeroline=F,showticklabels=F))

Result:

This does bring up error messages but they don't seem to be important? Adding a legend to this would probably be tricky.




回答2:


I'm not an expert in plotly, however, you could also use the alpha argument in ggplot and to achieve the same result and then convert the ggplot object to plotly. I know there is also an alpha argument in plotly, however, I found it a little difficult.

g <- ggplot(df, aes(x,y))+
    geom_point(aes(color = group, alpha = score), size = 3)+
    scale_color_manual(values = c("#66C2A5","#FC8D62","#8DA0CB"))+
    scale_alpha_continuous(range = c(0.3,1))+
    theme(panel.background = element_blank(),
        axis.text = element_blank(),
        axis.ticks = element_blank(),
        legend.position = "none")
gp <- ggplotly(g)
gp

I couldn't get the legend to format nicely with plotly, however in ggplot, we can keep the legend (omit the legend.position = "none") and we get the following:

You can also increase the number of different shades using the breaks argument in scale_alpha_continuous.



来源:https://stackoverflow.com/questions/51433666/color-code-a-scatter-plot-by-group-with-a-gradient

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!