Can't change the coordinates of a SpatialPolygonsDataFrame in R - r

This is my program:
library(sp)
library(RColorBrewer)
#get spatial data for Spain on region level
con <- url("http://gadm.org/data/rda/ESP_adm1.RData")
print(load(con))
close(con)
# plot Spain with colors
col = c("blue","blue","blue","blue","blue","blue","blue","blue","blue",
"blue","blue","blue","blue","blue","blue","blue","red","red")
spplot(gadm, "NAME_1", col.regions=col, main="Regiones de España",
colorkey=F, lwd=.4, col="black")
What I get when I run is what I am looking for, but I want to change the islands in the south west (Islas Canarias) to be closer to Spain country. I don't know what to do to change the coordinates of the islands. I just know they are here:
gadm[14,]
I try to make changes for example here:
gadm[14,]#polygons[[1]]#Polygons[[1]]#coords
but I get the message: no method for coercing this S4 class to a vector

One could also try the sf package - CRAN link here
The GADM data URL seems deprecated now, but one can manually download the RDS file containing the SpatialPolygonsDataFrame for Spain from http://gadm.org/.
library(sf)
spain <- readRDS(file = "ESP_adm1.rds") # downloaded from http://gadm.org/
# convert from sp to sf object
spain_sf <- st_as_sf(spain)
# Change the coordinates of Canary Islands - the 14th geometry of spain_sf,
# itself with 20 polygons, check str(st_geometry(spain_sf)[[14]])
# Will shift them closer to mainland Spain.
# The added values are degrees because the CRS is unprojected
# (e.g. add 10 to longitudes and 6 to latitudes)
for (i in 1:length(st_geometry(spain_sf)[[14]])) {
st_geometry(spain_sf)[[14]][[i]][[1]][, 1] <- st_geometry(spain_sf)[[14]][[i]][[1]][, 1] + 10
st_geometry(spain_sf)[[14]][[i]][[1]][, 2] <- st_geometry(spain_sf)[[14]][[i]][[1]][, 2] + 6
}
# plot to check
par(omi=c(0,0,0,2)) # make some space to the right for the legend
plot(spain_sf["NAME_1"],
axes = TRUE,
graticule = st_crs(spain_sf))
# dev.off() # resets par()

Related

Issue with country/province name from coordinates when points are on country coastal limits (in R) [duplicate]

This question already has an answer here:
Incorrect NA return when converting Lat/Long Coordinates to location in R
(1 answer)
Closed last year.
I have a set of coordinates that most fall within or near the Iberian Peninsula.
I'm interested in finding out the country name of a large set of coordinates and the province name. However, there are some problematic coordinates on the boundaries of the countries (coordinates near the coastal area) that are no detected within the country or province. First I have tried to find out the province name and after the country name and I find this issue with these two different approaches.
I'm aware that some coordinates could be typos but I have manually checked that some fall within the country limits.
Any advice of how to overcome this?
Here create here a minimal reproducible example:
First, I create a dataframe with the problematic coordinates. The last coordinate (36.76353, -4.425162) is a "correct one" in order to show that the function works.
lat <- c(36.81973, 43.69739, 36.51103, 38.50000, 42.25167, 42.25177, 39.31316, 36.76353)
long <- c(-2.411557, -5.919138, -4.635675, -0.100000, -8.804174, -8.790300, 2.995276, -4.425162)
coords <-data.frame(long, lat)
Then by readapting the answer of a colleague with the addition of library(mapSpain)
Latitude Longitude Coordinates to State Code in R I create this function that should tell the provinces where the different points are.
#I create a function that should tell the provinces of Spain from coordinates
library(sf)
library(spData)
library(mapSpain)
## pointsDF: A data.frame whose first column contains longitudes and
## whose second column contains latitudes.
##
## states: An sf MULTIPOLYGON object with 50 states plus DC.
##
## name_col: Name of a column in `states` that supplies the states'
## names.
lonlat_to_state <- function(pointsDF,
states = mapSpain::esp_get_prov(),
name_col = "ine.prov.name") {
## Convert points data.frame to an sf POINTS object
pts <- st_as_sf(pointsDF, coords = 1:2, crs = 4326)
## Transform spatial data to some planar coordinate system
## (e.g. Web Mercator) as required for geometric operations
states <- st_transform(states, crs = 3857)
pts <- st_transform(pts, crs = 3857)
## Find names of state (if any) intersected by each point
state_names <- states[[name_col]]
ii <- as.integer(st_intersects(pts, states))
state_names[ii]
}
lonlat_to_state(coords)
[1] NA NA NA NA NA NA NA "Málaga"
And again I have the same issue if I use
library(maps)
map.where(x = coords$long, y = coords$lat)
[1] NA NA NA NA NA NA NA "Spain"
Any advice would be more than welcome, thanks for your time!
st_intersects is working as expected, because the points (except one) lie outside the polygons. We can see this by plotting them (zooming in on each)
library(ggplot2)
for (i in seq_len(nrow(pts))) {
xlim = unlist(st_geometry(pts[i,]))[1] + c(-5000, 5000)
ylim = unlist(st_geometry(pts[i,]))[2] + c(-5000, 5000)
g = ggplot() +
geom_sf(data=states) +
geom_sf(data=pts) +
coord_sf(xlim = xlim, ylim = ylim)
print(g)
}
A few examples of the plots:

