i'm doing a simple enough operation, reprojecting a raster from WGS84 to British National Grid, but i am wondering about some of the results post reprojection. The sum of the resulting rasters are quite different; is this due to the resolution and the way the bilinear interpolation in 'projectRaster' works?
I started with a csv that has global data covering the range of -180 to 180 degrees in both latitude and longitude (integer values only), with some z-values. this is subsetted, made into a raster of projection WGS84 and converted to BNG (subset below):
x <- rep(c(-10:3), times = 10)
n <- 14
y <- rep(48:57, each=n)
z <- rnorm(n=140, mean=20, sd=5)
ind <- which(z %in% sample(z, 45))
z[ind]<-NA
df <- data.frame("x"=x,"y"=y,"value"=z)
bng <- '+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +ellps=airy +datum=OSGB36 +units=m +no_defs'
wgs84 <- '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs'
coordinates(df) = ~x + y
ras = rasterFromXYZ(df, crs=wgs84)
cellStats(ras,sum)
plot(ras)
ras_bng <- projectRaster(ras,crs=bng)
plot(ras_bng)
cellStats(ras_bng,sum)
the sum goes from 1919 to 2625 (in my case), a fair chunk.
Is it purely from the reprojection creating so many extra cells around the 'edges'? if i were to reproject to a raster of much smaller resolution (5km), would this reduce the differing sums considerably?
thanks, S
> ras
class : RasterLayer
dimensions : 10, 14, 140 (nrow, ncol, ncell)
resolution : 1, 1 (x, y)
extent : -10.5, 3.5, 47.5, 57.5 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs +towgs84=0,0,0
data source : in memory
names : layer
values : 3.243918, 32.21532 (min, max)
> ras_bng
class : RasterLayer
dimensions : 12, 19, 228 (nrow, ncol, ncell)
resolution : 67900, 111000 (x, y)
extent : -375677.8, 914422.2, -343553.2, 988446.8 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +ellps=airy +datum=OSGB36 +units=m +no_defs +towgs84=446.448,-125.157,542.060,0.1502,0.2470,0.8421,-20.4894
data source : in memory
names : layer
values : 8.174968, 28.31331 (min, max)
This is because the NA values in 'ras'.
The difference is small when you take out z[ind]<-NA. This is because projectRaster implicitly uses "na.rm=TRUE"; perhaps an argument is needed to change that. This is not as simple as in other cases, as, for example, only one of the cells interpolated from may be NA, in which case it should probably be computed.
In practice it is rare to find this many NA values, typically they are confined to the edges (of land) only.
By the way WGS84 is a datum,it is not a projection. The projection you are using would be 'longitude/latitude' (also known by other names) except that this is also not a projection since the whole point of a projection is to go from such angular coordinates to planar coordinates. So, you are transforming one coordinate reference system ('long/lat, WGS84') to another (BNG).
Related
I'm merging two MODIS DSR tiles using a R script that I developed, these are the products:
https://drive.google.com/drive/folders/1RG3JkXlbaotBax-h5lEMT7lEn-ObwWsD?usp=sharing
So, I open both products (tile h15v05 and tile h16v05) from same date (2019180), then I open each SDS and merge them together (00h from h15v05 with 00h from h16v05 and so on...)
Visualisation on Panoply (using the merge option) of the two products:
Purple square is the location of the division line that separates the two tiles.
With my code I obtain a plot with pixels with different resolution (and different min/max values) and I don't understand why:
I suspect that the results obtained are due to:
1- Changing from Sinusoidal CRS to longlat WGS84 CRS;
2- Using resample (method ngb) to work with mosaic.
My code is extensive, but here are some parts of it:
# Open scientific dataset as raster
SDSs <- sds(HDFfile)
SDS <- SDSs[SDSnumber]
crs(SDS) <- crs("+proj=sinu +lon_0=0 +x_0=0 +y_0=0 +a=6371007.181 +b=6371007.181 +units=m +no_defs")
SDSreprojected <- project(SDS, DesiredCRS)
SDSasRaster <- as(SDSreprojected, "Raster")
# Resample SDS based on a reference SDS (SDS GMT_1200_DSR of a first product), I need to do this to be able to use mosaic
SDSresampled <- resample(SDSasRaster,ResampleReference_Raster,method='ngb')
# Create mosaic of same SDS, but first convert stack to list to use mosaic
ListWith_SameSDS_OfGroupFiles <- as.list(StackWith_SameSDS_OfGroupFiles)
ListWith_SameSDS_OfGroupFiles.mosaicargs <- ListWith_SameSDS_OfGroupFiles
ListWith_SameSDS_OfGroupFiles.mosaicargs$fun <- mean
SDSmosaic <- do.call(mosaic, ListWith_SameSDS_OfGroupFiles.mosaicargs)
# Save SDSs mosaic stack to netCDF
writeRaster(StackWith_AllMosaicSDSs_OfGroupFiles, NetCDFpath, overwrite=TRUE, format="CDF", varname= "DSR", varunit="w/m2", longname="Downward Shortwave Radiation", xname="Longitude", yname="Latitude", zname="TimeGMT", zunit="GMT")
Does anyone have an idea of what could be the cause of this mismatch between results?
print(ResampleReference_Raster)
class : RasterLayer
dimensions : 1441, 897, 1292577 (nrow, ncol, ncell)
resolution : 0.01791556, 0.006942043 (x, y)
extent : -39.16222, -23.09196, 29.99652, 40 (xmin, xmax, ymin, ymax)
crs : +proj=longlat +datum=WGS84 +no_defs
source : memory
names : MCD18A1.A2019180.h15v05.061.2020343034815
values : 227.5543, 970.2346 (min, max)
print(SDSasRaster)
class : RasterLayer
dimensions : 1399, 961, 1344439 (nrow, ncol, ncell)
resolution : 0.01515284, 0.007149989 (x, y)
extent : -26.10815, -11.54627, 29.99717, 40 (xmin, xmax, ymin, ymax)
crs : +proj=longlat +datum=WGS84 +no_defs
source : memory
names : MCD18A1.A2019180.h16v05.061.2020343040755
values : 0, 0 (min, max)
print(SDSmosaic)
class : RasterLayer
dimensions : 1441, 897, 1292577 (nrow, ncol, ncell)
resolution : 0.01791556, 0.006942043 (x, y)
extent : -39.16222, -23.09196, 29.99652, 40 (xmin, xmax, ymin, ymax)
crs : +proj=longlat +datum=WGS84 +no_defs
source : memory
names : layer
values : 0, 62.7663 (min, max)
Also, some of the islands were ignored by the script (bottom right)...
sorry I didn't reply earlier. So I think you're right that this issue is extent to which you are resampling. I think you might be able to get around this by creating a dummy raster that has the extent of the raster you want to resample, but has the resolution of the raster you want to mosaic to.Try:
dummy<-raster(ext = SDSasRaster#extent, resolution=ResampledReference_Raster#res, crs=SDSasRaster#crs)
SDS2<-resample(SDSasRaster, dummy, method="ngb")
Final<-moasic(SDS2, ResampledReference_Raster, fun=mean)
I am trying to transform a raster layer to polygons based on its values. My raster looks like this:
> labels_rast
class : RasterLayer
dimensions : 26, 64, 1664 (nrow, ncol, ncell)
resolution : 0.03000146, 0.02999809 (x, y)
extent : 352032, 352033.9, 8551454, 8551455 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=utm +zone=18 +south +datum=WGS84 +units=m +no_defs+ellps=WGS84 +towgs84=0,0,0
data source : in memory
names : layer
values : 1, 3 (min, max)
When I apply the rasterToPolygons function (dissolve = TRUE), I get extra polygons (defined by horizontal lines):
How can I avoid the creation of the polygons defined by the horizontal lines?
It works for this very similar case:
library(raster)
r <- raster(nrow=26, ncol=64, xmn=352032, xmx=352033.9, ymn=8551454, ymx=8551455, crs="+proj=utm +zone=18 +south +datum=WGS84 +units=m", vals=3)
r[, 20:40] <- 2
r[1:3, 1:60] <- 1
r[24:26, 5:64] <- 1
x <- rasterToPolygons(r, dissolve=TRUE)
plot(r)
lines(x)
I am guessing that it does not work for you because of floating point imprecision. Would have to see your file to be sure. But, if so, perhaps you can round the extent (or resolution) a little bit.
For example
res(labels_rast) <- 0.03
y <- rasterToPolygons(labels_rast, dissolve=TRUE)
I have a raster file (created in QGIS, from a vectorial file).
I would like to know if it is possible, in R:
1) to change the values of the pixels? (I believe all the cells have the value "1" associated, or at least the blue pixels (check images below), and I don't know the values for the white pixels, but I would like to set it to "2", for instance, so it would be binary)
2) to "crop" the raster?
Here are the characteristics of the input raster:
> catC1raster
class : RasterLayer
dimensions : 1384, 2359, 3264856 (nrow, ncol, ncell)
resolution : 30, 30 (x, y)
extent : 325352.8, 396122.8, 4613074, 4654594 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=utm +zone=31 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0
names : CAT_C1_30m
And here is the plot:
To change the NA values (white on your plot) to 2, you can use reclassify
library(raster)
x <- reclassify(catC1raster, cbind(NA, 2))
Or, with the terra package use classify
library(terra)
x <- classify(catC1raster, cbind(NA, 2))
More info here:
https://rspatial.org/terra/spatial/8-rastermanip.html
I would like to resample a high resolution raster to a coarser resolution, but in such a way that the maximum values of cells are retained for the coarser grid cells.
As there is no fun argument in the resample function in R's raster package, I have put together a simply custom function:
resampleCustom <- function(r1, r2) {
resRatio <- as.integer(res(r2) / res(r1))
ret <- aggregate(r1, fact = resRatio, fun = max)
if (!compareRaster(ret, r2, stopiffalse = FALSE)) {
ret <- resample(ret, r2, method = 'bilinear')
}
return(ret)
}
Basically, I use aggregate, where I can provide a custom function, to get close to the target raster, and then I use resample to apply some final adjustments.
I applied this to a raster that represents the projected distribution of a species of fish (where cell values represent suitability scores ranging from 0 to 1), and the odd thing is that the resulting raster has values that are greater than the max values in the original rasters.
The two rasters can be downloaded here and here.
library(raster)
# read in species raster and template
sp <- raster('Abalistes_filamentosus.tif')
template <- raster('rasterTemplate.tif')
> sp
class : RasterLayer
dimensions : 360, 720, 259200 (nrow, ncol, ncell)
resolution : 48243.14, 40790.17 (x, y)
extent : -17367530, 17367530, -7342230, 7342230 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=cea +lon_0=0 +lat_ts=30 +x_0=0 +y_0=0 +ellps=WGS84 +units=m +no_defs
data source : /Users/pascaltitle/Dropbox/Abalistes_filamentosus.tif
names : Abalistes_filamentosus
values : -5.684342e-14, 1 (min, max)
> template
class : RasterLayer
dimensions : 49, 116, 5684 (nrow, ncol, ncell)
resolution : 3e+05, 3e+05 (x, y)
extent : -17367530, 17432470, -7357770, 7342230 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=cea +lon_0=0 +lat_ts=30 +x_0=0 +y_0=0 +ellps=WGS84 +units=m +no_defs
data source : /Users/pascaltitle/Dropbox/rasterTemplate.tif
names : rasterTemplate
values : 1, 1 (min, max)
> resampleCustom(sp, template)
class : RasterLayer
dimensions : 49, 116, 5684 (nrow, ncol, ncell)
resolution : 3e+05, 3e+05 (x, y)
extent : -17367530, 17432470, -7357770, 7342230 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=cea +lon_0=0 +lat_ts=30 +x_0=0 +y_0=0 +ellps=WGS84 +units=m +no_defs
data source : in memory
names : Abalistes_filamentosus
values : -0.2061382, 1.206138 (min, max)
The max value is 1.2, but how can this be when the bilinear method should essentially be taking averages of cell values? I would expect all values of the resulting raster to be within the bounds of the original raster values.
The extreme values are for cells at the edge of the raster, where values are extrapolated, as there are no neighbors at one side. This shows where these values are:
x <- resampleCustom(sp, template)
a <- xyFromCell(x, which.max(x))
b <- xyFromCell(x, which.min(x))
plot(x)
points(a)
points(b)
Or
plot(Which(x < 0))
plot(Which(round(x, 15) > 0))
To remove these extreme values, you can use raster::clamp.
xc <- clamp(x, 0, 1)
By the way, what you do, first aggregate then resampling, is also what is done within raster::resample.
The fundamental problem is that your high-res raster data do not line up with the low resolution aggregation you are seeking. That suggests a mistake earlier on in your work flow. The best way to avoid this problem is probably to make the habitat suitability predictions with predictor raster data that are aligned with the high resolution raster. You perhaps did not consider that when you projected the predictor variables to +proj=cea?
I have a raster with a forest cover of one area
class : RasterLayer
dimensions : 5436, 2633, 14312988 (nrow, ncol, ncell)
resolution : 100, 100 (x, y)
extent : -109346.5, 153953.5, -290837.1, 252762.9 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=tmerc +lat_0=39.66825833333333 +lon_0=-8.133108333333334 +k=1 +x_0=0 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs
data source : c://Total_Forest_cove
names : Total_Forest_cove
with values from 0 to 3 I want to create a dataset with random samples from the pixels with values higher than 0.
For that I do
library(dismo)
Forestcover[Forestcover < 1] <- NA
randompoints <- sampleRandom(Forestcover, size = 10, sp=TRUE, na.rm=TRUE)
plot(Forestcover, axes=FALSE, legend=FALSE)
randompoints <- coordinates(randompoints)
when I try to pull out the enviromental variables form worldclim
randpoints_wc <- extract(worldclim, randompoints)
randpoints_wc <- cbind(randompoints, randpoints_wc)
My dataset is always empty
Not sure if there is other method to extract random that can be apply here.
Regards
Your forest cover data set has a Mercator coordinate reference system
coord. ref. : +proj=tmerc
You do not show your WorldClim data, but presumably it has
coord. ref. : +proj=longlat
So, it is no surprise (and a good thing) that you get an empty result set. You can use rgadl::spTransform to make the coordinates match the raster.
For example:
fc <- reclassify(ForestCover, cbind(1, Inf, NA))
randompoints <- sampleRandom(fc, size = 10, sp=TRUE, na.rm=TRUE)
library(rgdal)
rp <- spTransform(randompoints, CRS("+proj=longlat +datum=WGS84"))
rp_wc <- extract(worldclim, rp)
rp_wc <- cbind(coordinates(randompoints), coordinates(rp), rp_wc)