• R语言
  • 请问如何用ggplot画出曲线簇?

Liechi 在你基础上改了一下:

library(ggplot2)
library(magrittr)
expand.grid(x =seq(0.1, 10, by = 0.1), z = 1:4) %>% 
  transform(y = z/x, z = factor(z)) %>% 
  ggplot() +
  geom_line(aes(x, y, color = z))

无管道版:

library(ggplot2)
ggplot(
  transform(
    expand.grid(
      x = seq(0.1, 10, by = 0.1), 
      z = 1:4),
    y = z / x,
    z = factor(z))) + 
  geom_line(aes(x, y, color = z))

    dapengde 哈哈,原来是 expand.grid(),我印象里有个函数可以产生这个效果,但是刚才没有想起来是哪个。

      Liechi 我也很少用。刚才试了一下,可以在 expand.grid() 里指定列名称,所以去掉了一行。

        谢谢各位。短路忘记color分类了。

        dapengde 顺便再精简一下,去掉 dplyr 的依赖

        library(ggplot2)
        library(magrittr)
        expand.grid(x =seq(0.1, 10, by = 0.1), z = 1:4) %>% 
          transform(y = z/x, z = as.factor(z)) %>% 
          ggplot() +
          geom_line(aes(x, y, color = z))

        PS 我刚精简完,发现 dapengde 修改了自己的回帖, 😅 然后默默地删,最后还是回一下

          再来个 Base R 版,去掉所有额外包的依赖,打擂:

          df <- transform(
            expand.grid(
              x = seq(0.1, 10, by = 0.1), 
              z = 1:4),
            y = z / x)
          plot(df$x[df$z == i], df$y[df$z == i], type = 'l', xlab = 'x', ylab = 'y')
          for(i in 2:4) lines(df$x[df$z == i], df$y[df$z == i], col = i)
          legend('topright', legend = 1:4, col = 1:4, lty = 1, title = 'z')

          以及 lattice 版:

          lattice::xyplot(y~x, groups = z, data = df, type = 'l', ylim = c(0, 10), auto.key = list(corner = c(1, 1), points = FALSE, lines = TRUE))

          相比之下,ggplot2 确实优雅。

            dapengde 来,老夫聊发个少年狂:论 R 基础图形,当今世上恐怕没几个人是我的对手,毕竟我是写过《古代统计图形》的,哈哈哈。两行代码给你搞定:

            for (z in 4:1) curve(z/x, 0, 10, add = z < 4, col = z)
            legend('topright', legend = 4:1, col = 4:1, lty = 1, title = 'z')

              yihui 看到这里方才惊觉,我被 tidyverse 暗中洗脑了。上面我的 Base R 方案完全没必要先生成 data.frame。下面这样就足够了:

              x = seq(0.1, 10, by = 0.1)
              plot(x, 1/x, type = 'l', xlab = 'x', ylab = 'y')
              for (z in 2:4) lines(x, z/x, col = z) 
              legend('topright', legend = 1:4, col = 1:4, lty = 1, title = 'z')

              curve() 我好像从没用过。

              @Liechi 瞧, expand.grid()根本用不上。

                yihui 看完你的解法,耳边响起了熟悉的旋律:

                问世间 是否此山最高
                或者另有高处比天高
                ...

                dapengde 我已用歌声表达了我的感受。

                我现在也有点极乐净土病了:最开始版本的代码,顺手祭出了神包 玛格丽特,写完后惊觉整个代码段,其实只有一处用了 %>%df %>% ggplot() + ...),赶紧灰溜溜地把 玛格丽特 请回去,改写成 ggplot(df, ...) + ...

                  matplot(outer(seq(0.1, 10, by = 0.1), 1:4, function(x, a) a / x),
                    xlab = "x", ylab = "z/x", type = "l", col = 1:4, lty = 1
                  )
                  legend("topright", legend = 4:1, col = 4:1, lty = 1, title = "z")

                    Liechi
                    df %>% ggplot的一个好处是ggplot里aes的列名自动补齐终于可以正常工作了…发现这一点之后我就再也回不到从前啦

                      Cloud2016 我来打个代码高尔夫,把你的代码略微缩一下(代价是不那么易懂了):

                      matplot(t(outer(1:4, (1:100)/10, `/`)),
                        xlab = "x", ylab = "z/x", type = "l", col = 1:4, lty = 1
                      )

                      不过还是不如我的 curve() 方案短小,主要是 curve() 自动生成了横纵坐标的标题。

                      画数据图的话,ggplot 完胜;画示意图的话,R 基础图形还是有点优势的。前者本来就是建设在数据框基础上的,所以要画示意图还得事先生造出一个干净的数据框,在那之后一切都简单多了;后者则是纸笔模型,自己拿着笔画点画线,所以用来画数据图形则会显得很繁琐。

                        涨见识了。我感觉我的极限就是 plot + lines,更高级的消化不了,隔断时间不用就忘干净。

                        建议以后对 cosx 所有的提问都给出 Base R 版和 Tidyverse 版 。做做大脑体操。简称 B 版和 T 版。我自告奋勇整理成书。书名我都想好了:BT 擂台赛。

                          dapengde 赞呐!

                          yihui 缩略的好,这次放出的《“古”代统计图形》是我看到最完整的,既然11年就有365页了,为啥当时不出版?现在看的话,部分内容需要更新了

                            tctcab 果然如此。这个差异以前没有意识到,看来是回不去了。

                            如果用 ggplot2, 可以用 stat_function 把生成数据这一步抽象掉。

                            library(ggplot2)
                            out <- ggplot(data.frame(x = c(0, 10)), aes(x))
                            for (i in 1:4) {
                              out = out + stat_function(fun = function(.x ,z) z/.x, 
                                                        color = i, 
                                                        args = list(z=i),
                                                        xlim=c(i/10,10) )
                            }
                            out

                            我以前画图用TikZ 或 Mathematica。 刚用 R 时,觉得画函数图像还得先“生成数据”这一步很奇怪,画出来的图不是“矢量图”。后来才发现 TikZ 不过是把“生成数据”这一步抽象掉了。

                            Update: 之前犯了两个错误 (i) 循环变量应该在 args 里,(ii) x得从 z/10开始,因为要求 y 在0到10取值。很奇怪 stat_function 没有 ylim 这个参数。dapengde 我给你那个 bookdown 项目交了 PR.