在使用数据数组时,D3图表无法显示柱状图中的柱子,遇到了麻烦
我有一组数据,包含年份和百分比,正在尝试用d3绘制柱状图。输入一组我确信能工作的数字时,可以画出一个柱状条,但在使用x 轴、y轴以及一个数据数组时,屏幕上却没有任何显示。我没有收到任何错误信息。
我对d3还很新,学习曲线也挺陡的,所以如果有人能解释这里的问题,我将不胜感激。
<!DOCTYPE html>
<div id="container"></div>
<script src="https://cdn.jsdelivr.net/npm/d3@7"></script>
<script type="module">
// Declare the chart dimensions and margins.
const width = 1140;
const height = 500;
const marginTop = 20;
const marginRight = 20;
const marginBottom = 50;
const marginLeft = 70;
// Declare the x (horizontal position) scale.
const x = d3.scaleUtc()
.domain([new Date("2017-01-01"), new Date("2024-01-01")])
.range([marginLeft, width - marginRight]); //same as .range([70,1120])
// Declare the y (vertical position) scale.
const y = d3.scaleLinear()
.domain([0, 1.00])
.range([height - marginBottom, marginTop]); //same as .range([350, 20])
// Create the SVG container.
const svg = d3.create("svg")
.attr("width", width)
.attr("height", height);
// Add the x-axis.
svg.append("g")
.attr("transform", `translate(0,${height - marginBottom})`)
.call(d3.axisBottom(x)
.ticks(d3.utcYear.every(1))
);
// Add the y-axis.
svg.append("g")
.attr("transform", `translate(${marginLeft},0)`)
.call(d3.axisLeft(y));
svg.append("text")
.attr("class", "x label")
.attr("text-anchor", "end")
.attr("x", width/2)
.attr("y", height - 6)
.text("Year");
svg.append("text")
.attr("class", "y label")
.attr("text-anchor", "end")
.attr("x", -height/3)
.attr("y", 6)
.attr("dy", ".75em")
.attr("transform", "rotate(-90)")
.text("Percent of students");
var heightOfY = height-marginBottom;
var Xmin = 2017;
var Xmax = 2024;
var numTicks = Xmax - Xmin;
var XmaxRange = width - marginRight - marginLeft;
var eachTickWidth = XmaxRange/numTicks;
var barWidth = eachTickWidth/3;
var arrMMR = [{year: '2017', percent: '1.00'},{year: '2018', percent: '0.98'},{year: '2019', percent: '0.98'},{year: '2021', percent: '1.00'},{year: '2022', percent: '1.00'},{year: '2023', percent: '0.83'},{year: '2024', percent: '1.00'}];
// this single bar works
/*svg.append('rect')
.attr('x', marginLeft)
.attr('y', function() {
return y(.9)//height/10 * 9) //height = 500, marginBottom = 50 //400
})
.attr('width', barWidth)
.attr('height', function() {
return ( (.9* height) - marginBottom - 12)
})
.attr('fill', 'steelblue');*/
svg.selectAll("mybar") //this doesn't work
.data(arrMMR)
.enter()
.append("rect")
.attr("x", function(d) { return x(d.year); })
.attr("y", function(d) { return y(d.percent); })
.attr("width", x.barWidth)
.attr("height", function(d) { return height - y(d.percent); })
.attr("fill", "#69b3a2")
// Append the SVG element.
container.append(svg.node());
</script>
解决方案
It has to do with the way I fed in the data. The percents should have been numbers, not strings. So the data should look like this:
var arrMMR = [{year: '2017', percent: 1.00},{year: '2018', percent: 0.98},{year: '2019', percent: 0.98},{year: '2021', percent: 1.00},{year: '2022', percent: 1.00},{year: '2023', percent: 0.83},{year: '2024', percent: 1.00}];
Then the code to put in the rectangles should treat the years as new Dates:
svg.selectAll("mybar") .data(arrMMR) .enter() .append("rect") .attr("x", function(d) { return x(new Date(d.year)) - (barWidth/2); }) .attr("y", function(d) { return y(d.percent); }) .attr("width", barWidth) .attr("height", function(d) { return heightOfY - y(d.percent); }) .attr("fill", "steelblue")
So the whole code looks like this:
`
// Declare the chart dimensions and margins. const width = 1140; const height = 500; const marginTop = 20; const marginRight = 20; const marginBottom = 50; const marginLeft = 70;
// Declare the x (horizontal position) scale.
const x = d3.scaleUtc() .domain([new Date("2016-01-01"), new Date("2025-01-01")]) .range([marginLeft, width - marginRight]); //same as .range([70,1120])
// Declare the y (vertical position) scale.
const y = d3.scaleLinear() .domain([0, 1.00]) .range([height - marginBottom, marginTop]); //same as .range([350, 20])
// Create the SVG container. const svg = d3.create("svg") .attr("width", width) .attr("height", height);
// Add the x-axis.
svg.append("g")
.attr("transform", translate(0,${height - marginBottom}))
.call(d3.axisBottom(x)
.ticks(d3.utcYear.every(1))
);
// Add the y-axis.
svg.append("g")
.attr("transform", translate(${marginLeft},0))
.call(d3.axisLeft(y));
svg.append("text") .attr("class", "x label") .attr("text-anchor", "end") .attr("x", width/2) .attr("y", height - 6) .text("Year");
svg.append("text") .attr("class", "y label") .attr("text-anchor", "end") .attr("x", -height/3) .attr("y", 6) .attr("dy", ".75em") .attr("transform", "rotate(-90)") .text("Percent of students");
var heightOfY = height-marginBottom; var Xmin = 2017; var Xmax = 2024; var numTicks = Xmax - Xmin; var XmaxRange = width - marginRight - marginLeft; var eachTickWidth = XmaxRange/numTicks; var barWidth = eachTickWidth/3;
var arrMMR = [{year: '2017', percent: 1.00},{year: '2018', percent: 0.98},{year: '2019', percent: 0.98},{year: '2021', percent: 1.00},{year: '2022', percent: 1.00},{year: '2023', percent: 0.83},{year: '2024', percent: 1.00}];
svg.selectAll("mybar") .data(arrMMR) .enter() .append("rect") .attr("x", function(d) { return x(new Date(d.year)) - (barWidth/2); }) .attr("y", function(d) { return y(d.percent); }) .attr("width", barWidth) .attr("height", function(d) { return heightOfY - y(d.percent); }) .attr("fill", "steelblue")
// Append the SVG element. container.append(svg.node());
`