有没有办法在 ggplot 的 scale_color_viridis_c 阈值后添加纯色?或者用 ggnewscale 分层 legends/color_bars?

Is there a way to add a solid color after a threshold with scale_color_viridis_c from ggplot? Or to layer legends/color_bars with ggnewscale?

我正在尝试为一组模型的准确性创建一个图表,这些模型的两个参数的组合不同。 任何模型的准确度都不超过 0.98,大多数模型的准确度在 0.94 到 0.98 之间(顺便说一句,这只是实践,没有真正的研究)。我发现将 scale_color_viridis_c()limits = c(.96, .98)values = c(.25, 1) 一起使用会产生一个很好的梯度,可以很好地可视化精度分布,但这样我就无法让 color_bar 上升到 1 - 结束于 0.98。

我的第一个方法是设置 limits = c(0.96, 1)values = c(.125, 0.5),但这导致每个高于 0.98 的值都注册为 NA,与低于 0.96 的值相同。 然后我尝试将第一个图与第二个图分层,第二个图与第一个图相同,但是以 > 0.98 黑色(即无)和 "fill" 上部 NA(即 0.98 到 1)的精度为数据点着色第一个 color_bar 为黑色,并降低所有透明度。

我创建了一个例子:

library(ggplot2)
library(ggnewscale)

set.seed(123)

# variable 1
v1 <- numeric()
for (i in 1:50) {
  v1 <- c(v1, rep(i, 56))
}

# variable 2
v2 <- rep(seq(50, 600, 10), 50)

# creating preliminary df
df <- data.frame(v1 = v1, v2 = v2)

# creating mock accuracy data
acc <- apply(df, 1, function(x) {
  temp_acc <- runif(1, 1, 10) * x[1]^0.6 / x[2]^0.65 * -1
})
acc <- (-1 * (acc / (10 * min(acc)))) - runif(1, -0.01, 0.01) + 0.99
acc <- acc - (max(acc) - 0.98) - 0.0005

#create complete df
df$acc <- acc

#plotting
g <- ggplot(data =  df, aes(x  = v1, y = v2, color = acc)) +
  geom_point() + scale_color_viridis_c(values = c(.125, 0.5), na.value = "grey80",
                                       breaks = seq(0.96, 1, 0.005), limits = c(0.96, 1),
                                       guide = guide_colorbar(barheight = 10)) +
  new_scale_color() +
  geom_point(aes(color = acc), alpha = 0.2) +
  scale_color_gradientn(colors = "black",
                        values = c(0.5, 1), na.value = NA,
                        breaks = seq(0.96, 1, 0.005), limits = c(0.96, 1),
                        guide = guide_colorbar(barheight = 10))
g

这几乎完全符合我的要求——情节部分很完美,但我希望两个 color_bar 合二为一。有没有办法做到这一点? 或者从不同的角度接近它:有没有办法为连续色标设置两个阈值,并让数据 above/below 将这些阈值用不同的颜色组合 color_bar?

这只是出于审美原因,我可以使用图像编辑软件(甚至是 MSPaint)轻松完成此任务,但我希望能够仅根据我的数据在 R 中完成这一切,而不是人为的编辑。

提前致谢!

大卫

plot with mock data

这可能不是最 'programmatic' 实现您想要的方法,因为您必须对第二组限制进行硬编码,但您可以进入越界行为规模。您可以通过使用您自己创建的函数设置 oob 参数来实现。在这种情况下,我们将包装 scales 包中的 squish() 函数,使超出限制的任何值成为最近的限制。

#plotting
g <- ggplot(data =  df, aes(x  = v1, y = v2, color = acc)) +
  geom_point() + 
  scale_color_viridis_c(
    values = c(.125, 0.5), na.value = "grey80",
    breaks = seq(0.96, 1, 0.005), limits = c(0.96, 1),
    guide = guide_colorbar(barheight = 10),
    oob = function(x, ...){scales::squish(x, c(0.965, 0.98))}
  )
g

我不确定我理解你的问题,但根据你的例子和你想要的("fuse" 两个量表)这样可以吗?它不需要 ggnewscale,令我很失望️

library(ggplot2)

set.seed(123)

# variable 1
v1 <- numeric()
for (i in 1:50) {
  v1 <- c(v1, rep(i, 56))
}

# variable 2
v2 <- rep(seq(50, 600, 10), 50)

# creating preliminary df
df <- data.frame(v1 = v1, v2 = v2)

# creating mock accuracy data
acc <- apply(df, 1, function(x) {
  temp_acc <- runif(1, 1, 10) * x[1]^0.6 / x[2]^0.65 * -1
})
acc <- (-1 * (acc / (10 * min(acc)))) - runif(1, -0.01, 0.01) + 0.99
acc <- acc - (max(acc) - 0.98) - 0.0005

#create complete df
df$acc <- acc

#plotting
ggplot(data =  df, aes(x  = v1, y = v2, color = acc)) +
  geom_point(aes(alpha = acc >= .965)) + 
  scale_alpha_discrete(range = c(0.2, 1), guide = "none") +
  scale_color_viridis_c(values = c(.125, 0.5), na.value = "black",
                        breaks = seq(0.96, 1, 0.005), 
                        limits = c(0.96, 1),
                        guide = guide_colorbar(barheight = 10)) 
#> Warning: Using alpha for a discrete variable is not advised.

reprex package (v0.3.0)

于 2020-05-06 创建

我找到了解决问题的方法,或者至少找到了一个对我来说足够有效的解决方法 - 关键是直接从 viridis() 获取颜色值,就像使用 rainbow() 一样].我之前尝试过但没有用,因为我没有加载 library(viridis) 或将其指定为 viridis::viridis() 所以我错误地认为没有像 viridis().[=17= 这样的东西]

但事实证明,你可以,所以这是我的代码:

library(ggplot2)
library(ggnewscale)
library(viridis)

set.seed(123)

# variable 1
v1 <- numeric()
for (i in 1:50) {
  v1 <- c(v1, rep(i, 56))
}

# variable 2
v2 <- rep(seq(50, 600, 10), 50)

# creating preliminary df
df <- data.frame(v1 = v1, v2 = v2)

# creating mock accuracy data
acc <- apply(df, 1, function(x) {
  temp_acc <- runif(1, 1, 10) * x[1]^0.6 / x[2]^0.65 * -1
})
acc <- (-1 * (acc / (10 * min(acc)))) - runif(1, -0.01, 0.01) + 0.99
acc <- acc - (max(acc) - 0.98) - 0.0005

# create complete df
df$acc <- acc

# grabbing the scale colors from viridis() and appending grey80,
# yielding a color vector that has the continuous viridis color of the length I need it,
# and then switches to a solid color of my choice
color_vector <- c(viridis(length(acc)), rep("grey80", times = length(acc)))

# plotting
g <- ggplot(data =  df, aes(x  = v1, y = v2, color = acc)) +
  geom_point() + scale_color_gradientn(colors = color_vector,
                                       values = c(0.2, 1), na.value = "grey45",
                                       guide = guide_colorbar(barheight = 15),
                                       breaks = seq(0.95, 1, 0.005),limits = c(0.95, 1))
g

我实际上将 0.98 以上的(不存在的)值更改为 "grey80" 而不是 "black",以及 NA.values(即低于 0.96 的所有值)从 "grey80""grey45" - 我发现这样在视觉上更明确。

外观如下: imgurlink because I can't add pictures yet

仍然感谢您的建议,它们在其他情况下会派上用场! :)