Convert Begin and End Coordinates into Spatial Lines in R
Here's a way:
## raw list to store Lines objects
l <- vector("list", nrow(begin.coord))
library(sp)
for (i in seq_along(l)) {
l[[i]] <- Lines(list(Line(rbind(as.matrix(begin.coord[i, ], end.coord[i,])))), as.character(i))
}
SpatialLines(l)
This makes a separate Lines object (each with a unique ID) for each pair, you otherwise might want a single object?
And just for fun, build as a spatstat psp object first and then coerce with methods in maptools:
library(spatstat)
p <- psp(begin.coord[,1], begin.coord[,2], end.coord[,1], end.coord[,2], owin(range(c(begin.coord[,1], end.coord[,1])), range(c(begin.coord[,2], end.coord[,2]))))
library(maptools)
as(p, "SpatialLines")
Retain start and end IDs when creating spatial lines from X Y points
In short:
newds2 <- SpatialLinesDataFrame(l.spatial, newds1, match.ID = FALSE)
## or you can use the rownames of newds1 in the lines loop)
There are 42 distinct lines, made by matching every coordinate to each other coordinate once.
FWIW, you don't need to convert from factor for numeric:
x <- c(2,4,6,3,7,9,1)
y <- c(6,4,8,2,9,6,1)
id <- c("a","b","c","d","e","f","g")
## don't coerce to character in the
##first place cbind(x, y, id) *must* be
## character and then data.frame
## converts characters to factors
dataset <- data.frame(x = x, y = y, id = id)
There are other ways to simplify your task, but here's a reasonably straightforward way (I think this is what you are after):
x <- c(2,4,6,3,7,9,1)
y <- c(6,4,8,2,9,6,1)
id<-c("a","b","c","d","e","f","g")
## don't coerce to character in the first place cbind(x, y, id) must be character
## and then data.frame converts characters to factors by default
dataset<-data.frame(x = x, y = y, id = id)
l <- vector("list", nrow(dataset) * (nrow(dataset) - 1))
origID <- destID <- character(length(l))
##xy <- as.matrix(dataset[, c("x", "y")])
cnt <- 0
for (i in seq(nrow(dataset))) {
pt0 <- as.matrix(dataset[i, c("x", "y") ])
pts <- dataset[-i, ]
for (j in seq(nrow(pts))) {
cnt <- cnt + 1
l[[cnt]] <- Lines(list(Line(rbind(pt0, as.matrix(pts[j, c("x", "y")])))), as.character(cnt))
destID[cnt] <- pts$id[j]
origID[cnt] <- dataset$id[i]
}
}
x <- SpatialLinesDataFrame(SpatialLines(l), data.frame(dest = destID, orig = origID, row.names = as.character(1:cnt)))
Pick out one line and investigate:
itest <- 10
## so for example
as.data.frame(x[itest, ])
index <- c(x$orig[itest], x$dest[itest])
plot(x)
plot(x[itest, ], lwd = 4, add = TRUE)
lines(dataset[index, c("x", "y")], col = "firebrick", lwd = 2)
text(dataset[index, c("x", "y")], label = dataset$id[index], col = "dodgerblue", cex = 4)
Spatial line start and end point in R
Since you tagged question with sf as well, I'll provide a solution in sf. Note you can transform your sp object to sf using
library(sf)
st_as_sf(sp_obj)
Create linestring
line <- st_as_sfc(c("LINESTRING(0 0 , 0.5 1 , 1 1 , 1 0.3)")) %>%
st_sf(ID = "poly1")
Convert each vertex to point
pt <- st_cast(line, "POINT")
Start and end are simply the first and last row of the data.frame
start <- pt[1,]
end <- pt[nrow(pt),]
plot - green is start point, red is end point
library(ggplot2)
ggplot() +
geom_sf(data = line) +
geom_sf(data = start, color = 'green') +
geom_sf(data = end, color = 'red') +
coord_sf(datum = NULL)
Connecting two sets of coordinates to create lines using sf/mapview
The tricky thing is to create a valid LINESTRING
object from the coordinate pairs in wide format. sf
expects linestring coordinates in rows of a matrix. Here's a way that works. The sfc
column of a sf
object is a list so here we use lapply
to loop over the rows of the data you provided.
library(sf)
library(mapview)
b = dat[, c("Blong", "Blat")]
names(b) = c("long", "lat")
e = dat[, c("Elong", "Elat")]
names(e) = c("long", "lat")
dat$geometry = do.call(
"c",
lapply(seq(nrow(b)), function(i) {
st_sfc(
st_linestring(
as.matrix(
rbind(b[i, ], e[i, ])
)
),
crs = 4326
)
}))
dat_sf = st_as_sf(dat)
mapview(dat_sf, zcol = "Flyway")
Connect xy points with spatial lines
I'm speculating a bit here as to what exactly you wanted, but I think you want to visualize the connections from any point to the others. If that's the case, then this might work.
But first, some assumptions:
- Your
x
andy
coordinates are starting points. Consequently,id
are thusid.origin
- All other points will need to become "destinations", and then their own coordinates will become
x_destination
and so on.
< disclaimer> There should be a better, more elegant way to do this. I'd appreciate if someone more experienced can jump in and show me any of the *ply
ways to do it. < /disclaimer>
Replicate the dataframe to cover for all possible combinations
dataset<-do.call(rbind, replicate(7, dataset, simplify=FALSE))
Now, create a matrix with all the same destination points, mixed:
nm=matrix(ncol=3)
for (i in 1:7){
nm<-rbind(nm,do.call(rbind,replicate(7,as.matrix(dataset[i,]),simplify=FALSE)))
}
nm<-nm[-1,]
Rename the columns of matrix, so they make sense, and bind the existing data frame with the new matrix
colnames(nm)<-c("x2","y2","id.dest")
newds<-cbind(dataset,as.data.frame(nm))
Remove duplicated trajectories:
newds<-newds[-which(newds$id.origin==newds$id.dest),]
and plot the result using geom_segment
:
p<-ggplot(newds,aes(x=x,y=y))+geom_segment(aes(xend=x2,yend=y2))
There is a way to name the segments, but from observing the plot I would't suggest doing it. Instead you might consider naming the points using geom_text
(other options are available, see ?annotate
for one).
p<-p + geom_text(aes(x=1.8,y=6.1,label="a"))
That will produce a plot like the one here:
How to Convert data frame to spatial coordinates
First, you take the columns of lon
and lat
and create an object for coord
. Then, you subtract them from the original data frame and create a new object. You finally use SpatialPointsDataFrame()
to create a SpatialPointsDataFrame
. When you create a SpatialPointsDataFrame
, you need to assign proj4string
. Choose an appropriate one for you.
In your case, you do not have any other columns but lon
and lat
, the method won't work. I purposely left lon
and lat
@data.
DATA
mydf <- structure(list(longitude = c(128.6979, 153.0046, 104.3261, 124.9019,
126.7328, 153.2439, 142.8673, 152.689), latitude = c(-7.4197,
-4.7089, -6.7541, 4.7817, 2.1643, -5.65, 23.3882, -5.571)), .Names = c("longitude",
"latitude"), class = "data.frame", row.names = c(NA, -8L))
### Get long and lat from your data.frame. Make sure that the order is in lon/lat.
xy <- mydf[,c(1,2)]
spdf <- SpatialPointsDataFrame(coords = xy, data = mydf,
proj4string = CRS("+proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0"))
#> str(spdf)
#Formal class 'SpatialPointsDataFrame' [package "sp"] with 5 slots
#..@ data :'data.frame': 8 obs. of 2 variables:
#.. ..$ longitude: num [1:8] 129 153 104 125 127 ...
#.. ..$ latitude : num [1:8] -7.42 -4.71 -6.75 4.78 2.16 ...
#..@ coords.nrs : num(0)
#..@ coords : num [1:8, 1:2] 129 153 104 125 127 ...
#.. ..- attr(*, "dimnames")=List of 2
#.. .. ..$ : NULL
#.. .. ..$ : chr [1:2] "longitude" "latitude"
#..@ bbox : num [1:2, 1:2] 104.33 -7.42 153.24 23.39
#.. ..- attr(*, "dimnames")=List of 2
#.. .. ..$ : chr [1:2] "longitude" "latitude"
#.. .. ..$ : chr [1:2] "min" "max"
#..@ proj4string:Formal class 'CRS' [package "sp"] with 1 slot
#.. .. ..@ projargs: chr "+proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0"
R from SpatialPointsDataFrame to SpatialLines
I have looked at the shapefile. There is an id
column, but if you plot the data, it seems that the id is not ordered north-south or something. The extra lines are created because the point order is not perfect, connecting points that are next to each other in the table, but far from each other in terms of space. You could try to figure out the correct ordering of the data by calculating distances between points and then ordering on distance.
A workaround is to remove those lines that are longer than a certain distance, e.g. 500 m.. First, find out where distance between consecutive coordinates is larger than this distance: the breaks
. Then take a subset of coordinates between two breaks
and lastly create Lines for that subset. You end up with a coastline consisting of several (breaks-1
) segments and without the erroneous ones.
# read data
library(rgdal)
pst<-readOGR("/data_spatial/coast/","points_coast")
coord<-as.data.frame(coordinates(pst))
colnames(coord) <- c('X','Y')
# determine distance between consective coordinates
linelength = LineLength(as.matrix(coord),sum=F)
# 'id' of long lines, plus first and last item of dataset
breaks = c(1,which(linelength>500),nrow(coord))
# check position of breaks
breaks = c(1,which(linelength>500),nrow(coord))
# plot extent of coords and check breaks
plot(coord,type='n')
points(coord[breaks,], pch=16,cex=1)
# create vector to be filled with lines of each subset
ll <- vector("list", length(breaks)-1)
for (i in 1: (length(breaks)-1)){
subcoord = coord[(breaks[i]+1):(breaks[i+1]),]
# check if subset contains more than 2 coordinates
if (nrow(subcoord) >= 2){
Slo1<-Line(subcoord)
Sli1<-Lines(list(Slo1),ID=paste0('section',i))
ll[[i]] = Sli1
}
}
# remove any invalid lines
nulls = which(unlist(lapply(ll,is.null)))
ll = ll[-nulls]
lin = SpatialLines(ll)
# add result to plot
lines(lin,col=2)
# write shapefile
df = data.frame(row.names=names(lin),id=1:length(names(lin)))
lin2 = SpatialLinesDataFrame(sl=lin, data=df)
proj4string(lin2) <- proj4string(pst)
writeOGR(obj=lin2, layer='coastline', dsn='/data_spatial/coast', driver='ESRI Shapefile')
Convert data frame to spatial lines data frame in R with x,y x,y coordintates
I believe what you want to end up with is a column in your data frame that for each row is a list (or data frame) with x.coord
and y.coord
columns. To achieve that, we can use unnest
and nest
from tidyr
with dplyr
:
library(dplyr)
library(tidyr)
result <- finalsub %>% mutate(coordinates = strsplit(coordinates,split=" ",fixed=TRUE)) %>%
unnest(coordinates) %>%
mutate(coordinates = strsplit(coordinates,split=",",fixed=TRUE),
x.coord = as.numeric(unlist(coordinates)[c(TRUE,FALSE)]),
y.coord = as.numeric(unlist(coordinates)[c(FALSE,TRUE)])) %>%
select(-coordinates) %>%
nest(x.coord,y.coord,.key=coordinates)
Notes:
- The first
mutate
splits the character vector in yourcoordinates
column by" "
to separate each coordinatex,y
resulting in alist
of these. unnest
separates this list into rows.- In the second
mutate
, we first split each coordinatex,y
, this time by","
to separate each coordinate intox
andy
. Then we create separatex.coord
andy.coord
columns to hold these. Note the conversion to numeric here. - Finally, we use
nest
to collect thex.coord
andy.coord
columns as a list under the column namedcoordinates
. Note that we first have to remove the originalcoordinates
column.
The result using your dput
data, printing only the coordinates
column:
print(result$coordinates)
##[[1]]
### A tibble: 284 x 2
## x.coord y.coord
## <dbl> <dbl>
##1 -1.294832 54.61024
##2 -1.294883 54.61008
##3 -1.294262 54.61002
##4 -1.294141 54.61001
##5 -1.293710 54.61004
##6 -1.293726 54.61014
##7 -1.293742 54.61025
##8 -1.293510 54.61026
##9 -1.293368 54.61026
##10 -1.292816 54.61019
### ... with 274 more rows
##
##[[2]]
### A tibble: 322 x 2
## x.coord y.coord
## <dbl> <dbl>
##1 -1.294832 54.61024
##2 -1.294883 54.61008
##3 -1.294262 54.61002
##4 -1.294141 54.61001
##5 -1.293710 54.61004
##6 -1.293726 54.61014
##7 -1.293742 54.61025
##8 -1.293510 54.61026
##9 -1.293368 54.61026
##10 -1.292816 54.61019
### ... with 312 more rows
Related Topics
Align Edges of Ggplot Choropleth (Legend Title Varies)
Setting Hex Bins in Ggplot2 to Same Size
Subset Observations That Differ by at Least 30 Minutes Time
Set Environment Variables for System() in R
Multiply Columns in a Data Frame by a Vector
Sine Curve Fit Using Lm and Nls in R
How to Use Custom Functions in Mutate (Dplyr)
Extracting Coefficients and Their Standard Error for Each Unit in an Lme Model Fit
Porting Set Operations from R's Data Frames to Data Tables: How to Identify Duplicated Rows
Rotate Labels in a Chorddiagram (R Circlize)
Simple Lookup to Insert Values in an R Data Frame
Add Missing Value in Column with Value from Row Above
Ggplot2: How to Adjust Fill Colour in a Boxplot (And Change Legend Text)
Creating a Monthly/Yearly Calendar Image with Ggplot2
Control Transparency of Smoother and Confidence Interval
How to Increase the Resolution of My Plot in R
Can't Connect to Local MySQL Server Through Socket Error When Using Ssh Tunel