将R dataframe转换为d3.hierarchy模型的严格JSON列表

将R dataframe转换为d3.hierarchy模型的严格JSON列表,r,json,d3.js,R,Json,D3.js,编辑:我已经清理了一些问题帖子,并添加了一个悬赏。我将在afk呆几天,但解决这个问题将是一个巨大的帮助 我想使用d3创建树模型的d3层次结构,使用篮球数据。我基本上想创建一个结构如下的括号: …其中,图形/模型是一棵树,其中每个节点正好有两个子节点(当然,除了所有的结束/叶节点)。这是一个教科书式的示例,说明了您何时需要使用d3.tree()和d3.hierarchy()功能,但它要求d3.hierarchy命令使用相当特定格式的JSON。特别是,对于8-4-2-1比赛中的8支篮球队,JSON

编辑:我已经清理了一些问题帖子,并添加了一个悬赏。我将在afk呆几天,但解决这个问题将是一个巨大的帮助

我想使用d3创建树模型的d3层次结构,使用篮球数据。我基本上想创建一个结构如下的括号:

…其中,图形/模型是一棵树,其中每个节点正好有两个子节点(当然,除了所有的结束/叶节点)。这是一个教科书式的示例,说明了您何时需要使用d3.tree()和d3.hierarchy()功能,但它要求d3.hierarchy命令使用相当特定格式的JSON。特别是,对于8-4-2-1比赛中的8支篮球队,JSON数据的格式如下:

const playoffData = {
  "name": "Rockets",
  "round": 4,
  "id": 15,
  "children": [
    { 
      "name": "Rockets",
      "round": 3,
      "id": 14,
      "children": [
        { 
          "name": "Rockets",
          "round": 2,
          "id": 9,
          "children": [
            { 
              "name": "Rockets", 
              "round": 1, 
              "id": 1 
            },
            { 
              "name": "Timberwolves", 
              "round": 1,
              "id": 8 
            }
          ]
        },
        { 
          "name": "Jazz",
          "round": 2,
          "id": 12,
          "children": [
            { 
              "name": "Jazz", 
              "round": 1, 
              "id": 4 
            },
            { 
              "name": "Thunder",
              "round": 1, 
              "id": 5
            }
          ]
        }
      ]
    },
    { 
      "name": "Warriors",
      "round": 3, 
      "id": 13,
      "children": [
        { 
          "name": "Warriors",
          "round": 2, 
          "id": 10,
          "children": [
            { 
              "name": "Warriors", 
              "round": 1, 
              "id": 2 
            },
            {
              "name": "Spurs", 
              "round": 1, 
              "id": 7
            }
          ]
        },
        { 
          "name": "Pelicans",
          "round": 2, 
          "id": 11,
          "children": [
            { 
              "name": "Pelicans",
              "round": 1,
              "id": 3
            },
            { 
              "name": "Trail Blazers",
              "round": 1, 
              "id": 6
            }
          ]
        }
      ]
    }
  ]
};
注意JSON的嵌套性质。根节点对应于括号中的获胜者,叶节点对应于括号第一轮中的团队

我有以下篮球数据的R数据框:

> dput(mydata)
structure(list(id = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 
13, 14, 15), teamname = c("Rockets", "Warriors", "Trail Blazers", 
"Jazz", "Thunder", "Pelicans", "Spurs", "Timberwolves", "Rockets", 
"Warriors", "Pelicans", "Jazz", "Rockets", "Warriors", "Rockets"
), conference = c("West", "West", "West", "West", "West", "West", 
"West", "West", "West", "West", "West", "West", "West", "West", 
"West"), seeding = c(1, 2, 3, 4, 5, 6, 7, 8, NA, NA, NA, NA, 
NA, NA, NA), round = c(1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 
3, 4), child1 = c(NA, NA, NA, NA, NA, NA, NA, NA, 1, 2, 3, 4, 
9, 11, 13), child2 = c(NA, NA, NA, NA, NA, NA, NA, NA, 8, 7, 
6, 5, 12, 10, 14), wins = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0), losses = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0), completed = c(FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE
), winprobs = c(NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
NA, NA, NA)), .Names = c("id", "teamname", "conference", "seeding", 
"round", "child1", "child2", "wins", "losses", "completed", "winprobs"
), row.names = c(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 17L, 18L, 19L, 
20L, 25L, 26L, 29L), class = "data.frame")


> mydata
> playoff.data


   id      teamname conference seeding round child1 child2 wins losses completed winprobs
