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