Reputation: 21
I am having an issue with binding data where the data is being bound to certain selections but not others.
For context, I have a series of rows in a csv file. Using d3, I iterate over each row and generate an svg for each row in the csv file. As demonstrated below.
var svgArea = d3.select("body").append("svg")
.attr("class", "barSvg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
I then intend to use this selection to bind a <g>
element and series of <rect>
elements to the svg selection:
//creating a <g> elements
var vehicleText = svgArea.select("g")
.data(d)
.enter()
.append("g")
.attr("id", function(d) {return "vehicle_" + d.vehicle});
//creating a grouped bar chart
var vehicleBars = svgArea.selectAll("rect")
.data(d.sales)
.enter()
.append("rect")
.attr("class", "vehicleBars")
.attr("id", function (d) {return "vehicle_" + d.vehicle + "_" + d.year})
.attr("width", width / 4)
.attr( "x", function (d){
return xYears(d.year)
})
.attr("y", function(d){
return yScale(d.value)
})
.attr("height", function(d) {return height - yScale(d.value)})
.attr("fill", function(d) {return colorScale(d.year)});
The issue is that the <g>
element doesn't appear however the <rect>
elements do despite using the exact same selection. I have been thinking that this is might be an issue with the way I am binding data to the elements. What exactly am I doing wrong here? Why does it bind the data for the one set of elements but not the set which proceeds it? For reference, here is my code
Upvotes: 2
Views: 166
Reputation: 102218
You have two main problems here:
There are already <g>
elements in the svg. So, instead of select("g")
, your enter selection should select something that doesn't exist, like selectAll("foo")
.
d
is an object. However, the data
function only accepts three things: an array, a function or nothing. So, it should be data([d])
.
This problem #2 explains why, as you said...
the data is being bound to certain selections but not others.
... and why your console.log(vehicleText.datum())
returns Cannot read property '__data__' of null
That being said, here is your updated plunker: https://plnkr.co/edit/igliOTB1eq1k31eQ9nY5?p=preview
This, however, is not the best way to achieve what you want, nor the way I'd do it myself: have in mind that here I'm only answering your question, and nothing more.
PS: don't use d
as the parameter for the data in your chartGenerator
function. In D3 codes, d
is usually used for the first parameter (the datum) in anonymous functions. Using d
as you did will add some confusion, specially for seasoned D3 coders.
Upvotes: 1
Reputation: 14589
You can directly set the properties to the label texts. Try this way.
var vehicleText = svgArea.append("g")
.attr("id", "vehicle_" + d.vehicle);
vehicleText.append("text")
.attr("class", "annotation")
.attr("dx","4em")
.attr("dy",height+20)
.text( d.vehicle);
var rows = [{
"vehicle": "Ford F - Series PU",
"Mar-2016": 65179,
"Mar-2017": 72089,
"perc_change": 10.6
},
{
"vehicle": "Chevrolet Silverado PU",
"Mar-2016": 45009,
"Mar-2017": 45280,
"perc_change": 0.6
},
{
"vehicle": "Dodge Ram PU",
"Mar-2016": 34152,
"Mar-2017": 36885,
"perc_change": 8
},
{
"vehicle": "Toyota Camry",
"Mar-2016": 30942,
"Mar-2017": 28189,
"perc_change": -8.9
},
{
"vehicle": "Toyota RAV4",
"Mar-2016": 27376,
"Mar-2017": 28116,
"perc_change": 2.7
},
{
"vehicle": "Honda Accord",
"Mar-2016": 25571,
"Mar-2017": 27182,
"perc_change": 6.3
},
{
"vehicle": "Toyota Corolla / Matrix",
"Mar-2016": 24183,
"Mar-2017": 26747,
"perc_change": 10.6
},
{
"vehicle": "Nissan Rogue",
"Mar-2016": 22566,
"Mar-2017": 26629,
"perc_change": 18
},
{
"vehicle": "Honda CR-V",
"Mar-2016": 25939,
"Mar-2017": 25758,
"perc_change": -0.7
},
{
"vehicle": "Honda Civic",
"Mar-2016": 25052,
"Mar-2017": 25303,
"perc_change": 1
},
{
"vehicle": "Ford Escape",
"Mar-2016": 20806,
"Mar-2017": 23012,
"perc_change": 10.6
},
{
"vehicle": "Chevrolet Equinox",
"Mar-2016": 19636,
"Mar-2017": 21600,
"perc_change": 10
},
{
"vehicle": "Toyota Highlander",
"Mar-2016": 12742,
"Mar-2017": 21241,
"perc_change": 66.7
},
{
"vehicle": "Nissan Altima",
"Mar-2016": 20573,
"Mar-2017": 20039,
"perc_change": -2.6
},
{
"vehicle": "Ford Explorer",
"Mar-2016": 16690,
"Mar-2017": 19628,
"perc_change": 17.6
},
{
"vehicle": "GMC Sierra PU",
"Mar-2016": 16520,
"Mar-2017": 18900,
"perc_change": 14.4
},
{
"vehicle": "Chevrolet Malibu",
"Mar-2016": 10813,
"Mar-2017": 18577,
"perc_change": 71.8
},
{
"vehicle": "Subaru Outback",
"Mar-2016": 13075,
"Mar-2017": 17769,
"perc_change": 35.9
},
{
"vehicle": "Ford Fusion",
"Mar-2016": 19446,
"Mar-2017": 17560,
"perc_change": -9.7
},
{
"vehicle": "Jeep Grand Cherokee",
"Mar-2016": 17653,
"Mar-2017": 17230,
"perc_change": -2.4
}
];
// Code goes here
//setting the margins
var margin = {
top: 20,
right: 20,
bottom: 20,
left: 20
}
//setting width and height
var width = 300 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
yearVals = ["Mar-2016", "Mar-2017"]
//ranges
var xVehicles = d3.scaleBand().rangeRound([0, width], .1).paddingInner(0.1);
var xYears = d3.scaleBand().domain(yearVals).range([0, xVehicles.bandwidth()])
.paddingInner(.1)
.paddingOuter(5.0);
var yScale = d3.scaleLinear().domain([0, 85000]).range([height, 0]);
var colorScale = d3.scaleOrdinal()
.range(["#87ceeb", "#00bfff"]);
rows.forEach(function(data) {
chartGenerator(data)
})
d3.selectAll("svg.barSvg")
.data(rows)
.enter()
.append("text")
.text(function(d) {
return d.vehicle;
})
function chartGenerator(d) {
d.sales = yearVals.map(function(year) {
return {
"vehicle": d.vehicle,
year: year,
value: +d[year]
}
})
//create vehicle name
var vehicle = []
vehicle["name"] = d.vehicle;
var svgArea = d3.select("body")
.append("svg")
.attr("class", "barSvg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.append("g");
//vehicleText not appended to g element
//console.log(vehicleText.datum());
var vehicleBars = svgArea.selectAll("rect")
.data(d.sales)
.enter()
.append("rect")
.attr("class", "vehicleBars")
.attr("id", function(d) {
return "vehicle_" + d.vehicle + "_" + d.year
})
.attr("width", width / 4)
.attr("x", function(d) {
return xYears(d.year)
})
.attr("y", function(d) {
return yScale(d.value)
})
.attr("height", function(d) {
return height - yScale(d.value)
})
.attr("fill", function(d) {
return colorScale(d.year)
});
var vehicleText = svgArea.append("g")
.attr("id", "vehicle_" + d.vehicle);
vehicleText.append("text")
.attr("class", "annotation")
.attr("dx", width / 4)
.attr("dy", height + 20)
.text(d.vehicle);
}
/* Styles go here */
body {
width: 1200px;
}
h2,
h3 {
font-family: sans-serif;
padding: 20px 50px 0px 50px;
}
.barSvg {
background: white;
}
.vehicleData {
background: grey;
width: 25px;
height: 15px;
}
.annotation {
stroke: black;
stroke-width: black;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<body>
<h2>Auto Sales - March 2017</h2>
</body>
Upvotes: 1