复杂 JSON 到 D3js 堆叠时间序列
Complex JSON to D3js stacked time series
我必须使用 D3 创建一个可视化效果,如下图所示,时间序列,堆叠条形图:
数据集来自一位顾问,格式为 json 个对象的嵌套数组:
[{
"period": "6/2017",
"data": [
{
"partner": "TR",
"val": 5201888581
},
{
"partner": "CH",
"val": 8509470105
},
{
"partner": "RU",
"val": 10677690328
},
{
"partner": "GB",
"val": 16086915825
},
{
"partner": "US",
"val": 17817589838
},
{
"partner": "CN",
"val": 26120939253
},
{
"partner": "TOTAL",
"val": 145385348496
}
]
},
{
"period": "7/2017",
"data": [
{
"partner": "TR",
"val": 4832746886
},
{
"partner": "CH",
"val": 8194483975
},
{
"partner": "RU",
"val": 10082530447
},
{
"partner": "US",
"val": 15251181551
},
{
"partner": "GB",
"val": 15515343080
},
{
"partner": "CN",
"val": 27480148190
},
{
"partner": "TOTAL",
"val": 142118881451
}
]
},
{
"period": "8/2017",
"data": [
{
"partner": "TR",
"val": 4827335758
},
{
"partner": "CH",
"val": 7087004314
},
{
"partner": "RU",
"val": 10372167568
},
{
"partner": "GB",
"val": 14555013893
},
{
"partner": "US",
"val": 16838219917
},
{
"partner": "CN",
"val": 27876046083
},
{
"partner": "TOTAL",
"val": 143363806063
}
]
}
...
]
更准确地说,每个对象包含句点和对象的子数组、国家/地区代码和值:
{
period,
data: [{country,value},{country,value},{country,value}...]
}
数据数组包含不同数量的对象(国家记录),从 3 到 10 个和不同的国家(它们可以是任何联合国国家)。
我尝试使用 D3 (v5) 中的标准布局,例如 "stack" 但是,如您所见,我的数据与 d3 布局中所需的数据格式不匹配,即表格数据,如:
time field1 field2 field3
t1 v11 v12 v13
t2 v21 v22 v23
...
我不知道如何管理我的数据,请帮忙。发送.
LE:我也尝试过 chart.js 但由于类似问题失败了。
由于国家/地区的数量不同,您可以创建自己的函数来附加国家/地区的矩形元素。该示例使用 d3.selection.each 调用新函数,并在此函数中创建一个新数据数组,其中包含每个矩形的 y 偏移量。
let data = [{
"period": "6/2017",
"data": [
{
"partner": "TR",
"val": 5201888581
},
{
"partner": "CH",
"val": 8509470105
},
{
"partner": "RU",
"val": 10677690328
},
{
"partner": "GB",
"val": 16086915825
},
{
"partner": "US",
"val": 17817589838
},
{
"partner": "CN",
"val": 26120939253
},
{
"partner": "TOTAL",
"val": 145385348496
}
]
},
{
"period": "7/2017",
"data": [
{
"partner": "TR",
"val": 4832746886
},
{
"partner": "CH",
"val": 8194483975
},
{
"partner": "RU",
"val": 10082530447
},
{
"partner": "US",
"val": 15251181551
},
{
"partner": "GB",
"val": 15515343080
},
{
"partner": "CN",
"val": 27480148190
},
{
"partner": "TOTAL",
"val": 142118881451
}
]
},
{
"period": "8/2017",
"data": [
{
"partner": "TR",
"val": 4827335758
},
{
"partner": "CH",
"val": 7087004314
},
{
"partner": "RU",
"val": 10372167568
},
{
"partner": "GB",
"val": 14555013893
},
{
"partner": "US",
"val": 16838219917
},
{
"partner": "CN",
"val": 27876046083
},
{
"partner": "TOTAL",
"val": 143363806063
}
]
}]
let width = 500
let height = 500
let margin = 50
let x = d3.scaleBand()
.domain(["6/2017","7/2017","8/2017"])
.range([0, width])
.padding(0.3)
let y = d3.scaleLinear()
.domain([0, 145385348496])
.range([height, 0])
var svg = d3.select("body").append("svg")
.attr("width", width + margin + margin)
.attr("height", height + margin + margin)
var g = svg.append("g")
.attr("transform", "translate(" + margin + ", " + margin + ")")
var periods = g.selectAll("g")
.data(data)
.enter()
.append("g")
.attr("class", "period")
.attr("transform", function(d){
return "translate(" + x(d.period) + ", " + 0 + ")"
})
.each(appendCountries)
function appendCountries(period, i){
let countries = []
let offset = 0
let colour = d3.scaleOrdinal(d3.schemeAccent);
period.data.forEach(function(c){
if (c.partner != "TOTAL") { //assuming that total should not be included
offset = offset + c.val
let obj = {}
obj.y = offset
obj.val = c.val
obj.partner = c.partner
countries.push(obj)
}
})
let rects = d3.select(this).selectAll("rect")
.data(countries)
.enter()
.append("rect")
.attr("width", x.bandwidth)
.attr("x", 0)
.attr("y", d => y(d.y))
.attr("height", d => height - y(d.val))
.style("fill", d => colour(d.partner))
.style("stroke", "white")
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
我必须使用 D3 创建一个可视化效果,如下图所示,时间序列,堆叠条形图:
数据集来自一位顾问,格式为 json 个对象的嵌套数组:
[{
"period": "6/2017",
"data": [
{
"partner": "TR",
"val": 5201888581
},
{
"partner": "CH",
"val": 8509470105
},
{
"partner": "RU",
"val": 10677690328
},
{
"partner": "GB",
"val": 16086915825
},
{
"partner": "US",
"val": 17817589838
},
{
"partner": "CN",
"val": 26120939253
},
{
"partner": "TOTAL",
"val": 145385348496
}
]
},
{
"period": "7/2017",
"data": [
{
"partner": "TR",
"val": 4832746886
},
{
"partner": "CH",
"val": 8194483975
},
{
"partner": "RU",
"val": 10082530447
},
{
"partner": "US",
"val": 15251181551
},
{
"partner": "GB",
"val": 15515343080
},
{
"partner": "CN",
"val": 27480148190
},
{
"partner": "TOTAL",
"val": 142118881451
}
]
},
{
"period": "8/2017",
"data": [
{
"partner": "TR",
"val": 4827335758
},
{
"partner": "CH",
"val": 7087004314
},
{
"partner": "RU",
"val": 10372167568
},
{
"partner": "GB",
"val": 14555013893
},
{
"partner": "US",
"val": 16838219917
},
{
"partner": "CN",
"val": 27876046083
},
{
"partner": "TOTAL",
"val": 143363806063
}
]
}
...
]
更准确地说,每个对象包含句点和对象的子数组、国家/地区代码和值:
{
period,
data: [{country,value},{country,value},{country,value}...]
}
数据数组包含不同数量的对象(国家记录),从 3 到 10 个和不同的国家(它们可以是任何联合国国家)。
我尝试使用 D3 (v5) 中的标准布局,例如 "stack" 但是,如您所见,我的数据与 d3 布局中所需的数据格式不匹配,即表格数据,如:
time field1 field2 field3
t1 v11 v12 v13
t2 v21 v22 v23
...
我不知道如何管理我的数据,请帮忙。发送.
LE:我也尝试过 chart.js 但由于类似问题失败了。
由于国家/地区的数量不同,您可以创建自己的函数来附加国家/地区的矩形元素。该示例使用 d3.selection.each 调用新函数,并在此函数中创建一个新数据数组,其中包含每个矩形的 y 偏移量。
let data = [{
"period": "6/2017",
"data": [
{
"partner": "TR",
"val": 5201888581
},
{
"partner": "CH",
"val": 8509470105
},
{
"partner": "RU",
"val": 10677690328
},
{
"partner": "GB",
"val": 16086915825
},
{
"partner": "US",
"val": 17817589838
},
{
"partner": "CN",
"val": 26120939253
},
{
"partner": "TOTAL",
"val": 145385348496
}
]
},
{
"period": "7/2017",
"data": [
{
"partner": "TR",
"val": 4832746886
},
{
"partner": "CH",
"val": 8194483975
},
{
"partner": "RU",
"val": 10082530447
},
{
"partner": "US",
"val": 15251181551
},
{
"partner": "GB",
"val": 15515343080
},
{
"partner": "CN",
"val": 27480148190
},
{
"partner": "TOTAL",
"val": 142118881451
}
]
},
{
"period": "8/2017",
"data": [
{
"partner": "TR",
"val": 4827335758
},
{
"partner": "CH",
"val": 7087004314
},
{
"partner": "RU",
"val": 10372167568
},
{
"partner": "GB",
"val": 14555013893
},
{
"partner": "US",
"val": 16838219917
},
{
"partner": "CN",
"val": 27876046083
},
{
"partner": "TOTAL",
"val": 143363806063
}
]
}]
let width = 500
let height = 500
let margin = 50
let x = d3.scaleBand()
.domain(["6/2017","7/2017","8/2017"])
.range([0, width])
.padding(0.3)
let y = d3.scaleLinear()
.domain([0, 145385348496])
.range([height, 0])
var svg = d3.select("body").append("svg")
.attr("width", width + margin + margin)
.attr("height", height + margin + margin)
var g = svg.append("g")
.attr("transform", "translate(" + margin + ", " + margin + ")")
var periods = g.selectAll("g")
.data(data)
.enter()
.append("g")
.attr("class", "period")
.attr("transform", function(d){
return "translate(" + x(d.period) + ", " + 0 + ")"
})
.each(appendCountries)
function appendCountries(period, i){
let countries = []
let offset = 0
let colour = d3.scaleOrdinal(d3.schemeAccent);
period.data.forEach(function(c){
if (c.partner != "TOTAL") { //assuming that total should not be included
offset = offset + c.val
let obj = {}
obj.y = offset
obj.val = c.val
obj.partner = c.partner
countries.push(obj)
}
})
let rects = d3.select(this).selectAll("rect")
.data(countries)
.enter()
.append("rect")
.attr("width", x.bandwidth)
.attr("x", 0)
.attr("y", d => y(d.y))
.attr("height", d => height - y(d.val))
.style("fill", d => colour(d.partner))
.style("stroke", "white")
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>