具有一般更新模式的堆积条形图 d3.js
Stacked Bar Chart with general update pattern d3.js
我知道这里有一些帖子,今天和昨天我已经非常努力地尝试了几个小时。
但是我无法让输入、更新、退出在最基本的意义上工作。
我一直在尝试将我制作的交互式条形图更改为堆叠条形图。
这根本没有用,我想尝试从示例 here 中获得最简单的案例。
然而,即使这样我也做不到。
我不明白为什么。
const margin = {top: 10, right: 30, bottom: 20, left: 50},
width = 800 - margin.left - margin.right,
height = 600 - margin.top - margin.bottom;
// append the svg object to the body of the page
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})`);
// Parse the Data
d3.csv("https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/data_stacked.csv").then( function(data) {
// List of subgroups = header of the csv files = soil condition here
const subgroups = data.columns.slice(1)
// List of groups = species here = value of the first column called group -> I show them on the X axis
const groups = data.map(d => (d.group))
// Add X axis
const x = d3.scaleBand()
.domain(groups)
.range([0, width])
.padding([0.2])
svg.append("g")
.attr("transform", `translate(0, ${height})`)
.call(d3.axisBottom(x).tickSizeOuter(0));
// Add Y axis
const y = d3.scaleLinear()
.domain([0, 60])
.range([ height, 0 ]);
svg.append("g")
.call(d3.axisLeft(y));
// color palette = one color per subgroup
const color = d3.scaleOrdinal()
.domain(subgroups)
.range(['#e41a1c','#377eb8','#4daf4a'])
//stack the data? --> stack per subgroup
const stackedData = d3.stack()
.keys(subgroups)
(data)
// Show the bars
let bars = svg.append("g")
.selectAll("g")
.data(stackedData, d => d)
bars.join(
enter => {
enter
.append('g')
.attr("fill", d => color(d.key))
.selectAll("rect")
.data(d=>d)
.attr("x", d => x(d.data.group))
.attr("y", d => y(d[1]))
.attr("height", d => y(d[0]) - y(d[1]))
.attr("width",x.bandwidth())
}, update => update, exit => exit.remove());
})
我只在 //Show the bars 之后更改了代码
如果不是 join(enter=> enter)
,它会起作用
我只用enter().append('g)
...等
我以为他们在做同样的事情?
最后,我一直在尝试直接从 D3 中绘制所有内容。自己做而不是使用 Observable 等地方的现成函数是不是很愚蠢?
我想学习,但我也想高效
感谢任何提示和帮助!
- 您需要 return
enter
选择(您使用的箭头函数没有 return 从中获取任何内容)
- 您需要在
selectAll('rect').data(d => d)
之后执行 .join('rect')
(如果您不加入,则不会向堆栈的 <g>
添加任何内容)
这是完整的工作解决方案(单击下面的 运行 代码片段 按钮):
const margin = {
top: 10,
right: 30,
bottom: 20,
left: 50
},
width = 800 - margin.left - margin.right,
height = 600 - margin.top - margin.bottom;
// append the svg object to the body of the page
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})`);
// Parse the Data
d3.csv(
"https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/data_stacked.csv"
).then(function(data) {
// List of subgroups = header of the csv files = soil condition here
const subgroups = data.columns.slice(1);
// List of groups = species here = value of the first column called group -> I show them on the X axis
const groups = data.map((d) => d.group);
// Add X axis
const x = d3.scaleBand().domain(groups).range([0, width]).padding([0.2]);
svg
.append("g")
.attr("transform", `translate(0, ${height})`)
.call(d3.axisBottom(x).tickSizeOuter(0));
// Add Y axis
const y = d3.scaleLinear().domain([0, 60]).range([height, 0]);
svg.append("g").call(d3.axisLeft(y));
// color palette = one color per subgroup
const color = d3
.scaleOrdinal()
.domain(subgroups)
.range(["#e41a1c", "#377eb8", "#4daf4a"]);
//stack the data? --> stack per subgroup
const stackedData = d3.stack().keys(subgroups)(data);
// Show the bars
let bars = svg
.append("g")
.selectAll("g")
.data(stackedData, (d) => d);
bars.join(
(enter) => {
// don't forget to return the enter selection after appending
return enter
.append("g")
.attr("fill", (d) => color(d.key))
.selectAll("rect")
.data((d) => d)
// don't forget to join 'rect'
.join("rect")
.attr("x", (d) => x(d.data.group))
.attr("y", (d) => y(d[1]))
.attr("height", (d) => y(d[0]) - y(d[1]))
.attr("width", x.bandwidth());
},
(update) => update,
(exit) => exit.remove()
);
});
<div id="chart"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.4.3/d3.min.js"></script>
我知道这里有一些帖子,今天和昨天我已经非常努力地尝试了几个小时。 但是我无法让输入、更新、退出在最基本的意义上工作。
我一直在尝试将我制作的交互式条形图更改为堆叠条形图。 这根本没有用,我想尝试从示例 here 中获得最简单的案例。 然而,即使这样我也做不到。 我不明白为什么。
const margin = {top: 10, right: 30, bottom: 20, left: 50},
width = 800 - margin.left - margin.right,
height = 600 - margin.top - margin.bottom;
// append the svg object to the body of the page
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})`);
// Parse the Data
d3.csv("https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/data_stacked.csv").then( function(data) {
// List of subgroups = header of the csv files = soil condition here
const subgroups = data.columns.slice(1)
// List of groups = species here = value of the first column called group -> I show them on the X axis
const groups = data.map(d => (d.group))
// Add X axis
const x = d3.scaleBand()
.domain(groups)
.range([0, width])
.padding([0.2])
svg.append("g")
.attr("transform", `translate(0, ${height})`)
.call(d3.axisBottom(x).tickSizeOuter(0));
// Add Y axis
const y = d3.scaleLinear()
.domain([0, 60])
.range([ height, 0 ]);
svg.append("g")
.call(d3.axisLeft(y));
// color palette = one color per subgroup
const color = d3.scaleOrdinal()
.domain(subgroups)
.range(['#e41a1c','#377eb8','#4daf4a'])
//stack the data? --> stack per subgroup
const stackedData = d3.stack()
.keys(subgroups)
(data)
// Show the bars
let bars = svg.append("g")
.selectAll("g")
.data(stackedData, d => d)
bars.join(
enter => {
enter
.append('g')
.attr("fill", d => color(d.key))
.selectAll("rect")
.data(d=>d)
.attr("x", d => x(d.data.group))
.attr("y", d => y(d[1]))
.attr("height", d => y(d[0]) - y(d[1]))
.attr("width",x.bandwidth())
}, update => update, exit => exit.remove());
})
我只在 //Show the bars 之后更改了代码
如果不是 join(enter=> enter)
我只用enter().append('g)
...等
我以为他们在做同样的事情?
最后,我一直在尝试直接从 D3 中绘制所有内容。自己做而不是使用 Observable 等地方的现成函数是不是很愚蠢? 我想学习,但我也想高效
感谢任何提示和帮助!
- 您需要 return
enter
选择(您使用的箭头函数没有 return 从中获取任何内容) - 您需要在
selectAll('rect').data(d => d)
之后执行.join('rect')
(如果您不加入,则不会向堆栈的<g>
添加任何内容)
这是完整的工作解决方案(单击下面的 运行 代码片段 按钮):
const margin = {
top: 10,
right: 30,
bottom: 20,
left: 50
},
width = 800 - margin.left - margin.right,
height = 600 - margin.top - margin.bottom;
// append the svg object to the body of the page
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})`);
// Parse the Data
d3.csv(
"https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/data_stacked.csv"
).then(function(data) {
// List of subgroups = header of the csv files = soil condition here
const subgroups = data.columns.slice(1);
// List of groups = species here = value of the first column called group -> I show them on the X axis
const groups = data.map((d) => d.group);
// Add X axis
const x = d3.scaleBand().domain(groups).range([0, width]).padding([0.2]);
svg
.append("g")
.attr("transform", `translate(0, ${height})`)
.call(d3.axisBottom(x).tickSizeOuter(0));
// Add Y axis
const y = d3.scaleLinear().domain([0, 60]).range([height, 0]);
svg.append("g").call(d3.axisLeft(y));
// color palette = one color per subgroup
const color = d3
.scaleOrdinal()
.domain(subgroups)
.range(["#e41a1c", "#377eb8", "#4daf4a"]);
//stack the data? --> stack per subgroup
const stackedData = d3.stack().keys(subgroups)(data);
// Show the bars
let bars = svg
.append("g")
.selectAll("g")
.data(stackedData, (d) => d);
bars.join(
(enter) => {
// don't forget to return the enter selection after appending
return enter
.append("g")
.attr("fill", (d) => color(d.key))
.selectAll("rect")
.data((d) => d)
// don't forget to join 'rect'
.join("rect")
.attr("x", (d) => x(d.data.group))
.attr("y", (d) => y(d[1]))
.attr("height", (d) => y(d[0]) - y(d[1]))
.attr("width", x.bandwidth());
},
(update) => update,
(exit) => exit.remove()
);
});
<div id="chart"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.4.3/d3.min.js"></script>