mapdeck icon indicating copy to clipboard operation
mapdeck copied to clipboard

Using data.table in add_path()

Open achateigner opened this issue 5 years ago • 9 comments

Dear Dave, to follow the discussion on Twitter, an excellent addition would be to be able to use a data.table in add_path(). This idea is part of a larger one of not having to use the sf format at all, but also to be able to combine mapdeck and [.data.table. An example (data set taken from here) :

library(data.table)
library(mapdeck)

df <- data.frame(
    station = c("A", "B", "C", "D", "E", "F"),
    latitude = c(-1.63, -1.62, -1.62, -1.77, -1.85, -1.85),
    longitude = c(34.3, 34.4, 34.7, 34.3, 34.5, 34.7),
    big = c(0, 20, 60, 90, 50, 10),
    small = c(100, 80, 40, 10, 50, 90),
    colour = c("blue", "blue", "red", "red", "black", "black"),
    group = c("A", "A", "B", "B", "C", "C")
)
setDT(df)

ms = mapdeck_style("light")

# Option 1 - grouping in add_path, 'by' argument
myMap <- mapdeck(style = ms,
                 pitch = 10,
                 location = c(mean(df$longitude), mean(df$latitude))) %>%
    add_path(
        data = df,
        stroke_colour = "colour",
        layer_id = "path",
        by = "group"
    )

myMap

# Option 2 - grouping in the `[.data.table`
pathFun <- function(dt){
    add_path(
        data = dt,
        stroke_colour = "colour",
        layer_id = "path"
    )
}
myMap <- mapdeck(style = ms,
                 pitch = 10,
                 location = c(mean(df$longitude), mean(df$latitude))) %>%
    df[, pathFun(.SD), by = "group"]

I am not sure of my code, though…

Thanks!

achateigner avatar Nov 26 '20 10:11 achateigner

Thanks - I see what you're suggesting, but I don't think there's a way to do what you're asking without taking on a dependency to data.table, which I'm not keen on doing. The simplest way I would do this at the moment is to use sfheaders to convert your data.table into the expected sf object. Where sfheaders is a very light library and the conversion to an sf object is minimal (I designed it exactly for your use-case).

set_token( secret::get_secret("mapbox"))

sf <- sfheaders::sf_linestring(
  obj = df
  , x = "longitude"
  , y = "latitude"
  , linestring_id = "group"
  , keep = TRUE
)

mapdeck() %>%
  add_path(
    data = sf
  )

But, having said that, I am working on other ways to get R objects into mapdeck without using sf. All centered around my interleave package, as this puts the data in the format expected by the underlying Deck.gl GPU buffers. But this is still work-in-progress and not ready for use yet.

dcooley avatar Nov 27 '20 09:11 dcooley

Are you an angel? I tried to create my object with sf_linestring and it works smoothly. Just a question, is there a way to keep the columns I pass as linestring_id in the object? An other point is that maybe you could detail this possibility in the help page for add_path(), as it would have saved me several days of work… Thanks a lot for all and I can’t wait to see interleave.

achateigner avatar Nov 27 '20 10:11 achateigner

If you say keep = TRUE it should return all the colums of the input object, including the ID. Here's an example - https://github.com/dcooley/sfheaders#where-are-the-examples

dcooley avatar Nov 27 '20 10:11 dcooley

I just tried and it does, but it transforms factors as integers, which surprised me.

achateigner avatar Nov 27 '20 10:11 achateigner

That might be a bug, I'll take a look tomorrow

dcooley avatar Nov 27 '20 10:11 dcooley

I just tried and it does, but it transforms factors as integers, which surprised me.

@achateigner do you have an example of this? I just tried and I get a factor column returned

df <- data.frame(
  x = 1:5
  , y = 1:5
  , val = letters[1:5]
  , stringsAsFactors = TRUE
)


sf <- sfheaders::sf_point(
  obj = df
  , x = "x"
  , y = "y"
  , keep = TRUE
)

str( sf$val )
# Factor w/ 5 levels "a","b","c","d",..: 1 2 3 4 5

dcooley avatar Nov 29 '20 21:11 dcooley

Yes, the problem rises with sf_linestring :

sf <- sfheaders::sf_linestring(
    obj = df
    , x = "x"
    , y = "y"
    , linestring_id = "val"
    , keep = TRUE
)

str( sf$val )
# int [1:5] 1 2 3 4 5

achateigner avatar Dec 02 '20 09:12 achateigner

oh yeah - I see what's gonig on. When not using an id field the factors are retained

sf <- sfheaders::sf_linestring(
  obj = df
  , x = "x"
  , y = "y"
  # , linestring_id = "val"
  , keep = TRUE
)

str( sf$val )
# Factor w/ 5 levels "a","b","c","d",..: 1

I'll look into it.

dcooley avatar Dec 02 '20 21:12 dcooley

I've created a new issue for this specific bug here - https://github.com/dcooley/sfheaders/issues/89

dcooley avatar Dec 02 '20 22:12 dcooley

the "factor" bug is now fixed in geometries. So closing this issue.

dcooley avatar Jan 03 '24 01:01 dcooley