1   1       Rockets       West       1     1     NA     NA    0      0     FALSE       NA
2   2      Warriors       West       2     1     NA     NA    0      0     FALSE       NA
3   3 Trail Blazers       West       3     1     NA     NA    0      0     FALSE       NA
4   4          Jazz       West       4     1     NA     NA    0      0     FALSE       NA
5   5       Thunder       West       5     1     NA     NA    0      0     FALSE       NA
6   6      Pelicans       West       6     1     NA     NA    0      0     FALSE       NA
7   7         Spurs       West       7     1     NA     NA    0      0     FALSE       NA
8   8  Timberwolves       West       8     1     NA     NA    0      0     FALSE       NA
17  9       Rockets       West      NA     2      1      8    0      0     FALSE       NA
18 10      Warriors       West      NA     2      2      7    0      0     FALSE       NA
19 11      Pelicans       West      NA     2      3      6    0      0     FALSE       NA
20 12          Jazz       West      NA     2      4      5    0      0     FALSE       NA
25 13       Rockets       West      NA     3      9     12    0      0     FALSE       NA
26 14      Warriors       West      NA     3     11     10    0      0     FALSE       NA
29 15       Rockets       West      NA     4     13     14    0      0     FALSE       NA
如果你能告诉我,我的R数据帧有一行表示我的d3图形中的每个节点。请特别注意树结构,以及用于标识子节点的child1和child2辅助列—对于最后一轮(第15行),其子节点是前一轮(第13和14行)中的两个节点。对于第13行(半决赛),其子节点是9和12,以此类推。前8行是第一轮,因此这些是叶节点,没有子节点

它有点长,但我想包含整个JSON和R数据框架以保持清晰。我还希望JSON结构中包含其他数据帧列(wins、LOSS、win probs),但是为了简洁起见,我没有在上面的JSON中显示这些列

最后一点注意:虽然我主要在R中工作,但这是我正在制作的一个d3图,因此我必须为此编写大量javascript代码。我的观点是,对于这种类型的数据manip,R更好,但是因为这是我们正在处理的一个嵌套JSON对象,所以JS可能更好。如果有一个eas(ier)解决方案涉及使用javasript将R数据帧的2D JSON版本映射到所需的嵌套JSON,那么这可能也就足够了


感谢您的帮助!我保证在我返回奖励时会选择一个最佳答案。

您可以将此递归函数与
jsonlite::toJSON()一起尝试:


您可以将此递归函数与
jsonlite::toJSON()一起尝试:


下面是一个
tidyverse
解决方案

我们重新格式化您的数据,并将data.frame拆分为4个data.frames

然后,我们将它们连接起来,在每一步嵌套相关列

最后,我们使用
toJSON
完成作业:

my.split <- my.data %>%
  gather(temp,children,child1,child2) %>%
  select(-temp) %>%
  select(name= teamname,round,id,children) %>% # change here to keep more columns
  distinct %>%
  split(.$round)

my.split[[1]] %>%
  select(-children) %>%
  right_join(my.split[[2]],by=c(id="children"),suffix=c("",".y")) %>%
  nest(1:3) %>% # change here to keep more columns
  setNames(names(my.split[[1]])) %>%
  right_join(my.split[[3]],by=c(id="children"),suffix=c("",".y")) %>%
  nest(1:4) %>% # change here to keep more columns
  setNames(names(my.split[[1]])) %>%
  right_join(my.split[[4]],by=c(id="children"),suffix=c("",".y")) %>%
  nest(1:4) %>% # change here to keep more columns
  setNames(names(my.split[[1]])) %>%
  jsonlite::toJSON(pretty=TRUE)

下面是一个
tidyverse
解决方案

我们重新格式化您的数据,并将data.frame拆分为4个data.frames

然后,我们将它们连接起来,在每一步嵌套相关列

最后,我们使用
toJSON
完成作业:

my.split <- my.data %>%
  gather(temp,children,child1,child2) %>%
  select(-temp) %>%
  select(name= teamname,round,id,children) %>% # change here to keep more columns
  distinct %>%
  split(.$round)

my.split[[1]] %>%
  select(-children) %>%
  right_join(my.split[[2]],by=c(id="children"),suffix=c("",".y")) %>%
  nest(1:3) %>% # change here to keep more columns
  setNames(names(my.split[[1]])) %>%
  right_join(my.split[[3]],by=c(id="children"),suffix=c("",".y")) %>%
  nest(1:4) %>% # change here to keep more columns
  setNames(names(my.split[[1]])) %>%
  right_join(my.split[[4]],by=c(id="children"),suffix=c("",".y")) %>%
  nest(1:4) %>% # change here to keep more columns
  setNames(names(my.split[[1]])) %>%
  jsonlite::toJSON(pretty=TRUE)

