Assign coordinates to raster r - r

I would like to assign lonlatto a rasterbrick, r. rwas read from a netcdf file which had latlon in it. However, after reading the data, the metadata looks like:
class : RasterBrick
dimensions : 699, 639, 446661, 4779 (nrow, ncol, ncell, nlayers)
resolution : 1, 1 (x, y)
extent : 0.5, 639.5, 0.5, 699.5 (xmin, xmax, ymin, ymax)
coord. ref. : NA
CRS=CRS("+proj=lcc +lat_1=33 +lat_2=45 +lat_0=40 +lon_0=-97 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs") # WRF proj4")
I then read in the latlon separately into R:
library(ncdf4)
ncname <- "file.nc"
ncfname <- paste(ncname, ".nc4", sep = "")
dname <- "tmp" # note: tmp means temperature (not temporary)
# open a NetCDF file
ncin <- nc_open(ncfname, write = T)
print(ncin)
#---------
lon <- ncvar_get(ncin, "XLONG")
nlon <- dim(lon)
head(lon)
lat <- ncvar_get(ncin, "XLAT", verbose = F)
nlat <- dim(lat)
head(lat)
print(c(nlon, nlat))
[1] 639 699 639 699
You will notice that nlon and nlat has the same dimensions as r.
I don't want to projectRaster.
Question:
How can I assign the imported lon and latto r such that the extent of r is min(lon), max(lon), min(lat), max(lat)?
I tried coordinates(dat)=c(lon,lat) but it did not work.
Thanks.

Related

How to extract data point for a xy coordiante from raster without projected lat lopn coordinates

Hi am trying to extract values for xy point from a sample raster stack ras_dt. The ras_dt is EQUATES data with gridded coordinates within the domain of -115.00,38.00,-110.05,45.00. How can I change the projection and the lat lon coordinates of this raster stack so that I can extract data for point xy as in the code below.
library(raster)
dturl<- "https://www.dropbox.com/s/ztxqpszjfjhpavz/EQUATES_ACONC_O3_SAM.nc?dl=1"
download.file(dturl, "EQUATES_ACONC_O3_SAM.nc")
ras_dt <- raster::stack("EQUATES_ACONC_O3_SAM.nc",varname = "O3")
ras_dt
# the data domain is -115.00,38.00,-110.05,45.00
plot(ras_dt)
xy <- data.frame(lon=-113.0,lat=40.0)
coordinates(xy) <- ~lon + lat
extr_dt <- raster::extract(ras_dt, xy) # how to get O3 values for xy here?
extr_dt
The ras_dt is in "lambertConformalProjection" with following info:
char LambertConformalProjection;
:grid_mapping_name = "lambert_conformal_conic";
:latitude_of_projection_origin = 40.0; // double
:longitude_of_central_meridian = -97.0; // double
:standard_parallel = 33.0, 45.0; // double
:earth_radius = 6370000.0; // double
:_CoordinateTransformType = "Projection";
:_CoordinateAxes = "x y";
You need to set the extent and the coordinate reference system (CRS). Then transform your lon/lat points to that CRS and use extract. From your edited question we now have the CRS.
You specify the "domain", but you need to coordinates in the actual CRS. I do not know what these are, so I will guestimate it, but it will not be correct.
The data
library(terra)
dturl<- "https://www.dropbox.com/s/ztxqpszjfjhpavz/EQUATES_ACONC_O3_SAM.nc?dl=1"
download.file(dturl, "EQUATES_ACONC_O3_SAM.nc", mode="wb")
ras_dt <- rast("EQUATES_ACONC_O3_SAM.nc", "O3")
pcrs <- "+proj=lcc +lon_0=-97 +lat_0=40 +lat_1=33 +lat_2=45 +r =6370000.0"
Rough estimate of the extent:
v <- vect(rbind(c(-115, 38), c(-115, 45), c(-110.05, 38), c(-110.05, 45)), crs="+proj=longlat")
p <- project(v, pcrs)
e <- crds(p) |> apply(2, range) |> as.vector()
e
#[1] -1562368.5 -1025418.3 -139104.3 693662.9
Set the extent and the crs
ext(ras_dt) <- e
crs(ras_dt) <- pcrs
Transform the points to the crs of the raster
xy <- vect(cbind(lon=-113.0,lat=40.0), crs="+proj=longlat")
pxy <- project(xy, pcrs)
And extract
extract(ras_dt, pxy)
# ID O3_LAY=1_TSTEP=1 O3_LAY=1_TSTEP=2
#1 1 41.88482 40.99662
So our raster now looks like this. The spatial resolution should probably be a round number (12,000?)
ras_dt
#class : SpatRaster
#dimensions : 70, 45, 2 (nrow, ncol, nlyr)
#resolution : 11932.23, 11896.67 (x, y)
#extent : -1562369, -1025418, -139104.3, 693662.9 (xmin, xmax, ymin, ymax)
#coord. ref. : +proj=lcc +lat_0=40 +lon_0=-97 +lat_1=33 +lat_2=45 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs
#source : EQUATES_ACONC_O3_SAM.nc:O3
#varname : O3 (O3 )
#names : O3_LAY=1_TSTEP=1, O3_LAY=1_TSTEP=2
#unit : ppbV , ppbV
Can you find and provide the correct extent somewhere in the documentation? And perhaps ask the data providers to follow the NetCDF conventions such that all the metadata required to use the data is stored in the files.

