Join the R Community at ShinyConf 2023

How to Use Viridis Colors with Plotly and Leaflet


Updated: December 30, 2022.

Choosing colors for your plot is not so simple. Why is that so? First of all, it depends on numerous things… What plot are you creating? What is its purpose? Who are the readers? Will it be readable when printed in black-and-white?

There are very interesting StackExchange discussions where you can read on how colors are perceived and why it’s not such a good idea to use red and green.
Probably, there is a place for a blog post solely on choosing colors for different kinds of plots, but let’s save that for another time.

Table of contents:


Viridis and other Color Palletes in R

If you are creating a data visualisation in R there are already a few color palettes available to make your life easier. The pallete that is colorful, perceptually uniform, robust and at the same time pleasing is viridis.

Have a look at SciPy 2015 matplotlib viridis authors’ talk that outlines the whole story of viridis. If you are still not convinced, have a look at this discussion on colormap viridis vs jet.

We cannot forget ColorBrewer palettes which are sequential, colorblind-safe and print-friendly. Check out this comparison. At the end the user needs to make a decision and choose the one “she” thinks suits the analysis the most and makes the visualization look pretty, which is of course a very subjective thing.

In this blog post we want to focus solely on viridis and show you how well it plays with ‘plotly’ and ‘leaflet’. ‘Ggplot2’ example is covered by ‘viridis’ documentation.
At this points make sure you have this package installed. Getting the package is easy since it’s available on CRAN so just run:

install.packages("viridis")

That’s it – you’re ready to work with the viridis package.

Viridis and Plotly

First let’s make a very simple plot using ‘plotly’.

# install.packages("plotly")

library(plotly)
library(tidyr)
library(viridis)

Animals <- c("giraffes", "orangutans", "monkeys")
SF_Zoo <- c(20, 14, 23)
LA_Zoo <- c(12, 18, 29)
NY_Zoo <- c(14, 38, 49)
data_animals <- data.frame(Animals, SF_Zoo, LA_Zoo, NY_Zoo)

data_animals_reshape <- data_animals %>%
  gather(Zoo, Count, SF_Zoo:NY_Zoo)

data_animals_reshape %>%
  plot_ly(
    type = "bar",
    x = ~Animals,
    y = ~Count,
    color = ~Zoo,
    colors = viridis_pal(option = "D")(3)
  )

Image 1 – Viridis palette with Plotly

We provide viridis colors to plotly using viridis_pal and by setting option argument to “D” the default “viridis” is selected. Other options are “A” for “magma” theme, “B” – “inferno” and “C” – “plasma”. Play with letters to check which one you like the most or which suits your plot the best.
As you can see this is pretty straightforward and there is no need to convert ‘viridis’ outcome in any way. ‘Plotly’ and ‘viridis’ play nice together.

How good are you at visualizing data? Here are 5 key data visualization principles you must know.

Viridis and Leaflet

[UPDATE: 2022] R Leaflet package now supports the Viridis color palette out of the box. Here’s the official feature.

Now let’s have a look at using ‘viridis’ with ‘leaflet’ maps. For this visualization we use Maritime data from our previous post on cross-filtering. Data contains information about a ship: it’s name, speed and position.

We want to display which ships are sailing and which are moored. In order to do that a new column ‘type’ is added to the data, assuming that if vessel speed is smaller than 4 knots the ship is ‘moored’, otherwise it’s ‘sailing’. That might not be 100% correct, but it will work for the purpose of this example.

# install.packages(c("leaflet", "dplyr"))

library(dplyr)
library(leaflet)

ships <- read.csv("https://raw.githubusercontent.com/Appsilon/crossfilter-demo/master/app/ships.csv")
ships_type <- ships %>% mutate(type = ifelse(speed < 4, "moored", "sailing"))
types <- ships_type$type %>% unique()

To provide colors to ‘leaflet’ we need to make use of colorFactor function and create mapping between group variable (in our case moored/sailing) and pallete colors.

pal <- leaflet::colorFactor(viridis_pal(option = "C")(2), domain = types)

Next we use our new variable pal and provide it to addCircleMarkers method. We call this method, because we want ships to be displayed as small circles on the map.
Last but not least, we need to add a legend to inform our readers which color represents which ship movement type. This is done by providing our viridis palette to colors argument in addLegend.

leaflet(ships_type) %>%
  addTiles() %>%
  addCircleMarkers(color = ~ pal(type)) %>%
  addLegend(
    position = "bottomright",
    colors = viridis_pal(option = "C")(2),
    labels = types
  )

Image 2 – Viridis palette with Leaflet

We have ships positions colored differently on the map, but something is wrong with the legend. Is doesn’t display our viridis colors.

Why? The reason is that viridis colors are specified as RGBA which are RGB color values with an alpha opacity parameter. The alpha parameter is a number between 0.0 (fully transparent) and 1.0 (fully opaque).

We need to convert our viridis colors to standard RGB (sRGB) in order to show the legend correctly. This can be done using col2Hex function from mapview package. Please note that function isn’t available in package namespace mapview:::col2Hex.
col2Hex is a very short function and can be easily reimplemented without using internal package function.

appsilon_col2Hex <- function(col) {
  mat <- grDevices::col2rgb(col, alpha = TRUE)
  grDevices::rgb(mat[1, ] / 255, mat[2, ] / 255, mat[3, ] / 255)
}

When we know what is going wrong with our legend we can fix it by creating a helper function get_viridis_color which will return our viridis palette in sRGB.

get_viridis_colors <- function(no_colors) { 
  appsilon_col2Hex(viridis::viridis_pal(option = "C")(no_colors)) 
} 

leaflet(ships_type) %>%
  addTiles() %>%
  addCircleMarkers(color = ~ pal(type)) %>%
  addLegend(
    position = "bottomright",
    colors = get_viridis_colors(2),
    labels = types
  )

Image 3 – Viridis palette with Leaflet (2)

It works! We get a nice legend displaying correct viridis colors!

Dive deeper into Leaflet – Here’s a full guide to stunning Geomaps in R.


Acknowledgement

Some concepts presented in this blog post were proposed by Tim Salabim in this answer on Stackoverflow.