How to calculate polygon means and map them? - r

I have the dataset (pts) like this:
x <- seq(-124.25,length=115,by=0.5)
y <- seq(26.25,length=46,by=0.5)
z = 1:5290
longlat <- expand.grid(x = x, y = y) # Create an X,Y grid
pts=data.frame(longlat,z)
names(pts) <- c( "x","y","data")
I knew that I can map the dataframe (pts) into a map by doing:
library(sp)
library(rgdal)
library(raster)
library(maps)
coordinates(pts)=~x+y
proj4string(pts)=CRS("+init=epsg:4326") # set it to long, lat
pts = spTransform(pts,CRS(" +init=epsg:4326 +proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs +towgs84=0,0,0"))
pts <- as(pts, "SpatialPixelsDataFrame")
r = raster(pts)
projection(r) = CRS(" +init=epsg:4326 +proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs +towgs84=0,0,0")
plot(r)
map("usa",add=T)
my question is that how I can calculate the means of the 10 EPA Regions and map the means?
the EPA regions can be found at the bottom of the webpage at
http://www.epa.gov/wed/pages/ecoregions/level_iii_iv.htm
Thanks

First read the shape file
er <- readOGR("Eco_Level_III_US.shp", "Eco_Level_III_US")
Then make sure ther raster r and the ecoregions er have the same projection
er.4326 <- spTransform(er, CRS("+init=epsg:4326 +proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs +towgs84=0,0,0"))
Extract the r raster data from the shapefile (that may take a few minutes), calculate the mean and add it to your polyongs.
er.v <- extract(r, er.4326)
means <- sapply(er.v, mean)
er.4326$means <- means
And finally plot it
spplot(er.4326, "means")

Related

Best approach to minimize data loss when converting raster from projected to geographic coordinate system

