Chain multiple tidyverse functions using map

Hi,

I was wondering if you can map/chain tidyverse functions together without explicitly needing to write them, but just change their input. Take this as an example:

myData = data.frame(x = 1:10, y = runif(10), z = LETTERS[1:10])
myData %>% mutate(A = 1) %>% mutate(B = 1) %>% mutate(C = 1)
    x         y z A B C
1   1 0.2343784 A 1 1 1
2   2 0.9754685 B 1 1 1
3   3 0.5395749 C 1 1 1
4   4 0.9732300 D 1 1 1
5   5 0.3909175 E 1 1 1
6   6 0.9226956 F 1 1 1
7   7 0.1892913 G 1 1 1
8   8 0.2193157 H 1 1 1
9   9 0.7612691 I 1 1 1
10 10 0.2245095 J 1 1 1

I know you can do this much easier all within the same mutate() but this is a dummy example where the function can be much more complex taking different data / inputs like for example different layers in a leaflet or ggplot.

I can implement this with the eval() function in R like this:

eval(parse(text = paste("myData", paste("%>% mutate(", c("A", "B", "C"), "= 1)", collapse = " "))))

... but this looks messy and is not great coding I think.

So I've beent trying to chain tidyverse functions together with map(), but I'm getting nowhere...

Am I trying to do something nonsensical?

Grtz,
PJ

1 Like

You can do specifically what you are after like this:

library(tidyverse)

myData = data.frame(x = 1:10, y = runif(10), z = LETTERS[1:10])

new_cols <- c("A", "B", "C") 
value_to_assign <- 1L

cols <- purrr::set_names(new_cols, new_cols) %>%
  purrr::map(~1L)

myData %>% mutate(!!!cols)
#>     x            y z A B C
#> 1   1 0.5787865331 A 1 1 1
#> 2   2 0.0467114132 B 1 1 1
#> 3   3 0.0353568699 C 1 1 1
#> 4   4 0.5724359839 D 1 1 1
#> 5   5 0.5490870494 E 1 1 1
#> 6   6 0.9562330989 F 1 1 1
#> 7   7 0.8984227306 G 1 1 1
#> 8   8 0.9230195784 H 1 1 1
#> 9   9 0.9601943099 I 1 1 1
#> 10 10 0.0000375309 J 1 1 1

Created on 2019-08-13 by the reprex package (v0.3.0)

However, I have a feeling that you've simplified your problem too much and this solution won't generalize to what you are actually doing. So maybe think of a more involved example that showcases your problem a bit more?

3 Likes

Hi,

@mishabalyasin : Thanks already for the great reply! I haven't figured out the full syntax yet, but it seems very clean and interesting.

I agree I should have come up with a more real world problem, so here it is:

library(dplyr)
library(leaflet)

m <- leaflet() %>% setView(lng = -71.0589, lat = 42.3601, zoom = 12)
m %>% addTiles() %>% 
  
  addCircles(-71.0589, 42.3601, 1000, color = "green", group = "group1") %>% 
  addCircles(-71.0200, 42.3601, 800, color = "purple", group = "group2") %>% 
  addCircles(-71.0869, 42.3206, 650, color = "blue", group = "group3") %>% 
  
  addLayersControl(
    overlayGroups = c("group1", "group2","group3"),
    options = layersControlOptions(collapsed = FALSE)
  )

You see how I need to repeat the addCircles several times (example only 3, but could be more, or based on dataset). I would love to be able to not have to write them out and just use a smart mapping function...

Again, I might be missing something, but I am confronted with things like this from time to time and just wonder how I could make it more efficient.

PJ

I think I have a suggestion -- although it may be a bit horrid, it seemed to have worked :slight_smile: - I took advantage of purrr::reduce()


library(tidyverse)
library(leaflet)
m0 <- leaflet() %>%
  setView(lng = -71.0589, lat = 42.3601, zoom = 12) %>% 
  addTiles()

df_circles <- tibble::tribble(
                    ~lng,    ~lat, ~radius,   ~color,   ~group,
                -71.0589, 42.3601,    1000,  "green", "group1",
                  -71.02, 42.3601,     800, "purple", "group2",
                -71.0869, 42.3206,     650,   "blue", "group3"
                )

list_circles <- split(df_circles, 1:nrow(df_circles))


add_circle0 <- function(map, list0){
  addCircles(map    = map, 
             lng    = list0$lng, 
             lat    = list0$lat, 
             radius = list0$radius,
             color  = list0$color,
             group  = list0$group)
}

m1 <- reduce(list_circles, add_circle0, .init = m0)

m1 %>%
  addLayersControl(
    overlayGroups = c("group1", "group2","group3"),
    options = layersControlOptions(collapsed = FALSE)
  )
2 Likes

Hi,

I think this looks very cool! It was more of a theoretical question anyway to see how to make code more flexible and avoid repetition and you did a great job!

PJ

This topic was automatically closed 21 days after the last reply. New replies are no longer allowed.