3

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
...     ...
Andrew Cheesman
  • 140
  • 1
  • 10
  • 1
    Are the line IDs assigned iteratively during data frame construction? As far as I know row.names are assigned during creation while the line IDs would refer back to the item within the line dataset. Is it possible to post a piece of this data or a link to where we can find similar data? I want to say `dput()` the data but I've never done it with spatial lines so I'm not sure how that will react. – Badger Oct 15 '15 at 14:51
  • No - the IDs that I'm trying to join on are a 7-digit key that uniquely identify segments. I'm assigning them explicitly as the `row.names` for the speed_object in its creation, and my alteration to Kyle's code above was intended to pull them in from the original dataset. Will include some data samples in an edit, right now. – Andrew Cheesman Oct 15 '15 at 14:55
  • Oh I see that as I re-read your question, sorry there. Any reason you are using `row.names` for the assignment? I feel like you could make the lines a `sldf` and then `match()` the id's assigning the speeds where the ids match. – Badger Oct 15 '15 at 14:58
  • OK, sure - np. I was focusing on `row.names` for the assignment to try to conform to the `SpatialLinesDataFrame()` requirements (or what I thought them to be!) but I'll give `match()` a shot. – Andrew Cheesman Oct 15 '15 at 15:03

3 Answers3

5

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.

Edzer Pebesma
  • 3,814
  • 16
  • 26
3

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!

Andrew Cheesman
  • 140
  • 1
  • 10
1

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.

Badger
  • 1,043
  • 10
  • 25
  • Hmm, no dice. `> class(sl_obj) [1] "SpatialLines" attr(,"package") [1] "sp"` The code you include throws this error: `Error in sl_obj$ID : no $ method for object without attributes` Also, I'm not using `readOGR` to create sl_obj - it's is created using `SpatialLines()` - see Kyle's process linked above. The relevant bit starts at `sp_lines <- SpatialLines...` – Andrew Cheesman Oct 15 '15 at 15:53
  • Yea I see that now (grabbed Kyles data), very puzzling. – Badger Oct 15 '15 at 16:38