如何在 ggplot2 中绘制函数系列

Jul*_*gio 5 plot r ggplot2

我需要绘制一组根据一组参数变化的函数,例如,一组依赖于均值和标准差的正态分布曲线。我在这里找到一个几乎可以完成任务的代码片段:

p9 <- ggplot(data.frame(x = c(0, 1)), aes(x = x)) +
    stat_function(fun = dnorm, args = list(0.2, 0.1),
                  aes(colour = "Group 1")) +
    stat_function(fun = dnorm, args = list(0.7, 0.05),
                  aes(colour = "Group 2")) +
    scale_x_continuous(name = "Probability",
                          breaks = seq(0, 1, 0.2),
                          limits=c(0, 1)) +
    scale_y_continuous(name = "Frequency") +
    ggtitle("Normal function curves of probabilities") +
    scale_colour_brewer(palette="Accent") +
    labs(colour = "Groups")
p9 
Run Code Online (Sandbox Code Playgroud)

在这种情况下,代码正好绘制了两条曲线,如下所示:

两条曲线

我的问题是系列中的曲线数量可以是任意的,因此我尝试按如下方式调整代码:

aa <- list(list(0.2, 0.1), list(0.7, 0.05), list(0.45, 0.2))
p9 <- ggplot(data.frame(x = c(0, 1)), aes(x = x))
for (i in 1:3) {
    p9 <- p9 + stat_function(fun = dnorm, args = aa[[i]],
                         aes(colour = paste("Group", i))
}
p9 <- p9 + 
  scale_x_continuous(name = "Probability",
                   breaks = seq(0, 1, 0.2),
                   limits=c(0, 1)) +
  scale_y_continuous(name = "Frequency") +
  ggtitle("Normal function curves of probabilities") +
  scale_colour_brewer(palette="Accent") +
  labs(colour = "Groups")
p9
Run Code Online (Sandbox Code Playgroud)

结果几乎是成功的,因为它描绘了三个曲线,只是它没有通过颜色和图例来区分它们,如下所示:

任意数量的曲线

我猜问题出在函数 aes() 管理其参数的方式上。您对如何重写我的代码有任何想法吗?

ali*_*ire 5

将列表添加到 ggplot

快速编辑:我刚刚从@BrodieG那里学到了一个非常适用的习语:您可以将 geoms 或 stats 的列表直接添加到ggplot调用中,这样您就可以避免Reduceforlapply或 even的卷积Map,这可以让您通过尽可能多的并行变量。结合@JulioSergio 的aes_方法,您将获得一个具有可读代码且易于定制的不错图:

ggplot(data.frame(x = 0:1), aes(x)) + 
    Map(function(params, name){stat_function(mapping = aes_(color = name), 
                                             fun = dnorm, args = params)}, 
        params = aa, 
        name = paste('Group', seq_along(aa)))
Run Code Online (Sandbox Code Playgroud)


Reduce

该结构使其本身相当不错,以Reduceinit一套初始ggplot呼叫。可以通过根据当时对象中的层数索引调色板函数来添加颜色:

Reduce(function(x, y){
    x + stat_function(fun = dnorm, args = y, 
                      colour = scales::brewer_pal('qual', 'Set1')(length(aa))[length(x$layers) + 1])}, 
    aa, 
    init = ggplot(data.frame(x = c(0, 1)), aes(x = x)))
Run Code Online (Sandbox Code Playgroud)

这种方法的缺点是它不会成为一个很好的图例,因为它是硬编码颜色。


预先计算

解决这个问题的一种方法是在绘图之前简单地进行计算,这使得绘图本身非常简单:

library(tidyverse)

aa <- list(list(0.2, 0.1), list(0.7, 0.05), list(0.45, 0.2))

aa %>% set_names(paste('Group', 1:3)) %>% 
    map_df(~dnorm(seq(0, 1, length = 100), .x[[1]], .x[[2]])) %>% 
    mutate(x = seq(0, 1, length = 100)) %>% 
    gather(Group, y, -x) %>% 
    ggplot(aes(x, y, color = Group)) + 
    geom_line()
Run Code Online (Sandbox Code Playgroud)