Cell operations are at the heart of raster grid logic. This vignette covers:
All functions use the standard vaster convention:
dimension is c(ncol, nrow) and
extent is c(xmin, xmax, ymin, ymax).
Cells are numbered starting from 1 at the top-left corner, proceeding row-wise (left-to-right, then top-to-bottom):
1 2 3 4
5 6 7 8
9 10 11 12
Use xy_from_cell() to get the centre
coordinates of cells:
## single cell
xy_from_cell(dimension, extent, 1)
#> [,1] [,2]
#> [1,] 0.5 2.5
## multiple cells
xy_from_cell(dimension, extent, c(1, 4, 9, 12))
#> [,1] [,2]
#> [1,] 0.5 2.5
#> [2,] 3.5 2.5
#> [3,] 0.5 0.5
#> [4,] 3.5 0.5
## all cells
xy_from_cell(dimension, extent, seq_len(n_cell(dimension)))
#> [,1] [,2]
#> [1,] 0.5 2.5
#> [2,] 1.5 2.5
#> [3,] 2.5 2.5
#> [4,] 3.5 2.5
#> [5,] 0.5 1.5
#> [6,] 1.5 1.5
#> [7,] 2.5 1.5
#> [8,] 3.5 1.5
#> [9,] 0.5 0.5
#> [10,] 1.5 0.5
#> [11,] 2.5 0.5
#> [12,] 3.5 0.5For just x or y coordinates:
x_from_cell(dimension, extent, 1:4)
#> [1] 0.5 1.5 2.5 3.5
y_from_cell(dimension, extent, c(1, 5, 9))
#> [1] 2.5 1.5 0.5Use cell_from_xy() to find which cell contains given
coordinates:
## coordinates at cell centres
xy <- cbind(c(0.5, 1.5, 2.5), c(2.5, 1.5, 0.5))
cell_from_xy(dimension, extent, xy)
#> [1] 1 6 11
## coordinates outside the grid return NA
xy_outside <- cbind(c(-1, 5), c(1.5, 1.5))
cell_from_xy(dimension, extent, xy_outside)
#> [1] NA NA
## coordinates on cell boundaries go to the cell below/right
## except at the grid edge where they go to the last cell
xy_edge <- cbind(c(1.0, 4.0), c(2.0, 0.0))
cell_from_xy(dimension, extent, xy_edge)
#> [1] 6 12
## get row and column for cells
rowcol_from_cell(dimension, extent, 1:12)
#> row col
#> [1,] 1 1
#> [2,] 1 2
#> [3,] 1 3
#> [4,] 1 4
#> [5,] 2 1
#> [6,] 2 2
#> [7,] 2 3
#> [8,] 2 4
#> [9,] 3 1
#> [10,] 3 2
#> [11,] 3 3
#> [12,] 3 4For just row or column:
row_from_cell(dimension, 1:12)
#> [1] 1 1 1 1 2 2 2 2 3 3 3 3
col_from_cell(dimension, 1:12)
#> [1] 1 2 3 4 1 2 3 4 1 2 3 4Note that row_from_cell() and
col_from_cell() only need dimension since
row/column positions don’t depend on extent.
Get cells for specific row/column combinations:
## single cell at row 2, column 3
cell_from_row_col(dimension, row = 2, col = 3)
#> [1] 7
## multiple cells (vectorized, with recycling)
cell_from_row_col(dimension, row = 1:3, col = 1:3) # diagonal cells
#> [1] 1 6 11Get all cells in specific rows or columns:
## all cells in row 2
cell_from_row(dimension, 2)
#> [1] 5 6 7 8
## all cells in column 3
cell_from_col(dimension, 3)
#> [1] 3 7 11Get the cross-product of rows and columns (all combinations):
## all cells in rows 1-2 AND columns 2-3
cell_from_rowcol_combine(dimension, row = 1:2, col = 2:3)
#> [1] 2 3 6 7Convert directly between row/column indices and coordinates:
## x coordinate of each column (centre)
x_from_col(dimension, extent, 1:4)
#> [1] 0.5 1.5 2.5 3.5
## y coordinate of each row (centre)
y_from_row(dimension, extent, 1:3)
#> [1] 2.5 1.5 0.5
## which column contains this x coordinate
col_from_x(dimension, extent, c(0.5, 2.5, 3.9))
#> [1] 1 3 4
## which row contains this y coordinate
row_from_y(dimension, extent, c(2.5, 1.5, 0.1))
#> [1] 1 2 3Get the bounding box that covers a set of cells:
## extent of a single cell
extent_from_cell(dimension, extent, 1)
#> [1] 0 1 2 3
## extent covering multiple cells
extent_from_cell(dimension, extent, c(1, 4)) # top row
#> [1] 0 4 2 3
extent_from_cell(dimension, extent, c(1, 12)) # full grid
#> [1] 0 4 0 3Find all cells within a given extent:
## cells within a sub-extent
sub_extent <- c(1, 3, 1, 2) # xmin=1, xmax=3, ymin=1, ymax=2
cell_from_extent(dimension, extent, sub_extent)
#> [1] 6 7The extent is automatically aligned to cell boundaries before finding cells.
Functions return NA for invalid inputs:
## invalid cell numbers
xy_from_cell(dimension, extent, c(0, 13, -1))
#> [,1] [,2]
#> [1,] 3.5 3.5
#> [2,] 0.5 -0.5
#> [3,] 2.5 3.5
## coordinates outside grid
cell_from_xy(dimension, extent, cbind(c(-1, 10), c(1, 1)))
#> [1] NA NA
## invalid row/column
cell_from_row_col(dimension, row = 0, col = 1)
#> [1] NA
cell_from_row_col(dimension, row = 4, col = 1) # only 3 rows exist
#> [1] NACreate a stratified sample by selecting one random point from each cell:
set.seed(42)
dimension <- c(5, 4)
extent <- c(0, 10, 0, 8)
## get cell centres
centres <- xy_from_cell(dimension, extent, seq_len(n_cell(dimension)))
## add random jitter within each cell
res <- c(x_res(dimension, extent), y_res(dimension, extent))
jitter_x <- runif(n_cell(dimension), -res[1]/2, res[1]/2)
jitter_y <- runif(n_cell(dimension), -res[2]/2, res[2]/2)
sample_points <- cbind(
x = centres[, 1] + jitter_x,
y = centres[, 2] + jitter_y
)
head(sample_points)
#> x y
#> [1,] 1.829612 7.808063
#> [2,] 3.874151 6.277420
#> [3,] 4.572279 7.977783
#> [4,] 7.660895 7.893336
#> [5,] 9.283491 6.164875
#> [6,] 1.038192 5.028424
## verify all points fall in expected cells
all(cell_from_xy(dimension, extent, sample_points) == seq_len(n_cell(dimension)))
#> [1] TRUEvignette("grid-fundamentals"): Basic grid conceptsvignette("extent-alignment"): Aligning extents to
gridsvignette("gdal-interop"): GDAL geotransform
operations