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

假装没事ソ 提交于 2019-12-06 12:46:03

There are simple ways to accomplish this, such as truncating your data beforehand, or using cut to create discrete bins for appropriate labels.

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

But I'd thought about this task before, and felt unsatisfied with that. The pre-truncating doesn't leave nice labels, and the cut option is always fiddly (particularly having to adjust the parameters of seq inside cut and figure out how to recenter the bins). So I tried to define a reusable transformation that would do the truncating and relabeling for you.

I haven't fully debugged this and I'm going out of town, so hopefully you or another answerer can take a crack at it. The main problem seems to be collisions in the edge cases, so occasionally the limits overlap the intended breaks visually, as well as some unexpected behavior with the formatting. I just used some dummy data to create your desired range of -100 to 150 to test it.

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

Also works with a boxed legend instead of a colorbar, just use ... + guides(fill = guide_legend(label.hjust = 1, reverse = T)) + ...

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!