rworldmap coordinates, how to match NetCDF data to the map?

Rworldmap looks like exactly what I need for mapping climate data, but I'm having a problem lining up the base map with the climate data. What I am mapping is ocean temperature data from JAMSTEC for August, 2015 from here:
http://www.jamstec.go.jp/ARGO/argo_web/ancient/MapQ/Mapdataset_e.html
The dataset name is TS_201508_GLB.nc. The R script I'm using is below. The country outlines are fine, but the data is for the oceans only and the data does not show in the oceans it is offset somehow. Can you tell me how to align the data to the map?
I've read lots of articles but I cannot tell how to align the two. The data I have is longitude and latitude. South latitude is negative and west longitude is negative, I don't see how they could be confused. How is the map shown, is there some sort of special convention for the lat/longs?
Thanks for any help you can provide.
The code:
library(RNetCDF)
library(sp)
library(rworldmap)
library(rgeos)
library(RColorBrewer)
library (classInt)
library(grid)
library(spam)
library(maps)
library(maptools)
library(fields)
library(methods)
library(rgdal)
library(rworldxtra)
fname <- "G:/Climate_Change/Ocean_Warming/MOAA_GPV_Jamstec_Temperature/TS_201508_GLB.nc"
moaa <- open.nc(fname)
# moaa
print.nc(moaa)
file.inq.nc(moaa)
#TOI is the temperature array extracted from the NCDF file
TOI = var.get.nc(moaa,"TOI",start=c(1,1,1),count=c(360,132,25))
TOI[1,1,1]
Long = var.get.nc(moaa,"LONGITUDE")
Lat = var.get.nc(moaa, "LATITUDE")
Pres = var.get.nc(moaa,"PRES")
# create grid
offset=c(-179.5,-60.50)
cellsize = c(abs(Long[1]-Long[2]),abs(Lat[1]-Lat[2]))
cells.dim = c(dim(Long), dim(Lat))
# create gt
gt <- GridTopology(cellcentre.offset=offset,cellsize=cellsize,cells.dim=cells.dim)
# create map window
mapDevice()
# Create a color pallette
colourPalette=c('blue','lightblue','white',brewer.pal(9,'YlOrRd'))
# Values at 2000 decibar for August 2015
ncMatrix <- TOI[,,25]
# Gridvalues
gridVals <-data.frame(att=as.vector(ncMatrix))
# create a spatialGridDataFrame
sGDF <-SpatialGridDataFrame(gt,data=gridVals)
# Vector to classify data
catMethod=seq(from=0,to=4,by=.33)
# plotting the map and getting params for legend
mapParams <- mapGriddedData( sGDF, nameColumnToPlot='att',catMethod=catMethod,colourPalette=colourPalette,addLegend=FALSE)
I finally figured it out. rworldmap wants the data organized from the upper left of the map(Northwest corner), that is Long = -180, Lat=90. The NetCDF data starts at Long=0 and Lat=-90(the middle of the map and south edge). So we have to reverse the values in the North-South direction:
#
# Flip the Latitude values so south is last
ncMatrix2 <- ncMatrix[,dim(Lat):1]
Then switch the values for east longitude and west longitude:
#
#Longitude values need to be from -180 to 0 then 0 to 180
# So we divide into East and West, then recombine with rbind
East_Long_values <-ncMatrix2[1:180,]
West_Long_Values <-ncMatrix2[181:360,]
ncMatrix3 <- rbind(West_Long_Values,East_Long_values)
Then everything else works.

