Advice on troubleshooting dotsInPolys error (maptools) - r

I am pretty new to R and am still learning some of the ways to troubleshoot problems I encounter. I'm running into one that I'm stuck on and wondered if anyone has suggestions.
I am trying to build a dot density map, but I'm running into an error with the dotsInPolys function. The line:
scc.rand <- dotsInPolys(sccpolys, as.integer(plotvar), f="random")
Which gives me the error:
> sccdots.rand <- dotsInPolys(sccpolys, as.integer(plotvar), f="random")
Error in dotsInPolys(sccpolys, as.integer(plotvar), f = "random") :
different lengths
The documentation indicates that sccpolys and plotvar need to be the same length, but I'm unsure on how to double-check that, or, more importantly, correct the problem. Does anyone have recommendations on how I can check what's wrong? Thanks ahead of time.
Here's the entire set of code I'm working on:
library(maptools)
# Population data
sccpop <- read.csv("nhgis0010_ds98_1970_tract.csv", stringsAsFactors = FALSE)
sccpop.sub <- sccpop[sccpop$COUNTY=="Santa Clara",c(1,3,21,22,23)]
# Shapefile for Census tracts
scctract.shp <- readShapePoly("1970-ca-tracts.shp")
sccpolys <- SpatialPolygonsDataFrame(scctract.shp, data=as(scctract.shp, "data.frame"))
# Merge datasets
sccdata <- merge(sccpolys#data, sccpop.sub, sort=FALSE)
plotvar <- sccdata$C0X001 / 1000 # one dot per 1,000 people
head(sccpolys#data)
head(sccpop.sub)
# Generate random dots in polygons
sccdots.rand <- dotsInPolys(sccpolys, as.integer(plotvar), f="random")
# County boundaries
baycounties.shp <- readShapePoly("ca-counties-1970.shp")
baycounties <- SpatialPolygonsDataFrame(baycounties.shp, data=as(baycounties.shp, "data.frame"))
par(mar=c(0,0,0,0))
plot(baycounties, lwd=0.1)
# Add dots
plot(sccdots.rand, add=TRUE, pch=19, cex=0.1, col="#00880030")

#LincolnMullen is right. After your merge you have:
> length(sccpolys)
[1] 787
and
> length(plotvar)
[1] 210
To account for this you could replace
sccdots.rand <- dotsInPolys(sccpolys, as.integer(plotvar), f="random")
with
sccdots.rand <- dotsInPolys(sccpolys[sccpolys$GISJOIN %in% sccdata$GISJOIN,], as.integer(plotvar), f="random")

The problem is that you have more tracts (i.e., polygons in your shapefile) than you wish to plot. There are 787 tracts and only 210 tracts in Santa Clara. In addition, there is some manipulation of the #data slot in the SpatialPolygonsDataFrame that is unnecessary. Here is a solution that cleans up the merge code.
library(maptools)
shp <- readShapePoly("1970-ca-tracts.shp")
sccpop <- read.csv("nhgis0010_ds98_1970_tract.csv", stringsAsFactors = FALSE)
sccpop.sub <- sccpop[sccpop$COUNTY=="Santa Clara",c(1,3,21,22,23)]
shp <- merge(shp, sccpop.sub)
Now we have a SpatialPolygonsDataFrame with the data, but there are missing values for all non Santa Clara counties. And we want to transform the population as you did above. The first line below does the transformation, adding a column to the data frame. It's easiest just to keep that inside the data frame instead of as an external variable. The second line filters out all the polygons that don't have population associated with them, i.e., the non-Santa Clara counties.
shp#data$plotvar <- as.integer(shp#data$C0X001 / 1000)
shp <- shp[!is.na(shp#data$plotvar), ]
Now we can proceed as you did before.
sccdots.rand <- dotsInPolys(shp, shp#data$plotvar, f="random")
baycounties.shp <- readShapePoly("ca-counties-1970.shp")
par(mar=c(0,0,0,0))
plot(baycounties.shp, lwd=0.1)
plot(sccdots.rand, add=TRUE, pch=19, cex=0.1, col="#00880030")
FWIW, I have had better results using rgdal::readOGR() for loading shapefiles, but maptools::readShapePoly() works fine here.

Related

R cran: sf Sew two MULTILINESTRING/LINESTRING

I try to sew/merge/bind two LINESTRINGs together (spanish coast + french coast) to have the full map of the whole coast. I found all the shpaefiles here:
https://www.marineregions.org/gazetteer.php?p=details&id=3417
https://www.marineregions.org/gazetteer.php?p=details&id=19888
Import and plot the data
frenchCoast_CoteBanyuls <- st_read("coasts_subnational/coasts_subnational.shp") %>%
st_geometry() #
plot(frenchCoast_CoteBanyuls)
spainCoast_CoteBanyuls <- st_read("coasts_subnational SPAIN/coasts_subnational.shp")%>%
st_geometry() #
spainCoast_CoteBanyuls <- st_cast(x = spainCoast_CoteBanyuls, to = "LINESTRING")
plot(spainCoast_CoteBanyuls, add = T)
This map and features seem ok.
According to all the posts I found, I tried to merge the two shapefiles together:
CoteBanyuls_c <- c(frenchCoast_CoteBanyuls, spainCoast_CoteBanyuls)
# CoteBanyuls_rbind <- rbind(frenchCoast_CoteBanyuls, spainCoast_CoteBanyuls)
# CoteBanyuls <- st_union(CoteBanyuls)
# CoteBanyuls <- union(CoteBanyuls)
# CoteBanyuls <- bind(CoteBanyuls)
plot(CoteBanyuls)
the c() function gives a shapefile that does not have the good dimensions (see below) and none of these solutions does plot the good shape of the two coast merged (seems to plot only the spanish coast).
What did I do wrong ? I do not understand why these solutions are not working...
Do you have some ideas ?
Thanks in advance !
Charlotte
I think the issue comes from extracting only the geometry attributes before you combine them. Try this:
frenchCoast_CoteBanyuls <- st_read("coasts_subnational/coasts_subnational.shp")
spainCoast_CoteBanyuls <- st_read("coasts_subnational SPAIN/coasts_subnational.shp")
combined_coast <- rbind(spainCoast_CoteBanyuls, frenchCoast_CoteBanyuls)
mapview::mapview(combined_coast)

R (Geosphere Library) - "Error in if (antipodal(p1, p2)) { : missing value where TRUE/FALSE needed"

I have an issue that I have tried for seven hours to fix without any success. Basically, I am trying to visualize the airport and flight data from openflights.org. This was supposed to be a simple, straightforward visualization, but it has turned in to a real hair puller.
Everything works up until the for loop. When I try and run the for loop in order to depict the flight paths on my map, it runs for a little and some lines appear on the map, but then it quits with the error:
Error in if (antipodal(p1, p2)) { : missing value where TRUE/FALSE needed
What I tried to do to fix it: As you can see, I have gone through the data set and removed any bad entries. For example, there were some IDs that were "\\N" and therefore I removed those entries entirely. Then I tried to change the IDs to be numbers rather than strings, just to see what would happen.
It always errors out around the same time after I run the for loop, is there a way I can view the line it got to when it returned the error? I am new too R.
I know a similar question has been asked before but none of the solutions they had there worked for me. Thank you for any help you can provide.
Code:
library('geosphere')
library('maps')
# Reading in the files from openflights.org
airports <- read.csv("airports.dat.txt", header=FALSE, col.names=c("Airport ID","Name","City","Country","IATA","ICAO","Latitude","Longitude",
"Altitude","Timezone","DST", "TZ Database","Type","Source"), as.is=TRUE)
flights <- read.csv("routes.dat.txt", header=FALSE, col.names=c("Airline","Airline ID","Source Airport","Source Airport ID","Destination Airport",
"Destination Airport ID","Codeshare","Stops","Equipment"), as.is=TRUE)
# Cleaning the data set, there are some instances of the value "\\N" in the flights data set.
flights <- flights[!grepl("\\N", flights$Source.Airport.ID),]
flights <- flights[!grepl("\\N", flights$Destination.Airport.ID),]
# Converting all of the IDs to numbers (I thought this might work but it did not)
flights$Source.Airport.ID <- as.numeric(flights$Source.Airport.ID)
flights$Destination.Airport.ID <- as.numeric(flights$Destination.Airport.ID)
airports$Airport.ID <- as.numeric(airports$Airport.ID)
# Creating a world background
map("world", col="white", border="gray10", fill=TRUE, bg="gray30")
# Adding all of the airports as points
points(x=airports$Longitude, y=airports$Latitude, pch=19,
cex=0.05, col="blue")
# Generating a color set to be used for mapping the flight paths
col.1 <- adjustcolor("limegreen", alpha=0.05)
col.2 <- adjustcolor("darkgreen", alpha=0.05)
edge.pal <- colorRampPalette(c(col.1, col.2), alpha = TRUE)
edge.col <- edge.pal(100)
# Now, generating the visualization of the flight paths.
# Here is where the error occurs, when I run this.
# It gets through some of the data but then errors out.
for(i in 1:nrow(flights)) {
node1 <- airports[airports$Airport.ID == flights[i,]$Source.Airport.ID,]
node2 <- airports[airports$Airport.ID == flights[i,]$Destination.Airport.ID,]
arc <- gcIntermediate( c(as.numeric(node1[1,]$Longitude), as.numeric(node1[1,]$Latitude)),
c(as.numeric(node2[1,]$Longitude), as.numeric(node2[1,]$Latitude)),
n=1000, addStartEnd=TRUE)
#edge.ind <- round(100*table(flights[i,]$Source.Airport.ID) / table(max(airports$Airport.ID)))
#lines(arc, col=edge.col[edge.ind], lwd=edge.ind/30)
lines(arc, col = "limegreen", lwd = 0.02)
}

Plot connecting lines on a projected map (mapproj, gcIntermediate)

I am unsuccessfully trying to plot lines on a world map with Mollweide projection. I also plotted points on that same map, and it worked out fine. For the lines, I tried to adapt this example to my needs: http://flowingdata.com/2011/05/11/how-to-map-connections-with-great-circles/.
I failed with the pre-test (Step 4 in the ex.) already. In the following code, the line is supposed to connect Kenya and Australia. It runs without errors, but there's no line in the output. (I also tested the example without mapproj and the line is there.)
library("maps")
library("mapproj")
library("geosphere")
map("world",proj="mollweide", orientation= c(90,0,0), fill=TRUE, col="white", bg="lightblue")
lon_ke <- 38
lat_ke <- 1
lon_aus <- 133
lat_aus <- -27
inter <- gcIntermediate(c(mapproject(lon_ke,lat_ke), proj="mollweide", orientation= c(90,0,0)),
c(mapproject(lon_aus,lat_aus), proj="mollweide", orientation= c(90,0,0)),
n=50, addStartEnd=TRUE)
lines(inter)
I found a solution to my problem, based on Thomas Rahlf's book (see comment). Here's my script (it helps visualizing where authors publish articles).
library(maps)
library(geosphere)
library(mapproj)
#load data
locations <- read.csv("articles-authors-locations.csv", header=TRUE, check.names = FALSE)
#plot map with Mollweide projection
myProj.type<-"mollweide"
myProj.orient<-c(90,0,0)
x<-map(proj=myProj.type,orient=myProj.orient,wrap=T,fill=TRUE, col="white", bg="lightblue",xlim=range(locations$ArticleLong),ylim=range(locations$ArticleLat)
)
#plot jittered points for authors' locations
myStartP<-mapproject(jitter(locations$AuthorLong,amount=3),jitter(locations$AuthorLat, amount=1),proj=myProj.type,orient=myProj.orient)
points(myStartP,col="darkblue",pch=20,cex=1)
#set transparent colors
myTColour<-rgb(0,0,0,50,maxColorValue=255)
red_transp <- adjustcolor("red", alpha.f = 0.4)
#plot lines and jittered points, connecting authors' and articles locations
for (i in 1:nrow(locations))
{
myGC1<-gcIntermediate(c(locations$AuthorLong[i],locations$AuthorLat[i]),c(locations$ArticleLong[i],locations$ArticleLat[i]),addStartEnd=T, n=50)
moll<-mapproject(myGC1[,1],myGC1[,2],projection=myProj.type,orientation=myProj.orient)
lines(moll$x,moll$y,lwd=2.5,col=myTColour)
myDestP<-mapproject(
jitter(locations$ArticleLong[i], amount=3),
jitter(locations$ArticleLat[i], amount=1),
proj=myProj.type,orient=myProj.orient)
points(myDestP,col=red_transp,pch=20,cex=1)
}

How can I add directional arrows to lines drawn on a map in R?

I've got a map that I've built using the maps and geosphere packages that looks like an airline map. However, I'd like to add arrows to the lines to show the directions of the "routes" in my map. You can see my current working code below (based off of the fabulous tutorial from FlowingData). I've tried before to use the arrows function in lieu of the lines function, yet I'm not sure how to make the arrows go with the geosphere curve, or ensure that the arrows are spaced along the line so that they look like this:
-->-->-->
I'm incredibly new to R, so any and all assistance would be greatly appreciated. Thanks in advance.
library(maps)
library(geosphere)
read.csv("http://marsiccr.github.io/Data/airports.csv", header=TRUE, as.is=TRUE) -> airports
read.csv("http://marsiccr.github.io/Data/leaders.csv", header=TRUE, as.is=TRUE) -> flights
pal <- colorRampPalette(c("#f2f2f2", "blue"))
colors <- pal(100)
colleges<-NULL
colleges$name <- airports$insname
colleges$long <- airports$long
colleges$lat <- airports$lat
colleges
map("state")
map("state", col="#f2f2f2", fill=TRUE, bg="white", lwd=0.25)
fsub <- flights[flights$type == "aau",]
fsub <- fsub[order(fsub$cnt),]
maxcnt <- max(fsub$cnt)
for (j in 1:length(fsub$type)) {
air1 <- airports[airports$unitid == fsub[j,]$school1,]
air2 <- airports[airports$unitid == fsub[j,]$school2,]
inter <- gcIntermediate(c(air1[1,]$long, air1[1,]$lat), c(air2[1,]$long, air2[1,]$lat), n=100, addStartEnd=TRUE)
colindex <- round( (fsub[j,]$cnt / maxcnt) * length(colors) )
lines(inter, col=colors[colindex], lwd=0.8)
}
Slipping this code into the for-loop just after inter<- got me arrowheads (and a few warnings)
tinter <- tail(inter,2)
arrows(tinter[1,1], tinter[1,2], tinter[2,1], tinter[2,2])
Obviously there's some tweaking to be done. See ?arrowsfor the full range of options. You could also use the second to last (or the fifth to last?) points in the inter matrix. You might also want to onlyy put in arrowheads for selected routes.

Intersect the contour and polygon in R

I have been trying for a few days to create the contour and then plot the shapefile and contour on the same file. Now, that I am able to create the contour and shapefile on the same plot. I want to clip the contour with the shapefile an only show the shapefile.
The data temp.csv can be found on this link https://www.dropbox.com/s/mg2bo4rcr6n3dks/temp.csv
Shapefile can be found on the following location: https://www.dropbox.com/sh/ztvmibsslr9ocmc/YOtiwB8p9p
The script file image.scale.R can be found on the following location "https://www.dropbox.com/s/2f5s7cc02fpozk7/image.scale.R "
The code that I have used so far is as follows:
## Required packages
library(maptools)
library(rgdal)
library(sp)
library(maptools)
library(sm)
require(akima)
require(spplot)
library(raster)
library(rgeos)
## Set Working Directory
setwd("C:\\Users\\jdbaba\\Documents\\R working folder\\shape")
## Read Data from a file
age2100 <- read.table("temp.csv",header=TRUE,sep=",")
x <- age2100$x
y <- age2100$y
z <- age2100$z
####################################
##Load the shape file
#####################################
shapefile <- readShapePoly("Export_Output_4.shp")
fld <- interp(x,y,z)
par(mar=c(5,5,1,1)) filled.contour(fld)
###Import the image.scale
source source("image.scale.R")
# http://menugget.blogspot.de/2011/08/adding-scale-to-image-plot.html
x11(width=8, height=7)
layout(matrix(c(1,2), nrow=1, ncol=2), widths=c(6,1), height=6, respect=TRUE)
layout.show(2)
par(mar=c(4,4,1,2))
image(fld,axes=T)
contour(fld, add=TRUE)
#points(age2100$x,age2100$y, pch=".", cex=2,legend=F)
plot(shapefile,add=T,lwd=2)
box()
par(mar=c(4,0,1,4))
image.scale(fld, xlab="Eastings", ylab="Northings", xaxt="n", yaxt="n", horiz=FALSE)
axis(4)
mtext("Salinity", side=4, line=2.5)
The output of the above code is as follows:
Now, I want to get rid of the colored gradients and the contours from the polygon shapefile and only leave the intersection part.
Any help is highly appreciated.
Research: I found this link https://gis.stackexchange.com/questions/25112/clip-depth-contour-with-spatial-polygon on Stack exchange Gis and I tried to follow this method I always get error while creating the contour.
I found another similar thread on https://stat.ethz.ch/pipermail/r-sig-geo/2009-May/005793.html . But I couldn't make it work on my dataset.
I would like to acknowledge Marc in the box for helping me in getting to this point.
Thanks.
Indeed, #baptiste gave you a strong hint for the solution, the recent paper by Paul Murrell. Paul was generous to provide us with the code for his entire paper manuscript, which you can get from his personal website. On the side topic, Paul shows beautiful example of reproducible research with this paper. Generally, I took the following approach:
extract latitude and longitude coordinates from the shapefile (a function to do this is here, by Paul Hiemstra),
plot everything with your code,
and use polypath to remove everything outside the boundaries defined by shapefile, using extracted coordinates as a baseline.
#function to extract coordinates from shapefile (by Paul Hiemstra)
allcoordinates_lapply = function(x) {
polys = x#polygons
return(do.call("rbind", lapply(polys, function(pp) {
do.call("rbind", lapply(pp#Polygons, coordinates))
})))
}
q = allcoordinates_lapply(shapefile)
#extract subset of coordinates, otherwise strange line connections occur...
lat = q[110:600,1]
long = q[110:600,2]
#define ranges for polypath
xrange <- range(lat, na.rm=TRUE)
yrange <- range(long, na.rm=TRUE)
xbox <- xrange + c(-20000, 20000)
ybox <- yrange + c(-20000, 20000)
#plot your stuff
plot(shapefile, lwd=2)
image(fld, axes=F, add=T)
contour(fld, add=T)
#and here is the magic
polypath(c(lat, NA, c(xbox, rev(xbox))),
c(long, NA, rep(ybox, each=2)),
col="white", rule="evenodd")

Resources