Search code examples
rggplot2tidyversemelt

facet_grid with multiple line colours


I have the following data frame resulting from simulations of ODEs with different parameter sets, e.g.

df <- data.frame(t = rep(seq(0,4), 4),
                 x1 = c(1.2*seq(1,5), 1.3*seq(1,5), 1.4*seq(1,5), 1.5*seq(1,5)),
                 x2 = c(0.2*seq(1,5), 0.3*seq(1,5), 0.4*seq(1,5), 0.5*seq(1,5)),
                 a = rep(c(rep(1, 5), rep(2,5)), 2),
                 b = c(rep(1, 10), rep(2,10))
)

I now would like to have a facet_grid with x1 and x2 on top and a and b on the right where the values of a and b determine the line colour.

I tried

df.1 <- df %>%
  gather(x, xval, -t, -a, -b) %>%
  gather(p, pval, -t, -x, -xval) %>%
  distinct()

df.1$pval <- as.factor(df.1$pval)

ggplot(df.1, aes(t, xval)) +
  geom_line(aes(colour = pval)) +
  facet_grid(p~x)

and

dm.1 <- melt(df[, c("t", "x1", "x2")], id = 't')
colnames(dm.1) <- c("t", "x", "xval")
dm.2 <- melt(df[, c("t", "a", "b")], id = 't')
colnames(dm.2) <- c("t", "p", "pval")
dm <- merge(dm.1, dm.2)

dm$pval <- as.factor(dm$pval)
ggplot(dm, aes(t, xval)) +
  geom_line(aes(colour = pval)) +
  facet_grid(p~x)

But both do not give the desired result. Any hint would be greatly appreciated.

Edit: The desired result would be to have two lines in each facet similar to my first solution but the correct ones, i.e. straight lines and not the zig-zag lines that result.


Solution

  • The problem that's causing the zigzag plots you're getting is that there are multiple repeats of the same combinations of p and x, but there isn't a way to demarcate one from the other. So you get the first plot below:

    library(tidyverse)
    
    df <- data.frame(t = rep(seq(0,4), 4),
                                     x1 = c(1.2*seq(1,5), 1.3*seq(1,5), 1.4*seq(1,5), 1.5*seq(1,5)),
                                     x2 = c(0.2*seq(1,5), 0.3*seq(1,5), 0.4*seq(1,5), 0.5*seq(1,5)),
                                     a = rep(c(rep(1, 5), rep(2,5)), 2),
                                     b = c(rep(1, 10), rep(2,10))
    )
    
    df_long <- df %>%
        gather(key = x, value = xval, x1, x2) %>%
        gather(key = p, value = pval, a, b) %>%
        mutate(pval = as.factor(pval))
    
    df_long %>%
        ggplot(aes(x = t, y = xval)) +
            geom_line(aes(color = pval)) +
            facet_grid(p ~ x)
    

    You can see what it looks like here when I filter for a specific pair of x, p values. This will just place data at the same value of t repeatedly, instead of knowing how to make distinct lines.

    df_long %>%
        filter(x == "x1", p == "a") %>%
        head()
    #>   t  x xval p pval
    #> 1 0 x1  1.2 a    1
    #> 2 1 x1  2.4 a    1
    #> 3 2 x1  3.6 a    1
    #> 4 3 x1  4.8 a    1
    #> 5 4 x1  6.0 a    1
    #> 6 0 x1  1.3 a    2
    

    Instead, before gathering, you can make an ID for each combination of a and b, and use that as your grouping variable in aes. There are probably other ways to do this, but a simple one is just interaction(a, b), which will give IDs that look like 1.1, 1.2, 2.1, 2.2, etc. Then add group = id inside your aes to make separate lines.

    df_long_id <- df %>%
        mutate(id = interaction(a, b)) %>%
        gather(key = x, value = xval, x1, x2) %>%
        gather(key = p, value = pval, a, b) %>%
        mutate(pval = as.factor(pval))
    
    df_long_id %>%
        ggplot(aes(x = t, y = xval, group = id)) +
        geom_line(aes(color = pval)) +
        facet_grid(p ~ x)
    

    Created on 2018-05-09 by the reprex package (v0.2.0).