Is this the correct way to crop, reproject and resample a raster file?

I'm working with environmental raster layers from WorldClim V2.1 (30 seconds resolution) in Latin America. I want the layers to be of a precise resolution (50km2 pixel size). However, I'm a bit unsure whether I'm following the correct steps to process the files. Any help on checking the process would be much appreciated.
And one last thing, I'm wondering what is the terra::resample doing with NAs.
Thanks !
Here's an example with average annual temperature
Libraries
library(rnaturalearth)
library(terra)
library(sf)
library(tidyverse)
Basemaps
# world and Latin America
world <- rnaturalearth::ne_countries(scale = 'medium', returnclass = 'sf')
bbox_Latam_unprojected <- c(xmin=-118.40137, ymin=-55.89170, xmax=-34.80547, ymax= 32.71533)
Latam_unprojected <- world %>% st_crop(bbox_Latam_unprojected)
# equal area projection (Equatorial Lambert azimuthal equal-area)
equalareaCRS <- '+proj=laea +lon_0=-73.125 +lat_0=0 +datum=WGS84 +units=m +no_defs'
Latam_projected <- sf::st_transform(Latam_unprojected, crs=equalareaCRS)
Latam <- st_union(Latam_projected)
# raster of Latin America to use as template - 50km^2 (50000m^2)
Latam.grid <- st_make_grid(Latam+1000, cellsize = 50000, crs = equalareaCRS) %>%
st_sf('geometry' = ., 'occ'= 0)
r <- rast(res=50000, ext(vect(Latam.grid)), crs=equalareaCRS)
Latam.raster <- terra::rasterize(x = vect(Latam.grid),
y = r, field = 'occ') %>% terra::mask(., vect(Latam))
Environmental layer
# annual temperature files
url <- 'https://biogeo.ucdavis.edu/data/worldclim/v2.1/base/wc2.1_30s_tavg.zip'
download.file(url, destfile='data/wc2.1_30s_tavg')
# average annual temperature
tavg_files <- list.files('data/wc2.1_30s_tavg', '.tif', full.names=TRUE)
world_tavg <- rast(tavg_files)
tavg_unprojected <- crop(world_tavg, ext(Latam_unprojected)+1)
tavg <- project(tavg_unprojected, equalareaCRS, method='near') # reproject to equal area
tavg <- mean(tavg)
names(tavg) <- 'tavg'
# resample to Latam's preferred resolution
tavg_Latam <- terra::resample(tavg, Latam.raster, method='bilinear')
tavg
class : SpatRaster
dimensions : 12512, 11213, 1 (nrow, ncol, nlyr)
resolution : 829.4488, 829.4488 (x, y)
extent : -5009004, 4291606, -6411068, 3966996 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=laea +lat_0=0 +lon_0=-73.125 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs
source : tavg.tif
name : tavg
min value : -15.775
max value : 29.56667
tavg_Latam
class : SpatRaster
dimensions : 199, 172, 1 (nrow, ncol, nlyr)
resolution : 50000, 50000 (x, y)
extent : -4409882, 4190118, -6080809, 3869191 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=laea +lat_0=0 +lon_0=-73.125 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs
source : memory
name : tavg
min value : -2.684936
max value : 29.17986
Cheers,
Flo

Issue Converting HDF5 into raster format

