堆积的条形图未显示,控制台日志中也没有错误

时间:2019-12-01 21:23:50

标签: javascript d3.js

我想用过滤选项绘制这张堆积的条形图,但是它没有显示出来,我也不知道问题出在哪里。我在控制台中没有任何错误。 Here是完整代码。

在下面,您可以找到我不知道为什么无法可视化条形图的javascript部分:

var csv = [
  {
    "Year": 2017,
    "State": "AL",
    "Under 5 Years": 552,
    "5 to 13 Years": 259,
    "14 to 17 Years": 310
  },
  {
    "Year": 2017,
    "State": "AK",
    "Under 5 Years": 856,
    "5 to 13 Years": 421,
    "14 to 17 Years": 520
  }
]


function chart(csv) {

    var keys = csv.columns.slice(2);

    var year   = [...new Set(csv.map(d => d.Year))]
    var states = [...new Set(csv.map(d => d.State))]

    var options = d3.select("#year").selectAll("option")
        .data(year)
    .enter().append("option")
        .text(d => d)

    var svg = d3.select("#chart"),
        margin = {top: 35, left: 35, bottom: 0, right: 0},
        width = +svg.attr("width") - margin.left - margin.right,
        height = +svg.attr("height") - margin.top - margin.bottom;

    var x = d3.scaleBand()
        .range([margin.left, width - margin.right])
        .padding(0.1)

    var y = d3.scaleLinear()
        .rangeRound([height - margin.bottom, margin.top])

    var xAxis = svg.append("g")
        .attr("transform", `translate(0,${height - margin.bottom})`)
        .attr("class", "x-axis")

    var yAxis = svg.append("g")
        .attr("transform", `translate(${margin.left},0)`)
        .attr("class", "y-axis")

    var z = d3.scaleOrdinal()
        .range(["steelblue", "darkorange", "lightblue"])
        .domain(keys);

    update(d3.select("#year").property("value"), 0)

    function update(input, speed) {

        var data = csv.filter(f => f.Year == input)

        data.forEach(function(d) {
            d.total = d3.sum(keys, k => +d[k])
            return d
        })

        y.domain([0, d3.max(data, d => d3.sum(keys, k => +d[k]))]).nice();

        svg.selectAll(".y-axis").transition().duration(speed)
            .call(d3.axisLeft(y).ticks(null, "s"))

        data.sort(d3.select("#sort").property("checked")
            ? (a, b) => b.total - a.total
            : (a, b) => states.indexOf(a.State) - states.indexOf(b.State))

        x.domain(data.map(d => d.State));

        svg.selectAll(".x-axis").transition().duration(speed)
            .call(d3.axisBottom(x).tickSizeOuter(0))

        var group = svg.selectAll("g.layer")
            .data(d3.stack().keys(keys)(data), d => d.key)

        group.exit().remove()

        group.enter().append("g")
            .classed("layer", true)
            .attr("fill", d => z(d.key));

        var bars = svg.selectAll("g.layer").selectAll("rect")
            .data(d => d, e => e.data.State);

        bars.exit().remove()

        bars.enter().append("rect")
            .attr("width", x.bandwidth())
            .merge(bars)
        .transition().duration(speed)
            .attr("x", d => x(d.data.State))
            .attr("y", d => y(d[1]))
            .attr("height", d => y(d[0]) - y(d[1]))

        var text = svg.selectAll(".text")
            .data(data, d => d.State);

        text.exit().remove()

        text.enter().append("text")
            .attr("class", "text")
            .attr("text-anchor", "middle")
            .merge(text)
        .transition().duration(speed)
            .attr("x", d => x(d.State) + x.bandwidth() / 2)
            .attr("y", d => y(d.total) - 5)
            .text(d => d.total)
    }

    var select = d3.select("#year")
        .on("change", function() {
            update(this.value, 750)
        })

    var checkbox = d3.select("#sort")
        .on("click", function() {
            update(select.property("value"), 750)
        })
}

chart(csv);

1 个答案:

答案 0 :(得分:1)

“控制台中没有错误” 是什么意思?错误明确指出:

  

未定义不是对象(评估“ csv.columns.slice”)

正在发生的事情是您正在使用名为columns的属性,但是csv中没有这样的属性,它只是一个JavaScript数组。加载外部CSV文件时,columns属性是由d3.csvd3.csvParse(在您的版本为d3.csv.parse)中创建的。

话虽如此,只要做:

var keys = Object.keys(csv[0]).slice(2);

这是上述D3方法创建的columns属性的简单替代方案。这就是它的作用:顾名思义,Object.keys是指定对象的密钥。由于数组中的所有对象都具有相同的键,因此我们只需要第一个键,因此就是csv[0]。然后,使用拼接,删除前两个键,即YearState

var csv = [{
  "Year": 2017,
  "State": "AL",
  "Under 5 Years": 552,
  "5 to 13 Years": 259,
  "14 to 17 Years": 310
}];
console.log(Object.keys(csv[0]).slice(2));

如您所见,重要信息是要删除的元素的索引。

这是您的代码,只有该更改:

