@rata ,
Thank you! Indeed, sf library works well for this task.
The only issue I faced at the beginning is that st_is_within_distance() does not care about multiple images in the same tibble. To solve this, I've just nested data by image number.
The fact that results from sf and my function are different is expected: as square has large area, the number of neighbors fit in this area might be slightly bigger.
library(tidyverse)
library(sf)
#> Linking to GEOS 3.9.0, GDAL 3.2.1, PROJ 7.2.1
library(ggforce)
test_data <- structure(list(ObjectNumber = c(1, 12, 15, 16, 19, 23, 24, 26,
37, 41, 42, 53, 55, 58, 60, 67, 73, 76, 79, 86, 87, 94, 98, 101,
109, 112, 1, 2, 3, 4, 21, 24, 28, 29, 35, 36, 37, 45, 48, 49,
50, 52, 58, 63, 66, 67, 68, 70, 77, 78, 85, 86, 87, 93, 95, 98,
100, 103, 106, 107, 113, 116, 117, 118, 124, 129, 134, 135, 141,
149, 150, 152, 153, 161, 167, 171, 172, 178, 182, 187, 192, 194,
195, 205, 208, 212, 213, 215, 225, 226, 227, 228),
ImageNumber = c(1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231,
231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231,
231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231,
231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231,
231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231,
231, 231, 231, 231),
Location_Center_X.nuc = c(2.7, 10.78, 16.5,
18.55, 18.97, 29.33, 31.96, 37.65, 57.55, 68.33, 68.42, 91.45,
97.53, 96.94, 100.7, 110.67, 125.04, 131.77, 144.7, 152.67, 156.71,
171.42, 182.47, 184.09, 188.84, 195.69, 3.34, 2.29, 5.03, 7.46,
11.12, 11.59, 19.03, 17.41, 19.12, 25.01, 23.44, 32.16, 33.52,
37.06, 36.52, 43.12, 45.1, 49.66, 52.97, 57.93, 55.05, 58.03,
62.17, 62.33, 69.31, 66.63, 70.4, 77.31, 76.77, 80.33, 86.56,
87.18, 90.12, 91.2, 95.23, 97.14, 95.75, 96.49, 104.34, 102.33,
109.73, 113.62, 114.56, 121.83, 123.6, 124.52, 130.46, 134.06,
137.46, 145.4, 141.91, 151.23, 157.52, 161.62, 166.79, 168.69,
168.55, 173.45, 176.47, 180.37, 182.56, 184.23, 194.7, 195.26,
195.93, 196.81),
Location_Center_Y.nuc = c(124.2, 9.07, 39.69,
88.32, 107.83, 130.32, 16.64, 163.7, 108.46, 79.67, 136.2, 147.17,
57.75, 82.03, 14.55, 33.63, 132.93, 41.27, 70.28, 165.24, 94.59,
123.95, 169.95, 59.19, 78.74, 122.71, 25.82, 80.05, 128.69, 153.43,
2.65, 60.69, 77.48, 114.76, 29.65, 95.9, 173.43, 16.66, 44.9,
154.85, 184.81, 116.33, 59.76, 99.47, 19.71, 134.08, 156.6, 189.99,
72.41, 110.83, 33.88, 79.92, 164.67, 184.14, 106.82, 143.57,
130.66, 79.56, 35.85, 98.25, 55.28, 157.38, 185.17, 119.71, 139.45,
12.83, 95.28, 74.37, 122.15, 151.17, 182.18, 102.21, 165.77,
127.62, 199.93, 14.21, 103.97, 72.85, 38.29, 112.84, 143.04,
81.42, 172.71, 19.45, 199.71, 68.15, 45.52, 8.35, 84.83, 134.14,
29.76, 172.72)),
row.names = c(NA, -92L),
class = c("tbl_df", "tbl", "data.frame"))
radius = 50
df_sf <- test_data %>%
group_by(ImageNumber) %>%
nest() %>%
mutate(data = map(data, ~st_as_sf(.x, coords = c("Location_Center_X.nuc", "Location_Center_Y.nuc"), remove = FALSE)),
data = map(data, .f = function(x){
x <- x %>%
mutate(neighbours = st_is_within_distance(x, dist = radius),
density_circle = map_int(neighbours, ~length(.x)-1L)) %>%
select(-neighbours)
return(x)
})) %>%
unnest(cols = data)
test_obj = 85
ggplot() +
geom_point(data = df_sf %>% filter(ImageNumber == 231),
aes(x = Location_Center_X.nuc,
y = Location_Center_Y.nuc)) +
geom_circle(data = df_sf %>% filter(ImageNumber == 231 & ObjectNumber == test_obj),
aes(x0 = Location_Center_X.nuc,
y0 = Location_Center_Y.nuc,
r = radius),
color = "red") +
theme_classic()

df_sf %>% filter(ImageNumber == 231 & ObjectNumber == test_obj)
#> # A tibble: 1 x 6
#> # Groups: ImageNumber [1]
#> ImageNumber ObjectNumber Location_Center_X.~ Location_Center_Y~ density_circle
#> <dbl> <dbl> <dbl> <dbl> <int>
#> 1 231 85 69.3 33.9 10
#> # ... with 1 more variable: geometry <POINT>
count_neighbors <- function(x, y, xVal, yVal, radius) {
sum(xVal >= x-radius & xVal <= x+radius &
yVal >= y-radius & yVal <= y+radius) - 1
}
df_sf <- df_sf %>%
mutate(
density_square = map2_dbl(Location_Center_X.nuc,
Location_Center_Y.nuc,
~count_neighbors(.x,
.y,
Location_Center_X.nuc,
Location_Center_Y.nuc,
radius))
)
df_sf %>%
filter(ImageNumber == 231) %>%
ggplot(aes(x = density_circle,
y = density_square)) +
geom_point() +
geom_abline(slope = 1) +
theme_classic()

Created on 2021-09-13 by the reprex package (v2.0.1)