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

medo 一个不漂亮的画法:

library(ggplot2)
x <- seq(0.1, 10, by = 0.1)
z <- c(1, 2, 3, 4)
y1 <- z[1]/x
y2 <- z[2]/x
y3 <- z[3]/x
y4 <- z[4]/x
z <- rep(c("z1", "z2", "z3", "z4"), each = 100)
x <- rep(x, 4)
y <- c(y1, y2, y3, y4)
df <- data.frame(z, x, y)
ggplot(df, aes(x = x, y = y, color = z)) + geom_line() + 
        coord_cartesian(ylim = c(0, 10), expand = F)

要是其他成员有比较好的方法,希望能学习一下。


受大鹏启发,精简一下:

library(ggplot2)
x <- seq(0.1, 10, by = 0.1)
z <- rep(1:4, each = 100)
df <- data.frame(x, y = z/x, z = factor(z))
ggplot(df, aes(x = x, y = y, color = z)) + geom_line() + 
        coord_cartesian(ylim = c(0, 10), expand = F)

给自己的笔记:产生数据组合,可以用 expand.grid()

    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.