'How can I add triangles to a ggplot2 colorbar in R to indicate out of bound values?

I'd like to make a plot using ggplot2 where some of the fill values are clipped, i.e. values above or below the limits of the color scale are displayed as the minimum/maximum color. I can get this to work like this, using a combination of limit and oob (out of bounds):

library(ggplot2)
library(scales)
ggplot() + ... + scale_fill_viridis(na.value="white", limit=c(0, 10), oob=squish)

But there is no information in the colorbar that indicates there are values present outside of the limits. How can I reproduce this matplotlib example in ggplot: https://stackoverflow.com/a/32072348

Specifically, how to get the triangles at the end of the colorbar?



Solution 1:[1]

Triangles? No idea. Colors? You can set a gradient with custom values where your normal range is manually defined and your extremes are something else.

library(ggplot2)
# example taken from ?viridis::scale_colour_viridis, even if I don't use that function
dsub <- subset(diamonds, x > 5 & x < 6 & y > 5 & y < 6)
dsub$diff <- with(dsub, sqrt(abs(x-y))* sign(x-y))
d <- ggplot(dsub, aes(x, y, colour=diff)) + geom_point()
d +
  scale_color_gradientn(
    colours=c("red", "red", "blue", "green", "yellow", "red", "red"),
    values = c(0, 0.1-1e-9, 0.1, 0.5, 0.9, 0.9+1e-9, 1),
    breaks = c(-0.51, -.4, 0, .4, .62),
    label = function(z) replace(z, c(1, length(z)), c("Min", "Max"))) +
  theme_bw()

ggplot2 with gradients and red ends

I doubled "red" on each end so that there would be no gradient transition with the neighboring colors. You can choose a different color for one end (while in this case it's clear if it's extreme-high or extreme-low).

I chose to manually control values= and labels= to include arbitrary points and labels for the extremes. This can be improved based on your preferences.

The disadvantage to this is that you have to define the viridis colors manually; should not be too difficult. I've hastily approximated it here, I'm confident you can choose better colors for the internal gradient portion.

Solution 2:[2]

library(gg.layers)
library(ggplot2)
library(rcolors)

brk <- c(-Inf, -1, 0, 1, 3, 6, 9, Inf)
nbrk <- length(brk) - 1
cols <- get_color(rcolors$amwg256, nbrk)

g <- make_colorbar(
  at = brk, col = cols, height = 1,
  tck = 0.4,
  space = "right",
  legend.text.location = c(0.3, 0.5),
  legend.text.just = c(0.5, 0.5),
  # legend.text = list(fontfamily = "Times", cex = 1.1),
  hjust = 0.05
)

p <- ggplot(mtcars, aes(mpg, disp)) + geom_point()
p + g

https://github.com/rpkgs/gg.layers

enter image description here

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 r2evans
Solution 2 Dongdong Kong