Home > Software design >  Adding lines using geom_segment on multiple plots with data from a list of DFs
Adding lines using geom_segment on multiple plots with data from a list of DFs

Time:05-20

I'm trying to add multiple lines to a saved ggplot object. The coordinates for the lines are stored on a list of dataframes, one data frame for each individual plot. I successfully have created multiple plots using lapply, however, the code fails when calling the geom_segment. Below example data and code.

library(ggplot2)
library(tidyverse)
data(iris)
#Dataframes
m.slen <- iris[,c(1,5)]
m.swid <- iris[,c(2,5)]
m.plen <- iris[,c(3,5)]
m.pwid <- iris[,c(4,5)]
#List of dataframes
m.list = list(m.slen = m.slen,
              m.swid = m.swid,
              m.plen = m.plen,
              m.pwid = m.pwid)
#Setting col names
m.list <- lapply(m.list, setNames, nm = c("data", "species"))
#Creating list of data frames with coordinates for geom_segment
meanV = lapply(m.list, function(x) mean(x$data, na.rm = TRUE))
coordy1 = lapply(m.list, function(x) x %>%
                     group_by(species) %>%
                     summarise(max = max(data, na.rm=TRUE)) %>%
                     pull(max)   2)
#Table with dynamic values
line.plot <- list()
for(i in 1:4) {
line.plot[[i]] <-
    tibble(x1 = meanV[[i]],
           x2 = meanV[[i]] 1,
           y1 = coordy1[[i]][1],
           y2 = coordy1[[i]][1])
               }
#Creating first set of plots, using first list of DFs
plots <- lapply(m.list,function(x)
    p <- ggplot(x, aes( x= data, fill = species))  
          geom_histogram(stat = "count")  
          ggtitle(names(m.list)))
print(plots)

#Adding segments using second list of DFs
final_plots <- lapply(plots,function(x)
     plots    geom_segment(data = line.plot,
                       aes(x = x1, y = y1, xend = x2, yend = y2)))

Everything works until the last step, I get the following error

Error in fortify(): ! data must be a data frame, or other object coercible by fortify(), not a list

Any input or advice is welcome. Thanks

CodePudding user response:

The issue is that line.plot is a list. To achieve your desired result you could use purrr::map2 to loop over both your list of plots and the list of dataframes for the segments:

Note: I also added inherit.aes = FALSE to geom_segment because otherwise you will get an error, too.

final_plots <- purrr::map2(plots, line.plot, function(x, y) {
  x   geom_segment(
    data = y,
    aes(x = x1, y = y1, xend = x2, yend = y2), inherit.aes = FALSE
  )
})

final_plots[[1]]

enter image description here

EDIT Using base R you could achieve the same result with mapply:

final_plots <- mapply(function(x, y) {
  x   geom_segment(
    data = y,
    aes(x = x1, y = y1, xend = x2, yend = y2), inherit.aes = FALSE
  )
}, x = plots, y = line.plot, SIMPLIFY = FALSE)

or thanks to the comment by @Parfait using Map:

final_plots <- Map(function(x, y) {
  x   geom_segment(
    data = y,
    aes(x = x1, y = y1, xend = x2, yend = y2), inherit.aes = FALSE
  )
}, x = plots, y = line.plot)
  • Related