I ran some species distribution models (SDM), using maxent of the 'dismo' package for several species, so I saved each one as a raster file.
After that I transformed this environmental suitability raster (SDM result) into a binary map based on a determined threshold value.
I used this function and these command lines to do the conversion:
bin <- function(x) {
ifelse(x <= 0.7, 0,
ifelse(x > 0.7, 1, NA)) }
sp_bin <- calc(spp, fun=bin) # "spp" is the object within my raster
writeRaster(sp_bin,filename='Results/RasterBin/Patagioenas_fasciata_bin.tif')
Now I have a raster of that binary map (i.e., with only two values, 0 and 1).
class : RasterLayer
dimensions : 1117, 1576, 1760392 (nrow, ncol, ncell)
resolution : 0.008333333, 0.008333333 (x, y)
extent : -68.39167, -55.25833, -0.7333333, 8.575 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0
data source : C:\Users\Ramiro\Desktop\SDM\Results\RasterBin\Patagioenas_fasciata_bin.tif
names : Patagioenas_fasciata_bin
values : 0, 1 (min, max)
I tried to use the following argument to bring the sum of the pixels with value 1, assuming that the others would be 0 and therefore the total sum would equal the area of all pixels with values 1:
cellStats(spp, stat='sum', na.rm=TRUE)
And I got a numerical result (12,471) that I thought was correct. However, I did this for other species, and therefore other rasters, and the result remains the same, although each species has a distinct binary map.
How can I calculate the area only for pixels with value "1" in a binary map raster in R?
Thank you all for the attention.
Related
I am reading a raster file using both terra and raster package
library(raster)
library(terra)
fl_terra <- terra::rast('my_raster.tif')
fl_raster <- raster::raster('my_raster.tif')
fl_terra
class : SpatRaster
dimensions : 157450, 327979, 1 (nrow, ncol, nlyr)
resolution : 0.0002777778, 0.0002777778 (x, y)
extent : -142.4107, -51.30541, 41.12569, 84.86181 (xmin, xmax, ymin, ymax)
coord. ref. : lon/lat WGS 84 (EPSG:4326)
source : xxxx.tif
categories : DepthBand
name : DepthBand
min value : 0.0m <= x <= 0.3m
max value : x > 9.0m
fl_raster
class : RasterLayer
dimensions : 157450, 327979, 51640293550 (nrow, ncol, ncell)
resolution : 0.0002777778, 0.0002777778 (x, y)
extent : -142.4107, -51.30541, 41.12569, 84.86181 (xmin, xmax, ymin, ymax)
crs : +proj=longlat +datum=WGS84 +no_defs
source : xxxx.tif
names : DepthBand
values : 1, 6 (min, max)
Why is reading the same file using the two packages showing different values?
If I open the same file in QGIS, the legend displays the values present in the fl_raster i.e. using the raster package.
The file has categorical values. fl_terra tells you that:
categories : DepthBand
And it also properly shows the (alphabetical) range of the categories (and it also uses them in the legend when using plot, and returns them when extracting cell values).
name : DepthBand
min value : 0.0m <= x <= 0.3m
max value : x > 9.0m
If you do not care about the categories, you can remove them with
levels(fl_terra) <- NULL
In contrast, fl_raster shows the numerical codes that are used to represent the categories (because the raster files can only store numeric cell values).
values : 1, 6 (min, max)
That makes it look like you have numeric values. But that is not the case.
The situation is similar to having a factor in R
f <- as.factor(c("red", "blue", "green"))
"terra" would show the category labels
f
#[1] red blue green
#Levels: blue green red
Whereas "raster" would show the equivalent of
as.integer(f)
#[1] 3 1 2
I am a beginner in using R for spatial data analysis and want to simply extract some values for certain locations (with lon/lat positions) from a raster stack. However, when using extract(), it returns only NAs, so I guess I made a mistake with the projection.
I loaded the lon/lat-locations into a SpatialPointsDataFrame, changed the lon/lat into numeric and set the crs to EPSG:4326.
The raster stack comes with the crs EPSG:3035, so I used "sftransform()" to project the lon/lat-locations accordingly. "compareCRS" for the two datasets gave the output "TRUE", so the projection supposedly worked.
When I try to use extract(), however, it returns only NA's.
When I put the coordinates into Google Maps, they are mapped correctly, with mapview() in R, however, they seem to be completely off grid, so I supposed something about the projection went wrong, but I have no idea what.
I hope that somebody here can help me out!
Loading in the raster stack named "texture"
> print(texture)
class : RasterStack
dimensions : 8073, 7781, 62816013, 3 (nrow, ncol, ncell, nlayers)
resolution : 500, 500 (x, y)
extent : 2635700, 6526200, 1385700, 5422200 (xmin, xmax, ymin, ymax)
crs : +proj=laea +lat_0=52 +lon_0=10 +x_0=4321000 +y_0=3210000 +ellps=GRS80 +units=m +no_defs
names : Clay_eu23, Sand_eu23, Silt_eu23
min values : 0, 0, 0
max values : 76.47613, 100.00000, 91.61756
Loading in the DF with Lon/Lat Locations
Datalogger Lat Lon
1 DL3 48.5932246 9.5576115
2 DL4 49.0160648 9.1887693
3 DL2 48.7100801 9.2141318
4 DL10 49.0038758 8.4934965
5 DL5 49.0034701 8.4954198
6 DL6 48.4183515 8.8958118
Changing the Lon/Lat columns to numeric
locations$Lon <- as.numeric(locations$Lon)
locations$Lat <- as.numeric(locations$Lat)
Setting the crs for the coordinates and creating SpatialPointsDF
coordinates(locations) <- ~Lon+Lat
proj4string(locations) <- CRS("+init=epsg:4326")
> print(locations)
class : SpatialPointsDataFrame
features : 10
extent : 1, 10, 1, 10 (xmin, xmax, ymin, ymax)
crs : +init=epsg:4326 +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0
variables : 1
names : Datalogger
min values : DL1
max values : DL9
Reprojecting the locations to the raster stack's (texture's) crs
loc_proj <- spTransform(locations, proj4string(texture))
Checking if crs is correct
compareCRS(texture, loc_proj)
Trying to extract values from rasterstack
values <- raster::extract(texture, loc_proj)
For values I only get NAs for each of the three rasters in the stack, even though when I call summary(texture) it returns valid data, and also the locations as such are valid. What did I do wrong with the projections?
Thank you very much already!!
You did
locations$Lon <- as.numeric(locations$Lon)
locations$Lat <- as.numeric(locations$Lat)
You got
print(locations)
#class : SpatialPointsDataFrame
#features : 10
#extent : 1, 10, 1, 10 (xmin, xmax, ymin, ymax)
That is, your longitude and latitude are between 1 and 10. This suggest that lon and lat were factor variables (for whatever reason); and that you made a mistake in changing them to numeric.
Consider this
x <- as.factor(c(9.5576115, 9.1887693, 9.2141318, 8.4934965, 8.4954198, 8.8958118))
as.numeric(x)
#[1] 6 4 5 1 2 3
as.numeric does not use the factor labels in the conversion. It cannot do that because these labels may contain letters. Instead, it gives you the indices
So, instead, you should do
as.numeric(as.character(x))
#[1] 9.557612 9.188769 9.214132 8.493496 8.495420 8.895812
In your code:
locations$Lon <- as.numeric(as.character(locations$Lon))
locations$Lat <- as.numeric(as.character(locations$Lat))
I downloaded worlclim/BIO climatic data which has 16 layers. 1-11 layers of which are temperature data. Rests are precipitation data. When I checked document, I should convert unit of temperature data by different conversion factors. 1-2,4-11 layers should be divided by 10 to convert degree celcius and 3-4 layers by 100. To do this, I wrote following code:
temp1<-clim[[1:2]]/10
temp2 <-clim[[5:11]]/10
temp3<-clim[[3:4]]/100
Stack them back according to the same order as they were in original data:
clim <-stack(temp1,temp3,temp2)
My question is how to calculate different formula on different layer and stack them back to original order? I want to know another way to do these steps.
Thank you!
Easist way could be to define a vector of "dividing factors" and then simply divide the stack by that vector. In this way, you do not need to put the bands in the "original" order:
library(raster)
a <- raster::raster(ncols = 10, nrows = 10)
a <- raster::init(a, runif)
# create a stack
b <- raster::stack(a,a,a,a,a,a)
# define vector of dividing factors
divs <- c(1,1,10,10,100,100)
# compute
c <- b / divs
c
class : RasterBrick
dimensions : 10, 10, 100, 6 (nrow, ncol, ncell, nlayers)
resolution : 36, 18 (x, y)
extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0
data source : in memory
names : layer.1, layer.2, layer.3, layer.4, layer.5, layer.6
min values : 5.919103e-03, 5.919103e-03, 5.919103e-04, 5.919103e-04, 5.919103e-05, 5.919103e-05
max values : 0.99532098, 0.99532098, 0.09953210, 0.09953210, 0.00995321, 0.00995321
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 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)