'Extract cells values of a matrix within a circle (in R)

In a matrix I would like to select a cell having a certain value (3 in the following example) and determine the number of cells having a value of 1 and 2, within a circle centered on this cell (having the value of 3). The radius of the circle could be by example of 5 cells. How to perform it ?

> setwd("F:/")
> ##Load matrix from excel
> mat <- read.csv("test.csv",  header = TRUE)
> 
> ##convert from data.frame to matrix
> mat <- as.matrix(mat)
> mat
      X1 X1.1 X1.2 X1.3 X1.4 X1.5 X1.6 X1.7 X1.8 X1.9 X1.10 X1.11 X1.12 X1.13
 [1,]  1    1    1    1    1    1    1    1    1    1     1     1     1     1
 [2,]  1    1    1    1    1    1    2    1    1    1     1     1     1     2
 [3,]  1    1    1    1    2    2    2    1    1    1     1     2     2     2
 [4,]  1    1    1    1    1    1    1    1    1    1     1     1     1     1
 [5,]  1    2    1    1    1    1    1    1    2    1     1     1     1     1
 [6,]  1    2    1    1    1    1    1    1    2    1     1     1     1     1
 [7,]  1    2    1    1    1    1    1    1    2    1     1     2     1     1
 [8,]  1    2    2    1    1    1    1    1    2    2     1     2     1     1
 [9,]  1    1    1    2    1    1    1    3    1    1     1     2     1     1
[10,]  1    1    1    1    1    1    1    1    1    1     1     1     1     1
[11,]  1    1    1    1    1    1    1    1    1    1     1     1     1     1
[12,]  1    1    1    1    1    1    1    1    1    2     2     2     1     1
[13,]  1    1    1    1    1    1    2    1    1    1     1     1     1     2
[14,]  1    1    1    1    2    2    2    1    1    1     1     2     2     2
[15,]  1    1    1    1    2    2    2    1    1    1     1     2     2     2
[16,]  1    1    2    2    2    1    1    1    1    1     1     1     1     1

To illustrate: enter image description here



Solution 1:[1]

Example Data

A 10x10 matrix with 3 assigned to two places([1, 1] and [5, 5]).

mat <- matrix(sample(1:2, 10*10, TRUE), 10)
mat[1, 1] <- 3
mat[5, 5] <- 3

Find the coordinates of center cells and the area to detect the number of cells having a value of 1 and 2.

cent <- which(mat == 3, arr.ind = TRUE)
#      row col
# [1,]   1   1
# [2,]   5   5

area <- arrayInd(which(mat %in% 1:2), dim(mat))

Calculate distances between centers and each cell in the detecting area, and then count the number of cells within the radius (I set 3 here)

apply(cent, 1, \(x) sum(sqrt(colSums((t(area) - x)^2)) <= 3))
# [1] 10 28

or output the coordinates of those cells directly.

apply(cent, 1, \(x) area[sqrt(colSums((t(area) - x)^2)) <= 3, ])

Solution 2:[2]

The proposed solution does not work on my computer, so I used the same idea but with a different code to calculate the distance as follow:

#Example Data
#A 10x10 matrix with 3 assigned to [5, 5]).

mat <- matrix(sample(1:2, 10*10, TRUE), 10)
mat[5, 5] <- 3
mat

#Find the coordinates of center cell having value of 3.
cent <- which(mat == 3, arr.ind = TRUE)
cent

#Find the area to detect the number of cells having a value of 1
area1 <- arrayInd(which(mat %in% 1), dim(mat))

#Find the area to detect the number of cells having a value of 2
area2 <- arrayInd(which(mat %in% 2), dim(mat))

library(raster)
#calculate distance between center and area1
distance1 <- pointDistance(cent, area1, lonlat=FALSE)
dataframe1 <- as.data.frame(distance1)

#extract only distance lower than 3
data1 <- as.data.frame(dataframe[dataframe1$distance < 3, ])
totalClass1 <- as.numeric(nrow(data1))

#calculate distance between center and area2
distance2 <- pointDistance(cent, area2, lonlat=FALSE)
dataframe2 <- as.data.frame(distance2)

#extract only distance lower than 3
data2 <- as.data.frame(dataframe[dataframe2$distance < 3, ])
totalClass2 <- as.numeric(nrow(data2))

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Laurent