Username Username - 6 months ago 17
HTML Question

D3 processes a stacked bar chart wrong

I have a CSV file named

dummydata_genreCountByYear.csv
. It looks like this:

Year,Unknown,show tunes,jazz,rock,heavy metal,rap,r&b,trap,hip hop
1950,1,2,5,,,,,,
1990,,,,2,2,2,,,
2016,,,,,,,5,1,3


I want to make a normalized stacked bar chart showing popularity of genres for each year. I'm mostly following this example of a normalized stacked bar chart.

Here's my
index.html
:

<div id="genre-by-year-chart-container" class="chart">
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.js" charset="utf-8"></script>
<script type="text/javascript">
var x, y, xAxis, yAxis;

var genreByYearContainerID= "genre-by-year-chart-container";
var margin= {
top: 50,
right: 30,
bottom: 100,
left: 0
};
var marginTop= margin.top;
var marginLeft= margin.left;
var marginBottom= margin.bottom;
var marginRight= margin.right;

var width= document.getElementById(genreByYearContainerID).clientWidth - marginRight - marginLeft;

var widthWithMargins= width+marginRight+marginLeft;
var height= 1000;

var chart= d3.select('#'+genreByYearContainerID)
.append("svg");
chart.attr('width',widthWithMargins);
chart.append('g')
.attr("transform","translate("+marginLeft+','+marginTop+')');

var color= d3.scale.category20();
d3.csv("dummydata_genreCountByYear.csv", function(error, data){
x= d3.scale
.ordinal()
.rangeRoundBands([0,width], 0.1);

y= d3.scale
.linear()
.rangeRound([height,0]);

xAxis= d3.svg.axis()
.scale(x)
.orient("bottom");

yAxis= d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(d3.format(".0%"));

color.domain(d3.keys(data[0])
.filter(function(key){
return key !== "Year";
}
));

data.forEach(function(d){
var y0= 0;
d.Genres= color.domain().map(function(name){
var obj= {
name: name,
y0: y0,
y1: y0 += +d[name]
};
return obj;
});

d.Genres.forEach(function(d){
d.y0 /= y0;
d.y1 /= y0;
});
});

data.sort(function(a,b){
return b.Genres[0].y1 + a.Genres[0].y1;
});

x.domain(data.map(function(d){
return d.Year;
}));

chart.append('g')
.attr("class","x axis")
.attr("transform","translate(0,"+height+')')
.call(xAxis);

chart.append('g')
.attr("class","y axis")
.call(yAxis);

var year= chart.selectAll(".year")
.data(data)
.enter()
.append('g')
.attr("class","year")
.attr("transform",function(d){
return "translate(" + x(d.Year) + ",0)";
});

year.selectAll("rect")
.data(function(d){
return d.Genres;
})
.enter()
.append("rect")
.attr("width",x.rangeBand())
.attr('y',function(d){
return y(d.y1);
})
.attr("height",function(d){
return y(d.y0) - y(d.y1);
})
.style("fill",function(d){
return color(d.name);
});
});
</script>


But when I open up the file, here's what I see:

Trying to make a normalized stacked bar chart

And when I inspect the elements of the DOM in my browser for each
.year
element, here's an example of what I see:

<g class="year" transform="translate(30,0)">
<rect width="261" y="1000" height="0" style="fill: rgb(31, 119, 180);">
<rect width="261" y="1000" height="0" style="fill: rgb(174, 199, 232);">
<rect width="261" y="1000" height="0" style="fill: rgb(255, 127, 14);">
<rect width="261" y="667" height="333" style="fill: rgb(255, 187, 120);">
<rect width="261" y="333" height="334" style="fill: rgb(44, 160, 44);">
<rect width="261" y="0" height="333" style="fill: rgb(152, 223, 138);">
<rect width="261" y="0" height="0" style="fill: rgb(214, 39, 40);">
<rect width="261" y="0" height="0" style="fill: rgb(255, 152, 150);">
<rect width="261" y="0" height="0" style="fill: rgb(148, 103, 189);">
</g>


The above HTML is for the leftmost
.year
element. The
rect
elements seem to have the correct
y
,
height
and
style
attributes. So why won't this code properly display a normalized stacked bar chart?

Answer

You have to define a height for your svg.

Something like (or whatever height you need for your area):

chart.attr('height', 1000);