3

Following with the answer to my previous question, let's say that I am plotting density curves by group with ggplot and I want to produce the corresponding normal curve for each group (with their corresponding means and standard deviations). What I tried first was

library(ggplot2)
mtcars$vs <- as.factor(mtcars$vs)
ggplot(mtcars,aes(x=mpg, fill = vs, colour = vs)) + geom_density(alpha = 0.1) + 
    stat_function(fun = dnorm, args = list(mean = mean(mtcars$mpg), sd = sd(mtcars$mpg)))

but it produces a unique normal curve. Then I found in this question (whose answer I don't see how can help me), that stat_function understands group aesthetics, so I tried

ggplot(mtcars,aes(x=mpg, fill = vs, colour = vs)) + geom_density(alpha = 0.1) + 
    stat_function(aes(group = vs), fun = dnorm, args = list(mean = mean(mtcars$mpg), sd = sd(mtcars$mpg)))

but plot does not change. So how can I tell to stat_function that I want the arguments should be taken for each vs-group? I also expect the colour of each of these normal curves would be the same that (or related to) the mpg curve colour of the same group.

I had also tried with

library(dplyr)
ggplot(mtcars %>% group_by(vs),...

but it had no effect.

Thanks!

iago
  • 2,990
  • 4
  • 21
  • 27

1 Answers1

2

Using loops:

Example 1:two variables

mtcars$vs <- as.factor(mtcars$vs)
p <- unique(mtcars$vs)
g <- ggplot(mtcars, aes(x = mpg, fill = vs, colour = vs))
for (i in seq_along(p))  {
  df <- mtcars %>% filter(vs == p[i])
  g <- g + geom_density(alpha = .05) +
    stat_function(data = df,
                  fun = dnorm,
                  args = list(mean = mean(df$mpg), sd = sd(df$mpg)))
}
g

enter image description here

Example 2: more than two variables

mtcars$cyl <- as.factor(mtcars$cyl)
p <- unique(mtcars$cyl)
g <- ggplot(mtcars, aes(x = mpg, fill = cyl, colour = cyl))
for (i in seq_along(p))  {
  df <- mtcars %>% filter(cyl == p[i])
  g <- g + geom_density(alpha = .05) +
    stat_function(data = df,
                  fun = dnorm,
                  args = list(mean = mean(df$mpg), sd = sd(df$mpg)))
}
g

enter image description here

Scrappy solution: adding two layers

library(ggplot2)

mtcars$vs <- as.factor(mtcars$vs)
mt1 <- filter(mtcars, vs == 1)
mt0 <- filter(mtcars, vs == 0)

ggplot(mtcars, aes(x = mpg, fill = vs, colour = vs)) + geom_density(alpha = 0.1) +
  stat_function(data = mt0, fun =  dnorm,
    args = list(mean = mean(mt0$mpg), sd = sd(mt0$mpg))) +
  stat_function(data = mt1, fun = dnorm,
                args = list(mean = mean(mt1$mpg), sd = sd(mt1$mpg)))

Output: enter image description here

mpalanco
  • 12,960
  • 2
  • 59
  • 67
  • Thanks for the answer. I have got another on https://github.com/tidyverse/ggplot2/issues/3362 – iago Jun 14 '19 at 08:45
  • @iago I will check that answer too. If my answer has solved your question please consider accepting it by clicking the check-mark. Thank you. – mpalanco Jun 14 '19 at 08:54