How to clip a polygon shapefile by another polygon shapefile in R?

I have two polygons shapefiles and I'd like to clip one by the other. I search on google but I could find only clipping by a bounding box or clipping points by polygons, and that's not what I need.
I also find something in other programming languague, except in R (http://rosettacode.org/wiki/Sutherland-Hodgman_polygon_clipping#Python).
Could you help me?
Thanks
Tiago
Although, the question is very old, providing a good answer might help anyone in the future landing on this page.
I think what you're trying to do is straight forward. To illustrate, lets assume i'm interested in eastern coastline of Saudi Arabia (SA) and i have a shape file that has the east and west coast of SA [ and another shapefile of the Gulf (prominent waterbody on the east coast of SA). We need the SF package to crop the two shape files
Load the SF package
library(sf)
Then load both shapefiles
ksa <- st_read("cropping_shape_file/ksa/saudi_arabia_coastline.shp")
gulf <- st_read("cropping_shape_file/gulf/ihoPolygon.shp")%>%
st_transform(st_crs(ksa)) # The st_transform added to this file ensure that both files have same CRS ssstem otherwise it will be impossible to crop.
you can also check if their CRS is same
st_crs(ksa)==st_crs(gulf)
The sf_read outputs shapefile information into three fields but we're interested in just the geometry
you can
cropped<-st_crop( ksa$geometry, gulf$geometry)
plot(cropped)
You should have an image like
i'm providng the two shape files here https://mega.nz/file/NnxHXajI#KOK_86gwVQGfjNs7X2HOAtvG2NOkIwcU5EhzQU5X6tg, note that a shape file has four component that needs to be kept together(.shp, .prj, .shx, .dbf )
Another way for clipping is to make an selection like "polygontoclip"["templatepolygon", ], found this for points (http://robinlovelace.net/r/2014/07/29/clipping-with-r.html), but also works with polygons.
This doesn't answer your question, but since you mention clipping by bounding box, so this post comes up in search strings:
From r-bloggers: Clipping by a bounding box
setwd("../")
library(rgdal)
zones <- readOGR("data", "london_sport")
make a bounding box:
b <- bbox(zones)
b[1, ] <- (b[1, ] - mean(b[1, ])) * 0.5 + mean(b[1, ])
b[2, ] <- (b[2, ] - mean(b[2, ])) * 0.5 + mean(b[2, ])
b <- bbox(t(b))
plot(zones, xlim = b[1, ], ylim = b[2, ])
Using a custom function:
library(raster)
library(rgeos)
## rgeos version: 0.3-5, (SVN revision 447)
## GEOS runtime version: 3.4.2-CAPI-1.8.2 r3921
## Polygon checking: TRUE
gClip <- function(shp, bb){
if(class(bb) == "matrix") b_poly <- as(extent(as.vector(t(bb))), "SpatialPolygons")
else b_poly <- as(extent(bb), "SpatialPolygons")
gIntersection(shp, b_poly, byid = T)
}
zones_clipped <- gClip(zones, b)
## Warning: spgeom1 and spgeom2 have different proj4 strings
plot(zones_clipped)
Note that due to the if statements in gClip’s body, it can handle almost any spatial data input, and still work.
westminster <- zones[grep("West", zones$name),]
zones_clipped_w <- gClip(zones, westminster)
## Warning: spgeom1 and spgeom2 have different proj4 strings
plot(zones_clipped_w); plot(westminster, col = "red", add = T)
Clip a shapefile by another shapefile
library(raster)
# library(rgdal) # if require
# library(rgeos) # if require
luxembourg <- shapefile(system.file("external/lux.shp", package="raster")) ### load a shape from raster package
plot(luxembourg)
another_shape <- as(extent(6, 6.4, 49.75, 50), 'SpatialPolygons') ### draw a simple shape / load your own
plot(another_shape, add=T, border="red", lwd=3)
luxembourg_clip <- crop(luxembourg, another_shape) ### crop (SpatialPolygon) luxembourg with another_shape
plot(luxembourg_clip, add=T, col=4) ### plot on
plot(luxembourg_clip, add=F, col=3) ### just plot
See some images: Map and Clip
Source: https://rdrr.io/cran/raster/man/crop.html

Check if point is in spatial object which consists of multiple polygons/holes

I have a SpatialPolygonsDataFrame with 11589 objects of class "polygons". 10699 of those objects consists of exactly 1 polygon, however the rest of those objects consists of multiple polygons (2 to 22).
If an object of consists of multiple polygons, three scenarios are possible:
Sometimes, those additional polygons describe a "hole" in the geographic ara describe by the first polygon in the object of class "polygons".
Sometimes, those additional polygons describe additional geographic areas, i.e. the shape of the region is quite complex and described by putting together multiple parts.
Sometimes, it might be a mix of both, 1) and 2).
Stackoverflow helped me to plot such an spatial object properly (Plot spatial area defined by multiple polygons).
However, I am still not able to answer how to determine whether a point (defined by longitude/latitude) is in a polygon.
Below is my code. I tried to apply the function point.in.polygon in the sp package, but found no way how it could handle such an object which consists of multiple polygons/holes.
# Load packages
# ---------------------------------------------------------------------------
library(maptools)
library(rgdal)
library(rgeos)
library(ggplot2)
library(sp)
# Get data
# ---------------------------------------------------------------------------
# Download shape information from the internet
URL <- "http://www.geodatenzentrum.de/auftrag1/archiv/vektor/vg250_ebenen/2012/vg250_2012-01-01.utm32s.shape.ebenen.zip"
td <- tempdir()
setwd(td)
temp <- tempfile(fileext = ".zip")
download.file(URL, temp)
unzip(temp)
# Get shape file
shp <- file.path(tempdir(),"vg250_0101.utm32s.shape.ebenen/vg250_ebenen/vg250_gem.shp")
# Read in shape file
map <- readShapeSpatial(shp, proj4string = CRS("+init=epsg:25832"))
# Transform the geocoding from UTM to Longitude/Latitude
map <- spTransform(map, CRS("+proj=longlat +datum=WGS84"))
# Pick an geographic area which consists of multiple polygons
# ---------------------------------------------------------------------------
# Output a frequency table of areas with N polygons
nPolys <- sapply(map#polygons, function(x)length(x#Polygons))
# Get geographic area with the most polygons
polygon.with.max.polygons <- which(nPolys==max(nPolys))
# Get shape for the geographic area with the most polygons
Poly.coords <- map[which(nPolys==max(nPolys)),]
# Plot
# ---------------------------------------------------------------------------
# Plot region without Google maps (ggplot2)
plot(Poly.coords, col="lightgreen")
# Find if a point is in a polygon
# ---------------------------------------------------------------------------
# Define points
points_of_interest <- data.frame(long=c(10.5,10.51,10.15,10.4),
lat =c(51.85,51.72,51.81,51.7),
id =c("A","B","C","D"), stringsAsFactors=F)
# Plot points
points(points_of_interest$long, points_of_interest$lat, pch=19)
You can do this simply with gContains(...) in the rgeos package.
gContains(sp1,sp2)
returns a logical depending on whether sp2 is contained within sp1. The only nuance is that sp2 has to be a SpatialPoints object, and it has to have the same projection as sp1. To do that, you would do something like this:
point <- data.frame(lon=10.2, lat=51.7)
sp2 <- SpatialPoints(point,proj4string=CRS(proj4string(sp1)))
gContains(sp1,sp2)
Here is a working example based on the answer to your previous question.
library(rgdal) # for readOGR(...)
library(rgeos) # for gContains(...)
library(ggplot2)
setwd("< directory with all your files >")
map <- readOGR(dsn=".", layer="vg250_gem", p4s="+init=epsg:25832")
map <- spTransform(map, CRS("+proj=longlat +datum=WGS84"))
nPolys <- sapply(map#polygons, function(x)length(x#Polygons))
region <- map[which(nPolys==max(nPolys)),]
region.df <- fortify(region)
points <- data.frame(long=c(10.5,10.51,10.15,10.4),
lat =c(51.85,51.72,51.81,51.7),
id =c("A","B","C","D"), stringsAsFactors=F)
ggplot(region.df, aes(x=long,y=lat,group=group))+
geom_polygon(fill="lightgreen")+
geom_path(colour="grey50")+
geom_point(data=points,aes(x=long,y=lat,group=NULL, color=id), size=4)+
coord_fixed()
Here, point A is in the main polygon, point B is in a lake (hole), point C is on an island, and point D is completely outside the region. So this code checks all of the points using gContains(...)
sapply(1:4,function(i)
list(id=points[i,]$id,
gContains(region,SpatialPoints(points[i,1:2],proj4string=CRS(proj4string(region))))))
# [,1] [,2] [,3] [,4]
# id "A" "B" "C" "D"
# TRUE FALSE TRUE FALSE
Since you can use the "point in polygon" routine, and this apparently isn't already suitably designed to handle the multi-polygon case in R (which I find a bit odd actually), you are left with having to cycle through each of the multiple polygons. Now the trick is, if you are inside an odd number of polygons, you are inside the multi-polygon. If you are inside an even number of polygons, then you are actually outside of the shape.
Point in polygon testing that uses ray-crossings should ALREADY be able to handle this, just by making sure you pass in all the vertices to the original point.in.polygon test, but I am not sure which mechanism R is using, so I can only give you the even/odd advice above.
I also found this code, not sure if it will help:
require(sp)
require(rgdal)
require(maps)
# read in bear data, and turn it into a SpatialPointsDataFrame
bears <- read.csv("bear-sightings.csv")
coordinates(bears) <- c("longitude", "latitude")
# read in National Parks polygons
parks <- readOGR(".", "10m_us_parks_area")
# tell R that bear coordinates are in the same lat/lon reference system
# as the parks data -- BUT ONLY BECAUSE WE KNOW THIS IS THE CASE!
proj4string(bears) <- proj4string(parks)
# combine is.na() with over() to do the containment test; note that we
# need to "demote" parks to a SpatialPolygons object first
inside.park <- !is.na(over(bears, as(parks, "SpatialPolygons")))
# what fraction of sightings were inside a park?
mean(inside.park)
## [1] 0.1720648
# use 'over' again, this time with parks as a SpatialPolygonsDataFrame
# object, to determine which park (if any) contains each sighting, and
# store the park name as an attribute of the bears data
bears$park <- over(bears, parks)$Unit_Name
# draw a map big enough to encompass all points (but don't actually plot
# the points yet), then add in park boundaries superimposed upon a map
# of the United States
plot(coordinates(bears), type="n")
map("world", region="usa", add=TRUE)
plot(parks, border="green", add=TRUE)
legend("topright", cex=0.85,
c("Bear in park", "Bear not in park", "Park boundary"),
pch=c(16, 1, NA), lty=c(NA, NA, 1),
col=c("red", "grey", "green"), bty="n")
title(expression(paste(italic("Ursus arctos"),
" sightings with respect to national parks")))
# now plot bear points with separate colors inside and outside of parks
points(bears[!inside.park, ], pch=1, col="gray")
points(bears[inside.park, ], pch=16, col="red")
# write the augmented bears dataset to CSV
write.csv(bears, "bears-by-park.csv", row.names=FALSE)
# ...or create a shapefile from the points
writeOGR(bears, ".", "bears-by-park", driver="ESRI Shapefile")

How to append a shp file to modify map boundaries?

Thanks to suggestions from #AriBFriedman and #PaulHiemstra and subsequently figuring out how to merge .shp files, I have managed to produce the following map using the following code and data:
Data:
Morocco and Western Sahara
Code:
# Loading administrative coordinates for Morocco maps
library(sp)
library(maptools)
library(mapdata)
# Loading shape files
Mor <- readShapeSpatial("F:/Purdue University/RA_Position/PhD_ResearchandDissert/PhD_Draft/Country-CGE/MAR_adm1.shp")
Sah <- readShapeSpatial("F:/Purdue University/RA_Position/PhD_ResearchandDissert/PhD_Draft/Country-CGE/ESH_adm1.shp")
# Ploting the maps individually
png("Morocco.png")
Morocco <- readShapePoly("F:/Purdue University/RA_Position/PhD_ResearchandDissert/PhD_Draft/Country-CGE/MAR_adm1.shp")
plot(Morocco)
dev.off()
png("WesternSahara.png")
WesternSahara <- readShapePoly("F:/Purdue University/RA_Position/PhD_ResearchandDissert/PhD_Draft/Country-CGE/ESH_adm1.shp")
plot(WesternSahara)
dev.off()
# Merged map of Morocco and Western Sahara
MoroccoData <- rbind(Mor#data,Sah#data) # First, 'stack' the attribute list rows using rbind()
MoroccoPolys <- c(Mor#polygons,Sah#polygons) # Next, combine the two polygon lists into a single list using c()
# summary(MoroccoData)
# summary(MoroccoPolys)
offset <- length(MoroccoPolys) # Next, generate a new polygon ID for the new SpatialPolygonDataFrame object
browser()
for (i in 1: offset)
{
sNew = as.character(i)
MoroccoPolys[[i]]#ID = sNew
}
ID <- c(as.character(1:length(MoroccoPolys))) # Create an identical ID field and append it to the merged Data component
MoroccoDataWithID <- cbind(ID,MoroccoData)
MoroccoPolysSP <- SpatialPolygons(MoroccoPolys,proj4string=CRS(proj4string(Sah))) # Promote the merged list to a SpatialPolygons data object
Morocco <- SpatialPolygonsDataFrame(MoroccoPolysSP,data = MoroccoDataWithID,match.ID = FALSE) # Combine the merged Data and Polygon components into a new SpatialPolygonsDataFrame.
Morocco#data$id <- rownames(Morocco#data)
Morocco.fort <- fortify(Morocco, region='id')
Morocco.fort <- Morocco.fort[order(Morocco.fort$order), ]
MoroccoMap <- ggplot(data=Morocco.fort, aes(long, lat, group=group)) +
geom_polygon(colour='black',fill='white') +
theme_bw()
Results:
Individual maps
Merged Map:
Question:
I want to eliminate the boundary that cuts through the middle of the map? Anyone with any suggestions and/or help?
Thx all
I did achieve the elimination of the extra polygon layer that cuts the map in two after merging by using QGIS software, which is free to download at this link QGIS

Resources