I’m working in R using terra and sf. I am working with some data products that are in sinusoidal projection (see crs string below, I can’t change the starting product projection) and I need to reproject them into a different equal area projection (currently selected EPSG:9311, but open to suggestions) so that other people can use and interpret the maps more easily. The issue is, when I reproject, the data seem to shift eastward about 2 grid cells. I think this has to do with some kind of rounding bias, but I really don’t have an explanation of why this is occurring. Can you help?
library(terra)
library(sf)
library(dplyr)
library(rnaturalearth)
# get sinusoidal projection and resolution of original raster
a_crs <- 'PROJCRS["unnamed",
BASEGEOGCRS["unnamed ellipse",
DATUM["unknown",
ELLIPSOID["unnamed", 6371007.181, 0,
LENGTHUNIT["metre", 1,
ID["EPSG", 9001]]]],
PRIMEM["Greenwich", 0,
ANGLEUNIT["degree", 0.0174532925199433,
ID["EPSG", 9122]]]],
CONVERSION["Sinusoidal",
METHOD["Sinusoidal"],
PARAMETER["Longitude of natural origin", 0,
ANGLEUNIT["degree", 0.0174532925199433],
ID["EPSG", 8802]],
PARAMETER["False easting", 0,
LENGTHUNIT["metre", 1],
ID["EPSG", 8806]],
PARAMETER["False northing", 0,
LENGTHUNIT["metre", 1],
ID["EPSG", 8807]]],
CS[Cartesian, 2],
AXIS["easting", east,
ORDER[1],
LENGTHUNIT["metre", 1,
ID["EPSG", 9001]]],
AXIS["northing", north,
ORDER[2],
LENGTHUNIT["metre", 1,
ID["EPSG", 9001]]]]'
a_res <- c(2962.807, 2962.8090)
#Get the state of Connecticut (the spatial error is more obvious in smaller states)
state <- ne_states(country = "United States of America", returnclass = "sf") |>
filter(name == 'Connecticut') |>
st_transform(a_crs)
# Define the extent of the test grid (xmin, xmax, ymin, ymax)
extent_grid <- ext(state)
# Create the raster with the specified extent and resolution
raster_grid <- rast(extent = extent_grid, resolution = a_res) # ~3km resolution
# Set the CRS of the raster
crs(raster_grid) <- a_crs
# assign a grid of values to the test grid
values(raster_grid) <- c(1,rep(0,9))
# grid cell touches the state or has centroid within the state
mask <- rasterize(vect(state), raster_grid, background=NA, touches = T)
raster_grid[!is.na(mask)] <- raster_grid[!is.na(mask)] + 3
# grid cell has centroid within the state
mask <- rasterize(vect(state), raster_grid, background=NA, fun = 'sum')
raster_grid[!is.na(mask)] <- raster_grid[!is.na(mask)] + 3
# view the starting (terrible) data projection and alignment with state vector geometry
plot(raster_grid)
plot(state$geometry, add = T)
# transform the state and raster to the new crs
transformed_state <- st_transform(state, crs('EPSG:9311'))
transformed_raster <- project(raster_grid, crs('EPSG:9311'), res = a_res, method='near')
# view problematic reprojection
plot(transformed_raster) #Why??!
plot(transformed_state$geometry, add = T)
This is the expected/desired output
# Get the current extent
current_extent <- ext(transformed_raster)
# Calculate the new extent by shifting 2 cells left
new_extent <- c(
xmin = current_extent$xmin - 2 * a_res[1],
xmax = current_extent$xmax - 2 * a_res[1],
ymin = current_extent$ymin,
ymax = current_extent$ymax)
# Create a new raster with the adjusted extent
shifted_raster <- rast(ncol= ncol(transformed_raster), nrow= nrow(transformed_raster),
ext= new_extent, crs= crs(transformed_raster))
# Copy the values from the original raster to the new raster
values(shifted_raster) <- values(transformed_raster)
# Plot shifted alignment
plot(shifted_raster)
plot(transformed_state$geometry, add = T)
This also occurs with other reprojection methods, such as bilinear interpolation. I wasn’t sure if there was a trigonometric reason for the shift, like perhaps it was sqrt(2)/2
in the south-easterly direction, but that didn’t seem to improve the accuracy either.
CodeUP is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.