--- title: "5. vector-raster conversions, reprojection, warping" author: "Edzer Pebesma" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{5. vector-raster conversions, reprojection, warping} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- **For a better version of the stars vignettes see** https://r-spatial.github.io/stars/articles/ ```{r setup, include=FALSE} knitr::opts_chunk$set(echo = TRUE, collapse = TRUE, dev = "png") suppressPackageStartupMessages(library(sf)) knitr::opts_chunk$set(fig.height = 4.5) knitr::opts_chunk$set(fig.width = 6) ev = TRUE ``` This vignette shows how `stars` object can be moved from vector and raster representations. # Rasterizing an `sf` vector object ```{r} library(stars) system.file("gpkg/nc.gpkg", package = "sf") %>% read_sf() %>% st_transform(32119) -> nc nc$dens = nc$BIR79 / units::set_units(st_area(nc), km^2) (nc.st = st_rasterize(nc["dens"], dx = 5000, dy = 5000)) plot(nc.st) ``` The algorithm used is the GDAL `rasterize` utility, all options of this utility can be passed to `st_rasterize`. The geometry of the final raster can be controlled by passing a target bounding box and either the raster dimensions `nx` and `ny`, or pixel size by the `dx` and `dy` parameters. # Vectorizing a raster object to an `sf` object `stars` objects can be converted into an `sf` object using `st_as_sf`. It has a number of options, depending on whether pixels represent the point value at the pixel center, or small square polygons with a single value. We will work again with the landsat-7 6-band image, but will select the first band and round the values: ```{r} tif = system.file("tif/L7_ETMs.tif", package = "stars") x = read_stars(tif)[, 1:50, 1:50, 1:2] x[[1]] = round(x[[1]]/5) ``` ## Polygonizing In case raster cells reflect point values and we want to get a vector representation of the whole field, we can draw contour lines and export the contour sets (only available when the GDAL version is at least 2.4.0): ```{r eval=ev} l = st_contour(x, contour_lines = TRUE, breaks = 11:15) plot(l[1], key.pos = 1, pal = sf.colors, lwd = 2, key.length = 0.8) ``` ## Exporting to points Alternatively, we can simply export all the pixels as points, and get them either as a wide table with all bands per point, and no replicated `POINT` geometries: ```{r} st_as_sf(x, as_points = TRUE, merge = FALSE) ``` or as a long table with a single attribute and all points replicated: ```{r} st_as_sf(x, as_points = TRUE, merge = FALSE, long = TRUE) ``` as we can see, an additional attribute `band` now indicates which band is concerned. ## Exporting to polygons Alternatively, we can export to polygons and either get a single polygon per pixel, as in ```{r} st_as_sf(x[1], as_points = FALSE, merge = FALSE) ``` or merge polygons that have identical pixel values; ```{r} p = st_as_sf(x, as_points = FALSE, merge = TRUE) ``` When plotted with boundaries, we see the resolved boundaries of areas with the same pixel value: ```{r} plot(p) ``` A further option `connect8` can be set to `TRUE` to use 8 connectedness, rather than the default 4 connectedness algorithm. In both cases, the polygons returned will often be invalid according to the simple feature standard, but can be made valid using `lwgeom::st_make_valid`. # Switching between vector and raster in `stars` objects We can convert a raster dimension to a vector dimension while keeping other dimensions as they are in a `stars` object by ```{r} x.sf = st_xy2sfc(x, as_points = TRUE) x.sf ``` which also requires setting the `as_points` arguments as in `st_as_sf`. # Reprojecting a raster If we accept that curvilinear rasters are rasters too, and that regular and rectilinear grids are special cases of curvilinear grids, reprojecting a raster is no longer a "problem", it just recomputes new coordinates for every raster cell, and generally results in a curvilinear grid (that sometimes can be brought back to a regular or rectilinear grid). If curvilinear grid cells are represented by coordinates of the cell center, the actual shape of a grid cell gets lost, and this may be a larger effect if grid cells are large or if the transformation is stronger non-linear. An example of the reprojection of the grid created above is ```{r} nc.st %>% st_transform("+proj=laea +lat_0=34 +lon_0=-60") -> nc.curv nc.curv plot(nc.curv, border = NA, graticule = TRUE) ``` where it should be noted that the dimensionality of the grid didn't change: the same set of raster cells has been replotted in the new CRS, but now in a curvilinear grid. # Warping a raster Warping a raster means creating a new _regular_ grid in a new CRS, based on a (usually regular) grid in another CRS. We can do the transformation of the previous section by first creating a target grid: ```{r} nc %>% st_transform("+proj=laea +lat_0=34 +lon_0=-60") %>% st_bbox() %>% st_as_stars() -> newgrid ``` and then warping the old raster to the new ```{r} nc.st %>% st_warp(newgrid) -> nc.new nc.new plot(nc.new) ``` This new object has a regular grid in the new CRS, aligned with the new x- and y-axes.