I have a worldwide raster file in PCS roughly at 1° resolution (extent is is 90 to -60 degrees latitude and 180 to -180 longitude) that I want to convert to GCS at 2° resolution but the current method that I use leads to data distortion. The origin raster contains categorical values but the same question would apply for continuous values. I wonder if there is a better way of doing this.
#create raster in PCS - CEA projection
x <- raster(ncol=360, nrow=142, xmn=-17367529, xmx=17367529, ymn=-6356742, ymx=7348382)
projection(x) <- "+proj=cea +lon_0=0 +lat_ts=30 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0"
values(x)=runif(51120, 1, 99)
# my target raster format
y <- raster(ncol=180, nrow=75, xmn=-180, xmx=180, ymn=-60, ymx=90)
projection(y) <- "+proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0"
values(y)=runif(13500, 1, 99)
#downscale to match my target raster resolution
x2deg=raster::aggregate(x,fact=2)
#when I try to project I get the first error
x2deg.gcs = projectRaster(x2deg, y)
Error in if (maxy == miny) { : missing value where TRUE/FALSE needed
In addition: Warning message:
In rgdal::rawTransform(projfrom, projto, nrow(xy), xy[, 1], xy[, :
48 projected point(s) not finite
#So I slightly cut the extent and get the desired result
extent(x2deg) <- c(xmin= -17367529, xmax= 17367529, ymin= 0.999*(-6356742), ymax= .999*(7348382))
x2deg.gcs = projectRaster(x2deg, y)
Should I perhaps downscale ncol and nrows in raster x using a different factor? I know I will have to do some uneven interpolation to go from 142 rows to 75 but for example aggregate doesn't take fractions in the argument frac. Maybe there is another package that handles this better such as rgdal?
This works better with terra
library(terra)
x <- rast(ncol=360, nrow=142, xmin=-17367529, xmax=17367529, ymin=-6356742, ymax=7348382)
crs(x) <- "+proj=cea +lon_0=0 +lat_ts=30 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs"
values(x) <- 1:ncell(x)
y <- rast(ncol=180, nrow=75, xmin=-180, xmax=180, ymin=-60, ymax=90)
crs(y) <- "+proj=longlat +datum=WGS84"
p <- project(x, y)

Set coordinate reference system to a polygon created in R

I am trying to create a zoom-in square(polygon) in a map that is plot using ggplot2::geom_sf()
Therefore, I need the polygon to be a simple feature so I can plot the square and the map together.
I could create the polygon using the following code.
zoom_square_1<- rbind(c(-10.821079,-68.403542),
c(-10.821079,-68.367060),
c(-10.862918,-68.367060),
c(-10.862918,-68.403542),
c(-10.821079,-68.403542)) # add the first point again to it wrap up.
zoom_square_1_pol <- st_polygon(list(zoom_square_1))
plot(zoom_square_1_pol) # it returns the polygon.
However, when I tried to assign a Coordinate reference system (CRS) to it, it does not work. These are the codes I have tried so far.
sp::proj4string(zoom_square_1_pol) <- CRS("+proj=longlat +datum=WGS84 +no_defs")
zoom_square_1_pol_ex1 <- st_as_sf(x = zoom_square_1_pol[[1]],
crs = "+proj=longlat +datum=WGS84 +no_defs")
zoom_square_1_pol_ex2 <- st_transform(x = zoom_square_1_pol,
crs = "+proj=longlat +datum=WGS84 +no_defs")
Any help is welcomed.
After Chris comment, I could actually plot the polygons using ggplot2::geom_sf() and realized that my lat and long coordenates were in the wrong position since the begging. So, this the is final version of the code:
zoom_square_1<- rbind(c(-68.403542,-10.821079),
c(-68.367060,-10.821079),
c(-68.367060,-10.862918),
c(-68.403542,-10.862918),
c(-68.403542,-10.821079)) #add the first point again to it wrap up.
zoom_square_1_pol <- st_polygon(list(zoom_square_1))
zoom_square_1_pol_CRS<- st_sfc(x = zoom_square_1_pol,
crs = "+proj=longlat +datum=WGS84 +no_defs")
I was able to set the crs by feeding the square as a list to st_as_sfc:
res <- st_as_sfc(list(zoom_square_1_pol),
crs = "+proj=longlat +datum=WGS84 +no_defs")

Conversion of Coordinate reference system in Raster objects in R

I am working on NDVI monitoring using Sentinel 2 imagery data.
I have village level boundaries for a region imported as SpatialPolygonsDataFrame in R. After getting to an NDVI rasterlayer when I try to crop out the area of interest, it says extents do not overlap.
I have found the CRS of my region variable to be different(longlat) from my NDVI layer(utm).
> crs(ndvi)
CRS arguments:
+proj=utm +zone=42 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0
> crs(region)
CRS arguments:
+proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0
> r <- crop(ndvi,extent(region))
Error in .local(x, y, ...) : extents do not overlap`
Any help would be appreciated.
You can use rgdal::spTranform on "region" to create an object that has the same crs as "ndvi"
library(rgdal)
reg <- spTransform(region, crs(ndvi))
and now
r <- crop(ndvi, reg)
Perhaps followed by
m <- mask(r, reg)

plot LAT/LON coordinates on geotiff in R

I have a sea ice map as a "geotiff". The eventual goal is to extract sea-ice concentrations at specific lat/lon coordinates.
The geotiff can be found at: http://www.iup.uni-bremen.de:8084/amsr2data/asi_daygrid_swath/n6250/2015/jan/asi-AMSR2-n6250-20150101-v5.tif
What i am trying to do is load the geotiff using raster() and then overlay it by my locations and then using the extract() function to acquire values from the raster file at the specific location.
However my lat/lon points accumulate in the centre of the map. Where do I go wrong? Any help or input is greatly appreciated!
library(raster)
library(sp)
r1 = raster("test.tif")
##check plot
plot(r1)
## check projection
projection(r1)
mydf <- structure(list(longitude = rep(22,7), latitude = seq(60,90,5)),.Names = c("longitude","latitude"), class = "data.frame", row.names = c(NA, -7L))
### Get long and lat from data.frame.
xy <- mydf[,c(1,2)]
spdf <- SpatialPointsDataFrame(coords = xy, data = mydf,
proj4string = CRS("+proj=stere +lat_0=90 +lat_ts=70 +lon_0=-45 +k=1 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0"))
points(spdf, col="red", lwd=2)
##extract RGB values as reference for sea-ice concentration
seaice_conc = extract(r1, spdf)
Geo-sp's solution would work, but is sub-optimal (slow and imprecise). You should always (re-)project your vector (points in this case) data and not your raster data. Projecting raster data changes values, while this is not the case with vector data. Projecting raster data is also much more computationally intensive.
Thus, you should do something like this:
library(raster)
r <- raster("asi-AMSR2-n6250-20150101-v5.tif")
crs(r)
# CRS arguments:
# +proj=stere +lat_0=90 +lat_ts=70 +lon_0=-45 +k=1 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0
df <- data.frame(longitude = rep(22,7), latitude = seq(60,90,5), ID=1:7)
spdf <- SpatialPointsDataFrame(coords = df[,1:2], data = df,
proj4string = CRS("+proj=longlat +datum=WGS84"))
library(rgdal)
p <- spTransform(spdf, crs(r))
extract(r, p)
It is important to note that you made a very common mistake:
spdf <- SpatialPointsDataFrame(coords = xy, data = mydf, proj4string =
CRS("+proj=stere +lat_0=90 +lat_ts=70 +lon_0=-45 +k=1 +x_0=0 +y_0=0 +datum=WGS84 +units=m"))
You create a SpatialPointsDataFrame and assign the wrong coordinate reference system (crs). You must assign the crs that actually matches your data, which is "+proj=longlat +datum=WGS84". After that, you can transform the data to the crs that you would like to have (using spTransform).
You can use projectRaster to reproject your raster file. Then you can overlay the points and extract the values.
newproj <- CRS("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs +towgs84=0,0,0")
p <- projectRaster(r1, newproj)

Map raw data and mean data based on the shapefile

sI have the dataset (pts) like this:
x <- seq(-124.25,length=115,by=0.5)
y <- seq(26.25,length=46,by=0.5)
z = 1:5290
longlat <- expand.grid(x = x, y = y) # Create an X,Y grid
pts=data.frame(longlat,z)
names(pts) <- c( "x","y","data")
I knew that I can map the dataframe (pts) into a map by doing:
library(sp)
library(rgdal)
library(raster)
library(maps)
coordinates(pts)=~x+y
proj4string(pts)=CRS("+init=epsg:4326") # set it to long, lat
pts = spTransform(pts,CRS(" +init=epsg:4326 +proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs +towgs84=0,0,0"))
pts <- as(pts, "SpatialPixelsDataFrame")
r = raster(pts)
projection(r) = CRS(" +init=epsg:4326 +proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs +towgs84=0,0,0")
plot(r)
map("usa",add=T)
Now I would like to create a separate map which shows the means of pts across different regions. The shapefile I want to use is from ftp://ftp.epa.gov/wed/ecoregions/cec_na/NA_CEC_Eco_Level2.zip , however, this is a north america map. How can I create the map showing only US based on this north america map? Or is there another better way to do this? thanks so much.
I think that cutting out the non-US data based on the data in the shapefile alone would be hard, since the regions do not correspond to political boundaries - that could be done with rgeos though.
Assuming that "eco" is a SpatialPolygonsDataFrame read in by rgdal::readOGR or maptools::readShapeSpatial, see the available key data for indexing:
sapply(as.data.frame(eco), function(x) if(!is.numeric(x)) unique(x) else NULL)
If you just want to plot it, set up a map with only the US region to start with and then overplot.
library(maps)
map("usa", col = "transparent")
We see that the data is in Lambert Azimuthal Equal Area:
proj4string(eco)
[1] " +proj=laea +lat_0=45 +lon_0=-100 +x_0=0 +y_0=0 +a=6370997 +b=6370997 +units=m +no_defs"
So
require(rgdal)
eco.laea <- spTransform(eco, CRS("+proj=longlat +ellpse=WGS84"))
plot(eco.laea, add = TRUE)
If you want to plot in the original Lambert Azimuthal Equal Area you'll need to get the bounding box in that projection and start the plot based on that, I just used existing data to make an easy example. I'm pretty sure the data could also be cropped with rgeos against another boundary too, but depends what you actually want.

Resources