crazysantaclaus
crazysantaclaus

Reputation: 623

use a counter to access named list elements as ggtitle within mapply call

I'm generating and plotting multiple ggplots based on data from two lists, therefore I'm using mapply. One of the lists has named elements, which I would like to use as ggtitle. But it only takes the first element for all the plots

> names(sample_subset_list)
[1] "water after day 43 dna min reads per OTU 5"
[2] "biofilm after day 43 dna min reads per OTU 5"
[3] "water after day 43 cdna min reads per OTU 5"
[4] "biofilm after day 43 cdna min reads per OTU 5"
[5] "water after day 44 dna min reads per OTU 5"
[6] "biofilm after day 44 dna min reads per OTU 5"
[7] "water after day 44 cdna min reads per OTU 5"
[8] "biofilm after day 44 cdna min reads per OTU 5"

and this is the plotting function:

ordination_plots <- list()
counter <- 0
ordination_plots <- mapply(function(x,y,counter) {
                        counter <- counter + 1 
                        plot_ordination(x, y, type = "sample") + 
                            ggtitle(names(sample_subset_list)[counter]) +
}, x = sample_subset_list, y = ordination_nmds, counter = 0, SIMPLIFY = FALSE)

this will give me plots where the title is always the first element of

names(sample_subset_list).

The same happens calling ggtitle(names(sample_subset_list)[]) +

If I use counter <<- (suggested here: Using a counter inside an apply structured loop in R) or call ggtitle like

ggtitle(names(sample_subset_list)) +

or

ggtitle(names(sample_subset_list)[[]]) +

I get no title at all.

I started without a counter, which also gave me the same title for all plots. Could someone explain to me how I can iterate over the names of the list elements to use them for the ggplots?

Upvotes: 0

Views: 78

Answers (1)

hrbrmstr
hrbrmstr

Reputation: 78832

Let's reduce the complexity of the example:

counter <- 0

invisible(mapply(function(letter, counter) {

  counter <- counter + 1
  cat("Letter: ", letter, "; Counter: ", counter, "\n", sep="")

}, letters[1:10], counter))

NOTE: I only used invisible() to stop printing the result of mapply().

letters[1:10] is a 10-element vector of lower-case letter (built in data).

You define counter outside of mapply(). Unlike for or while, functions in mapply() do not — by default — create or modify variables in the parent scope (outside of mapply(), so the result is this:

Letter: a; Counter: 1
Letter: b; Counter: 1
Letter: c; Counter: 1
Letter: d; Counter: 1
Letter: e; Counter: 1
Letter: f; Counter: 1
Letter: g; Counter: 1
Letter: h; Counter: 1
Letter: i; Counter: 1
Letter: j; Counter: 1

It's fine to pass in a second parameter with info to the function argument of mapply() but if the intent is to have a side-effect of incrementing something outside the scope of the function in mapply() then you really shouldn't pass it to in as parameter and just modify it using the <<- operator, which — according to the help page:

"The operators <<- and ->> are normally only used in functions, and cause a search to be made through parent environments for an existing definition of the variable being assigned. If such a variable is found (and its binding is not locked) then its value is redefined, otherwise assignment takes place in the global environment."

So, we can just do this:

# TO MY FUTURE SELF AND TEAM MEMBERS
# `counter` is modified as a side-effect of operations in the `mapply()`
# that follows the object declaration
counter <- 0

invisible(mapply(function(letter) {

  counter <<- counter + 1
  cat("Letter: ", letter, "; Counter: ", counter, "\n", sep="")

}, letters[1:10]))

to get this:

Letter: a; Counter: 1
Letter: b; Counter: 2
Letter: c; Counter: 3
Letter: d; Counter: 4
Letter: e; Counter: 5
Letter: f; Counter: 6
Letter: g; Counter: 7
Letter: h; Counter: 8
Letter: i; Counter: 9
Letter: j; Counter: 10

The comment was not meant for snark. You are using a side-effect that may be non-obvious to your future self or folks you share the code with so noting it will help you re-figure out and them figure out what's happening.

Upvotes: 2

Related Questions