I am trying to convert my h5 daily files into a raster format. I converted into raster format. When I extracted my area of interest. I could not extract my area of interest from the raster image Kindly anyone guides me on how to solve this issue. The R code and hf5 file and after conversion raster image are present in link (attached). Thanks
library(rhdf5)
library(sp)
library(raster)
h5ls("reconstruction_indus_CY2001.h5")
h5readAttributes(file = "reconstruction_indus_CY2001.h5", name = "Grid")
h5f = H5Fopen("reconstruction_indus_CY2001.h5")
# h5f
# h5f&'Grid'
#system.time( swe <- h5f$Grid$swe )
system.time( melt <- h5f$Grid$melt )
locations <- data.frame(
lon=c(74.86764,73.48753, 74.87066 , 73.37798 , 78.82102 ,75.85160 ,75.78263 , 78.46446 ),
lat = c(35.16700, 36.25674, 36.49362, 35.21188, 34.20916, 34.48459, 35.76965, 33.23380)
)
coordinates(locations) <- ~lon+lat
proj4string(locations) <- CRS("+proj=longlat")
swe180 <- melt[,,180]
b <- swe180 == 65535
# table(b)
swe180[b] <- -1
b <- swe180 > 200
# table(b)
swe180[b] <- 200
b <- swe180 < 0
# table(b)
swe180[b] <- 20
# image(swe180)
# image(swe180)
# str(swe180)
# h5readAttributes(file = "reconstruction_Sierra_2016.h5", name = "Grid")$ReferencingMatrix
RM <- h5readAttributes(file = "reconstruction_indus_CY2001.h5", name = "Grid")$ReferencingMatrix
#GT <- GridTopology(c(RM[3,1], RM[3,2]+RM[1,2]*dim(swe)[1]), c(RM[2,1], -RM[1,2]), c(dim(swe)[2],dim(swe)[1]))
GT <- GridTopology(c(RM[3,1], RM[3,2]+RM[1,2]*dim(melt)[1]), c(RM[2,1], -RM[1,2]), c(dim(melt)[2],dim(melt)[1]))
# GT <- GridTopology(c(-1.088854e+07, 4718608.3619-463.3127*1978), c(463.3127, 463.3127), c(2171,1978))
# GT
SG = SpatialGrid(GT)
# str(SG)
# proj4string(SG) <- CRS("+proj=sinu")
# str(SG)
proj4string(SG) <- CRS("+proj=utm +zone=43 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0")
locations_aea <- spTransform(locations, CRS(proj4string(SG)))
SGDF = SpatialGridDataFrame(SG, data.frame(melt = as.numeric(t(swe180))))
gridded(SGDF)<- TRUE
r = raster(SGDF)
plot(SGDF, axes=T)
writeRaster(r,"test_2001.tif",overwrite=TRUE)
## Open Raster Files and Extract Area of Interest
shp= readOGR("Hunza.shp")
e = extent(shp)
r1 = raster("test_2001.tif")
crs(r1) = "+proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0 "
plot(r1)
r1_mask = raster::mask(r1,shp)
plot(r1_mask,axes = TRUE,ext = extent(shp))
# Extracting Values as Data Frame
r1_extract = raster::extract(r1,shp, df=TRUE,na.rm = TRUE)
# Stroing as Raster
writeRaster(r1_mask,paste0('/shared/MODIS/shastaH5SWEinR/2001_swe/Hunza/','hunza.tif'))
c = cbind(r1_extract,y)
c1=t(c)
write.csv(c1,file = 'Hunza_SWE_2001.csv')
https://drive.google.com/drive/folders/18-hj2LEYWBN-uIDDTdqZ-x-WUxpCJu7H?usp=sharing
You can use the terra package (raster replacement) to shortcut this. terra can read hdf5 files directly.
The file has multiple sub-datasets, so it is easiest to read it as a SpatDataSet
library(terra)
f <- "reconstruction_indus_CY2001.h5"
s <- sds(f)
s
#class : SpatDataSet
#subdatasets : 3
#dimensions : 3651, 1641 (nrow, ncol)
#nlyr : 1, 365, 365
#resolution : 0.2193784, 0.04930156 (x, y)
#extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
#coord. ref. : +proj=longlat +datum=WGS84 +no_defs
#names : maxswedates, melt, swe
And now get the variable of interest
r <- s$swe
r
#class : SpatRaster
#dimensions : 3651, 1641, 365 (nrow, ncol, nlyr)
#resolution : 0.2193784, 0.04930156 (x, y)
#extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
#coord. ref. : +proj=longlat +datum=WGS84 +no_defs
#data source : swe
#names : swe_1, swe_2, swe_3, swe_4, swe_5, swe_6, ...
A more direct way to get the same result is
r <- rast(f, "//Grid/swe")
And you can discover what is inside of a HDF5 file by running
sds_info(f)
Plot the first layer
plot(r, 1)
Extract area of interest, for example like this
v <- vect("Hunza.shp")
x <- crop(r, v)
y <- mask(x, v)
To save as a raster file you can add a filename to the functions above. Or you can do it later like this
y <- writeRaster(y, "hunza.tif")
To save the values to a csv file:
vy <- values(y)
write.csv(vy, 'Hunza_SWE_2001.csv', row.names=FALSE)
Most function names in terra are the same as in raster. See ?terra for differences. If you want to continue in raster you can do
library(raster)
b <- brick(y)

