1

I'd like to be able to build a string based on the number of columns in my matrix and pass that to ggplot as an aesthetic. This doesn't seem to be covered by the aes_string() function. The reason I want this is that I'm using the ggalluvial package but the intricacies matter less than the principle. My code looks like this:

library(ggplot2)
library(ggalluvial)
my_alluvial_plot <- function(scores, n_groups = 5) {

  score_names <- names(scores)
  scr_mat <- data.matrix(scores)
  n_cols <- ncol(scores)

  # create ntiles of scores so that flow can be seen between groups
  ranks <- apply(scr_mat, 2, function(x) {
    rk <- dplyr::ntile(x, n_groups)
    return(as.factor(rk))
  })

  to_plot <- data.frame(ranks)

  # build the string for the aes() function
  a_string <- ""
  for (i in 1:n_cols) {
    a_string <- paste0(a_string, "axis", i, " = to_plot[, ", i, "],")
  }
  # remove final comma
  a_string <- substr(a_string, 1, nchar(a_string) - 1)

  ggplot(to_plot,
         aes(eval(a_string))) +
    geom_alluvium(aes(fill = to_plot[, n_cols], width = 1/12)) +
    geom_stratum(width = 1/12, fill = "black", color = "grey") +
    scale_x_continuous(breaks = 1:n_cols, labels = score_names) +
    scale_fill_brewer(type = "qual", palette = "Set1")
}

df <- data.frame(col1 = runif(10),
                 col2 = runif(10),
                 col3 = rnorm(10),
                 col4 = rnorm(10))
my_alluvial_plot(df)

This produces a blank plot with the following error:

Warning: Ignoring unknown aesthetics: width
Error: Discrete value supplied to continuous scale

Basically, I want to build an alluvial plot that can support an arbitrary number of columns, so the ggplot code as it's evaluated would end up being like

ggplot(to_plot,
       aes(axis1 = data[, 1], axis2 = data[, 2], axis3 = data[, 3], ...))

But neither eval() or parse() produce anything sensible. aes_string() produces the same problem. Is there any way to do this systematically?

data princess
  • 1,130
  • 1
  • 23
  • 42
  • 2
    You may need to show a small reproducible example for others to test – akrun Jun 26 '18 at 04:16
  • Yep. I was away from my work computer where the more relevant code was, haha. Thank you for the tip. – data princess Jun 26 '18 at 13:34
  • The "Error: Discrete value..." is due to the fact that you are using scale_x_continuous(...) - did you try scale_x_discrete(...) instead? – Wolfgang Arnold Jun 26 '18 at 13:58
  • Yeah, I've always used `scale_x_continuous()` for alluvial plots. I think it's only being thrown because it's not able to read the first part properly. Same reason the `width` warning is there. It's basically reading an empty aesthetic. – data princess Jun 26 '18 at 14:09

1 Answers1

0

The reason you can't run parse() or eval() on strings like "axis1 = col1, axis2 = col2" is that such is a string by itself is not valid R code. But the entire ggplot call? That can be parsed!

If you rework the plot call like this, it produces the alluvial plot just fine:

gg_string <- paste0("ggplot(to_plot,
                            aes(", a_string, ")) +
                       geom_alluvium(aes(fill = to_plot[, n_cols], width = 1/12)) +
                       geom_stratum(width = 1/12, fill = 'black', color = 'grey') +
                       scale_x_continuous(breaks = 1:n_cols, labels = score_names) +
                       scale_fill_brewer(type = 'qual', palette = 'Set1')")

eval(parse(text = gg_string))
data princess
  • 1,130
  • 1
  • 23
  • 42