Adjusting coordinates of a raster - r

I am working with air pollution data and I am unable to figure out how to adjust the coordinates of the raster file I am working with. The raw data I am working with is in the form of NETcdf4 at a resolution of .01*.01 available here
This is how it looks like:
a <- raster("V4NA03_PM25_NA_201701_201701-RH35.nc")
a <- as.data.frame(a, xy=T)
Raster info
Dataframe
I use this file to crop out USA, but I require the latitudes and longitudes at .5*.5 resolution, in the form of, for instance, x = -170.5 y = -65.5, x = -170, y = -65, x = -169.5 y = -64.5 etc.
I use the following command:
a <- aggregate(a, fact = 50)
a <- as.data.frame(a, xy = T)
But then I get the following lat longs: -167.75, -167.25, 67.95, with number of rows down to 16296.
enter image description here
Am I doing something wrong? Or is my approach entirely wrong? Would rotation or reprojection help my cause?
Any help is appreciated. Thanks.

Related

How can I plot a map using ggplot2 that includes the latitude and longitude of the data?

I have data that includes the longitude and latitude of certain locations in Arizona however its over 9000 observations and ggplot2 keeps giving me "Error in st_as_sf.data.frame(data, coords = c(x, y), remove = FALSE, crs = crs) : missing values in coordinates not allowed". This data also has missing longitudes and latitudes that may be affecting the code. I need help plotting geolocations for over 9000 observations located in an excel file, excluding missing data.
I tried using ggplot2 but it kept giving me error codes and I tried mapview but I think that it may only work for smaller data observations. I still have to merge this data with 2 other 9000 observations. I think it may be because I need a bigger data visualization program but I don't know. I was expecting all the observations to be displayed on a map by themselves and then all together (layered). Any assistance would be greatly appreciated.
Would ggmap package be helpful?
You may use it to download a map of Arizona and plot the data points according to their longitude and latitude on the map.
For example,
AZmap = get_stamenmap(bbox=c(left = -115.63, bottom = 31.25, right =
-108.84, top = 37.18),zoom = 2)
ggmap(AZmap)+ geom_point(aes(x = your longitude,
y = your latitude,
data = your data,
alpha = 0.1, size = 1, color = 'red')
I tried get_map or get_googlemap before but they required API key. get_stamenmap works best for me.

How to access multiple elevation points at the same time with get_elev_point

I hava another geodata question. I am trying to access the elevation data for specific points with the get_elev_point ()
I have about 160 points that I would like to get the elevation data for, so I would like to not do it one by one but I do not know how to retrieve them all at once.
I have made a data.frame of all my points where the first column x is longitude and the second column y is latitude and these are the only data in the data.frame.
I am using the elevatr package
Reproducible example:
location_1 <- data.frame (x=-7.37,y=5.775)
location_1_elev <-get_elev_point(locations = location_1, units="meters", prj = ll_prj, src = "aws")
When I do this, everything is fine and I get an elevation point back, but when I try to access several points at the same time I run into errors.
I took the earthquake data from R and transformed it into a data.frame that has only the longitude and latitiude. Then tried to access the elevation points via get_elev_points and got the error message:
data(quakes)
head(quakes)
locations <- data.frame(x = c(quakes$long, 1000), y = c(quakes$lat, 1000))
quakes_elev <-get_elev_point(locations = locations, units="meters", prj = ll_prj, src = "aws")
Error: API did not return tif
Do you have any tips how to make this happen, to be able to access multiple elevation points?
Thank you!
ps.: Sorry for my clumsy asking, I am only learning now.
It's likely the error is caused because the points are in the sea so there is no land elevation tif file to get an elevation from. For example, here is an example that tries to find the elevation of a point in the sea and then a point on land.
library(elevatr)
ll_prj <- "EPSG:4326"
sea <- data.frame(x=181.62, y=-20.42)
# This errors
sea_elev <- get_elev_point(locations = sea, units='meters', prj=ll_prj, src='aws')
# Error: This url: https://s3.amazonaws.com/elevation-tiles-prod/geotiff/5/32/18.tif did not return a tif
land <- data.frame(x=-71.3036, y=44.2700)
# This works
land_elev <- get_elev_point(locations = land, units='meters', prj=ll_prj, src='aws')
land_elev$elevation
# [1] 1478
Using the epqs option returns NA without error so I suppose you could replace that with 0 if you want to use sea level as the elevation.
I finally had time to look into this.
The root causes of the problem are 1) data near 180 degrees, and 2) longitude using 0 to 360.
The first issue was a problem as I was grabbing the next higher tile for a given longitude. The end result is an x/y/z tile that didn't exist and thus would return an error. I have a fix that only grabs the tile that corresponds with a given longitude and not the next higher. This is fixed and pushed to https://github/jhollist/elevatr.
The second issue is a problem as elevatr assumes longitude between -180 and 180. So if you convert the quakes dataset to this and use the newer version of elevatr on GitHub, #kamilla-choni-pléh code will work.
install.packages("remotes")
remotes::install_github("jhollist/elevatr")
library(elevatr)
ll_prj <- "EPSG:4326"
data(quakes)
locations <- data.frame(x = c(quakes$long), y = c(quakes$lat))
locations$x <- ifelse(locations$x >= 180, locations$x - 360, locations$x)
quakes_elev <-get_elev_point(locations = locations, units="meters", prj = ll_prj, src = "aws")
quakes_elev$elevation
If using a higher zoom level, though it may complain as it is currently creating a raster that spans -180 to 180 (i.e. the globe). I am still mulling over how I should deal with that in elevatr.