Extract raster value based on list of coordinates - spTransform?

I wish to extract raster values based on a list of coordinates. I’ve found online some scripts that include coordinates(), SpatialPoints(), crs() and spTransform() and other that don’t. Could someone kindly explain if script 1 or script 2 is correct and why? Thank you very much!
SCRIPT 1
sites <- read.csv("df.csv")
coordinates(sites)= ~ Longitude+ Latitude
mypoints = SpatialPoints(sites,proj4string = CRS("+init=epsg:4326"))
myproj = CRS(myraster)
points.proj = spTransform(mypoints, myproj)
myvalues = extract(myraster, points.proj)
SCRIPT 2
sites <- read.csv("df.csv")
myvalues = extract(myraster, cbind(sites$Longitude, y=sites$Latitude), df=TRUE, method='simple', cellnumbers=T)
Either could be correct. With RasterLayer r and data.frame sites you can do
v <- extract(r, sites[, c("Longitude", "Latitude")])
Under the assumption that "Longitude" and "Latitude" are variables in sites.
However that only works when r also has a ("Longitude", "Latitude") coordinate reference system. That may not be the case. Consider this RasterLayer
f <- system.file("external/test.grd", package="raster")
r <- raster(f)
r
#class : RasterLayer
#dimensions : 115, 80, 9200 (nrow, ncol, ncell)
#resolution : 40, 40 (x, y)
#extent : 178400, 181600, 329400, 334000 (xmin, xmax, ymin, ymax)
#crs : +proj=sterea +lat_0=52.15616055555555 +lon_0=5.38763888888889 +k=0.9999079 +x_0=155000 +y_0=463000 +ellps=bessel +units=m +towgs84=565.237,50.0087,465.658,-0.406857,0.350733,-1.87035,4.0812 +no_defs
#source : C:/soft/R/R-3.6.1/library/raster/external/test.grd
#names : test
#values : 128.434, 1805.78 (min, max)
The crs is "sterea ..." and the extent "178400, 181600, ...) shows that the coordinates are clearly not longitude and latitude (they are expressed in meters away from the origin of the crs.)
In this case, you might have a point in the area covered by r
site <- data.frame(Longitude=5.745039, Latitude=50.96254)
But extract returns NA because the crs do not match
extract(r, site)
# [,1]
#[1,] NA
So we do
pts <- SpatialPoints(site)
crs(pts) <- "+proj=longlat +datum=WGS84"
rcrs <- crs(r)
ptrans <- spTransform(pts, rcrs)
And now it works
extract(r, ptrans)
#1529.66

projectRaster returns all NA values

