Article Image
Article Image
read

“… avoiding catastrophe becomes the first principle in bringing color to information: Above all, do no harm.”

  • Envisioning Information, Edward Tufte, Graphics Press, 1990

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? And so on…
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.

Viridis and other color pallets 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 viridis vs. jet/rainbow comparison.

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")

Viridis and Plotly

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

install.packages(c("plotly", "tidyr"))
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))

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.

Viridis and Leaflet

Now let’s have a look at using ‘viridis’ with ‘leaflet’ maps. For this visualization we use Maritime data from our previous post about 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(leaflet)
library(dplyr)

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)

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)

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

Acknowledgement

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

🎉 Subscribe to our mailing list

Blog Logo

Olga Mierzwa-Sulima


Published

Image

Appsilon Data Science Blog

How to create and use technology to deliver business results.

Back to the top