-1

I want to pull the name of a list element out as the text for a plot title within an lapply() or map() function.

The point is to self-identify a list elements name within the lapply or map call, rather then supply them as an additional argument. My real use case already has other arguments going into the function, and I am curious if there is a way around doing that because it would simplify things quite a bit.

Self Identify a list element within purrr::map or lapply Say I have a list

library(tidyverse)
my_list <- list(A = data.frame(level = factor(1:5),
                               value = rnorm(5)),
                B = data.frame(level = factor(1:5),
                               value = rnorm(5)))

And a simple function to plot it

test_fun <- function(named_list) {
  ggplot(named_list) +
    geom_col(aes(level, value)) +
    ggtitle(named_list)
}

And I want to do something like this:

purrr::map(my_list, test_fun) 

...But have them titled "A" & "B".

The goal is to identify the name of elements "A" or "B" within map/lapply That way I can pass that name as the plot title without supplying them as another function argument.

I've tried these within the function:

names(named_list)
# &
attr(named_list, "name")

But they each will pull the names within element A or B, which is not the desired behavior. I want to be up one level.

I know that I could pass the names as a separate object with map2

my_names <- names(my_list)
test_fun2 <- function(named_list, my_names) {
  ggplot(named_list) +
    geom_col(aes(level, value)) +
    ggtitle(my_names)
}

Then do this:

map2(my_list, my_names, test_fun2)

But is there a way to just insert the list element name instead of doing that? If there isn't that is fine, I am curious whether a way exists or if I'm stuck supplying the names.

EDIT: Looking for clarity on imap() answer:

I can get the imap() suggestions to work on my simple example but only with an anonymous function. If I could get some clarity on the below example I should be able to scale up to the more complicated use.

Why does this fail

test_fun_imap <- function(named_list) {
  ggplot(.x) +
    geom_col(aes(level, value)) +
    ggtitle(.y)
}

imap(my_list, test_fun_imap)

But this works

imap(my_list, ~{
  ggplot(.x) +
    geom_col(aes(level, value)) +
    ggtitle(.y)
}
)
Adam Kemberling
  • 301
  • 1
  • 11
  • 2
    See `purrr::imap` or `purrr::map2`. – joran May 14 '19 at 22:36
  • Could you provide an example of how imap would work in this instance? I know map2 can be used, but as mentioned in the question I'm curious if I can circumvent that option. – Adam Kemberling May 14 '19 at 22:45
  • 1
    @adamkemberling: see this https://stackoverflow.com/a/55114232/786542 – Tung May 14 '19 at 22:48
  • You shouldn't change your question to ask a new question in an "edit." If this answer raises a new question for you, you should start a new post. – MrFlick May 15 '19 at 01:33
  • @MrFlick I agree with your point, and won't do that in the future. In this case though its still an extension of the original question. I will do better though moving forward, thank you. – Adam Kemberling May 15 '19 at 13:11

1 Answers1

3

As mentioned by @joran you can use imap but for that you need to pass two arguments to the function for it to work

test_fun_imap <- function(x, y) {
   ggplot(x) +
    geom_col(aes(level, value)) +
    ggtitle(y)
}

and then you can call

purr::imap(my_list, test_fun_imap)

As far as knowing why it will not work with map or lapply, you can debug the function by adding browser() in the function

test_fun <- function(named_list) {
   browser()
  ggplot(named_list) +
    geom_col(aes(level, value)) +
    ggtitle(named_list)
}

Now, call it using map

purrr::map(my_list, test_fun)  

Check what is passed as parameter named_list

Called from: .f(.x[[i]], ...)
Browse[1]> named_list
#  level    value
#1     1 -1.20707
#2     2  0.27743
#3     3  1.08444
#4     4 -2.34570
#5     5  0.42912

You see that the dataframe is passed and there is no information of name of that list ("A") hence, it is not possible to use that as title of the plot. As you already know you can use map2 or mapply for that passing the name of the list separately.

Ronak Shah
  • 377,200
  • 20
  • 156
  • 213