Calculate slope over a gridded latitude/longitude coordinate area with corresponding depths in r

I have built a gridded area in the Gulf of Alaska with a resolution of 0.02 decimal degrees (~1nm);
library(sp)
library(rgdal)
# Set interval for grid cells.
my.interval=0.02 #If 1 is 1 degree, which is 60nm, than 0.1 is every 6nm, and 0.05 is every
3nm, so 0.0167 is every 1nm
# Select range of coordinates for grid boundaries (UTM to maintain constant grid cell area regardless of geographic location).
lonmin = -140.5083
lonmax = -131.2889
latmin = 53.83333
latmax = 59.91667
LON = seq(lonmin, lonmax, by=my.interval)
LAT = seq(latmin, latmax, by=my.interval)
# Compile series of points for grid:
mygrd = expand.grid(
Longitude = seq(lonmin, lonmax, by=my.interval),
Latitude = seq(latmin, latmax, by=my.interval)) %>%
#mutate(z=1:n()) %>%
data.frame
I exported that grid as a .csv file and brought it into ArcGIS where I used a few bathymetry rasters to extract the bottom depth at the midpoint of each cell. I then exported that from GIS back into R as a .csv file data frame. So now it has another column called "Depth" on it.
For now, I'll just add a column with random "depth" numbers in it:
mygrd$Depth<-NA
mygrd$Depth<-runif(nrow(mygrd), min=100, max=1000)
I would like to calculate the slope at the midpoint of each cell (between points).
I've been trying to do this with the slope() function in SDMTools package, which requires you to have a SpatialGridDataFrame in the sp package.
I can't get this to work; I am also not sure if this is the easiest way to do that?
I have a data frame with 3 columns: Longitude, Latitude, and Depth. I'd like to calculate slope. If anyone knows any better way to do this, let me know! Any help is much appreciated!
Here is some of the code I've been trying to use:
library(SDMTools)
proj <- CRS('+proj=longlat +datum=WGS84')
coords <- mygrd[,1:2]
t2 <- SpatialPointsDataFrame(coords=coords, data=mgrd proj4string=proj)
t2<-SpatialPixelsDataFrame(points=t2[c("Longitude","Latitude")], data=t1[,c(1,2)])
t3 <- SpatialGridDataFrame(grid=NULL, data=t2, proj4string=CRS("+proj=longlat +datum=WGS84"))
class(t3)
slope.test<-slope(t3, latlon=TRUE)

create raster brick from ncdf of irregularly spaced x and y

