我无法理解分组条形图中的exit()
选择如何工作。我的示例中只有空白的exit()
选择,因此在更新图表时不会从图表中删除任何内容。
这类似于此处发布的问题:d3 grouped bar chart update pattern not working。但是由于我在'g'
对象后附加了chartArea
,所以我认为该解决方案不适用。
我从这里松散地遵循分组/堆叠的条形图示例:https://bl.ocks.org/aholachek/fb0c1cd7ea9707bc8ff55a82402c54b1
完整的jsfiddle https://jsfiddle.net/fg_ti/ka306sjc/68/和代码:
var data1 = [
{
"sex": "female",
"n_patients": 5,
"grouping":"A"
},
{
"sex": "male",
"n_patients": 10,
"grouping": "A"
},
{
"sex": "female",
"n_patients": 25,
"grouping":"B"
},
{
"sex": "male",
"n_patients": 10,
"grouping":"B"
}];
var data2 = [
{
"sex": "female",
"n_patients": 62,
"grouping":"A"
},
{
"sex": "male",
"n_patients": 55,
"grouping":"A"
},
{
"sex": "female",
"n_patients": 25,
"grouping": "B"
},
{
"sex": "male",
"n_patients": 83,
"grouping":"B"
},
{
"sex": "female",
"n_patients": 25,
"grouping": "D"},
{
"sex": "male",
"n_patients": 83,
"grouping": "D"
}];
width = 350;
height = 450;
var initData = d3.nest().key(d => d.grouping).entries(data1)
var margin = ({top:10, right:10, bottom:10, left:30});
var Gwidth = width - margin.left - margin.right
var Gheight = height - margin.top - margin.bottom
var barPadding = 0.1;
var colors = ['#ffe1e1', '#d1ecfd']
svg = d3.select('body').append('svg')
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
var topG = svg.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top +')')
// Initial scale
// Scale between the keys (i.e. b/w age groups, edu, etc`)
var scaleX = d3.scaleBand()
.domain(initData.map(d => d.key))
.range([0, Gwidth])
.padding(barPadding);
var scaleColors = d3.scaleOrdinal()
.range(colors)
// Initial axis
var yAxis = topG.append('g')
.attr("class", "y axis")
var xAxis = topG.append('g')
.attr("class", "x axis")
xAxis.call(d3.axisBottom(scaleX))
.attr("transform", 'translate(' + 0 + "," + Gheight + ')');
var chartArea = topG.append("g")
.attr("class", "chartArea");
// UPDATE FUNCTION - will be called by r2d3.onRender()
function update(inData) {
// Reshape data
var newData = d3.nest()
.key(d => d.grouping)
.entries(inData);
var maxY = d3.max(newData, d => d3.max(d.values, k => k.n_patients));
grouping1Names = newData.map(d => d.key);
grouping2Names = newData[0].values.map(d => d.sex);
var t = 1000;
// Scales used in updates
var scaleY = d3.scaleLinear()
.domain([0, maxY])
.range([Gheight, 0]);
var scaleX = d3.scaleBand()
.domain(grouping1Names)
.range([0, Gwidth])
.padding(barPadding);
var scaleX1 = d3.scaleBand()
.domain(grouping2Names)
.rangeRound([0, scaleX.bandwidth()]);
// Perform the data join
var barGroupWithData = chartArea
.selectAll('.barGroup')
.data(newData);
barGroupWithData.exit().remove();
// Join rect elements with data - specified with keys
var bars = barGroupWithData.enter()
.append("g")
.attr("transform", d => "translate(" + scaleX(d.key) + ",0)")
.attr("fill", "steelblue")
.merge(barGroupWithData)
.selectAll("rect")
.data(d => Object.keys(d.values)
.map(k => ({ keyL2: grouping2Names[k], value: d.values[k].n_patients }) ));
console.log(bars)
// Remove rect elements joined with data that is no longer present
bars.exit().remove()
bars.enter()
.append("rect")
.attr("fill", d => scaleColors(d.keyL2))
.attr("y", d => scaleY(0))
.merge(bars)
.attr("x", (d) => scaleX1(d.keyL2))
.attr("width", scaleX1.bandwidth())
.transition()
.duration(t)
.ease(d3.easeLinear)
.attr('y', d => scaleY(d.value))
.attr("height", d => scaleY(0) - scaleY(d.value));
console.log(bars)
// Udpate axes
yAxis.transition()
.duration(t)
.call(d3.axisLeft(scaleY))
xAxis.transition()
.duration(t)
.call(d3.axisBottom(scaleX))
}
//
update(data1);
// Update the data
setInterval(function (newDat) {
if(Math.random()>0.5) {
d = data1
} else {
d = data2
}
return update(d);
}, 3000);
我怀疑我没有正确加入数据,但是无法查明错误的出处。该问题的第一个发布答案似乎很接近,但不适用于我的解决方案:Exit() is not working for d3 group bar chart。
是否有建议从图表中正确删除旧数据?
====================编辑============
为澄清起见,我修改了数据以更好地突出问题(updated jsfidlde)。数据似乎可以很好地加入rect
元素-每次更新时,都会添加新的小节。但是,不会删除旧的rect
元素。
由于将数据连接到rect
的键是这样指定的:
(.data(d => Object.keys(d.values)
.map(k => ({ keyL2: grouping2Names[k], value: d.values[k].n_patients }) ));` `.enter()`
因此,我希望.data()
将传入数据与现有rect
元素中的数据进行匹配。 如果传入数据的n_patients
或grouping
具有不同的值,我认为d3会将新数据识别为“正在输入”,并附加地添加n_patient
中已经存在的数据或grouping
的值与“退出”并删除的新数据不匹配。这是基于以下问题的答案:D3 Key Function;以及来自Mike Bostock的old blog post
由于在每个rect
调用中都添加了新的.enter()
,因此d3似乎正在识别“输入”数据,但未按照编写代码的方式识别“正在退出”数据。有人可以阐明这一点吗?