如果点落在与另一个点一定距离内,如何生成点为 'repelled' 的数据?
How do I generate data where points are 'repelled' if they land within a certain proximity to another point?
我正在使用 runifdisc
在圆盘上绘制随机点,但我不希望这些点落在其他点的某个邻近范围内。这些点目前被解析为正方形和三角形。我正在使用 spatstat
包。
有办法吗?
这是我的代码:
dots = runifdisc(210, radius=1)
plot(dots, type="n")
points(dots$x[1:45], dots$y[1:45], pch=15, col="red", cex=2)
points(dots$x[46:90], dots$y[46:90], pch=15, col="red", cex=2)
points(dots$x[91:151], dots$y[91:151], pch=17, col="blue", cex=2)
points(dots$x[152:210], dots$y[152:210], pch=17, col="blue", cex=2)
我什至可以接受这些点的均匀分布,例如在我可以设置大小的圆盘内的网格上,以确保没有重叠。
您可以编写自己的函数来执行此操作。它需要三个参数:你想要的点数,包含圆的半径,点与点之间的最小距离。
它只是从 x 和 y 的两个空向量开始,然后生成从均匀分布中抽取的随机 x、y 对。如果此 x, y 对在单位圆之外或在现有点的给定距离内,则将其丢弃并绘制另一对。否则保留该点。重复此过程,直到 x 和 y 向量已满。此时,将创建一个数据框,其中 x 和 y 值乘以所需的圆半径以生成结果。
如果在多次尝试后仍找不到放置新点的位置,则会抛出错误。给出的 210 个点的示例仅在最小距离为 0.1 时才适合:
repelled_points <- function(n, r_circle, r_clash) {
container_x <- numeric(n)
container_y <- numeric(n)
j <- i <- 1
while(i <= n)
{
j <- j + 1
if(j == 100 * n) stop("Cannot accommodate the points in given space")
x <- runif(1, -1, 1)
y <- runif(1, -1, 1)
if(x^2 + y^2 > 1) next
if(i > 1) {
dist <- sqrt((x - container_x[seq(i-1)])^2 + (y - container_y[seq(i-1)])^2)
if(any(dist < r_clash)) next
}
container_x[i] <- x
container_y[i] <- y
i <- i + 1
j <- 1
}
`class<-`(list(window = disc(centre = c(0, 0), radius = r_circle),
n = n, x = container_x * r_circle,
y = container_y * r_circle, markformat = "none"), "ppp")
}
其中,当您 运行 您的绘图代码时,returns 结果如下:
dots <- repelled_points(210, 1, 0.1)
plot(dots, type="n")
points(dots$x[1:45], dots$y[1:45], pch=15, col="red", cex=2)
points(dots$x[46:90], dots$y[46:90], pch=15, col="red", cex=2)
points(dots$x[91:151], dots$y[91:151], pch=17, col="blue", cex=2)
points(dots$x[152:210], dots$y[152:210], pch=17, col="blue", cex=2)
不是最优雅的解决方案,但这是一种方法
# sample_size = 3000
total_points = 210
find_repelled_dots <- function(total_points, radius = 1, min_distance = 0.1, max_iterations = 10000){
# Initialize the first point
selected_dots = runifdisc(1, radius=1)
selected_dots = c(selected_dots$x, selected_dots$y)
# Initialize iterators
picked = 1
i = 1
while (picked < total_points & i < max_iterations) { # Either enough points or max iterations
dots_sample = runifdisc(1, radius = radius) # Choose a data points
selected_dots_temp = rbind(selected_dots, c(dots_sample$x, dots_sample$y)) # Find distance between existing points
if (min(dist(selected_dots_temp)) > min_distance){ # If sufficiently far from all the other points, add to the mix, else try again
picked = picked + 1 # Keep track of picked points
selected_dots = selected_dots_temp # Update picked list
}
i = i + 1 # Keep track of iterations
}
if (i > 10000){
stop("Max iterations passed! Increase number of iterations")
}
return(list(x = selected_dots[,1], y = selected_dots[,2]))
}
dots = find_repelled_dots(210)
plot(dots, type="n")
points(dots$x[1:45], dots$y[1:45], pch=15, col="red", cex=2)
points(dots$x[46:90], dots$y[46:90], pch=15, col="red", cex=2)
points(dots$x[91:151], dots$y[91:151], pch=17, col="blue", cex=2)
points(dots$x[152:210], dots$y[152:210], pch=17, col="blue", cex=2)
spatstat
中有几个函数可以用最小值模拟点
距离。 rHardcore()
这些点在某种意义上独立于每个点
其他,但点数是随机的。 rSSI()
你得到一个固定的
点数(如果可能的话,在算法放弃之前):
library(spatstat)
X <- rSSI(0.1, 210, win = disc(1))
您可以将标记随机附加到点上以绘制它们
不同的字符:
marks(X) <- sample(c(rep("a", 90), rep("b", 120)))
plot(X, main = "", cols = c("red", "blue"))
这不是特别快。
spatstat
中有函数可以做到这一点,包括rSSI
、rMaternI
、rMaternII
、rHardcore
、rStrauss
和rmh
。这取决于你希望点如何“到达”以及它们应该如何“排斥”。
rSSI
:点数一一到达。每个点都是随机放置的,条件是它不会离现有点太近。当不可能在任何地方放置新点时游戏停止(“简单顺序抑制”)
rMaternI
:积分同时到达。然后删除太靠近另一点的任何点。 (物质抑制模型 1)
rMaternII
:积分在一定时间内随机到达。他们的到达时间被记录下来。在此期间结束时,任何与另一点 较早到达的点 太近的点都将被删除。 (物质抑制模型 2)
rHardcore
和 rmh
:点数不断到达,随机时间,永远。如果新到达的点太靠近现有点,则会被拒绝并删除。现有点的生命周期有限,并在其生命周期结束时被删除。这个过程运行好久,然后拍个快照。 (使用空间生灭过程模拟的吉布斯硬核过程)。
spatstat
中的函数已经过彻底调试和测试,因此我建议尽可能使用它们而不是编写新代码。
有关文档,请参阅 the spatstat book
的第 5.5 节和第 13 章
我正在使用 runifdisc
在圆盘上绘制随机点,但我不希望这些点落在其他点的某个邻近范围内。这些点目前被解析为正方形和三角形。我正在使用 spatstat
包。
有办法吗? 这是我的代码:
dots = runifdisc(210, radius=1)
plot(dots, type="n")
points(dots$x[1:45], dots$y[1:45], pch=15, col="red", cex=2)
points(dots$x[46:90], dots$y[46:90], pch=15, col="red", cex=2)
points(dots$x[91:151], dots$y[91:151], pch=17, col="blue", cex=2)
points(dots$x[152:210], dots$y[152:210], pch=17, col="blue", cex=2)
我什至可以接受这些点的均匀分布,例如在我可以设置大小的圆盘内的网格上,以确保没有重叠。
您可以编写自己的函数来执行此操作。它需要三个参数:你想要的点数,包含圆的半径,点与点之间的最小距离。
它只是从 x 和 y 的两个空向量开始,然后生成从均匀分布中抽取的随机 x、y 对。如果此 x, y 对在单位圆之外或在现有点的给定距离内,则将其丢弃并绘制另一对。否则保留该点。重复此过程,直到 x 和 y 向量已满。此时,将创建一个数据框,其中 x 和 y 值乘以所需的圆半径以生成结果。
如果在多次尝试后仍找不到放置新点的位置,则会抛出错误。给出的 210 个点的示例仅在最小距离为 0.1 时才适合:
repelled_points <- function(n, r_circle, r_clash) {
container_x <- numeric(n)
container_y <- numeric(n)
j <- i <- 1
while(i <= n)
{
j <- j + 1
if(j == 100 * n) stop("Cannot accommodate the points in given space")
x <- runif(1, -1, 1)
y <- runif(1, -1, 1)
if(x^2 + y^2 > 1) next
if(i > 1) {
dist <- sqrt((x - container_x[seq(i-1)])^2 + (y - container_y[seq(i-1)])^2)
if(any(dist < r_clash)) next
}
container_x[i] <- x
container_y[i] <- y
i <- i + 1
j <- 1
}
`class<-`(list(window = disc(centre = c(0, 0), radius = r_circle),
n = n, x = container_x * r_circle,
y = container_y * r_circle, markformat = "none"), "ppp")
}
其中,当您 运行 您的绘图代码时,returns 结果如下:
dots <- repelled_points(210, 1, 0.1)
plot(dots, type="n")
points(dots$x[1:45], dots$y[1:45], pch=15, col="red", cex=2)
points(dots$x[46:90], dots$y[46:90], pch=15, col="red", cex=2)
points(dots$x[91:151], dots$y[91:151], pch=17, col="blue", cex=2)
points(dots$x[152:210], dots$y[152:210], pch=17, col="blue", cex=2)
不是最优雅的解决方案,但这是一种方法
# sample_size = 3000
total_points = 210
find_repelled_dots <- function(total_points, radius = 1, min_distance = 0.1, max_iterations = 10000){
# Initialize the first point
selected_dots = runifdisc(1, radius=1)
selected_dots = c(selected_dots$x, selected_dots$y)
# Initialize iterators
picked = 1
i = 1
while (picked < total_points & i < max_iterations) { # Either enough points or max iterations
dots_sample = runifdisc(1, radius = radius) # Choose a data points
selected_dots_temp = rbind(selected_dots, c(dots_sample$x, dots_sample$y)) # Find distance between existing points
if (min(dist(selected_dots_temp)) > min_distance){ # If sufficiently far from all the other points, add to the mix, else try again
picked = picked + 1 # Keep track of picked points
selected_dots = selected_dots_temp # Update picked list
}
i = i + 1 # Keep track of iterations
}
if (i > 10000){
stop("Max iterations passed! Increase number of iterations")
}
return(list(x = selected_dots[,1], y = selected_dots[,2]))
}
dots = find_repelled_dots(210)
plot(dots, type="n")
points(dots$x[1:45], dots$y[1:45], pch=15, col="red", cex=2)
points(dots$x[46:90], dots$y[46:90], pch=15, col="red", cex=2)
points(dots$x[91:151], dots$y[91:151], pch=17, col="blue", cex=2)
points(dots$x[152:210], dots$y[152:210], pch=17, col="blue", cex=2)
spatstat
中有几个函数可以用最小值模拟点
距离。 rHardcore()
这些点在某种意义上独立于每个点
其他,但点数是随机的。 rSSI()
你得到一个固定的
点数(如果可能的话,在算法放弃之前):
library(spatstat)
X <- rSSI(0.1, 210, win = disc(1))
您可以将标记随机附加到点上以绘制它们 不同的字符:
marks(X) <- sample(c(rep("a", 90), rep("b", 120)))
plot(X, main = "", cols = c("red", "blue"))
这不是特别快。
spatstat
中有函数可以做到这一点,包括rSSI
、rMaternI
、rMaternII
、rHardcore
、rStrauss
和rmh
。这取决于你希望点如何“到达”以及它们应该如何“排斥”。
rSSI
:点数一一到达。每个点都是随机放置的,条件是它不会离现有点太近。当不可能在任何地方放置新点时游戏停止(“简单顺序抑制”)rMaternI
:积分同时到达。然后删除太靠近另一点的任何点。 (物质抑制模型 1)rMaternII
:积分在一定时间内随机到达。他们的到达时间被记录下来。在此期间结束时,任何与另一点 较早到达的点 太近的点都将被删除。 (物质抑制模型 2)rHardcore
和rmh
:点数不断到达,随机时间,永远。如果新到达的点太靠近现有点,则会被拒绝并删除。现有点的生命周期有限,并在其生命周期结束时被删除。这个过程运行好久,然后拍个快照。 (使用空间生灭过程模拟的吉布斯硬核过程)。
spatstat
中的函数已经过彻底调试和测试,因此我建议尽可能使用它们而不是编写新代码。
有关文档,请参阅 the spatstat book
的第 5.5 节和第 13 章