I'm fairly new to using R for GIS purposes. I have a netcdf file containing several variables with multiple dimensions (x,y,z,value and time). I am trying to turn this into a raster brick. The data is quite large so I need to pull data from a specified time window and z(depth). This has not been a problem and extract an array with the appropriate dimensions using the below code .
library(ncdf4)
library(raster)
t <- ncvar_get(nc, "model_time")
t1<-ncvar_get(nc,"model_time_step")
tIdx<-t[t> 20120512 & t < 20120728]
tIdx2<-which(t> 20120512 & t < 20120728)
# Depths profiles < 6 meters
dIdx<-which(nc$dim$depthu$vals <6)
# ncdf dimension lengths
T3 <- nc$var[[7]]
varsize <- T3$varsize
# Define the data (depths,time,etc.) you wish to extract from the ncdf
start <- c(x = 1, y= 1,depthu=1, time_counter = min(tIdx2))
count <- c(x = max(varsize[1]), y = max(varsize[2]),depthu=1, time_counter =
max(tIdx2)-min(tIdx2)+1)
# order of the dimensions
dim.order <- sapply(nc$var$votemper$dim, function(x) x$name)
temp<-ncvar_get(nc,"votemper",start=start[dim.order],count=count[dim.order])
nc$var$votemper
An example of my data (dropping the depth/z and the time dimensions)
temp<-structure(c(0,0,0,0,0,0,0,15.7088003158569,15.3642873764038,14.9720048904419,,15.9209365844727,14.9940872192383,15.0184164047241,15.0260219573975, 0,15.7754755020142, 15.424690246582, 15.6697931289673,15.6437339782715, 0,15.6151847839355, 15.5979156494141, 15.6487197875977,15.432520866394), .Dim = c(x = 5L, y = 5L))
The latitudes and longitudes extracted from the ncdf are irregularly spaced and two dimensions each (i.e. An irregular spaced lat and lon for each cell)
lon<-structure(c(-71.2870483398438,-71.2038040161133,-71.1205596923828,-71.0373153686523, -70.9540710449219, -71.2887954711914, -71.2055587768555,-71.122314453125, -71.0390701293945,-70.9558258056641,-71.2905654907227,-71.2073211669922,-71.1240844726562,-71.0408401489258,-70.9576034545898,-71.292350769043,-71.209114074707, -71.1258773803711, -71.0426330566406,-70.9593963623047, -71.2941513061523, -71.2109222412109, -71.127685546875,-71.0444488525391, -70.9612045288086), .Dim = c(5L, 5L))
lat<-structure(c(38.5276718139648, 38.529125213623, 38.5305824279785,38.532039642334, 38.5334968566895, 38.5886116027832, 38.5900802612305,38.591552734375, 38.5930252075195, 38.5944976806641, 38.6494789123535,38.6509628295898, 38.6524467468262, 38.6539344787598, 38.6554222106934,38.7102699279785, 38.7117652893066, 38.713264465332, 38.7147674560547,38.7162704467773, 38.7709808349609, 38.7724952697754, 38.7740097045898,38.7755241394043, 38.777042388916), .Dim = c(5L, 5L))
Typically I would generate a raster brick from this data using
Temp_brick <- brick(temp, xmn=min(lat), xmx=max(lat), ymn=min(lon), ymx=max(lon),transpose=T)
Temp_brick<-t(flip(Temp_brick,1))
This, however does not account for the irregular spacing and raster cell values are located in the wrong position (lon,lat). I have searched across stack overflow and other gis help sources and I can't find a similar problem with a solution or I'm not asking the right question. I'm not particularly sure how to go about this. Not sure whether this should be dealt with when extracting the data from the netcdf or if it should be dealt with after the raster brick has been created without defined extent. I have tried to find a way to define the lon lats for the raster without any luck. Tried converting lon,lat and value to 3 column dataframe and then use the raster::rasterFromXYZ function. This won't work quick enough for the size of the data I'm dealing with, which in reality is 197(x)*234(y)*2(z)*900(time)*5(variables)*12(years(separate netcdf files).
Any help is greatly appreciated
an option with akima to first interp the data to a regular grid and then turn it into a raster:
# define the regular lon lat or just pass the nx, ny param to interp functions
lonlat_reg <- expand.grid(lon = seq(min(lon), max(lon), length.out = 5),
lat = seq(min(lat), max(lat), length.out = 5))
# interp irregular data to a regular grid
# both solution return the same results because
# i've define the regular grid as akima default
test <- interp(x = as.vector(lon), y = as.vector(lat), z = as.vector(temp),
xo = unique(lonlat_reg[,"lon"]), yo = unique(lonlat_reg[,"lat"]),
duplicate = "error", linear = FALSE, extrap = FALSE)
test <- interp(x = as.vector(lon), y = as.vector(lat), z = as.vector(temp),
nx = 5, ny = 5, linear = FALSE, extrap = FALSE)
# turn into a raster
test_ras <- raster(test)
Check the arguments of the function to choose the interpolation performed etc and be careful if you use extrapolation!
I've seen also that method
Cheers

Plotting netcdf file with raster package leads to distorted representation, R

I want to properly plot this netcdf file: http://www.filedropper.com/sshgridsv16092015060412nc (Downloaded originally from here: https://opendap.jpl.nasa.gov/opendap/allData/merged_alt/L4/cdr_grid/contents.html)
But run into issues:
I should be able to just plot the raster (the SLA variable):
library(RNetCDF)
library(raster)
library(maptools)
d <- raster("ssh_grids_v1609_2015060412.nc.nc4", varname = "SLA")
plot(d)
#plot SLA
But the result is very weird as you can see with the provided file.
Especially when plotting a world map on top:
data(wrld_simpl)
plot(wrld_simpl, add = T)
They don't match at all :/
So I thought maybe the problem is with the longitude (ranging from 4.839944e-09 to 360)
Then I read that raster::rotate(d)
should be perfect for that (to get longitude to -180 to 180), but it won't let me. I get this warning message:
Warning message:
In .local(x, ...) :
this does not look like an appropriate object for this function
and
plot(d)
still looks the same.
Any advice would be greatly appreciated!
Cheers
The Netcdf file is not only "rotated" in longitude but x and y are also at the wrong position. The way it has been entered in the netcdf is not usual apparently.
I downloaded the netcdf directly on the OpenDap server because your filedropper link seems to be corrupt.
Anyway, here is my proposition:
library(raster)
library(maptools)
d <- raster("ssh_grids_v1609_2015060412.nc.nc4", varname = "SLA")
# transpose x to y and double flip the map
m.r <- flip(flip(t(d), direction = "y"), direction = "x")
# then rotate from 0:360 to -180:180
rm.r <- rotate(m.r)
data(wrld_simpl)
plot(rm.r)
plot(wrld_simpl, add = T)

Resources