在下面的代码段中,我正在使用以下过滤器方法来获取所需的数据:
var data = csv.filter(d => d.date.includes(year))
这里的问题是,每当我更新图表时,每个柱形图都会从顶部重绘,而不是从先前的数据更新。
这是因为我在更新函数中重新声明了data
变量,因此它没有从以前的数据中更新吗?
是否有一种简单的方法来解决此问题,还是我必须每年重新映射和分隔一个新的数据数组,并以此为基础建立我的更新模式?
代码如下:
var csvData = `date,value
2018-jan,100
2018-feb,75
2018-mar,45
2018-apr,65
2019-jan,21
2019-feb,43
2019-mar,55
2019-apr,33`;
var csv = d3.csvParse(csvData, d => d)
var margin = {top: 25, bottom: 25, left: 25, right: 25};
var svg = d3.select("#chart"),
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)
.paddingOuter(0.2)
var xAxis = g => g
.attr("transform", "translate(0," + (height - margin.bottom) + ")")
.call(d3.axisBottom(x).tickSizeOuter(0))
svg.append("g")
.attr("class", "x-axis")
var y = d3.scaleLinear()
.range([height - margin.bottom, margin.top])
update("2018")
function update(year) {
var data = csv.filter(d => d.date.includes(year))
y.domain([0, d3.max(data, d => Math.max(d.value))])
x.domain(data.map(d => d.date))
svg.selectAll(".x-axis")
.call(xAxis);
var bar = svg.selectAll(".bar")
.data(data, d => d.date)
bar.exit().remove();
bar = bar
.enter()
.append("rect")
.attr("class", "bar")
.attr("fill", "steelblue")
.attr("width", x.bandwidth())
.attr("x", d => x(d.date))
.merge(bar)
.transition().duration(750)
.attr("y", d => y(d.value))
.attr("height", d => y(0) - y(d.value))
}
d3.select("#year").on("change", function() {
update(this.value)
})
body {
padding-top: 25px;
margin: auto;
width: 450px;
font: 11px arial;
}
<script src="https://d3js.org/d3.v5.min.js"></script>
Choose year
<select id="year">
<option value="2018">2018</option>
<option value="2019">2019</option>
</select><br>
<svg id="chart" width="450" height="200"></svg>
答案 0 :(得分:2)
这里的问题与过滤数据,重新分配变量,合并选择或问题和注释中提到的任何其他问题无关。
这里的问题仅仅是key function。当您指定键功能时,每个元素的数据将根据其字符串标识符进行绑定。而且,由于日期不同,因此预期的行为是应删除小节并绘制新的小节。
您想要的不是索引连接,而是索引连接。因此,将数据方法从...更改为
.data(data, d => d.date)
.. to:
.data(data)
仅此更改是您的代码:
var csvData = `date,value
2018-jan,100
2018-feb,75
2018-mar,45
2018-apr,65
2019-jan,21
2019-feb,43
2019-mar,55
2019-apr,33`;
var csv = d3.csvParse(csvData, d => d)
var margin = {top: 25, bottom: 25, left: 25, right: 25};
var svg = d3.select("#chart"),
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)
.paddingOuter(0.2)
var xAxis = g => g
.attr("transform", "translate(0," + (height - margin.bottom) + ")")
.call(d3.axisBottom(x).tickSizeOuter(0))
svg.append("g")
.attr("class", "x-axis")
var y = d3.scaleLinear()
.range([height - margin.bottom, margin.top])
update("2018")
function update(year) {
var data = csv.filter(d => d.date.includes(year))
y.domain([0, d3.max(data, d => Math.max(d.value))])
x.domain(data.map(d => d.date))
svg.selectAll(".x-axis")
.call(xAxis);
var bar = svg.selectAll(".bar")
.data(data)
bar.exit().remove();
bar = bar
.enter()
.append("rect")
.attr("class", "bar")
.attr("fill", "steelblue")
.attr("width", x.bandwidth())
.attr("x", d => x(d.date))
.merge(bar)
.transition().duration(750)
.attr("y", d => y(d.value))
.attr("height", d => y(0) - y(d.value))
}
d3.select("#year").on("change", function() {
update(this.value)
})
body {
padding-top: 25px;
margin: auto;
width: 450px;
font: 11px arial;
}
<script src="https://d3js.org/d3.v5.min.js"></script>
Choose year
<select id="year">
<option value="2018">2018</option>
<option value="2019">2019</option>
</select><br>
<svg id="chart" width="450" height="200"></svg>
答案 1 :(得分:1)
因此,我自己发现自己可以像这样在data
方法本身中进行过滤...
var bar = svg.selectAll(".bar")
.data(data.filter(f => f.date.includes(year)))
...并且所有内容都已正确更新,不确定是否应该关闭问题,但还是将其保留为当前状态:
这是更新的代码:
var csvData = `date,value
2018-jan,100
2018-feb,75
2018-mar,45
2018-apr,65
2019-jan,21
2019-feb,43
2019-mar,55
2019-apr,33`;
var data = d3.csvParse(csvData, d => d)
var margin = {top: 25, bottom: 25, left: 25, right: 25};
var svg = d3.select("#chart"),
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)
.paddingOuter(0.2)
var xAxis = g => g
.attr("transform", "translate(0," + (height - margin.bottom) + ")")
.call(d3.axisBottom(x).tickSizeOuter(0))
svg.append("g")
.attr("class", "x-axis")
var y = d3.scaleLinear()
.range([height - margin.bottom, margin.top])
update("2018")
function update(year) {
var maxVal = d3.max(data, function(d) {
var f = d.date.includes(year)
return (f == true ? d.value : null)
})
y.domain([0, maxVal]).nice()
x.domain(data.map(d => d.date).filter(f => f.includes(year)))
svg.selectAll(".x-axis")
.call(xAxis);
var bar = svg.selectAll(".bar")
.data(data.filter(f => f.date.includes(year)));
bar.exit().remove();
bar.enter()
.append("rect")
.attr("class", "bar")
.attr("fill", "steelblue")
.attr("width", x.bandwidth())
.attr("x", d => x(d.date))
.merge(bar)
.transition().duration(750)
.attr("y", d => y(d.value))
.attr("height", d => y(0) - y(d.value))
}
d3.select("#year").on("change", function() {
update(this.value)
})
body {
padding-top: 25px;
margin: auto;
width: 650px;
font: 11px arial;
}
<script src="https://d3js.org/d3.v5.min.js"></script>
Choose year
<select id="year">
<option value="2018">2018</option>
<option value="2019">2019</option>
</select><br>
<svg id="chart" width="650" height="200"></svg>