简体   繁体   中英

Trim scale_color_gradient() legend in ggplot

I am trying to 'trim' the legend of the plot below:

df <- data.frame(x = seq(0, 15 , 0.001), 
                 y = seq(0, 15, 0.001))

ggplot(df, aes(x=x, y=y, col = y)) +
  geom_line() +
  scale_color_gradientn(colours = c("green", "black", "red", "red"), 
                        values = rescale(x = c(0, 2, 4, 15), to = c(0,1), from = c(0, 15) ))

在此处输入图像描述

I am able to set the required breaks and values by adding breaks = c(0,2,4), labels = c("0", "2", "4+") :

在此处输入图像描述

But when I add the limits=c(0,4) , the gradient gets messed up.

Question

Is it possible to 'trim' the legend, so that it shows the values from 0 to 4+ (ie, and omits all values above)?

The following is what you probably want.

library(ggplot2)
library(scales)

df <- data.frame(x = seq(0, 15 , 0.001), 
                 y = seq(0, 15, 0.001))

ggplot(df, aes(x=x, y=y, col = y)) +
  geom_line() +
  scale_color_gradientn(colours = c("green", "black", "red", "red"), 
                        values = rescale(x = c(0, 2, 4, 15), from = c(0, 4)),
                        oob = squish,
                        limits = c(0, 4))

What's happening is as follows. Suppose we have some values in data space (meaning they haven't been rescaled yet).

# Colour positions in data space
print(col_pos_data <- c(0, 2, 4, 15))
#> [1]  0  2  4 15

By default, the scales::rescale() function brings everything into the [0,1] interval. However, when you set a custom range, any out of bounds values will be scaled linearly with the in bounds values. You'll notice that the 15 becomes 3.75 in this case.

# Colour positions in [0,1] interval
col_pos_scaled <- rescale(col_pos_data, from = c(0, 4))
print(col_pos_scaled)
#> [1] 0.00 0.50 1.00 3.75

However, the default manner that ggplot enforces the limits of continuous scales, is to set anything that exceeds the limits to NA , which is often removed later.

# Default ggplot limit enforcing
print(censor(col_pos_scaled))
#> [1] 0.0 0.5 1.0  NA

Now that is a bit too bad for your scale purposes, but one of the alternatives is to 'squish' the data. This brings any (finite) out of bounds values to the nearest limit. Notice that the last value is no longer NA but set to the largest limit in the [0,1] interval.

print(scaled_squish <- squish(col_pos_scaled))
#> [1] 0.0 0.5 1.0 1.0

The same thing holds true for values in data space if the range is adjusted accordingly.

print(censor(col_pos_data, range = c(0, 4)))
#> [1]  0  2  4 NA

print(data_squish <- squish(col_pos_data, range = c(0, 4)))
#> [1] 0 2 4 4

Internally, ggplot rescales all data to the limits and the order of operations doesn't matter for squishing/rescaling, so the data values and the colour positions in [0,1] line up nicely.

# So when data values are rescaled, they match up the colours
identical(rescale(data_squish), scaled_squish)
#> [1] TRUE

Created on 2020-04-24 by the reprex package (v0.3.0)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM