RoyalTS RoyalTS - 4 months ago 123
R Question

Custom discrete color scale in plotly

I would like to customize the colors in a

plotly
plot. This works fine for continuous variables and scales as per the docs:

library(plotly)

plot_ly(iris, x = Petal.Length, y = Petal.Width,
color = Sepal.Length, colors = c("#132B43", "#56B1F7"),
mode = "markers")


If I make the argument to color discrete (character or factor), however, this still works but throws a warning:

> plot_ly(iris, x = Petal.Length, y = Petal.Width,
color = Sepal.Length>6, colors = c("#132B43", "#56B1F7"),
mode = "markers")


Warning message:
In RColorBrewer::brewer.pal(N, "Set2") :
minimal value for n is 3, returning requested palette with 3 different levels


How do I do this correctly?

Answer

This isn't a plotly issue, but a design feature of ColorBrewer (and the associated RColorBrewer package). You'll notice that the warning disappears when you assign color to factors with equal to or more than three levels, e.g.

plot_ly(iris, x = Petal.Length, y = Petal.Width,
        color = cut(Sepal.Length, 3), colors = "Set1",
        mode = "markers")

This is because ColorBrewer's minimum number of data classes is three (which you can see from http://colorbrewer2.org/ where can't select fewer than three classes). For instance, in ?brewer.pal (the function referenced by plotly), it specifically says

All the sequential palettes are available in variations from 3 different values up to 9 different values.

[...]

For qualitative palettes, the lowest number of distinct values available always is 3

Since build_plotly() (the function plotly() calls internally) always calls brewer.pal() (see line 474 here), it's not possible to fix this without rewriting the build_plotly() function to not call brewer.pal() with fewer than 3 data classes.

In the meantime, to turn off the warning, assign the plot output to an object and wrap the print(object) statement in suppressWarnings() like this:

plotly_plot <- plot_ly(iris, x = Petal.Length, y = Petal.Width,
      color = Sepal.Length>6, colors = c("#132B43", "#56B1F7"),
      mode = "markers")

suppressWarnings(print(plotly_plot))