I am working with temperature .nc files from NARCCAP. These data have a polar stereographic projection. From temperature minimums and maximums, I've created a matrix of days that qualify as maple syrup production days.
I want to turn this matrix into a raster, and project this raster to a lon/lat projection.
## This is the metadata for the projection from the .nc file:
# float lat[xc,yc]
# long_name: latitude
# standard_name: latitude
# units: degrees_north
# axis: Y
# float lon[xc,yc]
# long_name: longitude
# standard_name: longitude
# units: degrees_east
# axis: X
# float tasmax[xc,yc,time]
# coordinates: lon lat level
# _FillValue: 1.00000002004088e+20
# original_units: K
# long_name: Maximum Daily Surface Air Temperature
# missing_value: 1.00000002004088e+20
# original_name: T_MAX_GDS5_HTGL
# units: K
# standard_name: air_temperature
# cell_methods: time: maximum (interval: 24 hours)
# grid_mapping: polar_stereographic
# grid_mapping_name: polar_stereographic
# latitude_of_projection_origin: 90
# standard_parallel: 60
# false_easting: 4700000
# false_northing: 8400000
# longitude_of_central_meridian: 263
# straight_vertical_longitude_from_pole: 263
# The production days matrix I've created is called from a saved file:
path.ecp2 <- paste0("E:/all_files/production/narccap/GFDL/Production_Days_SkinnerECP2",
year, ".RData")
file.ecp2 <- get(load(path.ecp2))
dim(file.ecp2)
# 147 116
rast.ecp2 <- raster(file.ecp2)
rast.ecp2 <- flip(t(rast.ecp2), 2)
# class : RasterLayer
# dimensions : 116, 147, 17052 (nrow, ncol, ncell)
# resolution : 0.006802721, 0.00862069 (x, y)
# extent : 0, 1, 0, 1 (xmin, xmax, ymin, ymax)
# coord. ref. : NA
# data source : in memory
# names : layer
# values : 0, 671 (min, max)
# I assign the polar stereographic crs to this production days raster:
crs("+init=epsg:3031")
ecp2.proj <- "+proj=stere +lat_0=-90 +lat_ts=-71 +lon_0=0 +k=1 +x_0=4700000 +y_0=8400000 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0"
crs(rast.ecp2) <- crs(ecp2.proj)
rast.ecp2
# class : RasterLayer
# dimensions : 116, 147, 17052 (nrow, ncol, ncell)
# resolution : 0.006802721, 0.00862069 (x, y)
# extent : 0, 1, 0, 1 (xmin, xmax, ymin, ymax)
# coord. ref. : +proj=stere +lat_0=-90 +lat_ts=-71 +lon_0=0 +k=1 +x_0=4700000 +y_0=8400000 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0
# data source : in memory
# names : layer
# values : 0, 671 (min, max)
When I use the steps that worked for me previously (see here), the values of rast.ecp2 all go to NA. Where am I going wrong?
# The projection I want to project TO:
source_rast <- raster(nrow=222, ncol=462, xmn=-124.75, xmx=-67, ymn=25.125, ymx=52.875,
crs="+proj=longlat +datum=WGS84")
rast.ecp2LL <- projectRaster(rast.ecp2, source_rast)
rast.ecp2LL
# class : RasterLayer
# dimensions : 222, 462, 102564 (nrow, ncol, ncell)
# resolution : 0.125, 0.125 (x, y)
# extent : -124.75, -67, 25.125, 52.875 (xmin, xmax, ymin, ymax)
# coord. ref. : +proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0
# data source : in memory
# names : layer
# values : NA, NA (min, max)
I am posting the solution I found to work. It is based on this post and answer. I had to first convert the xc and yc coordinates of the .nc file to longitude and latitude points. Then I could properly reproject the raster. Below is the code that worked.
Note that mycrs is the CRS that "came with" the .nc file. It has to be assigned to the SpatialPoints since converting from xc/yc to SpatialPoints drops the associated CRS.
years <- seq(from=1971, to=2000, by=5)
model <- "CRCM"
convert.lonlat <- function(model, year)
{
max.stem <- "E:/all_files/www.earthsystemgrid.org/CCSM/tasmax_"
inputfile <- paste0(max.stem, model, "_ccsm_", year, "010106.nc")
lat <- raster(inputfile, varname="lat")
lon <- raster(inputfile, varname = "lon")
plat <- rasterToPoints(lat)
plon <- rasterToPoints(lon)
lonlat <- cbind(plon[,3], plat[,3])
lonlat <- SpatialPoints(lonlat, proj4string = crs(base.proj))
mycrs <- crs("+proj=stere +lon_0=263 +x_0=3475000 +y_0=7475000 +lat_0=90 +ellps=WGS84")
plonlat <- spTransform(lonlat, CRSobj = mycrs)
maxs <- brick(inputfile, varname="tasmax")
projection(maxs) <- mycrs
extent(maxs) <- extent(plonlat)
max.lonlat <- projectRaster(maxs, base.proj)
save(max.lonlat, file=paste0("E:/all_files/production/narccap/CCSM/", model, "max_lonlat_", year, ".RData"))
min.stem <- "E:/all_files/www.earthsystemgrid.org/CCSM/tasmin_"
inputfile <- paste0(min.stem, model, "_ccsm_", year, "010106.nc")
lat <- raster(inputfile, varname="lat")
lon <- raster(inputfile, varname = "lon")
plat <- rasterToPoints(lat)
plon <- rasterToPoints(lon)
lonlat <- cbind(plon[,3], plat[,3])
lonlat <- SpatialPoints(lonlat, proj4string = crs(maurer.proj))
mycrs <- crs("+proj=stere +lon_0=263 +x_0=3475000 +y_0=7475000 +lat_0=90 +ellps=WGS84")
plonlat <- spTransform(lonlat, CRSobj = mycrs)
mins <- brick(inputfile, varname="tasmin")
projection(mins) <- mycrs
extent(mins) <- extent(plonlat)
min.lonlat <- projectRaster(mins, maurer.proj)
save(min.lonlat, file=paste0("E:/all_files/production/narccap/CCSM/", model, "min_lonlat_", year, ".RData"))
}
lapply(years, convert.lonlat, model=model)
From here I go on to make the matrix of production days based on the saved files max.lonlat and min.lonlat.

Resources