Andrew Cheesman
Andrew Cheesman

Reputation: 150

Creating SpatialLinesDataFrame from SpatialLines object and basic df

Using leaflet, I'm trying to plot some lines and set their color based on a 'speed' variable. My data start at an encoded polyline level (i.e. a series of lat/long points, encoded as an alphanumeric string) with a single speed value for each EPL.

I'm able to decode the polylines to get lat/long series of (thanks to Max, here) and I'm able to create segments from those series of points and format them as a SpatialLines object (thanks to Kyle Walker, here).

My problem: I can plot the lines properly using leaflet, but I can't join the SpatialLines object to the base data to create a SpatialLinesDataFrame, and so I can't code the line color based on the speed var. I suspect the issue is that the IDs I'm assigning SL segments aren't matching to those present in the base df.

The objects I've tried to join, with SpatialLinesDataFrame():

  1. "sl_object", a SpatialLines object with ~140 observations, one for each segment; I'm using Kyle's code, linked above, with one key change - instead of creating an arbitrary iterative ID value for each segment, I'm pulling the associated ID from my base data. (Or at least I'm trying to.) So, I've replaced:

    id <- paste0("line", as.character(p))

    with

    lguy <- data.frame(paths[[p]][1]) id <- unique(lguy[,1])

  2. "speed_object", a df with ~140 observations of a single speed var and row.names set to the same id var that I thought I created in the SL object above. (The number of observations will never exceed but may be smaller than the number of segments in the SL object.)

My joining code:

splndf <- SpatialLinesDataFrame(sl = sl_object, data = speed_object)

And the result:

row.names of data and Lines IDs do not match

Thanks, all. I'm posting this in part because I've seen some similar questions - including some referring specifically to changing the ID output of Kyle's great tool - and haven't been able to find a good answer.

EDIT: Including data samples.

From sl_obj, a single segment:

print(sl_obj)

Slot "ID":
[1] "4763655"

[[151]]
An object of class "Lines"
Slot "Lines":
[[1]]
An object of class "Line"
Slot "coords":
           lon      lat
1955 -74.05228 40.60397
1956 -74.05021 40.60465
1957 -74.04182 40.60737
1958 -74.03997 40.60795
1959 -74.03919 40.60821

And the corresponding record from speed_obj:

row.names speed
...     ...
4763657 44.74
4763655 34.8 # this one matches the ID above
4616250 57.79
...     ...

Upvotes: 3

Views: 6171

Answers (3)

Edzer Pebesma
Edzer Pebesma

Reputation: 4121

To get rid of this error message, either make the row.names of data and Lines IDs match by preparing sl_object and/or speed_object, or, in case you are certain that they should be matched in the order they appear, use

splndf <- SpatialLinesDataFrame(sl = sl_object, data = speed_object, match.ID = FALSE)

This is documented in ?SpatialLinesDataFrame.

Upvotes: 5

Andrew Cheesman
Andrew Cheesman

Reputation: 150

All right, I figured it out. The error wasn't liking the fact that my speed_obj wasn't the same length as my sl_obj, as mentioned here. ("data = object of class data.frame; the number of rows in data should equal the number of Lines elements in sl)

Resolution: used a quick loop to pull out all of the unique lines IDs, then performed a left join against that list of uniques to create an exhaustive speed_obj (with NAs, which seem to be OK).

ids <- data.frame()
for (i in (1:length(sl_obj))) {
id <- data.frame(sl_obj@lines[[i]]@ID)
ids <- rbind(ids, id)
}

colnames(ids)[1] <- "linkId"
speed_full <- join(ids, speed_obj)
speed_full_short <- data.frame(speed_obj[,c(-1)])
row.names(speed_full_short) <- speed_full$linkId

splndf <- SpatialLinesDataFrame(sl_obj, data = speed_full_short, match.ID = T)

Works fine now!

Upvotes: 3

Badger
Badger

Reputation: 1053

I may have deciphered the issue.

When I am pulling in my spatial lines data and I check the class it reads as "Spatial Lines Data Frame" even though I know it's a simple linear shapefile, I'm using readOGR to bring the data in and I believe this is where the conversion is occurring. With that in mind the speed assignment is relatively easy.

sl_object$speed <-  speed_object[ match( sl_object$ID , row.names( speed_object ) ) , "speed" ]

This should do the trick, as I'm willing to bet your class(sl_object) is "Spatial Lines Data Frame".

EDIT: I had received the same error as OP, driving me to check class()

I am under the impression that the error that was populated for you is because you were trying to coerce a data frame into a data frame and R wasn't a fan of that.

Upvotes: 1

Related Questions