Avril
Avril

Reputation: 23

R: Populate rectangular grid with coordinate pair

Given a list of xy coordinates how can one populate a rectangular xy grid with standard incremental changes of 0.5 with where a given coordinate pair occurs?

For example, say we have the following coordinate pairs:

pts <- data.frame(X = c(1.9,2.4,1.1), Y = c(4.5,1.2,3.2))

And empty grid such as:

gridX = seq(0,2.5,by=0.5)
gridY = seq(0,5,by=0.5)

How to create a result which indicates whether a grid section contains a coordinate pair such that:

    result
      0 0.5 1 1.5 2 2.5 3 3.5 4 4.5 5
1 0.0 0   0 0   0 0   0 0   0 0   0 0
2 0.5 0   0 0   0 0   0 0   0 0   0 0
3 1.0 0   0 0   0 0   0 0   0 0   0 0
4 1.5 0   0 0   0 0   0 0   1 0   1 0
5 2.0 0   0 0   0 0   0 0   0 0   0 0
6 2.5 0   0 0   1 0   0 0   0 0   0 0

A somewhat similar question is posed here (using Python): How to check if a coordinate pair (lat,lon) exists in a coordinate grid?. However I need to figure out how to this for multiple coordinate pairs, including instances where more than one coordinate pair might fall within the same grid section, that grid section would still be 1.

Upvotes: 2

Views: 261

Answers (2)

MacOS
MacOS

Reputation: 1159

You can build upon the following.

pts <- data.frame(X = c(1.9,2.4,1.1), Y = c(4.5,1.2,3.2))

gridX = seq(0, 2.5, by=0.5)
gridY = seq(0, 5, by=0.5)

grid.matrix <- matrix(0, nrow=length(gridY), ncol=length(gridX))

grid <- data.frame(
  grid.matrix,
  row.names=gridY)

colnames(grid) <- gridX

The only thing left now is to find the correct row and column. This can be done with an iflese, for example.

EDIT

A better way to do it is to use match and aggregate. The full code listening looks as follows.

pts <- data.frame(X = c(1.9,2.4,1.1), Y = c(4.5,1.2,3.2))

gridX = seq(0, 2.5, by=0.5)
gridY = seq(0, 5, by=0.5)

grid.matrix <- matrix(0, nrow=length(gridY), ncol=length(gridX))

grid <- data.frame(
  grid.matrix,
  row.names=gridY)

colnames(grid) <- gridX

pts$X.in.grid <- round(pts$X*2)/2
pts$Y.in.grid <- round(pts$Y*2)/2

pts$X.idx.in.grid <- match( pts$X.in.grid , colnames(grid) )
pts$Y.idx.in.grid <- match( pts$Y.in.grid , row.names(grid))

df.update <- aggregate(
  X.idx.in.grid + Y.idx.in.grid ~ X.idx.in.grid + Y.idx.in.grid ,
  pts, length )
colnames(df.update)[3] <- "value"

for (index in 1:nrow(df.update)) {
  grid[ df.update$Y.idx.in.grid[index], df.update$X.idx.in.grid[index] ] <- df.update$value[index]
}

which gives you.

structure(list(`0` = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), `0.5` = c(0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0), `1` = c(0, 0, 0, 0, 0, 0, 1, 0, 
0, 0, 0), `1.5` = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), `2` = c(0, 
0, 0, 0, 0, 0, 0, 0, 0, 1, 0), `2.5` = c(0, 0, 1, 0, 0, 0, 0, 
0, 0, 0, 0)), row.names = c("0", "0.5", "1", "1.5", "2", "2.5", 
"3", "3.5", "4", "4.5", "5"), class = "data.frame")

Upvotes: 0

Martin Gal
Martin Gal

Reputation: 16978

Since your grid uses a step width of 0.5 you could use

> floor(pts*2)/2
    X   Y
1 1.5 4.5
2 2.0 1.0
3 1.0 3.0

to get the points on your grid.

Depending on your rounding logic, you could replace floor by

> ceiling(pts*2)/2
    X   Y
1 2.0 4.5
2 2.5 1.5
3 1.5 3.5

or simply by rounding

> round(pts*2)/2
    X   Y
1 2.0 4.5
2 2.5 1.0
3 1.0 3.0

Adding the points to your grid

Adding the points to your grid depends on the data structure your grid is stored in.

For example: Your grid is stored in a matrix with named rows and columns

grid <- matrix(0, ncol=length(gridX), nrow=length(gridY))
rownames(grid) <- gridX
colnames(grid) <- gridY

and your new points are given by

new_pts <- round(pts*2)/2

In this case retrieve your desired matrix by

grid[as.character(new_pts$X), as.character(new_pts$Y)] <- diag(1,nrow(new_pts))

That's not very sophisticated, but it works.

Upvotes: 1

Related Questions