Raphus
Raphus

Reputation: 57

How to loop df subsetting and ggplot?

I would like to include sub-setting within a loop to produce multiple ggplots using R. I tried adapting the solutions that have been suggested in other posts but none worked.

name  char  stat  z
n1    c1    2.1   1
n1    c2    1.9   2
n1    c3    2.0   4
n1    c4    3.4   4
n2    c1    1.1   2
n2    c2    1.2   1
n2    c3    2.0   3
n2    c4    1.8   4
n3    c1    5.1   2
n3    c2    3.3   3
n3    c3    4.7   1
n3    c4    0.5   2

up to n12 (and potentially more).

Currently I manually subset the dataframe based on the name I need and produce its plot:

n1 <- df[df$name=="n1",]
p1 <- ggplot(n1, aes(x=char, y=stat)) +
  geom_col(fill = palette[n1$z])
p1

Is there a way to create a loop that automatically subset df into n1/n2/n3 and creates p1/p2/p3, so that then I can either export them individually or wrap them into a single image?

I tried:

for (i in df$name) {
  ggplot(df[df$name[i]], aes(x=char, y=stat))
}

but it returns

Error: Can't use NA as column index with `[` at positions 1, 2, 3, 4, 5, and 16 more.

Similarly, I tried creating a function so that I could use lapply to cycle it:

draft <- function(var) {
  ggplot(var, aes(x=char, y=stat))
}
draft(n1)

but it returns

Error in ggplot(var, aes(x = char, y = stat)) : 
  object 'n1' not found.

I tried adapting some other solutions but - still - it does not work. Do you have any suggestion?

Upvotes: 0

Views: 64

Answers (1)

abreums
abreums

Reputation: 196

I built a solution based on information from this blog: https://aosmith.rbind.io/2018/08/20/automating-exploratory-plots/

You can first make a function for which should be provided the sub-set. And use purrr::map function to iterate.

df <- tibble(name = c("n1", "n1","n1", "n1", "n2","n2","n2","n2","n3","n3","n3","n3"),
            char = c("c1", "c2", "c3", "c4","c1", "c2", "c3", "c4","c1", "c2", "c3", "c4"),
            stat = c(2.1, 1.9,2.0,3.4,1.1,1.2,2.0,1.8,5.1,3.3,4.7,0.5),
            z = c(1,2,4,4,2,1,3,4,2,3,1,2))


plot_function <- function(sub_set) {
  n <- df %>% filter(name %in% c(sub_set))
  p <- n %>% ggplot(aes(x=char, y=stat, fill = z)) +
    geom_col()
} 

uniq_names <- df %>% distinct(name)
all_groups <- uniq_names$name
all_groups = set_names(all_groups)

all_plots <- map(all_groups, ~plot_function(.x))

all_plots$n1
all_plots$n2
all_plots$n3

Extra bonus is the nice tip of naming the list so you can use them as references - all_plots$n2 - instead of all_plots[2].

Upvotes: 1

Related Questions