Merge (mosaic) of rasters changes resolution - r

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)

Related

Extraction of land cover data in two rasters with different resolution and extent

I have three rasters. Raster1 is a landcover file for a land cover types. Raster2 and raster3 are rasters showing variable 'NPP'. As you can see each raster has different extent & resolution. I want to know how much NPP is in both raster 2 and 3 in accordance with the landcover for raster1. However what could be done in order to bring all rasters to same extent and resolution and find NPP in raster2 and raster3 accordance with the landcover class in raster1?
(How can I know which resolution should I choose for all the rasters?)
> raster1
class : RasterLayer
dimensions : 2803, 5303, 14864309 (nrow, ncol, ncell)
resolution : 0.008333333, 0.008333333 (x, y)
extent : 60.85, 105.0417, 15.95833, 39.31667 (xmin, xmax, ymin, ymax)
crs : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0
source :XXXXX
names : landusemaskedme
values : 1, 12 (min, max)
raster2
class : RasterLayer
dimensions : 2336, 4419, 10322784 (nrow, ncol, ncell)
resolution : 0.01, 0.01 (x, y)
extent : 60.85, 105.04, 15.96, 39.32 (xmin, xmax, ymin, ymax)
crs : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0
source : memory
names : NPP
values : 0, 31.78096 (min, max)
> raster3
class : RasterLayer
dimensions : 47, 89, 4183 (nrow, ncol, ncell)
resolution : 0.5, 0.5 (x, y)
extent : 60.75, 105.25, 15.75, 39.25 (xmin, xmax, ymin, ymax)
crs : NA
source : memory
names : NPP
values : 0, 21.141 (min, max)
I can see that your rasters are having almost same extent and coordinate system except for raster3 which does not have any reference system (crs: NA). First, you need to have rasters of the same extent and coordinate reference system, then you can use resample function from raster package like
library(raster)
#To have the same projection for raster3 as that of your base landcover class in raster1
newproj <- projection(raster1)
praster3 <- projectRaster(raster3, crs=newproj)
#Conversion of rasters into same extent
raster2_resampled <- resample(raster2, raster1, method='bilinear')
raster3_resampled <- resample(praster3, raster1, method='bilinear')
It is always better to resample a finer resolution raster to coarser resolution, not the vice versa though it can be done as you have asked in your question. In your case, raster1 has the finer resolution (0.008333333 x 0.008333333) followed by raster2 (0.01 x 0.01). raster3 has the coarsest resolution (0.5 x 0.5). So, it would be better to convert all the rasters to the resolution and extent of raster3. Hope that helps you out.

Why rasterToPolygons is creating horizontal lines?

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)

Make raster stack with different extent

