plot LAT/LON coordinates on geotiff in R - 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)

Related

Projecting Rasters, shift to the north. Can i correct it?

I would like to project one raster onto another and while doing so I think the values are changing their position "to the north".
Is this an expected behavior?
I was hoping to create a longlat raster to use it for lookups and GeoJSON generation.
Strangely (or maybe expected, I don't know) resulting GeoJSON positions are shifted (what feels like 10km) to the north.
Do I have a logical mistake somewhere?
This is an example:
x <- raster(ncol=900, nrow=900)
x_proj <- "+proj=stere +lat_0=90 +lat_ts=90 +lon_0=10 +k=0.93301270189 +x_0=0 +y_0=0 +a=6378137 +b=6356752.3142451802 +to_meter=1000 +no_defs "
proj <- CRS(x_proj)
extent(x) <- extent(-523.4622, 376.5378, -4658.645, -3758.645)
projection(x) <- x_proj
x[seq(450,455),seq(1,900)]<-1
new_raster<-raster(ncols=900,nrows=900)
new_raster_crs<- "+proj=longlat +datum=WGS84 +zone=34 +no_defs +ellps=WGS84"
new_raster_proj <- CRS(new_raster_crs)
extent(new_raster) <- extent(3.5889,14.6209, 47.0705, 54.7405)
projection(new_raster) <- new_raster_proj
new_raster<-projectRaster(x,new_raster,method = "bilinear")
Plot of raster x
Plot of Raster new_raster
Is there something I could to with source/dest raster to create a "true" longlat lookup / GeoJSON possibility?
Is there a mistake somewhere ?
Can i maybe change +y_0=0 value to correct this?
If thats the case how can I get the exact value of shift?
Currently I only see the change visually.
That is as expected. Map projections distort (at least one of) shape, size, distance, and direction. In this case, you observe a change in shape.
You do make a mistake here:
new_raster_crs <- "+proj=longlat +datum=WGS84 +zone=34 +no_defs +ellps=WGS84"
"zone" is only relevant for the "UTM" coordinate reference system (and perhaps others), and if you define a datum, you should not also define an ellipsoid. So it should be
new_raster_crs <- "+proj=longlat +datum=WGS84"
But it seems that the other parts you add are simply ignored.
Another mistake is that you still use raster, as it has been replaced by terra. With terra it goes like this:
library(terra)
x <- rast(ncol=900, nrow=900, ext=c(-523.4622, 376.5378, -4658.645, -3758.645),
crs="+proj=stere +lat_0=90 +lat_ts=90 +lon_0=10 +k=0.93301270189 +x_0=0 +y_0=0 +a=6378137 +b=6356752.3142451802 +to_meter=1000 +no_defs")
x[seq(450,455),seq(1,900)]<-1
y <- rast(ncols=900, nrows=900, ext= c(3.5889,14.6209, 47.0705, 54.7405), crs="+proj=longlat +datum=WGS84")
z <- project(x, y)
plot(z)

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")

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.

How to calculate polygon means and map them?

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")

Resources