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!
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.
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.
That might be a bug, I'll take a look tomorrow
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
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.
I've created a new issue for this specific bug here - dcooley/sfheaders#89
the "factor" bug is now fixed in geometries. So closing this issue.