I am in trouble making raster stack which have slightly different extent. The answer (1st one) given here is useful but did not help in my case. For example, I want to make a raster stack using bio2 raster for Australia and this Australian raster. The second raster comes for Australia only and the first one is global. So I cropped the global bio2 raster to the same extent of Australian raster using crop() function, but the resultant raster extent (i.e., bio2.au) is slightly different (therefore, I cannot make raster using the cropped raster and the Australian raster, awc). Sample code is below:
library(raster)
awc <- raster("path to Australian raster")
bio2.g <- raster("path to Bio2 global raster")
# crop bio2.g to the same extent of awc
bio2.au <- crop(bio2.g, extent(awc))
# make a raster stack
st <- stack(awc, bio2.au)
Error in compareRaster(x) : different extent
I have also tried using quick=TRUE within the stack() function. But in this case the cell values in awc is lost. Note: the size of awc raster is 4gb.
# first make a list of rasters saved in the computer
li <- list.files("path to file", pattern = ".tif$", full.names = TRUE)
st <- stack(li, quick=TRUE)
st[[1]] # no cell values for awc
Your suggestions will be highly appreciated. My ultimate goal is to crop several bioclim rasters to the same extent of Australian raster awc and stack them together so that raster cell values are not lost.
Edit (after comment of #Cobin):
Below is the attribute of each raster
# global raster (bigger raster)
> r
class : RasterLayer
dimensions : 21600, 43200, 933120000 (nrow, ncol, ncell)
resolution : 0.008333333, 0.008333333 (x, y)
extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0
data source : D:\Worldclim2_Bioclim\wc2.0_bio_30s_02.tif
names : wc2.0_bio_30s_02
values : 0, 37.06667 (min, max)
# Australian raster (smaller raster)
> r1
class : RasterLayer
dimensions : 43201, 49359, 2132358159 (nrow, ncol, ncell)
resolution : 0.0008333333, 0.0008333333 (x, y)
extent : 112.8921, 154.0246, -44.00042, -7.999583 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0
data source : D:\SoilAWC5cm.EV1.tif
names : SoilAWC5cm.EV1
values : 2.997789, 27.86114 (min, max)
# new raster, after crop() function is applied
> r2 <- crop(r,extent(r1))
> r2
class : RasterLayer
dimensions : 4320, 4936, 21323520 (nrow, ncol, ncell)
resolution : 0.008333333, 0.008333333 (x, y)
extent : 112.8917, 154.025, -44, -8 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0
data source : C:\Users\Anwar\AppData\Local\Temp\Rtmpmg9fyF\raster\r_tmp_2018-11-23_164300_11308_65747.grd
names : wc2.0_bio_30s_02
values : 1.933333, 18.15833 (min, max)
# rebuild r2 to match r1
> r22 <- raster(vals=values(r2),ext=extent(r1), nrows=dim(r1)[1],ncols=dim(r1)[2])
Error in setValues(r, vals) :
length(values) is not equal to ncell(x), or to 1
I suppose that the extent of two raster are differet though the raster masked by crop function.You
should check the both of awc and bio.au extent base on same reolution, rows and columns. Because I couldn't download data from
hyperlink, I give an example of my own data.
r <- raster('/big_raster')
r1 <- raster('/small_raster')
r2 <- crop(r,extent(r1))
r1
class : RasterLayer
dimensions : 74, 157, 11618 (nrow, ncol, ncell)
resolution : 0.0833333, 0.0833333 (x, y)
extent : 89.2185, 102.3018, 30.96238, 37.12905 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0
data source : D:\D\temp\Rtest\modis8km.tif
names : modis8km
values : -32768, 32767 (min, max)
r2
class : RasterLayer
dimensions : 74, 157, 11618 (nrow, ncol, ncell)
resolution : 0.08333333, 0.08333333 (x, y)
extent : 89.25, 102.3333, 31, 37.16667 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0
data source : in memory
names : g201401a
values : -32768, 7789 (min, max)
Though r1 and r1 with same resolution and dimension, the extent have tiny offset. It cause stack error.
stack(r1,r2)
Error in compareRaster(x) : different extent
So, you should rebuid the r2 to match r1:
r22 <- raster(vals=values(r2),ext=extent(r1),crs=crs(r1),
nrows=dim(r1)[1],ncols=dim(r1)[2])
Now stack(r22,r1) will be successful.

resampled raster values out of range

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?

rasters with same crs, extent, dimension, resolution do not align

I am finding the average production days per year for maple syrup. My maple distribution data is in an ascii file. I have a raster (created from NetCDF files) called brick.Tmax. I want to match the specs of brick.Tmax to my maple distribution data.
## These are the specs I want to use for my maple distribution
brick.Tmax
class : RasterBrick
dimensions : 222, 462, 102564, 366 (nrow, ncol, ncell, nlayers)
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 : E:\all_files\gridded_obs.daily.Tmax.1980.nc
names : X1980.01.01, X1980.01.02, X1980.01.03, X1980.01.04, X1980.01.05, X1980.01.06, X1980.01.07, X1980.01.08, X1980.01.09, X1980.01.10, X1980.01.11, X1980.01.12, X1980.01.13, X1980.01.14, X1980.01.15, ...
Date : 1980-01-01, 1980-12-31 (min, max)
varname : Tmax
## reading in red maple data from ascii file into rasterLayer
red_raster <- raster("E:/all_files/Maple_Data/redmaple.asc")
red_raster
class : RasterLayer
dimensions : 140, 150, 21000 (nrow, ncol, ncell)
resolution : 20000, 20000 (x, y)
extent : -1793092, 1206908, -1650894, 1149106 (xmin, xmax, ymin, ymax)
coord. ref. : NA
data source : E:\all_files\Maple_Data\redmaple.asc
names : redmaple
values : -2147483648, 2147483647 (min, max)
How can I project all specs (dimension, crs, resoluion, and extent) from brick.Tmax onto red_raster, while still preserving the values of red_raster? It seems like the two are mutually exclusive.
NOTE: In an attempt to streamline my question, I edited my question quite a bit from my original post, so apologies if the comments below are confusing in the current context. (I removed the raster prodavg_rastwhich was acting like a middleman).
The two rasters clearly do not have the same extent. In fact are in different universes (coordinate reference systems). brick.Tmax has angular (longitude/latitude) coordinates: +proj=longlat +datum=WGS84
but red_raster clearly does not given extent : -1793092, 1206908, -1650894, 1149106. So to use these data together, one of the two needs to be transformed (projected into the the coordinate reference system of the other). The problem is that we do not know what the the crs of red_raster is (esri ascii files do not store that information!). So you need to find out what it is from your data source, or by guessing giving the area covered and conventions. After you find out, you could do something like:
library(raster)
tmax <- raster(nrow=222, ncol=462, xmn=-124.75, xmx=-67, ymn=25.125, ymx=52.875, crs="+proj=longlat +datum=WGS84")
red <- raster(nrow=140, ncol=150, xmn=-1793092, xmx=1206908, ymn=-1650894, ymx=1149106, crs=NA)
crs(red) <- " ?????? "
redLL <- projectRaster(red, tmax)
Projectiong rasters takes time. A good way to test whether you figured out the crs would be to transform some polygons that can show whether things align.
library(rgdal)
states <- shapefile('states.shp')
sr <- spTransform(states, crs(red)
plot(red)
plot(sr, add=TRUE)

Resources