UrbanAnalyst / dodgr

Distances on Directed Graphs in R
https://urbananalyst.github.io/dodgr/
127 stars 16 forks source link

dplyr::mutate does not work with dodgr::graph #231

Closed chinhqho closed 2 months ago

chinhqho commented 2 months ago

@mpadge, I can't get my head around why dplyr::mutate() function does not work on an object of data.frame and dodgr_streetnet class. Below is a reproducible example.

packageVersion("dodgr") # ‘0.4.0.11’
packageVersion("dplyr") #‘1.0.7’
graph <- weight_streetnet (hampi)
n <- 20
set.seed (2L)
from <- sample (graph$from_id, size = n)
to <- sample (graph$to_id, size = n)
stopifnot (!to %in% from)
flows <- rep(1, n)

graph1 <- dodgr_flows_aggregate (graph, from = from, to = to, flows = flows, pairwise = TRUE)
graph1 %>%
    as.data.frame() %>% # works with as_tibble() 
    mutate(newvar = 1) # got error below

Error in vec_data(): ! x must be a vector, not a <data.frame/dodgr_streetnet> object. Backtrace:

  1. graph1 %>% as.data.frame() %>% mutate(newvar = 1)
  2. dplyr:::mutate.data.frame(., newvar = 1)
  3. dplyr:::dplyr_col_modify.data.frame(.data, cols)
  4. dplyr:::dplyr_vec_data(data)
  5. vctrs::vec_data(x)

Replacing the as.data.frame() with as_tibble() works. I don't want to convert the graph to tibble because I just need to aggregate the flows after parallel processing multiple sets of froms and tos on the same graph dataset - then use other dodgr functions such as merge_directed_graph to work with graph1.

mpadge commented 2 months ago

That's just because dplyr expects pure data.frame or directly derived objects, but dodgr produces its own special class of data.frame objects:

library (dodgr)
graph <- weight_streetnet (hampi)
class (graph)
#> [1] "data.frame"      "dodgr_streetnet"

class (as.data.frame (graph))
#> [1] "data.frame"      "dodgr_streetnet"

class (tibble::as_tibble (graph))
#> [1] "tbl_df"     "tbl"        "data.frame"

Created on 2024-06-06 with reprex v2.1.0

Converting to tibble removes the dodgr_streetnet class information, and that will then prevent dodgr functionality from working with the graph. This is perfectly standard S3 dispatch methodology, and just something you have to live with in R. It's up to users to strip the class information if they want to pass dodgr graphs through dplyr routines.