SymbolixAU / mapdeck

R interface to Deck.gl and Mapbox

Home Page:https://symbolixau.github.io/mapdeck/articles/mapdeck.html

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Using data.table in add_path()

achateigner opened this issue · 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!

commented

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.

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.

commented

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

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

commented

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

commented

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

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
commented

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.

commented

I've created a new issue for this specific bug here - dcooley/sfheaders#89

commented

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