Multiple curves in ggplot2

Hi all,

I am trying to plot a number of non-linear curves in ggplot (it's actually loglogistic, but I can't imagine that would make a difference). I have a function loglogistic_fn(x, omega, theta). I have a data frame (called df1) with many different omega and theta possibilities, and I want to show each of them on 1 graph.

If I had was just trying to plot one version, and stored the variables as omega0 and theta0, I could plot it as

ggplot(data = tibble(x = 0:17), aes(x)) +
  stat_function(fun = loglogistic_fn, args = list(omega = omega1, theta = theta1))

If I was just adding in one or two other curves, I could just copy/paste the second line, changing the arguments of omega and theta, but I have too many to do it manually. Is there an automatic way to do it in ggplot? I tried doing

ggplot(data = tibble(x = 0:17), aes(x)) +
  stat_function(fun = loglogistic_fn, args = list(omega = df$omega, theta = df$theta))

but that did not work.

Thanks for your help,

Alan

The reduce2 method I used here works reasonably well:

suppressPackageStartupMessages(library(tidyverse))

norm_curves <- tribble(
  ~Mean, ~SD,
  5, 3,
  10, 1,
  16, 4
)

reduce2(.x = norm_curves$Mean,
        .y = norm_curves$SD,
        .init = ggplot(data = tibble(x = 0:17), aes(x)),
        function(prev, .x, .y) {
          prev + stat_function(fun = dnorm,
                               args = list(mean = .x,
                                           sd = .y))
        })

image

Edit: Oh, and because it was bugging me that color was potentially problematic with reduce2:

suppressPackageStartupMessages(library(tidyverse))

norm_curves <- tribble(
  ~Group, ~Mean, ~SD,
  "A", 5, 3,
  "B", 10, 1,
  "C", 16, 4
)

pmap(norm_curves,
     function(Group, Mean, SD) {
       stat_function(data = . %>% mutate(Group = Group),
                     aes(color = Group),
                     fun = dnorm,
                     args = list(mean = Mean,
                                 sd = SD))
     }) %>% 
  reduce(.init = ggplot(data = tibble(x = 0:17),
                        aes(x)),
         `+`)

image

1 Like

Thanks!

That mostly works. I had been assuming that there would be something within ggplot itself .

This method works when I don't have too many rows (it so far worked when I had 100). However, when I tried 1000 rows (plotting each line with alpha = 0.002, I received the following error:

Error: evaluation nested too deeply: infinite recursion / options(expressions=)?

Its not the end of the world for me to randomly sample 100 rows from my data frame and plot that...but my immediate reaction is to be greedy and to try to plot all 3000 :wink:

I'm not sure whether it's purrr or ggplot2 causing the recursion error. That said, given the large number of lines that you're drawing, you may want to create a data frame with the data pre-run through your function instead. That's what I did before I found stat_function, though I was never plotting that many curves!

suppressPackageStartupMessages(library(tidyverse))

N <- 1000

norm_curves <- tibble(Group = 1:N,
                      Mean = rnorm(N, 5, .01),
                      SD = rgamma(N, shape = 1000, rate = 1000))

plot_data <- 
  pmap_df(norm_curves,
          function(Group, Mean, SD) {
            tibble(Group = Group,
                   x = seq(0, 10, by = .25),
                   y = dnorm(x, Mean, SD))
          })

ggplot(data = plot_data) +
  geom_line(aes(group = Group, x = x, y = y), alpha = .01)

image

2 Likes

Thanks! Creating it as a data frame and just plotting that worked.

I may just decide anyway to randomly sample before plotting -- there seems to be a lower limit on the alpha one can choose (0.002), so with 3000, even using such a small alpha leads to more overplotting that I would have liked.

Thanks for all your help!

Alan