控制 n 个重叠区域的 alpha 混合/不透明度
Control alpha blending / opacity of n overlapping areas
我很难理解(和控制)alpha 的混合 - 不幸的是,alpha 值不只是 "add up"(0.5 + 0.5 不是 1)。但我怎样才能做到这一点?
目的是定义重叠区域相对于观察总数的(绝对)灰度值。 参见下面的示例。
我试过设置scale_alpha(range = c(0,1))
没有用,可能是我没有正确使用。
library(ggplot2)
library(ggforce)
grid_df = data.frame(x = c(1:2, 2.5), y = rep(1,3), r = 1)
ggplot()+
geom_circle(data = grid_df, mapping = aes(x0 = x, y0 = y, r = r), alpha = 0.33, fill = 'black') +
coord_fixed()
可以使用以下方法添加 Alpha (https://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending)
两个合并形状的 alpha 计算如下:
A(out) = A(src) + A(dst) * 1-A(src)
因此,对于 A(src) = A(dst) = 0.33,我们得到:
x = 0.33
y = x + x*(1-x)
y
[1] 0.5511
如果我们有三个形状,A = 0.33,我们得出:
y = x + x*(1-x) + x*(1-(x + x*(1-x)))
y
[1] 0.699237
我可以继续讨论将 2 个或 3 个形状相加时哪些值会导致 1,但最有用的评论是 alpha 不是以相加方式组合的。
添加到@MKBakker 的答案中,可以使用函数从任意数量的层和 alpha 值预测生成的 alpha:
alpha_out <- function(alpha, num = 1) {
result = alpha
if(num == 1) return(result)
for(i in 2:num) { result = result + alpha * (1-result) }
return (result)
}
alpha_out(0.33, 1)
#[1] 0.33
alpha_out(0.33, 2)
#[1] 0.5511
alpha_out(0.33, 3)
#[1] 0.699237
这样可以更容易地看出 alpha 在层数更多的情况下逐渐接近 1。
alpha_out(0.33, 40)
#[1] 0.9999999
如果假设 0.99 是 "close enough," 你需要使用 0.8 来达到三层
alpha_out(0.8, 3)
#[1] 0.992
编辑:添加了结果图表
我们可以看到从一系列 alpha 和图层中得到的结果:
library(tidyverse)
alpha_table <-
tibble(
alpha = rep(0.01*1:99, 10),
layers = rep(1:10, each = 99)
)
alpha_table <- alpha_table %>%
rowwise() %>%
mutate(result = alpha_out(alpha, layers))
ggplot(alpha_table, aes(alpha, result, color = as_factor(layers),
group = layers)) +
geom_line()
我们还可以看到在给定每个层数的情况下,我们需要多少 alpha 才能通过组合不透明度的阈值。例如,这里是给定层数要达到 0.99 总不透明度所需的 alpha 值。例如,对于 5 层,您需要 alpha = 0.61
。
alpha_table %>%
group_by(layers) %>%
filter(result >= 0.99) %>%
slice(1)
## A tibble: 10 x 3
## Groups: layers [10]
# alpha layers result
# <dbl> <int> <dbl>
# 1 0.99 1 0.99
# 2 0.9 2 0.99
# 3 0.79 3 0.991
# 4 0.69 4 0.991
# 5 0.61 5 0.991
# 6 0.54 6 0.991
# 7 0.49 7 0.991
# 8 0.44 8 0.990
# 9 0.41 9 0.991
#10 0.37 10 0.990
综上所述,我认为没有一个简单的实现可以满足您的需求。如果你想在重叠区域 100% 黑暗,你可以尝试这些方法:
事后图像处理(也许可以使用 imagemagick
)应用亮度曲线使黑暗区域 100% 黑色,并使其他区域缩放到您期望的黑暗级别。
将图形转换为 sf
对象并分析形状以某种方式计算在任何给定点有多少形状重叠。然后您可以手动将它们映射到您想要的黑暗级别。
首先,向@JonSpring +1——这只是他们答案末尾的想法的扩展。如果你做一个sf
对象,你可以很容易地得到多边形的交点。您最终绘制的不是圆圈本身,而是通过分割相交部分得到的多边形。
从您的网格开始,为每一行创建一个点,将其转换为 sf
数据框,然后在列 r
中给定的半径处获取点的缓冲区。这会将每个点变成一个以该点坐标为中心的圆,并且对于不同的半径是灵活的。 3个圆之间是6个相交的多边形,如图结果所示
library(dplyr)
library(sf)
library(ggplot2)
library(ggforce)
grid_df <- data.frame(x = c(1:2, 2.5), y = rep(1,3), r = 1)
grid_sf <- grid_df %>%
mutate(geometry = purrr::map2(x, y, ~st_point(c(.x, .y)))) %>%
st_as_sf() %>%
st_buffer(dist = .$r, nQuadSegs = 60) %>%
st_intersection()
grid_sf
#> Simple feature collection with 6 features and 5 fields
#> geometry type: GEOMETRY
#> dimension: XY
#> bbox: xmin: 0 ymin: 0 xmax: 3.5 ymax: 2
#> epsg (SRID): NA
#> proj4string: NA
#> x y r n.overlaps origins geometry
#> 1 1.0 1 1 1 1 POLYGON ((1.5 0.1339746, 1....
#> 1.1 1.0 1 1 2 1, 2 POLYGON ((1.75 0.3386862, 1...
#> 2 2.0 1 1 1 2 MULTIPOLYGON (((2.258819 0....
#> 1.2 1.0 1 1 3 1, 2, 3 POLYGON ((2 1, 1.999657 0.9...
#> 2.1 2.0 1 1 2 2, 3 POLYGON ((3 1, 2.999657 0.9...
#> 3 2.5 1 1 1 3 MULTIPOLYGON (((3.5 1, 3.49...
使用来自 st_intersection
的 n.overlaps
列分配 alpha。默认情况下,alpha 将从 0 缩放到 1,但我认为您实际上不希望圆的外部非重叠部分为 0 alpha,因此我缩放它以获得最小 alpha。
alpha_range <- range(grid_sf$n.overlaps) / max(grid_sf$n.overlaps)
grid_sf %>%
ggplot() +
geom_sf(aes(alpha = n.overlaps), fill = "black") +
scale_alpha(range = alpha_range)
只是为了进一步扩展并使不同的多边形更加清晰,请使用离散填充比例而不是 alpha 进行查看:
grid_sf %>%
ggplot() +
geom_sf(aes(fill = as.factor(n.overlaps))) +
scale_fill_brewer(palette = "YlGnBu")
我很难理解(和控制)alpha 的混合 - 不幸的是,alpha 值不只是 "add up"(0.5 + 0.5 不是 1)。但我怎样才能做到这一点?
目的是定义重叠区域相对于观察总数的(绝对)灰度值。 参见下面的示例。
我试过设置scale_alpha(range = c(0,1))
没有用,可能是我没有正确使用。
library(ggplot2)
library(ggforce)
grid_df = data.frame(x = c(1:2, 2.5), y = rep(1,3), r = 1)
ggplot()+
geom_circle(data = grid_df, mapping = aes(x0 = x, y0 = y, r = r), alpha = 0.33, fill = 'black') +
coord_fixed()
可以使用以下方法添加 Alpha (https://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending)
两个合并形状的 alpha 计算如下:
A(out) = A(src) + A(dst) * 1-A(src)
因此,对于 A(src) = A(dst) = 0.33,我们得到:
x = 0.33
y = x + x*(1-x)
y
[1] 0.5511
如果我们有三个形状,A = 0.33,我们得出:
y = x + x*(1-x) + x*(1-(x + x*(1-x)))
y
[1] 0.699237
我可以继续讨论将 2 个或 3 个形状相加时哪些值会导致 1,但最有用的评论是 alpha 不是以相加方式组合的。
添加到@MKBakker 的答案中,可以使用函数从任意数量的层和 alpha 值预测生成的 alpha:
alpha_out <- function(alpha, num = 1) {
result = alpha
if(num == 1) return(result)
for(i in 2:num) { result = result + alpha * (1-result) }
return (result)
}
alpha_out(0.33, 1)
#[1] 0.33
alpha_out(0.33, 2)
#[1] 0.5511
alpha_out(0.33, 3)
#[1] 0.699237
这样可以更容易地看出 alpha 在层数更多的情况下逐渐接近 1。
alpha_out(0.33, 40)
#[1] 0.9999999
如果假设 0.99 是 "close enough," 你需要使用 0.8 来达到三层
alpha_out(0.8, 3)
#[1] 0.992
编辑:添加了结果图表
我们可以看到从一系列 alpha 和图层中得到的结果:
library(tidyverse)
alpha_table <-
tibble(
alpha = rep(0.01*1:99, 10),
layers = rep(1:10, each = 99)
)
alpha_table <- alpha_table %>%
rowwise() %>%
mutate(result = alpha_out(alpha, layers))
ggplot(alpha_table, aes(alpha, result, color = as_factor(layers),
group = layers)) +
geom_line()
我们还可以看到在给定每个层数的情况下,我们需要多少 alpha 才能通过组合不透明度的阈值。例如,这里是给定层数要达到 0.99 总不透明度所需的 alpha 值。例如,对于 5 层,您需要 alpha = 0.61
。
alpha_table %>%
group_by(layers) %>%
filter(result >= 0.99) %>%
slice(1)
## A tibble: 10 x 3
## Groups: layers [10]
# alpha layers result
# <dbl> <int> <dbl>
# 1 0.99 1 0.99
# 2 0.9 2 0.99
# 3 0.79 3 0.991
# 4 0.69 4 0.991
# 5 0.61 5 0.991
# 6 0.54 6 0.991
# 7 0.49 7 0.991
# 8 0.44 8 0.990
# 9 0.41 9 0.991
#10 0.37 10 0.990
综上所述,我认为没有一个简单的实现可以满足您的需求。如果你想在重叠区域 100% 黑暗,你可以尝试这些方法:
事后图像处理(也许可以使用
imagemagick
)应用亮度曲线使黑暗区域 100% 黑色,并使其他区域缩放到您期望的黑暗级别。将图形转换为
sf
对象并分析形状以某种方式计算在任何给定点有多少形状重叠。然后您可以手动将它们映射到您想要的黑暗级别。
首先,向@JonSpring +1——这只是他们答案末尾的想法的扩展。如果你做一个sf
对象,你可以很容易地得到多边形的交点。您最终绘制的不是圆圈本身,而是通过分割相交部分得到的多边形。
从您的网格开始,为每一行创建一个点,将其转换为 sf
数据框,然后在列 r
中给定的半径处获取点的缓冲区。这会将每个点变成一个以该点坐标为中心的圆,并且对于不同的半径是灵活的。 3个圆之间是6个相交的多边形,如图结果所示
library(dplyr)
library(sf)
library(ggplot2)
library(ggforce)
grid_df <- data.frame(x = c(1:2, 2.5), y = rep(1,3), r = 1)
grid_sf <- grid_df %>%
mutate(geometry = purrr::map2(x, y, ~st_point(c(.x, .y)))) %>%
st_as_sf() %>%
st_buffer(dist = .$r, nQuadSegs = 60) %>%
st_intersection()
grid_sf
#> Simple feature collection with 6 features and 5 fields
#> geometry type: GEOMETRY
#> dimension: XY
#> bbox: xmin: 0 ymin: 0 xmax: 3.5 ymax: 2
#> epsg (SRID): NA
#> proj4string: NA
#> x y r n.overlaps origins geometry
#> 1 1.0 1 1 1 1 POLYGON ((1.5 0.1339746, 1....
#> 1.1 1.0 1 1 2 1, 2 POLYGON ((1.75 0.3386862, 1...
#> 2 2.0 1 1 1 2 MULTIPOLYGON (((2.258819 0....
#> 1.2 1.0 1 1 3 1, 2, 3 POLYGON ((2 1, 1.999657 0.9...
#> 2.1 2.0 1 1 2 2, 3 POLYGON ((3 1, 2.999657 0.9...
#> 3 2.5 1 1 1 3 MULTIPOLYGON (((3.5 1, 3.49...
使用来自 st_intersection
的 n.overlaps
列分配 alpha。默认情况下,alpha 将从 0 缩放到 1,但我认为您实际上不希望圆的外部非重叠部分为 0 alpha,因此我缩放它以获得最小 alpha。
alpha_range <- range(grid_sf$n.overlaps) / max(grid_sf$n.overlaps)
grid_sf %>%
ggplot() +
geom_sf(aes(alpha = n.overlaps), fill = "black") +
scale_alpha(range = alpha_range)
只是为了进一步扩展并使不同的多边形更加清晰,请使用离散填充比例而不是 alpha 进行查看:
grid_sf %>%
ggplot() +
geom_sf(aes(fill = as.factor(n.overlaps))) +
scale_fill_brewer(palette = "YlGnBu")