出于兩個原因,我將使其變得有點冗長:
- 為了證明我已經努力嘗試解決我提出的問題,因為互聯網上有太多轉瞬即逝的東西
- D3 很棒,因為它很復雜,很難完全理解。最近的主要版本強調了資料連接的使用,旨在簡化一般的更新模式。
因此,這可能是一篇文章,但我真的很想了解我的問題的答案,所以請耐心等待。
語境
我想創建一個動態堆疊水平條形圖,以可視化
在上面的例子中,資料系結不是按月,而是按水果。

最終狀態很好,但動態(過渡)資料更改將很困難。
這是一個比較復雜的領域。我坦率地承認我不理解博斯托克對堆疊的使用,取自他上面提到的例子:
// Compute a nested array of series where each series is [[x1, x2], [x1, x2],
// [x1, x2], …] representing the x-extent of each stacked rect. In addition,
// each tuple has an i (index) property so that we can refer back to the
// original data point (data[i]). This code assumes that there is only one
// data point for a given unique y- and z-value.
const series = d3.stack()
.keys(zDomain)
.value(([, I], z) => X[I.get(z)])
.order(order)
.offset(offset)
(d3.rollup(I, ([i]) => i, i => Y[i], i => Z[i]))
.map(s => s.map(d => Object.assign(d, {i: d.data[1].get(s.key)})));
嵌套資料連接
也許有人可以進一步闡明上述情況。也許我對堆疊不了解(很可能;)。也許如果圖表是垂直的而不是水平的,事情會更容易嗎?不知道。
我決定放棄 D3 Stacks,轉而使用資料連接嵌套資料,有點回歸基礎。
重復閱讀博斯托克關于
Thank you for reading and happy new year :))
-* Unfortunately I can not post links to JSFiddle as the most recent D3 version supported is version 5 and I am (perhaps unnecessarily) using the most recent version, 7. Bostock has started using a platform that allows experimentation called Observable but I find to be confusing.
uj5u.com熱心網友回復:
這是一個使用水果資料集的示例。該圖表具有影片效果,因此一次顯示一種水果的條形圖。為此,我為每個水果的條提供了不同的過渡延遲。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script src="https://d3js.org/d3.v7.js"></script>
</head>
<body>
<div id="chart"></div>
<script>
// set up
const margin = { top: 10, right: 10, bottom: 20, left: 40 };
const width = 300 - margin.left - margin.right;
const height = 200 - margin.top - margin.bottom;
const svg = d3.select('#chart')
.append('svg')
.attr('width', width margin.left margin.right)
.attr('height', height margin.top margin.bottom)
.append('g')
.attr('transform', `translate(${margin.left},${margin.top})`);
// data
const data = [
{month: "Jan", apples: 3840, bananas: 1920, cherries: 960, dates: 400},
{month: "Feb", apples: 1600, bananas: 1440, cherries: 960, dates: 400},
{month: "March", apples: 640, bananas: 960, cherries: 640, dates: 400},
{month: "Apr", apples: 3120, bananas: 1480, cherries: 640, dates: 400}
];
const fruit = Object.keys(data[0]).filter(d => d != "month");
const months = data.map(d => d.month);
const stackedData = d3.stack()
.keys(fruit)(data);
const xMax = d3.max(stackedData[stackedData.length - 1], d => d[1]);
// scales
const x = d3.scaleLinear()
.domain([0, xMax]).nice()
.range([0, width]);
const y = d3.scaleBand()
.domain(months)
.range([0, height])
.padding(0.25);
const color = d3.scaleOrdinal()
.domain(fruit)
.range(d3.schemeTableau10);
// axes
const xAxis = d3.axisBottom(x).ticks(5, '~s');
const yAxis = d3.axisLeft(y);
svg.append('g')
.attr('transform', `translate(0,${height})`)
.call(xAxis)
.call(g => g.select('.domain').remove());
svg.append("g")
.call(yAxis)
.call(g => g.select('.domain').remove());
// draw bars
// create one group for each fruit
const layers = svg.append('g')
.selectAll('g')
.data(stackedData)
.join('g')
.attr('fill', d => color(d.key));
// transition for bars
const duration = 1000;
const t = d3.transition()
.duration(duration)
.ease(d3.easeLinear);
layers.each(function(_, i) {
// this refers to the group for a given fruit
d3.select(this)
.selectAll('rect')
.data(d => d)
.join('rect')
.attr('x', d => x(d[0]))
.attr('y', d => y(d.data.month))
.attr('height', y.bandwidth())
.transition(t)
// i is the index of this fruit.
// this will give the bars for each fruit a different delay
// so that the fruits will be revealed one at a time.
// using .each() instead of a normal data join is needed
// so that we have access to what fruit each bar belongs to.
.delay(i * duration)
.attr('width', d => x(d[1]) - x(d[0]));
});
</script>
</body>
</html>
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/401971.html
標籤:d3.js
上一篇:如何使用d3js設定比例?