var csv = [
  {
    "Year": 2017,
    "State": "AL",
    "Under 5 Years": 552,
    "5 to 13 Years": 259,
    "14 to 17 Years": 310
  },
  {
    "Year": 2017,
    "State": "AK",
    "Under 5 Years": 856,
    "5 to 13 Years": 421,
    "14 to 17 Years": 520
  },
  {
    "Year": 2017,
    "State": "AZ",
    "Under 5 Years": 828,
    "5 to 13 Years": 362,
    "14 to 17 Years": 515
  },
  {
    "Year": 2017,
    "State": "AR",
    "Under 5 Years": 343,
    "5 to 13 Years": 157,
    "14 to 17 Years": 202
  },
  {
    "Year": 2017,
    "State": "CA",
    "Under 5 Years": 449,
    "5 to 13 Years": 215,
    "14 to 17 Years": 270
  },
  {
    "Year": 2017,
    "State": "CO",
    "Under 5 Years": 587,
    "5 to 13 Years": 261,
    "14 to 17 Years": 358
  },
  {
    "Year": 2017,
    "State": "CT",
    "Under 5 Years": 403,
    "5 to 13 Years": 196,
    "14 to 17 Years": 211
  },
  {
    "Year": 2017,
    "State": "DE",
    "Under 5 Years": 794,
    "5 to 13 Years": 474,
    "14 to 17 Years": 593
  },
  {
    "Year": 2018,
    "State": "AL",
    "Under 5 Years": 310,
    "5 to 13 Years": 552,
    "14 to 17 Years": 259
  },
  {
    "Year": 2018,
    "State": "AK",
    "Under 5 Years": 520,
    "5 to 13 Years": 556,
    "14 to 17 Years": 421
  },
  {
    "Year": 2018,
    "State": "AZ",
    "Under 5 Years": 515,
    "5 to 13 Years": 828,
    "14 to 17 Years": 362
  },
  {
    "Year": 2018,
    "State": "AR",
    "Under 5 Years": 202,
    "5 to 13 Years": 343,
    "14 to 17 Years": 157
  },
  {
    "Year": 2018,
    "State": "CA",
    "Under 5 Years": 270,
    "5 to 13 Years": 449,
    "14 to 17 Years": 215
  },
  {
    "Year": 2018,
    "State": "CO",
    "Under 5 Years": 358,
    "5 to 13 Years": 587,
    "14 to 17 Years": 261
  },
  {
    "Year": 2018,
    "State": "CT",
    "Under 5 Years": 211,
    "5 to 13 Years": 403,
    "14 to 17 Years": 196
  },
  {
    "Year": 2018,
    "State": "DE",
    "Under 5 Years": 593,
    "5 to 13 Years": 994,
    "14 to 17 Years": 474
  }
]


function chart(csv) {

	var keys = Object.keys(csv[0]).slice(2);

	var year   = [...new Set(csv.map(d => d.Year))]
	var states = [...new Set(csv.map(d => d.State))]

	var options = d3.select("#year").selectAll("option")
		.data(year)
	.enter().append("option")
		.text(d => d)

	var svg = d3.select("#chart"),
		margin = {top: 35, left: 35, bottom: 0, right: 0},
		width = +svg.attr("width") - margin.left - margin.right,
		height = +svg.attr("height") - margin.top - margin.bottom;

	var x = d3.scaleBand()
		.range([margin.left, width - margin.right])
		.padding(0.1)

	var y = d3.scaleLinear()
		.rangeRound([height - margin.bottom, margin.top])

	var xAxis = svg.append("g")
		.attr("transform", `translate(0,${height - margin.bottom})`)
		.attr("class", "x-axis")

	var yAxis = svg.append("g")
		.attr("transform", `translate(${margin.left},0)`)
		.attr("class", "y-axis")

	var z = d3.scaleOrdinal()
		.range(["steelblue", "darkorange", "lightblue"])
		.domain(keys);

	update(d3.select("#year").property("value"), 0)

	function update(input, speed) {

		var data = csv.filter(f => f.Year == input)

		data.forEach(function(d) {
			d.total = d3.sum(keys, k => +d[k])
			return d
		})

		y.domain([0, d3.max(data, d => d3.sum(keys, k => +d[k]))]).nice();

		svg.selectAll(".y-axis").transition().duration(speed)
			.call(d3.axisLeft(y).ticks(null, "s"))

		data.sort(d3.select("#sort").property("checked")
			? (a, b) => b.total - a.total
			: (a, b) => states.indexOf(a.State) - states.indexOf(b.State))

		x.domain(data.map(d => d.State));

		svg.selectAll(".x-axis").transition().duration(speed)
			.call(d3.axisBottom(x).tickSizeOuter(0))

		var group = svg.selectAll("g.layer")
			.data(d3.stack().keys(keys)(data), d => d.key)

		group.exit().remove()

		group.enter().append("g")
			.classed("layer", true)
			.attr("fill", d => z(d.key));

		var bars = svg.selectAll("g.layer").selectAll("rect")
			.data(d => d, e => e.data.State);

		bars.exit().remove()

		bars.enter().append("rect")
			.attr("width", x.bandwidth())
			.merge(bars)
		.transition().duration(speed)
			.attr("x", d => x(d.data.State))
			.attr("y", d => y(d[1]))
			.attr("height", d => y(d[0]) - y(d[1]))

		var text = svg.selectAll(".text")
			.data(data, d => d.State);

		text.exit().remove()

		text.enter().append("text")
			.attr("class", "text")
			.attr("text-anchor", "middle")
			.merge(text)
		.transition().duration(speed)
			.attr("x", d => x(d.State) + x.bandwidth() / 2)
			.attr("y", d => y(d.total) - 5)
			.text(d => d.total)
	}

	var select = d3.select("#year")
		.on("change", function() {
			update(this.value, 750)
		})

	var checkbox = d3.select("#sort")
		.on("click", function() {
			update(select.property("value"), 750)
		})
}

chart(csv);
.axis .domain {
  display: none;
}
<html>
<head>
<meta charset ="utf-8">
<script src="https://d3js.org/d3.v5.min.js"></script>
<style>
	
body {
	margin: auto;
	width: 650px;
	font: 12px arial;
}

</style>
</head>

<body>

<svg id="chart" width="650" height="400"></svg>

Select year: 
<select id="year"></select>

<input type="checkbox" id="sort">	
Toggle sort 


</body>
</html>