Why the box is so broad when plotting raster in R? - r

I want to plot the raster ,using code as follows:
library(raster)
tmp <- scan(what='')
'D:\temp\m2001EOS.tif'
ra<-raster(tmp)
plot(ra)
ra attribution as follows:
class : RasterLayer
dimensions : 1941, 1832, 3555912 (nrow, ncol, ncell)
resolution : 981.8572, 981.8572 (x, y)
extent : 4723620, 6522382, 4203136, 6108921 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=aea +lat_1=25 +lat_2=47 +lat_0=0 +lon_0=105 +x_0=4000000 +y_0=0 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0
data source : D:\temp\m2001EOS.tif
names : m2001EOS
values : -32768, 32767 (min, max)
The plot is so wide that is not match xmin and xmax, but the range of height seem reasonable to ymin and ymax. Which parameter causes different patterns?
And how to adjust the box outline?
The example file is m2001EOS.tif

Using the volcano data set, we can get a simple reproducible example which does not require downloading data from a remote link:
library(raster)
plot(raster(volcano))
When plotting rasters (using raster::plot):
The shape of the bounding box is determined by the aspect ratio (shape) of the device window in which it is plotted.
The scale size is forced to be the same in x and y directions, as this is standard practice for spatial data (because we don't want to distort the shape of spatial data by stretchng it out to fit the box). We can see this in the example plot above by the fact that the raster is exactly square.
Given these two constraints, the need to fill the bounding box with blank areas follows as a direct consequence.
So how to avoid this? One way is to simply change the height to width ratio of the plot window or output file.
pdf(height = 4, width = 4)
plot(raster(volcano))
dev.off()
Even better is to use rasterVis::levelplot for nicer plotting:
library(rasterVis)
levelplot(raster(volcano), margin = F)

Related

R how to get a vector of latitudes from a regular tif using brick

I have a tif file that I read in using brick. I can see the spatial extend of the tif file:
b<-brick("t.tif")
b
class : RasterBrick
dimensions : 10, 10, 100, 1 (nrow, ncol, ncell, nlayers)
resolution : 0.0001851853, 0.0001851854 (x, y)
extent : -18.61944, -18.61759, 37.83856, 37.84041 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0
data source : /scratch/tompkins/water_allafrica/t.tif
names : t
min values : 0
max values : 255
extent(SpatialPoints(b))
class : Extent
xmin : -18.61935
xmax : -18.61769
ymin : 37.83865
ymax : 37.84031
But I can't work out how to get a vector of latititudes and longitudes easily that I need to define a netcdf file header which I want to write out. I could do it manually but I am presuming there is a built in function that is easier to use.
Example input file here: http://clima-dods.ictp.it/Users/tompkins/stackoverflow/t.tif
This might be what you need:
ext <- extent(b)
lat <- seq(ext#ymin,ext#ymax,res(b)[2])
lon <- seq(ext#xmin,ext#xmax,res(b)[1])
So basically your're creating a sequence vector from x/y min to max with spacing of the brick's resolution.
The values refer to the corner coordinates of the cell ... you could be also interested in the cell centers.
Just for illustration:
# create testraster
x <- raster(resolution=c(40,40))
x[]<- 1:ncell(x)
# plot
plot(x)
# add corner coordinates
plot(SpatialPoints(cbind(rep(extent(x)#xmin,10),seq(extent(x)#ymin,extent(x)#ymax,res(x)[2])),proj4string = crs(x)),
col='red',pch='*',cex=5,add=T)
# add cell centers
plot(SpatialPoints(xyFromCell(x,cellFromRowCol(x,1:nrow(x),1)),proj4string = crs(x)),
col='blue',pch='*',cex=5,add=T)
So the method above gives you the latitudes indicated by the red asterisks. If you need the blue ones, you could use xyFromCell which returns the coordinates of a raster's cell.

Changing values in a raster

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

R: How is it possible to export from R an image from a raster layer while maintaining image resolution?

I have been attempting to export a geographic raster layer which is projected in terms of the Lambert Conformal Conic projection (with a resolution of 1000 m by 1000 m) as an image file (e.g. as an *.eps) after having plotted it with some overlaid points (which is straightforward enough), but upon opening the image after export, it is clear that it has a resolution of a lesser quality than the aforementioned.
I've been using the 24 Bioclimate layers downloadable from: https://sites.ualberta.ca/~ahamann/data/climatewna.html. Here is an example of one of those layers (which was saved as a *.tif), and its resolution:
Below is the section of the script I have been running which is of relevance:
> projection <- raster("prediction.grd")
> projection
class : RasterLayer
dimensions : 3132, 2359, 7388388 (nrow, ncol, ncell)
resolution : 1000, 1000 (x, y)
extent : -3594000, -1235000, 4703000, 7835000 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=lcc +lat_1=49 +lat_2=77 +lat_0=0 +lon_0=-95 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0
data source : C:\Users\User\Documents\Project\prediction.grd
names : layer
values : 7.006775e-12, 0.001495079 (min, max)
> plot(projection, col = colorPalette(14, "jc"), colNA = 'black', axes = FALSE);
> points(train_locality_points, col='white', pch=15, cex=0.2)
Following the running of this code, I've gone about exporting the plot generated via the 'export' dropdown menu of R Studio to save it as an image with an extension that can be viewed outside of R instead of as a file with its original extension or something similar. I can open the image which is saved, but it evidently is not of the same quality as what the resolution of the layer is stated as above.
The image below is one I've saved in the way just described. To illustrate the trouble I've been having, Vancouver Island ( i.e. the large one with many white dots clustered at its southern end) is about 500 kilometres in length, which should correspond to about 500 pixels in the image if the resolution were 1 km by 1 km as the raster layer is. In this image the length of the island is represented by about a fifth of that number (...yes, I counted).
Any help as to how this issue could be remedied I would greatly appreciate. Thank-you for taking the time to read through and consider this question.
To get an image with same resolution as RasterLayer r, you can do
png('file.png', height=nrow(r), width=ncol(r))
plot(r, maxpixels=ncell(r))
dev.off()

Can't change raster's extent

I want to crop an elevation raster to add it to a raster stack. It's easy, I did this before smoothly, adding a ecoregions raster to the same stack. But with the elevation one, just doesn't work. Now, there are several questions here in overflow adressing this issue and I tryed a lot of things...
First of all, we need this:
library(rgdal)
library(raster)
My stack is predictors2:
#Downloading the stack
predictors2_full<-getData('worldclim', var='bio', res=10)
#Cropping it, I don' need the whole world
xmin=-120; xmax=-35; ymin=-60; ymax=35
limits <- c(xmin, xmax, ymin, ymax)
predictors2 <- crop(predictors2_full,limits)
Then I've downloaded the terr_ecorregions shapefile here: http://maps.tnc.org/files/shp/terr-ecoregions-TNC.zip
setwd("~/ORCHIDACEAE/Ecologicos/w2/layers/terr-ecoregions-TNC")
ecoreg = readOGR("tnc_terr_ecoregions.shp") # I've loaded...
ecoreg2 <- crop(ecoreg,extent(predictors2)) # cropped...
ecoreg2 <- rasterize(ecoreg2, predictors2) # made the shapefile a raster
predictors4<-addLayer(predictors2,elevation,ecoreg2) # and added the raster
# to my stack
With elevation, I just can't. The Digital elevation model is based in GMTED2010, which can be downloaded here: http://edcintl.cr.usgs.gov/downloads/sciweb1/shared/topo/downloads/GMTED/Grid_ZipFiles/mn30_grd.zip
elevation<-raster("w001001.adf") #I've loaded
elevation<-crop(elevation,predictors2) # and cropped
But elevation gets a slightly different extent instead of predictors2's extent:
> extent(elevation)
class : Extent
xmin : -120.0001
xmax : -35.00014
ymin : -60.00014
ymax : 34.99986
>
I tried to make then equal by all means I read about in questions here...
I tried to extend so elevation's ymax would meet predictors2's ymax
elevation<-extend(elevation,predictors2) #didn't work, extent remains the same
I tried the opposite... making predictors2 extent meet elevation's extent... nothing either.
But then I read that
You might not want to play with setExtent() or extent() <- extent(), as you could end with wrong geographic coordinates of your rasters - #ztl, Jun 29 '15
And I tried to get the minimal common extent of my rasters, following #zlt answer in another extent question, by doing this
# Summing your rasters will only work where they are not NA
r123 = r1+r2+r3 # r123 has the minimal common extent
r1 = crop(r1, r123) # crop to that minimal extent
r2 = crop(r2, r123)
r3 = crop(r3, r123)
For that, first I had to set the resolutions:
res(elevation)<-res(predictors2) #fixing the resolutions... This one worked.
But then, r123 = r1+r2+r didn't work:
> r123=elevation+ecoreg2+predictors2
Error in elevation + ecoreg2 : first Raster object has no values
Can anyone give me a hint on this? I really would like to add my elevation to the raster. Funny thing is, I have another stack named predictors1 with the exact same elevation's extent... And I was able to crop ecoreg and add ecoreg to both predictors1 and predictors2... Why can't I just do the same to elevation?
I'm quite new to this world and runned out of ideas... I appreciate any tips.
EDIT: Solution, Thanks to #Val
I got to this:
#Getting the factor to aggregate (rasters are multiples of each other)
res(ecoreg2)/res(elevation)
[1] 20 20 #The factor is 20
elevation2<-aggregate(elevation, fact=20)
elevation2 <- crop(elevation2,extent(predictors2))
#Finally adding the layer:
predictors2_eco<-addLayer(predictors2,elevation2,ecoreg)
New problem, thought...
I can't write stack to a geotiff
writeRaster(predictors2_eco, filename="cropped_predictors2_eco.tif", options="INTERLEAVE=BAND", overwrite=TRUE)
Error in .checkLevels(levs[[j]], value[[j]]) :
new raster attributes (factor values) should be in a data.frame (inside a list)
I think you're having issues because you're working with rasters of different spatial resolutions. So when you crop both rasters to the same extent, they'll have a slightly different actual extent because of that.
So if you want to stack rasters, you need to get them into the same resolution. Either you disaggregate the raster with the coarser resolution (i.e. increase the resolution by resampling or other methods) or you aggregate the raster with the higher resolution (i.e. decrease the resolution with for instance taking the mean over n pixel).
Please note that if you change the extent or resolution with setExtent(x), extent(x) <-, res(x) <- or similar will NOT work, since you're just changing slots in the raster object, not the actual underlying data.
So to bring the rasters into a common resolution, you need to change the data. You can use the functions (amongst others) aggregate, disaggregate and resample for that purpose. But since you're changing data, you need to be clear on what you're and the function you use is doing.
The most handy way for you should be resample, where you can resample a raster to another raster so they match in extent and resolution. This will be done using a defined method. Per default it's using nearest neighbor for computing the new values. If you're working with continuous data such as elevation, you might want to opt for bilinear which is bilinear interpolation. In this case you're actually creating "new measurements", something to be aware of.
If your two resolutions are multiples of each other, you could look into aggregate and disaggregate. In the case of disaggregate you would split a rastercell by a factor to get a higher resolution (e.g. if your first resolution is 10 degrees and your desired resolution is 0.05 degrees, you could disaggregate with a factor of 200 giving you 200 cells of 0.05 degree for every 10 degree cell). This method would avoid interpolation.
Here's a little working example:
library(raster)
library(rgeos)
shp <- getData(country='AUT',level=0)
# get centroid for downloading eco and dem data
centroid <- coordinates(gCentroid(shp))
# download 10 degree tmin
ecovar <- getData('worldclim', var='tmin', res=10, lon=centroid[,1], lat=centroid[,2])
ecovar_crop <- crop(ecovar,shp)
# output
> ecovar_crop
class : RasterBrick
dimensions : 16, 46, 736, 12 (nrow, ncol, ncell, nlayers)
resolution : 0.1666667, 0.1666667 (x, y)
extent : 9.5, 17.16667, 46.33333, 49 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0
data source : in memory
names : tmin1, tmin2, tmin3, tmin4, tmin5, tmin6, tmin7, tmin8, tmin9, tmin10, tmin11, tmin12
min values : -126, -125, -102, -77, -33, -2, 19, 20, 5, -30, -74, -107
max values : -31, -21, 9, 51, 94, 131, 144, 137, 106, 60, 18, -17
# download SRTM elevation - 90m resolution at eqt
elev <- getData('SRTM',lon=centroid[,1], lat=centroid[,2])
elev_crop <- crop(elev, shp)
# output
> elev_crop
class : RasterLayer
dimensions : 3171, 6001, 19029171 (nrow, ncol, ncell)
resolution : 0.0008333333, 0.0008333333 (x, y)
extent : 9.999584, 15.00042, 46.37458, 49.01708 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0
data source : in memory
names : srtm_39_03
values : 198, 3865 (min, max)
# won't work because of different resolutions (stack is equal to addLayer)
ecoelev <- stack(ecovar_crop,elev_crop)
# resample
elev_crop_RS <- resample(elev_crop,ecovar_crop,method = 'bilinear')
# works now
ecoelev <- stack(ecovar_crop,elev_crop_RS)
# output
> ecoelev
class : RasterStack
dimensions : 16, 46, 736, 13 (nrow, ncol, ncell, nlayers)
resolution : 0.1666667, 0.1666667 (x, y)
extent : 9.5, 17.16667, 46.33333, 49 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0
names : tmin1, tmin2, tmin3, tmin4, tmin5, tmin6, tmin7, tmin8, tmin9, tmin10, tmin11, tmin12, srtm_39_03
min values : -126.0000, -125.0000, -102.0000, -77.0000, -33.0000, -2.0000, 19.0000, 20.0000, 5.0000, -30.0000, -74.0000, -107.0000, 311.7438
max values : -31.000, -21.000, 9.000, 51.000, 94.000, 131.000, 144.000, 137.000, 106.000, 60.000, 18.000, -17.000, 3006.011

Importing projected GeoTIFF and transforming to latitude and longitude coordinates in R

While I am not new to R, I am new to visualizing spatial data in it rather than ArcGIS.
I am attempting to import a GeoTIFF image from a public-access GIS website that is already projected in Mercator (image can be found here). Using the raster package in R, I can successfully import the GeoTIFF into R and plot it (see below).
> library(raster)
> mb <- raster("/Maps/mb_srelief10m/mb_srelief10m.tif")
> mb
class : RasterLayer
dimensions : 8060, 7220, 58193200 (nrow, ncol, ncell)
resolution : 10, 10 (x, y)
extent : -48598.54, 23601.46, 3850014, 3930614 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=merc +lon_0=-70.31666666666668 +lat_ts=41.65 +x_0=0 +y_0=0 +datum=NAD83 +units=m +no_defs +ellps=GRS80 +towgs84=0,0,0
data source : C:\Users\Connor\Documents\ArcGIS\Maps\mb_srelief10m\mb_srelief10m.tif
names : mb_srelief10m
values : 0, 255 (min, max)
attributes :
ID COUNT BinValues Value
from: 0 1460797 0 0
to : 51 14795988 255 255
As you can see, the x- and y-axis labels represent the NAD83 values from the raster file (red boxes in image). Yet, when I attempt to use the crop function to use only a portion of this raster file, I cannot select the appropriate area because my user-defined extent object is in latitude and longitude coordinates. I understand I can use the drawExtent function to manually select the area but I want to automate this process.
My question is:
How do I transform the raster file so that my axes are in latitude and longitude and I can crop the file using latitude and longitude coordinates?
If this post would be more appropriate elsewhere, please let me know and I will remove the file. Thank you!

Resources