预期输出总是将获胜者作为第一个子项,即使这与表中的
child1
不对应。我不确定这对OP是否重要。事实上,我假设OP是手工生成输出的,它要么是错误的,要么是无关的,但可以公平地指出。实际上,OP的样本数据中id 13是火箭,id 14是勇士,所以我只能假设这是OP的错误,据我所知,你的产出似乎和我的一样。OP可能会让我们知道他什么时候来。@RalfStubner我不喜欢孩子们的顺序,只要孩子们是正确的。当我使用数据创建图形时,顺序可能很重要,但这不是我遇到的问题yet@Moody_MudskipperThe预期输出总是将获胜者作为第一个子项,即使这与表中的
child1
不对应。我不确定这对OP是否重要。事实上,我假设OP是手工生成输出的,它要么是错误的,要么是无关的,但可以公平地指出。实际上,OP的样本数据中id 13是火箭,id 14是勇士,所以我只能假设这是OP的错误,据我所知,你的产出似乎和我的一样。OP可能会让我们知道他什么时候来。@RalfStubner我不喜欢孩子们的顺序,只要孩子们是正确的。当我使用数据创建图形时,顺序可能很重要,但这不是我遇到的问题yet@Moody_MudskipperWith我的完整数据集,有时子名称是NA(如果某个特定的季后赛系列尚未开始,teamname列将为空)。我没有说清楚,但我认为更新相当简单(只需删除最后一个else案例就可以了),尽管我是tidyverse的粉丝,为了可读性,因为我在寻找递归解决方案,我会接受这个答案,尽管两者都很好。谢谢guys@Canovice也可以使用未调整子元素顺序的早期版本。它甚至更短;-)在我的完整数据集中,有时子名称是NA(如果某个特定的季后赛系列赛尚未开始,teamname列将为空)。我没有说清楚,但我认为更新相当简单(只需删除最后一个else案例就可以了),尽管我是tidyverse的粉丝,为了可读性,因为我在寻找递归解决方案,我会接受这个答案,尽管两者都很好。谢谢guys@Canovice也可以使用未调整子元素顺序的早期版本。它甚至更短;-)
my.split <- my.data %>%
  gather(temp,children,child1,child2) %>%
  select(-temp) %>%
  select(name= teamname,round,id,children) %>% # change here to keep more columns
  distinct %>%
  split(.$round)

my.split[[1]] %>%
  select(-children) %>%
  right_join(my.split[[2]],by=c(id="children"),suffix=c("",".y")) %>%
  nest(1:3) %>% # change here to keep more columns
  setNames(names(my.split[[1]])) %>%
  right_join(my.split[[3]],by=c(id="children"),suffix=c("",".y")) %>%
  nest(1:4) %>% # change here to keep more columns
  setNames(names(my.split[[1]])) %>%
  right_join(my.split[[4]],by=c(id="children"),suffix=c("",".y")) %>%
  nest(1:4) %>% # change here to keep more columns
  setNames(names(my.split[[1]])) %>%
  jsonlite::toJSON(pretty=TRUE)
[
  {
    "name": "Rockets",
    "round": 4,
    "id": 15,
    "children": [
      {
        "name": "Rockets",
        "round": 3,
        "id": 13,
        "children": [
          {
            "name": "Rockets",
            "round": 2,
            "id": 9,
            "children": [
              {
                "name": "Rockets",
                "round": 1,
                "id": 1
              },
              {
                "name": "Timberwolves",
                "round": 1,
                "id": 8
              }
              ]
          },
          {
            "name": "Jazz",
            "round": 2,
            "id": 12,
            "children": [
              {
                "name": "Jazz",
                "round": 1,
                "id": 4
              },
              {
                "name": "Thunder",
                "round": 1,
                "id": 5
              }
              ]
          }
          ]
      },
      {
        "name": "Warriors",
        "round": 3,
        "id": 14,
        "children": [
          {
            "name": "Pelicans",
            "round": 2,
            "id": 11,
            "children": [
              {
                "name": "Trail Blazers",
                "round": 1,
                "id": 3
              },
              {
                "name": "Pelicans",
                "round": 1,
                "id": 6
              }
              ]
          },
          {
            "name": "Warriors",
            "round": 2,
            "id": 10,
            "children": [
              {
                "name": "Warriors",
                "round": 1,
                "id": 2
              },
              {
                "name": "Spurs",
                "round": 1,
                "id": 7
              }
              ]
          }
          ]
      }
      ]
  }
  ]