Reputation: 449
I obtain a matrix from a calculation. This matrix can have spots of 1 while the rest of the matrix presents values of 0, 2 and 3.
> ##Working folder
> setwd("C:/Users/laure/Desktop/Code")
> ##Load matrix from excel
> mat <- read.csv("test.csv", header = TRUE)
> mat <- as.matrix(mat)
> mat
X1 X1.1 X0 X0.1 X0.2 X0.3 X1.2 X1.3
[1,] 1 0 0 0 3 0 0 2
[2,] 1 2 0 3 1 1 0 0
[3,] 0 0 0 0 3 1 0 0
[4,] 2 0 0 0 0 0 0 0
[5,] 0 0 0 0 0 0 2 2
[6,] 0 0 1 0 0 0 2 2
[7,] 0 1 1 1 0 0 2 2
[8,] 0 0 1 1 0 0 2 2
[9,] 0 0 1 0 0 0 0 0
[10,] 0 0 0 0 0 0 0 0
[11,] 0 0 0 0 2 0 0 1
[12,] 0 0 0 0 2 2 1 1
[13,] 1 1 0 0 0 0 1 1
[14,] 1 1 0 0 0 1 1 1
[15,] 1 1 1 0 0 1 1 1
I would like to replace all the spots of 1 that are completely surrounded by cell values of 0 (in this example have only 1 spot completely surrounded by 0). I do not want to include the spot of 1 on the borders as there are not completely surrounded. I do not know the location and the number of the spots as it depends of the calculation performed before.
I can find the all spots having value of 1 using clump
function but how to find the surrounding cells value and replace the spot cells.
####convert matrix into raster
r <-raster(mat)
####select cells with criteria based on cell value
rx <- r == 1
###extract IDs of clumps according the criteria
rc <- clump(rx)
f <- freq(rc, useNA="no")
> f
value count
[1,] 1 2
[2,] 2 3
[3,] 3 7
[4,] 4 11
[5,] 5 7
Upvotes: 1
Views: 110
Reputation: 20329
Adopting the approach from compute_neighb_sum
you can use the following code:
embed_matrix <- function(mx) {
cbind(Inf, rbind(Inf, mx, Inf), Inf)
}
disembed_matrix <- function(mx) {
mx[-c(1, nrow(mx)), -c(1, ncol(mx)), drop = FALSE]
}
is_valid_idx <- function(idx, dim) {
rowSums(t(t(idx) > dim | t(idx) < 0)) == 0
}
sum_neighbor_cells <- function(m, include_corner = TRUE, include_element = FALSE) {
em <- embed_matrix(m)
dims <- dim(em)
offsets <- as.matrix(expand.grid(r = -1:1, c = -1:1))
exclude_offsets <- matrix(integer(0), ncol = 2)
if (!include_element) {
exclude_offsets <- rbind(exclude_offsets, c(0, 0))
}
if (!include_corner) {
exclude_offsets <- rbind(exclude_offsets,
matrix(c(-1, -1, 1, 1, -1, 1, -1, 1), ncol = 2))
}
dupes <- duplicated(rbind(offsets, exclude_offsets), fromLast = TRUE)
offsets <- offsets[!dupes[seq_len(nrow(offsets))], , drop = FALSE]
idx <- cbind(c(row(em)), c(col(em)))
res <- apply(offsets, 1, function(row) {
t(t(idx) + row)
})
dim(res) <- c(dim(idx), nrow(offsets))
idx <- aperm(res, 3:1)
res <- apply(idx, 3, function(i) {
valid_idx <- i[is_valid_idx(i, dims), ,
drop = FALSE]
sum(em[valid_idx])
})
dim(res) <- dims
res <- disembed_matrix(res)
res
}
Then you can use sum_neighbor_cells
to get the sum of all neighboring cells (with ot without the corner cells):
set.seed(123)
(m <- matrix(sample(0:1, 25, TRUE), 5))
# [,1] [,2] [,3] [,4] [,5]
# [1,] 0 1 1 0 0
# [2,] 0 1 1 1 1
# [3,] 0 1 1 0 0
# [4,] 1 0 0 0 0
# [5,] 0 0 1 0 0
sum_neighbor_cells(m, include_corner = FALSE)
# [,1] [,2] [,3] [,4] [,5]
# [1,] Inf Inf Inf Inf Inf
# [2,] Inf 3 4 2 Inf
# [3,] Inf 2 2 2 Inf
# [4,] Inf 2 2 0 Inf
# [5,] Inf Inf Inf Inf Inf
sum_neighbor_cells(m, include_corner = TRUE)
# [,1] [,2] [,3] [,4] [,5]
# [1,] Inf Inf Inf Inf Inf
# [2,] Inf 5 6 4 Inf
# [3,] Inf 4 4 4 Inf
# [4,] Inf 4 3 2 Inf
# [5,] Inf Inf Inf Inf Inf
With this function you can get the indices of cells with have only 0's
as neighboring cells easily via:
(idx <- which(sum_neighbor_cells(m, include_corner = FALSE) == 0, arr.ind = TRUE))
# row col
# [1,] 4 4
m[idx] <- NA
m
# [,1] [,2] [,3] [,4] [,5]
# [1,] 0 1 1 0 0
# [2,] 0 1 1 1 1
# [3,] 0 1 1 0 0
# [4,] 1 0 0 NA 0
# [5,] 0 0 1 0 0
Upvotes: 1