创建关于 r 中出现次数的平行坐标图

Create parallel-coordinate plot regarding to number of occurrences in r

我有如下DF。它包含有关两个学生的 3 个学期和科目的信息,无论他们是否通过。
我想画一条平行坐标的学生轨迹。我想看看走哪条路才能走到尽头

ID  term  subject  result
1    1     math01    fail
1    1     Phys01    pass
1    1     chem01    pass
1    2     math01    pass
1    2     math02    fail
1    3     math02    fail
1    3     cmp01     pass
2    1     math01    fail
2    1     phys01    pass
2    2     math01    pass
2    2     math02    pass
2    3     cmp01     pass

期望的结果类似于下图。
每个学期的每个块都显示了 result 列(失败或通过)的主题别名。块的大小应与拍摄对象的数量相对应。例如,如果大多数学生在第 1 学期 math01 不及格,则 math01fail 的块应该是下面第 1 学期的最大块。

连接线连接学生在本学期和下学期选修的科目。线的粗细对应于该点的连接数。例如,如果许多学生在第一学期未通过 math01 (math01fail) 并在第二学期重新参加 math01 并通过它 (math01pass),则 math01fail 和 math01pass 之间的连接线在出现次数方面应该更粗。

如何在 R 中创建这样的绘图?

我认为你最好从图形的角度来解决这个问题,而不是在平行坐标的上下文中。

这是我会做的:

  1. 从加载必要的库开始

    library(tidyverse)
    library(igraph)
    
  2. 首先我们定义图的边列表。为此,我们将 dfID 和 select 对应于连续(递增)项的行进行自连接。然后每一行对应于每个学生从学期 i 到 i+1 的 link。

    el <- left_join(df, df, by = "ID") %>%
        filter(term.x == term.y - 1) %>%
        mutate_at(vars(starts_with("term")), funs(paste0("term", .))) %>%
        unite(from, term.x, subject.x, result.x, sep = "\n") %>%
        unite(to, term.y, subject.y, result.y, sep = "\n") %>%
        select(from, to) %>%
        group_by(from, to) %>%
        summarise(weight = (n() - 1) * 5 + 1)
    

    我们为每条边添加了一个与学生人数成正比的权重列。我们不简单地做 weight = n() 的原因纯粹是出于美学考虑,我们希望为 >1 名学生设置更粗的线条。

  3. 接下来我们定义一个节点列表。这里的关键是添加列 xy,这将决定节点的网格布局。

    nl <- df %>%
        mutate(term = paste0("term", term)) %>%
        arrange(term) %>%
        distinct(term, subject, result) %>%
        mutate(x = as.integer(as.factor(term))) %>%
        group_by(term) %>%
        mutate(y = 1:n()) %>%
        unite(node, term, subject, result, sep = "\n")
    

    请注意,nl 第一列中的条目需要与 el 前两列中的条目匹配。

  4. 我们现在准备好从两个 data.frame 构造一个 igraph 并绘制图形。

    gr <- graph_from_data_frame(d = el, vertices = nl, directed = F)
    plot(
        gr,
        edge.width = E(gr)$weight,
        vertex.shape = "rectangle",
        vertex.size = 50, vertex.size2 = 50,
        vertex.color = "white",
        vertex.label.family = "sans",
        vertex.label.cex = 0.7)
    

    生成的图可能需要进一步 tweaking/polishing,但这应该可以帮助您入门。