Reputation: 2617
I have a simplified version of my project that I condensed into this snippet:
var margins = {top:20, bottom:300, left:100, right:100};
var height = 600;
var width = 1200;
var totalWidth = width+margins.left+margins.right;
var totalHeight = height+margins.top+margins.bottom;
var svg = d3.select('body')
.append('svg')
.attr('width', totalWidth)
.attr('height', totalHeight);
var graphGroup = svg.append('g')
.attr('transform', "translate("+margins.left+","+margins.top+")");
var data = [
{'manager':'ABC-CA', 'aum':230561804112.86996, 'type':'JV'},
{'manager':'AEGON-Industrial', 'aum':187676730861.82004, 'type':'JV'},
{'manager':'AVIC', 'aum':677643221.8599999, 'type':'DM'},
{'manager':'AXA-SPDB', 'aum':111220010833.66998, 'type':'JV'},
{'manager':'Baoying', 'aum':26328526612.41, 'type':'DM'},
{'manager':'Beixin Ruifeng', 'aum':10500065729.3, 'type':'JV'},
{'manager':'BOB-Scotiabank', 'aum':69159188249.67, 'type':'JV'},
{'manager':'BOC IM', 'aum':396466612963.73, 'type':'DM'},
{'manager':'BOCI Securities', 'aum':57940275708.97, 'type':'JV'}
];
var yExtents = d3.extent(data, function(d) {return d.aum; })
var xScale = d3.scaleBand()
.rangeRound([0, width])
.domain(data.map(function(d) {return d.manager; }));
var yScale = d3.scaleLinear()
.range([height,0])
.domain(yExtents);
graphGroup.append("g")
.attr("class", "axis axis--y")
.attr("transform", "translate(0," + 0 + ")")
.call(d3.axisRight(yScale))
.selectAll("text")
.attr('text-align','right')
.attr("transform", "translate(-90,0)");
graphGroup.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(xScale))
.selectAll("text")
.attr("transform", "translate(0,0)");
var bars = graphGroup.selectAll('rect')
.data(data)
.enter()
.append('rect')
.attr('x', function(d) {return xScale(d.manager); })
.attr('y', function(d) {return yScale(d.aum); })
.attr('width', xScale.bandwidth())
.attr('height', function(d) {return height-yScale(d.aum); })
.style('fill','#003366');
d3.select('#rd1').on('click', function() {
var newData = data;
bars.data(newData).enter()
.append('rect');
bars.transition()
.duration(750)
.attr('x', function(d) {return xScale(d.manager); })
.attr('y', function(d) {return yScale(d.aum); })
.attr('height', function(d) {return height-yScale(d.aum); })
.style('fill','#003366');
});
d3.select('#rd2').on('click', function() {
var newData = data.filter(function(d) {return d.type=="JV"});
bars.data(newData).exit().remove();
bars.enter()
.attr('x', function(d) {return xScale(d.manager); })
.attr('y',height);
bars.transition()
.duration(750)
.attr('x', function(d) {return xScale(d.manager); })
.attr('y', function(d) {return yScale(d.aum); })
.attr('height', function(d) {return height-yScale(d.aum); });
});
<form>
<label class='radio-label'>All <input type="radio" name="level" value="all" checked="checked" id='rd1'></input></label>
<label class='radio-label'>JV <input type="radio" name="level" value="jv" id='rd2'></input></label>
</form>
<script src="https://d3js.org/d3.v5.min.js"></script>
My intent is to filter the data by d.type=='JV'
when the user clicks on the "JV" radio button, and that much works. However, my function for the "All" radio button doesn't work as I anticipated and troubleshooting it has proven problematic. The "All" radio button is supposed to display the whole data set again, but it only displays part of the data set, so it's missing values and I can't figure out how to make it right.
In the console log the console.log(newData.length)
is the correct number: 9, but there are only 5 rects appended.
Is my enter, update, exit implementation flawed, and if so, how do I fix it such that my data can be displayed in full again after filtering?
Upvotes: 2
Views: 184
Reputation: 2896
var margins = {
top: 20,
bottom: 300,
left: 100,
right: 100
};
var height = 600;
var width = 1200;
var totalWidth = width + margins.left + margins.right;
var totalHeight = height + margins.top + margins.bottom;
var svg = d3.select('body')
.append('svg')
.attr('width', totalWidth)
.attr('height', totalHeight);
var graphGroup = svg.append('g')
.attr('transform', "translate(" + margins.left + "," + margins.top + ")");
var data = [{
'manager': 'ABC-CA',
'aum': 230561804112.86996,
'type': 'JV'
},
{
'manager': 'AEGON-Industrial',
'aum': 187676730861.82004,
'type': 'JV'
},
{
'manager': 'AVIC',
'aum': 677643221.8599999,
'type': 'DM'
},
{
'manager': 'AXA-SPDB',
'aum': 111220010833.66998,
'type': 'JV'
},
{
'manager': 'Baoying',
'aum': 26328526612.41,
'type': 'DM'
},
{
'manager': 'Beixin Ruifeng',
'aum': 10500065729.3,
'type': 'JV'
},
{
'manager': 'BOB-Scotiabank',
'aum': 69159188249.67,
'type': 'JV'
},
{
'manager': 'BOC IM',
'aum': 396466612963.73,
'type': 'DM'
},
{
'manager': 'BOCI Securities',
'aum': 57940275708.97,
'type': 'JV'
}
];
var yExtents = d3.extent(data, function(d) {
return d.aum;
})
var xScale = d3.scaleBand()
.rangeRound([0, width])
.domain(data.map(function(d) {
return d.manager;
}));
var yScale = d3.scaleLinear()
.range([height, 0])
.domain(yExtents);
graphGroup.append("g")
.attr("class", "axis axis--y")
.attr("transform", "translate(0," + 0 + ")")
.call(d3.axisRight(yScale))
.selectAll("text")
.attr('text-align', 'right')
.attr("transform", "translate(-90,0)");
graphGroup.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(xScale))
.selectAll("text")
.attr("transform", "translate(0,0)");
function applyData(newData) {
var bars = graphGroup
.selectAll('rect')
.data(newData);
bars.exit().remove();
bars.enter()
.append('rect')
.attr('x', function(d) {
return xScale(d.manager);
})
.attr('y', height)
.attr('width', xScale.bandwidth())
.style('fill', '#003366')
.merge(bars)
.transition()
.duration(750)
.attr('x', function(d) {
return xScale(d.manager);
})
.attr('y', function(d) {
return yScale(d.aum);
})
.attr('height', function(d) {
return height - yScale(d.aum);
});
}
d3.select('#rd1').on('click', function() {
applyData(data);
});
d3.select('#rd2').on('click', function() {
var newData = data.filter(function(d) {
return d.type == "JV"
});
applyData(newData);
});
applyData(data);
<form>
<label class='radio-label'>All <input type="radio" name="level" value="all" checked="checked" id='rd1'></input></label>
<label class='radio-label'>JV <input type="radio" name="level" value="jv" id='rd2'></input></label>
</form>
<script src="https://d3js.org/d3.v5.min.js"></script>
Selections are immutable -- you cannot save and reuse bars
selection in between different data
invokes. Also, you're duplicating your code in 3 places -- initial data and in each of the click handlers. I refactored your code by extracting it into one method.
Upvotes: 5