ggplot2:通过设置连续色标来处理极值

ggplot2: dealing with extremes values by setting a continuous color scale

我正在尝试绘制一些全球地图(光栅文件),但在为我的数据设置良好的色标时遇到了一些问题。我想做的是使用不同的调色板(例如 cm.colors)绘制我的数据,我想将这种比例的颜色 "white" 居中,值为零,但不必设置比例中的对称值(即负值和正值相同,即 limits=c(-1,1))。此外,我想用相同的颜色绘制所有高于 and/or 且低于某个值的值。

换句话说,如果我们假设我的地图的范围是 -100 到 150,我想用 "white" 颜色对应于值 0 的发散调色板绘制我的地图,并且具有所有值,例如低于 -20 和高于 50 用相同的颜色绘制,即分别使用调色板的负极端和正极端。

这里是我目前使用的代码示例:

ggplot(df, aes(y=Latitude, x=Longitude)) +
  geom_raster(aes(fill=MAP)) +
  coord_equal()+ 
  theme_gray() +
  theme(panel.background = element_rect(fill = 'skyblue2', colour = 'black'), 
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        legend.position = "right",
        legend.key = element_blank()) +
  scale_fill_gradientn("MAP", limits=c(-0.5,1), colours=cm.colors(20))

有一些简单的方法可以实现这一点,例如预先截断数据,或使用 cut 为适当的标签创建离散的 bin。

require(dplyr)
df %>% mutate(z2 = ifelse(z > 50, 50, ifelse(z < -20, -20, z))) %>% 
  ggplot(aes(x, y, fill = z2)) + geom_tile() + 
  scale_fill_gradient2(low = cm.colors(20)[1], high = cm.colors(20)[20])

df %>% mutate(z2 = cut(z, c(-Inf, seq(-20, 50, by = 10), Inf)),
              z3 = as.numeric(z2)-3) %>% 
  {ggplot(., aes(x, y, fill = z3)) + geom_tile() + 
  scale_fill_gradient2(low = cm.colors(20)[1], high = cm.colors(20)[20],
                       breaks = unique(.$z3), labels = unique(.$z2))}

但我之前考虑过这个任务,对此感到不满意。预截断不会留下漂亮的标签,并且 cut 选项总是很繁琐(特别是必须调整 cut 内部的 seq 的参数并弄清楚如何使垃圾箱重新居中) .所以我尝试定义一个可重用的转换,它会为您进行截断和重新标记。

我还没有完全调试这个,我要出城了,所以希望你或其他回答者能尝试一下。主要问题似乎是边缘情况下的冲突,因此有时限制会在视觉上与预期的中断重叠,以及格式的一些意外行为。我只是使用了一些虚拟数据来创建您想要的 -100 到 150 范围来测试它。

require(scales)
trim_tails <- function(range = c(-Inf, Inf)) trans_new("trim_tails", 
                transform = function(x) {
                  force(range)
                  desired_breaks <- extended_breaks(n = 7)(x[x >= range[1] & x <= range[2]])
                  break_increment <- diff(desired_breaks)[1]
                  x[x < range[1]] <- range[1] - break_increment
                  x[x > range[2]] <- range[2] + break_increment
                  x
                },
                inverse = function(x) x,

                breaks = function(x) {
                  force(range)
                  extended_breaks(n = 7)(x)
                },
                format = function(x) {
                  force(range)
                  x[1] <- paste("<", range[1])
                  x[length(x)] <- paste(">", range[2])
                  x
                })

ggplot(df, aes(x, y, fill = z)) + geom_tile() + 
  guides(fill = guide_colorbar(label.hjust = 1)) +
  scale_fill_gradient2(low = cm.colors(20)[1], high = cm.colors(20)[20],
                       trans = trim_tails(range = c(-20,50)))

也适用于带框的图例而不是颜色条,只需使用 ... + guides(fill = guide_legend(label.hjust = 1, reverse = T)) + ...