How can I add a lat-long grid to a projected map? - r

EDIT: question really pertains to how one can add lat/long gridlines to a projected map. I changed title to match.
I have some layers in geographic coords. I want to plot them in LCC projection, but have a geographic (lat/long) grid. From mapproj I can use map.grid() to add a grid, with the limits set by the lim argument. It takes a vector or a range object:
a vector of 4 numbers specifying limits: c(lon.low, lon.high, lat.low,
lat.high). lim can also be a list with a component named range, such
as the result of map, from which limits are taken.
I construct my map by clipping a large vector layer with a clipping polygon:
myPoly <- readOGR(dsn=".", layer="myPolygon") # just a shapefile in geographic coords
library(raster) # To convert an 'extent' object to a SpatialPolygons object
cp <- as(extent(146, 149, -39, -37.5), "SpatialPolygons")
proj4string(cp) <- CRS(proj4string(myPoly)) # copy from shapefile
# Transform and plot:
lcc <- CRS("+init=epsg:3111")
myPoly.proj <- spTransform(myPoly, lcc)
cp.proj <- spTransform(cp, lcc) # transform the clip box
myPoly.proj.clip <- gIntersection(myPoly.proj, cp.proj, byid=TRUE)
plot(myPoly.proj.clip)
# Then finally, add a lat/long grid:
map.grid(lim=as.vector(cp.proj#bbox), labels=TRUE)
That last line is not correct, as the #bbox returned is xmin, ymin, xmax, ymax, but needs to be in xmin, xmax, ymin, ymax. There must be a simple solution to all this, but as usual I am lost in the vortex. I could manually create a limits vector, but really?

EDIT: the OP points out rgdal::llgridlines which is a better solution.
You are using context from sp/rgdal which uses a different system to that of mapproj/maps.
Try this (untested):
library(rgdal)
gl <- gridlines(myPoly)
cp.gl <- spTransform(gl, lcc)
plot(cp.gl, add = TRUE)
See ?gridlines for more on using this with labels. I find it works well as long as you stay away from circumpolar maps.

Related

How can I project a raster in lat-long coordinates to UTM, for plotting in tmap?

I have a map with an elevation raster that is in lat/long coordinates but I now need to display the map in easting/northing. How can I accomplish this?
I have tried reprojecting the raster from lat/long to UTM but this warps the map (I assume for reasons discussed in this SO post).
A minimal working example follows a description of the code that I am using to produce the map in lat/long coordinates. I used a manually defined bounding box, extent, to download the elevation raster of interest from FedData. I then plotted the raster using tmap.
# - Libraries ----
library(proj4)
library(FedData)
library(rgdal)
library(tmap)
# extent defined manually
extent <- rgeos::readWKT("POLYGON((-118.25 36.45, -118.25 36.6, -118.25 36.9, -118.8 36.9, -118.8 36.45, -118.25 36.45))")
# define shape polygon on lat/long coordinates
proj4string(extent) <- "+proj=longlat +ellps=GRS80 +datum=NAD83 +no_defs"
# - Get national elevation raster ----
# download National Elevation Database elevation data in extent
# default resolution is 1 arcsecond (res="1);
# to get 1/3 arcsecond (res="13)
ned_raster<-FedData::get_ned(template=extent, label="ned_raster", res="1", force.redo = T)
# - Plot with tmap ----
tm_shape(ned_raster,unit.size=1)+
tm_graticules() +
tm_raster(legend.show=FALSE)
Update I'm updating the question with some additional clarification after Robert Hijmans' answer. I am including the code that I used for the reprojection here:
ned_raster2 <- raster::projectRaster(ned_raster, crs=CRS("+proj=utm +init=epsg:26711 +zone=11 +north +no_defs"))
The output is comparable to the one in the map you included in your answer. By modifying the bounding box with tmaptools::bb I can clip the map with tmap so that the projection is correct but it does not "appear" warped:
# - Project from angular to planar ----
ned_raster2 <- raster::projectRaster(ned_raster, crs=CRS("+proj=utm +init=epsg:26711 +zone=11 +north +no_defs"))
# redefine extent/bounding box
e2 = tmaptools::bb(ned_raster2)
e2 = e2*c(1.01,1.001,.99,.999)
# - Plot with tmap ----
tm_shape(ned_raster2,unit.size=1,bbox=e2)+
tm_graticules(n.x=5) +
tm_raster(legend.show=FALSE)
From this, how can I include the appropriate axes (in easting/northing) on this map?
I now need to display the map in easting/northing.
I understand that in stead of angular (lon/lat) coordinates you want to use planar (Cartesian) coordinates. That means that you need to choose an appropriate coordinate reference system (CRS). You say you used UTM, and that could be reasonable, but you found that the results are "warped". You should show the code you used because you probably made a mistake. There always is some distortion, but for a small area like this is would not be an issue if you specify the CRS correctly. (otherwise, explain "warped" and why it matters.)
For example
library(raster)
library(FedData)
# extent defined manually
e <- as(extent(-118.8, -118.25, 36.45, 36.9), "SpatialPolygons")
crs(e) <- "+proj=longlat"
ned <- FedData::get_ned(template=e, label="ned_raster", res="1", force.redo = T)
ned2 <- projectRaster(ned, crs="+proj=utm +zone=11")
plot(ned2)
For larger areas you cannot use UTM and you would need to use another CRS.
Alternatively, you could create grid-lines (graticule) from the projected raster, store their coordinates, and transform these back to longlat. That would be a bit odd. Normally, one might want to show longlat coordinates on a otherwise projected (planar) map.

How to plot a extracted raster in proper xy coordinates?

I have a ndvi raster. I had to extract the values using a threshold conditon.When I plot the graph of the extracted raster, the x y coordinated are not lat long.
I have tried the ggplot() , also the used rastertopoints and rasterfromXYZ to plot the raster but in vain.
The code is below.
Unable to plot s. xy coordiantes are not lat long.
library(raster)
library(rgdal)
raster <- ("D:/Project/ndvisoybean.tif")
plot(ndvi)
ndvi[is.na(ndvi)] <-0
s <- ndvi[ndvi#data#values<maxValue(ndvi) & ndvi#data#values>0.3*maxValue(ndvi)]
I want a graph of the extracted raster s with proper lat long coordinates in x y.
As fa as I know there is no appropriate case to plot lon/lat xy coordinate map if the raster is not WGS84 projection.
One way is that converting raster layer to WGS84 projection.So that the plot coordiante is lon/lat. It is only appreciate for small map or world map.
The other way is using coord_map function in ggplot.But the import data must be lon/lat dataframe rather than ohter projection coordinate. So it is low efficiency to plot map. More serous it is very slow when converting data.frame point coordinate to another. this way is only suitable for small width/height raster. Code example:
Primaly you should convert your raster to WGS84 coordiante.
df=rasterToPoint(raster_WGS84)
ggplot(df, aes(y=lon, x=lat, color=values)) +
geom_point(size=2, shape=15) +
theme() +
scale_color_distiller(palette='Spectral') +
coord_map('lambert', lat0=30, lat1=65, xlim=c(-20, 39), ylim=c(19, 75))
Summary: If your raster is projected coordinate,such as Albers,lambert rather than lon/lat WGS84 coordiate, it is inconvenient to plot a map with lon/lat xy coodiate.

geom_sf does not use geometry coordinates in axes but plots correct shape of polygon?

My overall aim is to combine multiple shape files (polygons of river sub-basins from within a large river basin) into one file and plot as a map. This new combined file will later combine with variable data e.g.(rainfall) and plot by aes().
My problem is:
ggplot()+geom_sf() plots the correct shapes of the polygons but doesn't have the correct co-ordinates on the axes - it doesn't use the values given in the geometry column on the axes.
My thoughts on what is wrong, but I'm not sure how to correct:
The shape file read in has geometry in 'long' 'lat' (crs= 4326) but the crs is saying the coordinates are in UTM Zone 48N WGS84 (crs=32648). If I try and force the crs to 4326 the coordinate values change as if the conversion formula is trying to correct them.
geom_sf and coord_sf are doing something that I don't understand!
.
library(sp)
library(raster)
library(ggplot2)
library(sf)
library(ggsf)
library(rgdal)
library(plyr)
library(dplyr)
library(purrr)
setwd("/Users/.../Sub_Basin_Outlines_withSdata/")
list.files('/Users/.../Sub_Basin_Outlines_withSdata/', pattern='\\.shp$')
Read in individual polygon shape files from folder. Combine with ID.
bangsai <- st_read("./without_S_data/", "Nam Bang Sai")
BasinID <- "BGS"
bangsai <- cbind(bangsai,BasinID)
ing <- st_read("./without_S_data/", "Nam Ing Outline")
BasinID <- "ING"
The two individual shape files import as simple features, see image of R code
Combine the individual sub-basin polygon shape files into one shapefile with multiple features.
all_sub_basins <- rbind(bangsai,ing)
The image shows the values of the coordinates of the polygons/features in all_sub_basins$geometry. They are long lat format yet the proj4sting suggests UTM?
Plot the all_sub_basins simple feature shapefile in ggplot
subbasins <- ggplot()+
geom_sf(data=all_sub_basins, colour="red", fill=NA)
subbasins
The result is a correctly plotted shape file with multiple features (there are more polygons in this image than read in above). However the axes are incorrect (nonsense values) and are not plotting the same values as in the geometry field.
If I add in coord_sf and confirm the crs:
subbasins <- ggplot() +
geom_sf(data=all_sub_basins, colour="red", fill=NA)
coord_sf(datum=st_crs(32648), xlim = c(94,110), ylim = c(9,34))
subbasins
Then I get the Correct axes values but not as coordinates with N and E. It seems as if the geometry isn't recognised as coordinates, just as forced numbers?
I don't mind if the coordinates are UTM Zone 48N or lat long. Could I fix it in any of these ways? If so, how do I achieve that?
Change the shape file crs without changing the values in the geometry column so geom_sf would know to plot the correct axes text.
Extract the geometry from the shape file into a two column .csv file with long and lat columns. Convert csv into a sf and create my own shape file with correct crs.
Last resort, leave the plot as it is and replace new axes text manually.
Any help is much appreciated!

Is ggplot map spatial raster/grid so slow while using coord_map to convert projection?

The raster data contianing projection wgs84 whose coordinates is lon/lat degree. If I want to map local area meeting suitable projection such as albers. main code as follows:
ras <- raster('r2008-03.tif')
ras_mtx <- rasterToPoints(ras_aea)
ras_df <- as.data.frame(ras_mtx)
colnames(ras_df) <- c('lon','lat','val')
basemap <- ggplot(data=ras_df,aes(x=lon,y=lat,fill=val))+
geom_tile()+
borders('world',xlim=range(ras_df$lon),ylim=range(ras_df$lat),
colour='black')+
coord_map(projection='albers',lat0=25,lat1=47)
It takes a long time (>10min) on mapping a small raster (260*400 resolution). The step coord_map for tranforming each grid point is slow. I think the input data.frame of ggplot reduce the efficiency of projection transform.
Why not use matrix to mapping grid like python basemap?
So I convert raster projection firstly ,then map it. Now the xy coordinate unit is meter. How to convert the xy to lon/lat degree is another problem?
ras_aea <- projectRaster(ras,crs='+proj=aea +lat_1=25 +lat_2=47 +datum=WGS84')
ras_mtx <- rasterToPoints(ras_aea)
ras_df <- as.data.frame(ras_mtx)
colnames(ras_df) <- c('lon','lat','val')
bm <- ggplot(data=ras_df,aes(x=lon,y=lat,fill=val))+
geom_raster()
First comment #Z.Lin has illuminated that the coord_map is actully slow rather than code error. Therefore I should tranform raster projection before mapping. So my purpose is that change the geographic xy coordinate label(unit meter) to lon/lat (as upper fig).

Assigning spatial coordinates to an array in R

I have downloaded a text file of data from the following link: http://radon.unibas.ch/files/us_rn_50km.zip
After unzipping I use the following lines of code to plot up the data:
# load libraries
library(fields)
# function to rotate a matrix (and transpose)
rotate <- function(x) t(apply(x, 2, rev))
# read data
data <- as.matrix(read.table("~/Downloads/us_rn_50km.txt", skip=6))
data[data<=0] <- NA
# rotate data
data <- rotate(data)
# plot data
mean.rn <- mean(data, na.rm=T)
image.plot(data, main=paste("Mean Rn emissions =", sprintf("%.3f", mean.rn)) )
This all looks OK, but I want to be able to plot the data on a lat-long grid. I think I need to convert this array into an sp class object but I don't know how. I know the following (from the web site): "The projection used to project the latitude and longitude coordinates is that used for the Decade of North American Geology (DNAG) maps. The projection type is Spherical Transverse Mercator with a base latitude of zero degrees and a reference longitude of 100 degrees W. The scale factor used is 0.926 with no false easting or northing. The longitude-latitude datum is NAD27 and the units of the xy-coordinates are in meters. The ellipsoid used is Clarke 1866. The resolution of the map is 50x50km". But don't know what to do with this data. I tried:
proj4string(data)=CRS("+init=epsg:4267")
data.sp <- SpatialPoints(data, CRS("+proj=longlat+ellps=clrk66+datum=NAD27") )
But had various problems (with NA's) and fundamentally I think that the data isn't in the right format.. I think that the SpatialPoints function wants a data on location (in 2-D) and a third array of values associated with those locations (x,y,z data - I guess my problem is working out the x and the y's from my data!)
Any help greatly appreciated!
Thanks,
Alex
The file in question is an ASCII raster grid. Coordinates are implicit in this format; a header describes the position of the (usually) lower left corner, as well as the grid dimensions and resolution. After this header section, values separated by white space describe how the variable varies across the grid, with values given in row-major order. Open it in a text editor if you're interested.
You can import such files to R with the fantastic raster package, as follows:
download.file('http://radon.unibas.ch/files/us_rn_50km.zip',
destfile={f <- tempfile()})
unzip(f, exdir=tempdir())
r <- raster(file.path(tempdir(), 'us_rn_50km.txt'))
You can plot it immediately, without assigning the projection:
If you didn't want to transform it to another CRS, you wouldn't necessarily need to assign the current coordinate system. But since you do want to transform it to WGS84 (geographic), you need to first assign the CRS:
proj4string(r) <- '+proj=tmerc +lon_0=-100 +lat_0=0 +k_0=0.926 +datum=NAD27 +ellps=clrk66 +a=6378137 +b=6378137 +units=m +no_defs'
Unfortunately I'm not entirely sure whether this proj4string correctly reflects the info given at the website that provided the data (it would be great if they actually provided the definition in a standard format).
After assigning the CRS, you can project the raster with projectRaster:
r.wgs84 <- projectRaster(r, crs='+init=epsg:4326')
And if you want, write it out to a raster format of your choice, e.g.:
writeRaster(r.wgs84, filename='whatever.tif')

Resources