简体   繁体   English

如何在ggplot2中绘制函数族

[英]How to plot a function family in ggplot2

I need to plot a family of functions variying according to a set of parameters, say, a family of normal distribution curves that depend on the mean and standard deviation. 我需要根据一组参数绘制一系列函数,例如,一系列依赖于平均值和标准偏差的正态分布曲线。 I found here , a code snipet that almost do the task: 我在这里找到一个几乎完成任务的代码snipet:

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 

In this case, the code plots exactly two curves, as shown below: 在这种情况下,代码会精确绘制两条曲线,如下所示:

两条曲线

My problem is that the number of curves in the family could be any , thus I tried to adapt the code as follows: 我的问题是该系列中的曲线数量可以是任意数 ,因此我尝试按如下方式调整代码:

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

The result is almost successful in that it depicts the three curves, except that it does not distinguish them by colors nor in the legend ,as it is shown below: 结果几乎是成功的,因为它描绘了三条曲线,除了它没有按颜色和图例区分它们,如下所示:

任意数量的曲线

I guess the problem arises from the manner the function aes() manages its arguments. 我想问题来自函数aes()管理其参数的方式。 Do you have any idea on how to rewrite my code? 你对如何重写我的代码有任何想法吗?

Add a list to ggplot 添加一个列表到ggplot

A quick edit: I just learned an idiom I just learned from @BrodieG that's very applicable here: you can add a list of geoms or stats directly to a ggplot call, which allows you to avoid the convolutions of Reduce for lapply or even Map , which lets you pass as many variables in parallel as you like. 快速编辑:我刚刚从@BrodieG那里学到了一个非常适用的成语 :你可以直接在ggplot调用中添加一个geoms或stats列表,这样你就可以避免使用Reduce来解决lapply甚至Map ,它允许您根据需要并行传递尽可能多的变量。 Combined with @JulioSergio's aes_ approach, you get a decent plot with readable code that's easily customizable: 结合@ 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)))


Reduce

The structure lends itself reasonably well to Reduce with init set to the initial ggplot call. 该结构使其本身相当不错,以Reduceinit设置为初始ggplot电话。 Colors can be added by indexing a palette function by the number of layers in the object at that point: 可以通过在该点对象中的层数索引调色板函数来添加颜色:

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)))

The disadvantage of this approach is that it does not make a nice legend, as it's hardcoding colors. 这种方法的缺点是它没有成为一个很好的传说,因为它是硬编码的颜色。


Precalculate 预先计算

One way around this is to simply do the calculations before plotting, which makes the plotting itself very simple: 解决这个问题的一种方法是在绘图之前简单地进行计算,这使得绘图本身非常简单:

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()

Reduce, with aes_() to add legend 减少,用aes_()添加图例

The following answer uses aes_() function instead of aes() to perform the aesthetics mapping, since, I learnt, it is more suitable for programming. 下面的答案使用aes_()函数而不是aes()来执行美学映射,因为,我了解到,它更适合编程。 I took as a basis the answer given by alistaire . 我把alistaire给出的答案作为基础。

library(ggplot2)
aa <- list(list(0.2, 0.1), list(0.7, 0.05), list(0.45, 0.2))
p9 <- Reduce(function(x, y){
  x + stat_function(fun = dnorm, args = y, 
                  aes_(colour = paste("Group", length(x$layers)+1)))}, 
  aa, 
  init = ggplot(data.frame(x = c(0, 1)), aes(x = x)))
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

The figure below shows the result: 下图显示了结果:

结果

The advantage, in this case, is that the resulting image has a legend with the proper labels. 在这种情况下,优点是结果图像具有带有适当标签的图例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM